Compare commits
1009 commits
v2.4.3-bet
...
develop
Author | SHA1 | Date | |
---|---|---|---|
|
7923e815f7 | ||
|
72d4968471 | ||
|
c286012bef | ||
|
c415c68443 | ||
|
e5fc8be2a8 | ||
|
20a087f64c | ||
|
a2eb68963b | ||
|
89be61ccf8 | ||
|
98d0bcac20 | ||
|
a282440118 | ||
|
7e72386da1 | ||
|
6f1e8e5853 | ||
|
906a3fed78 | ||
|
8329cf5537 | ||
|
1dd2d48068 | ||
|
43310f399d | ||
|
591f2457c3 | ||
|
8be5b722aa | ||
|
7249adb232 | ||
|
fbd1b9e78b | ||
|
2581c43ae7 | ||
|
2035619587 | ||
|
37f634ac80 | ||
|
d1e3e546f2 | ||
|
f8d80b2877 | ||
|
8589b2ed65 | ||
|
6645b1e36f | ||
|
316b9761d5 | ||
|
e2a62e99a0 | ||
|
692d0cb132 | ||
|
573e34fb48 | ||
|
f2bb5eb501 | ||
|
7ad6fca011 | ||
|
640150bcbe | ||
|
75c98a408c | ||
|
b8a8de98c3 | ||
|
85eb730186 | ||
|
024ea00a95 | ||
|
1530ad39a1 | ||
|
505a9b6846 | ||
|
30c341ef8b | ||
|
ccb64b1721 | ||
|
a1b3a612a5 | ||
|
247129c760 | ||
|
bb71dff815 | ||
|
ba18bed4d7 | ||
|
eb5fe6fef1 | ||
|
16a0f043b1 | ||
|
b760759906 | ||
|
2ce567e495 | ||
|
1143fba023 | ||
|
41279ae943 | ||
|
985187f866 | ||
|
53fef9021d | ||
|
df4a5a5867 | ||
|
3f3bf3e77e | ||
|
1b79f0b340 | ||
|
428549778c | ||
|
d9dae7af04 | ||
|
5f6be07fbd | ||
|
a94f7c6161 | ||
|
086c34a6a7 | ||
|
0044b2dee8 | ||
|
0cc4acd494 | ||
|
0d5bf1e467 | ||
|
85a98afcd9 | ||
|
96d89ca9d5 | ||
|
de79733957 | ||
|
af1b9f128e | ||
|
5145190584 | ||
|
314576ae13 | ||
|
87c022780d | ||
|
a8bd0bcd44 | ||
|
2f0c5d2eb9 | ||
|
ae32ca6917 | ||
|
5856517b0f | ||
|
1586cc2b49 | ||
|
bcf41ddd17 | ||
|
4017c4acb5 | ||
|
a646801c15 | ||
|
cb504c4bfb | ||
|
21e4552360 | ||
|
cdb9a220bd | ||
|
2d3809e6f7 | ||
|
0ff69bd24c | ||
|
dec4855816 | ||
|
89eaf3440a | ||
|
7953309c78 | ||
|
17e1ba60e5 | ||
|
4d84c491f1 | ||
|
79cf67eca6 | ||
|
c8c49b1ba2 | ||
|
8f2cb9c355 | ||
|
9ac27704fb | ||
|
97b39dfd76 | ||
|
8fc158e35b | ||
|
83d4878044 | ||
|
c9c71b40ef | ||
|
8cd4ac24a8 | ||
|
ca6b4a08a7 | ||
|
be9dbf52e0 | ||
|
4c4e36a534 | ||
|
7c4e3ad76e | ||
|
0c2c40d494 | ||
|
ecf5f07dbb | ||
|
8957ceb74d | ||
|
0deadc03c8 | ||
|
d5a5401db9 | ||
|
0aefdb3f21 | ||
|
9ad1c9f26b | ||
|
48b61f6953 | ||
|
2af05e4008 | ||
|
a13abe446b | ||
|
5ce9d47126 | ||
|
581af57bfd | ||
|
60abba3bfe | ||
|
5323ca64fa | ||
|
1b2fa594e8 | ||
|
36677fdccd | ||
|
896be7fb5f | ||
|
a2a6618959 | ||
|
39291bf1ce | ||
|
fbd468e03e | ||
|
d91c857fdc | ||
|
8eb124b54c | ||
|
f3624a3fa2 | ||
|
de4cf5219e | ||
|
7fdc43b69d | ||
|
df37641fa8 | ||
|
8edc14cfe7 | ||
|
8f2ac67659 | ||
|
c5ba4cb198 | ||
|
d44515f764 | ||
|
ccd68f1e78 | ||
|
fc16c6c3e8 | ||
|
b4e8bb0e12 | ||
|
5ca5ee6723 | ||
|
ce50158167 | ||
|
d5f7182cf4 | ||
|
9d97df04a7 | ||
|
bf32d59844 | ||
|
caf3cdea3d | ||
|
434c32003f | ||
|
48a31e8154 | ||
|
3fe3eda27b | ||
|
65070cb675 | ||
|
311d0b51b6 | ||
|
aca0a185b7 | ||
|
14bf9ac55f | ||
|
cf145123f5 | ||
|
c2a97f3100 | ||
|
296c459252 | ||
|
a176913bda | ||
|
721167a079 | ||
|
7e94208574 | ||
|
ef016cfb76 | ||
|
c2cbf36a87 | ||
|
6379533065 | ||
|
eec83daaf5 | ||
|
00a6724900 | ||
|
69e098d6e5 | ||
|
5bf24d6eac | ||
|
b6f1e76ae4 | ||
|
1fdb76008e | ||
|
681b477543 | ||
|
c2fa27329c | ||
|
299bf090fc | ||
|
a8f5f54a62 | ||
|
75f97ce32f | ||
|
09a96e6db9 | ||
|
f9558f960a | ||
|
1de94ca929 | ||
|
b639915fd4 | ||
|
12525e21ec | ||
|
3177578c64 | ||
|
4ea2fa8c31 | ||
|
a1c24359d2 | ||
|
6529fbf211 | ||
|
d881880c38 | ||
|
0a01420e9d | ||
|
c6f22a2753 | ||
|
c7b204022a | ||
|
1c7ad4d5bb | ||
|
be4cc1abe8 | ||
|
4969d28988 | ||
|
6962c399ea | ||
|
9533b55d8f | ||
|
c4d7f37cc2 | ||
|
5c4724d524 | ||
|
dfdd9b69cb | ||
|
475923d6d5 | ||
|
2674639383 | ||
|
d2fc602618 | ||
|
85bd7d40a5 | ||
|
303ca98d0b | ||
|
c63367b067 | ||
|
42ac0d33cc | ||
|
2a59c708b2 | ||
|
75b703d39f | ||
|
0f4fdf89b2 | ||
|
d2756db940 | ||
|
cfcbd8e6b7 | ||
|
cb69bb474c | ||
|
525cce3e92 | ||
|
cf6aef7ae0 | ||
|
b77ea37b2c | ||
|
488998cd33 | ||
|
f5378dea74 | ||
|
23b169708c | ||
|
b899130009 | ||
|
bb838ed83a | ||
|
4c53cd8830 | ||
|
1aa1ac0976 | ||
|
f4db877ddd | ||
|
0da41a1328 | ||
|
9970873ff5 | ||
|
129428ef80 | ||
|
e1501fd4d1 | ||
|
34c7903300 | ||
|
dd09ece4e7 | ||
|
c6b9114c42 | ||
|
7a9bc929a5 | ||
|
235ba679e3 | ||
|
32f7b9de62 | ||
|
9735a60883 | ||
|
b4088bf8b8 | ||
|
a1de9589b5 | ||
|
875b6d2b35 | ||
|
12355e087c | ||
|
6e8d6e9aee | ||
|
2a05aad0e9 | ||
|
4f1a21819d | ||
|
12e663ee93 | ||
|
9edc7c5cc0 | ||
|
793a5e22c5 | ||
|
10cf68161e | ||
|
21c4aa0b3a | ||
|
649254d0ac | ||
|
f5dc5fbae0 | ||
|
5124a805c8 | ||
|
982e597742 | ||
|
4a7057c038 | ||
|
78d11d74bd | ||
|
b1843ab14b | ||
|
4cb5d1e436 | ||
|
959e18ad91 | ||
|
4292d85a22 | ||
|
9f4ca2683f | ||
|
3e44027ab5 | ||
|
98d2a3b3ec | ||
|
0d8fc9028c | ||
|
f5e5d817be | ||
|
d5f00edb9d | ||
|
6e9fade8dd | ||
|
7045e97a24 | ||
|
fdc87ff8c4 | ||
|
81313c2445 | ||
|
0b8b4244bd | ||
|
7a8b86aadb | ||
|
1f59c15f5e | ||
|
da0c49da83 | ||
|
8f2eb27793 | ||
|
a1a68f7eea | ||
|
cd850c068d | ||
|
e987e34c78 | ||
|
53342c944e | ||
|
0b55c477e1 | ||
|
7e09c4eb66 | ||
|
adeb1acced | ||
|
95836a7dd1 | ||
|
88aa2491b0 | ||
|
73aa146f8a | ||
|
7d237c887f | ||
|
8d95e0bfe9 | ||
|
bd147fa285 | ||
|
ab9128ffb6 | ||
|
d2c92511ff | ||
|
9bd16473c9 | ||
|
ad3b8396be | ||
|
8a22f9db56 | ||
|
b00f5f1531 | ||
|
fc83bee80b | ||
|
0b64d50f4b | ||
|
ea6a5da3eb | ||
|
5bcdcdd5c6 | ||
|
9581b1b81a | ||
|
10216988d4 | ||
|
745373df6a | ||
|
23551a379b | ||
|
deef870213 | ||
|
37b731ff14 | ||
|
3c923ae943 | ||
|
b3c6f90a35 | ||
|
a2b217fdfc | ||
|
0725ea6b87 | ||
|
dad2744e71 | ||
|
94f079293b | ||
|
55f7328b3e | ||
|
5a74b0e722 | ||
|
3764946dfe | ||
|
1b7afe588b | ||
|
f7e2a59332 | ||
|
fc9def0879 | ||
|
7cd301fcbf | ||
|
16fec7c87f | ||
|
a7021b03e7 | ||
|
d24a73e349 | ||
|
d67310ec90 | ||
|
0f203fb198 | ||
|
aa8433f881 | ||
|
e54908be0d | ||
|
22bf6595da | ||
|
427485a1d7 | ||
|
23150ddb31 | ||
|
1a67fd5dec | ||
|
2d0b15ea7b | ||
|
611f3af772 | ||
|
e6804f1627 | ||
|
fecd696b2a | ||
|
3c87111710 | ||
|
592e7bcf27 | ||
|
d81b5ad955 | ||
|
fcac94a30e | ||
|
18397b13eb | ||
|
b4da3a51f7 | ||
|
b41a988d6f | ||
|
6c6937c507 | ||
|
6b179e673b | ||
|
2d1a52afe5 | ||
|
d4ce2a84cf | ||
|
7bd15d12ad | ||
|
17c987c605 | ||
|
fff05eb646 | ||
|
7be67accc1 | ||
|
a13726d4c5 | ||
|
9547411390 | ||
|
120c54a29e | ||
|
a6f2d34b7e | ||
|
458faff8a8 | ||
|
2cec8bdc5b | ||
|
8da6029624 | ||
|
9274ab16ed | ||
|
d5d39971b4 | ||
|
907566b39f | ||
|
7229d77bda | ||
|
d94325127f | ||
|
fe08cfd3ab | ||
|
fcc8d8e3fa | ||
|
e6e08e5d3e | ||
|
92a8ec4f68 | ||
|
b7a3110e7e | ||
|
b508ed6c9a | ||
|
1e69495728 | ||
|
30b41fdb88 | ||
|
c1eb0c54a3 | ||
|
cb7e0ed289 | ||
|
e6130dbf4a | ||
|
8e482321f2 | ||
|
8ad9e2bdd6 | ||
|
51e9ce5638 | ||
|
9150f07984 | ||
|
cd47070894 | ||
|
44e2ace833 | ||
|
5cf9311502 | ||
|
74b7ac834e | ||
|
a77a3d5a56 | ||
|
847dadac5d | ||
|
60590e0c49 | ||
|
415fc336ec | ||
|
81771eff4f | ||
|
6f9a3eb536 | ||
|
c6479c70c1 | ||
|
6cd8c35598 | ||
|
ffdd4f923d | ||
|
c32acd0123 | ||
|
63850a33c1 | ||
|
619de775fd | ||
|
48c528d76a | ||
|
52f82fc855 | ||
|
41e5d5ffff | ||
|
d7242d81a4 | ||
|
a925c81ba8 | ||
|
ceff398a01 | ||
|
dd7f59cef7 | ||
|
ff24ee604d | ||
|
560d076a5f | ||
|
2df7acf488 | ||
|
057f31407a | ||
|
e9be61cae2 | ||
|
66d26cfed6 | ||
|
b5a22379b8 | ||
|
405e0c2199 | ||
|
bd02c52d5a | ||
|
8032aa9f2f | ||
|
a95cd333d5 | ||
|
0618ff57e4 | ||
|
a3ce9bdb55 | ||
|
43d7dc026c | ||
|
0d7acafc44 | ||
|
080fcde440 | ||
|
adc505cef9 | ||
|
cc703ae3c6 | ||
|
7b2e2de3df | ||
|
06a5dab129 | ||
|
4d4f328527 | ||
|
49fc1e4e40 | ||
|
b2f53d48f7 | ||
|
75008dcb1a | ||
|
37af7b8db6 | ||
|
8a7225a249 | ||
|
55e0162a87 | ||
|
76392620be | ||
|
0e2d16982b | ||
|
fbb819d7a0 | ||
|
11119a6143 | ||
|
57adea3cc1 | ||
|
a923be53cd | ||
|
a107c868a0 | ||
|
3efe09ad72 | ||
|
f65f07dbcb | ||
|
bb6491bd06 | ||
|
0cc771f633 | ||
|
0fddb07c09 | ||
|
3c50b01c23 | ||
|
72d1a044d9 | ||
|
b26fdb424b | ||
|
1f58452b76 | ||
|
5a5d31f213 | ||
|
8948334d5d | ||
|
4eb9c9fdec | ||
|
5dcc721f15 | ||
|
803b3956fa | ||
|
fd981216da | ||
|
671f403602 | ||
|
33607acbb6 | ||
|
6f4e669e0d | ||
|
a6756ebe0f | ||
|
4b53d16ea0 | ||
|
5387763169 | ||
|
fb473007da | ||
|
c92ee47632 | ||
|
611d6d7b11 | ||
|
6f4df4b55e | ||
|
6ade0da597 | ||
|
a78632768c | ||
|
62f65ce3b9 | ||
|
049d2a72c8 | ||
|
94d126b0c8 | ||
|
e233ab4a74 | ||
|
506cc664b2 | ||
|
2d15a7a5cf | ||
|
80bfff384e | ||
|
252c63f4dd | ||
|
08c366d950 | ||
|
7b5106dd08 | ||
|
24ee35b95b | ||
|
ec8bbd2187 | ||
|
e695180049 | ||
|
3a5316cedc | ||
|
c45bed7f6c | ||
|
ca1f2a76d8 | ||
|
50b320063a | ||
|
bfe58a18e5 | ||
|
db6f80d721 | ||
|
0279637fe4 | ||
|
97cb7a678e | ||
|
0f2962a95f | ||
|
20254f7434 | ||
|
3fd109b6cd | ||
|
8b955ef002 | ||
|
23bc0f2c8f | ||
|
856f361271 | ||
|
e531d575be | ||
|
c0ebf12cc8 | ||
|
ed4f8eacea | ||
|
28051046d5 | ||
|
5fb5e1140a | ||
|
7dccc469b5 | ||
|
bd590213a1 | ||
|
fe2b976849 | ||
|
2981de95b0 | ||
|
51ab747019 | ||
|
c1c70e643a | ||
|
f5e052937c | ||
|
9639c5386f | ||
|
7e7d374263 | ||
|
37ef1d9bc6 | ||
|
86bc9bfd80 | ||
|
f53110c69b | ||
|
4d683a13c0 | ||
|
e2978029a5 | ||
|
024de4d8b3 | ||
|
b66e28faa0 | ||
|
c07cdbed3c | ||
|
c043f5058f | ||
|
e758986985 | ||
|
1c35c6951d | ||
|
36121007b1 | ||
|
19d579fc5c | ||
|
bb0a6f5854 | ||
|
7f91d512b8 | ||
|
de6a90a5ee | ||
|
fd8d64098f | ||
|
11209b4b42 | ||
|
663f151974 | ||
|
7771afc1a7 | ||
|
ea6df4705c | ||
|
1ce7ce8bfc | ||
|
86c8466ae4 | ||
|
55b72a49b6 | ||
|
33c9dce80d | ||
|
e6ed64ac7a | ||
|
8458cdb06f | ||
|
4dacd86bc3 | ||
|
792f188ecc | ||
|
71c1d38d50 | ||
|
74200f8dc4 | ||
|
048c9d40e7 | ||
|
41e4b81192 | ||
|
6a12853b65 | ||
|
d6d6db0aa3 | ||
|
d21398ee60 | ||
|
2b3cf88097 | ||
|
e2f0f8cc9b | ||
|
97f326a59c | ||
|
4d72f0be62 | ||
|
3d036256b2 | ||
|
96d45847f9 | ||
|
026cafad3f | ||
|
2c626844ef | ||
|
650aeb387b | ||
|
23839305d8 | ||
|
17e09df050 | ||
|
d405e92292 | ||
|
a969f9b3fb | ||
|
a40d4536f6 | ||
|
edc2e524f7 | ||
|
bc42f74b2b | ||
|
a1117918dd | ||
|
7cb8345e85 | ||
|
7a42800168 | ||
|
d3de5b778b | ||
|
e46b5a171f | ||
|
5273f8769d | ||
|
d6ff04cf17 | ||
|
b4e7246526 | ||
|
20d6eda1ad | ||
|
2ec4567f69 | ||
|
117e0de5bc | ||
|
f9a0695865 | ||
|
c2f1d19eaf | ||
|
9bceb39e26 | ||
|
72fea986d0 | ||
|
fa874ace12 | ||
|
cfeb9e01b7 | ||
|
4b6a8efe0f | ||
|
f37062c9b6 | ||
|
cd865e048e | ||
|
f890e2fcd3 | ||
|
972af21bca | ||
|
967ec86d9d | ||
|
a8f0b18219 | ||
|
0773d6b1d3 | ||
|
b1e228ea40 | ||
|
5463476a00 | ||
|
aa2c77abfc | ||
|
1fbb788528 | ||
|
49930e16f7 | ||
|
5555557cec | ||
|
d0921fb7b6 | ||
|
e7f24527c3 | ||
|
c4c60efab2 | ||
|
bf757bdc90 | ||
|
256aab9877 | ||
|
3b0c7992d2 | ||
|
bb0d96a005 | ||
|
2244f1ff77 | ||
|
28b6126853 | ||
|
2ab485de8c | ||
|
3518e37087 | ||
|
e9e75ea36b | ||
|
4552936e89 | ||
|
bf0a4e0d1a | ||
|
ba8a59b26f | ||
|
a3aeb38611 | ||
|
9e99a2ea96 | ||
|
882721f859 | ||
|
03940ad598 | ||
|
a1f6d78e04 | ||
|
ba3fd2202f | ||
|
ffc8bdd5f1 | ||
|
5e45f305ac | ||
|
55dd9484c9 | ||
|
bbfa32a115 | ||
|
7a70bbc51e | ||
|
93d59edb67 | ||
|
06ee6db7e7 | ||
|
a354b13139 | ||
|
ae009099ed | ||
|
5057c290c1 | ||
|
e242aa4ced | ||
|
e082156779 | ||
|
99c19b2a64 | ||
|
f608e176c1 | ||
|
8cabf0f87a | ||
|
b4ccf44d3a | ||
|
c68c13ab6e | ||
|
54c9a058df | ||
|
b1ba88c138 | ||
|
533d770753 | ||
|
8cc891a77f | ||
|
156ddee97c | ||
|
b93b7cdfd6 | ||
|
9f5c2f6829 | ||
|
62dc037d80 | ||
|
ae1ad39806 | ||
|
d347dac19e | ||
|
44edb9bdee | ||
|
a98f3f78af | ||
|
1196b05ff6 | ||
|
7d8823da6d | ||
|
593245f3fd | ||
|
60c9ed124d | ||
|
4c0fb344d1 | ||
|
9f16cc42f5 | ||
|
614be34081 | ||
|
b932cfc9ad | ||
|
73806c2d30 | ||
|
79e3c94669 | ||
|
f67e8947a5 | ||
|
d968730adf | ||
|
fabdac887e | ||
|
6f6ee7b54f | ||
|
087b038d77 | ||
|
73145888e6 | ||
|
3615abd4e2 | ||
|
72f2d14427 | ||
|
8ccaf4ac1d | ||
|
778c1de6eb | ||
|
a32aefe541 | ||
|
3c561af93d | ||
|
7eaeef821e | ||
|
7030185e4f | ||
|
5abf974682 | ||
|
fa146b1434 | ||
|
c52e878c01 | ||
|
050c17ee06 | ||
|
7109374d42 | ||
|
08350b884b | ||
|
bacbf8109b | ||
|
3e5a55b1e9 | ||
|
9de723d014 | ||
|
a0a3ef669e | ||
|
1c63d94736 | ||
|
32b5a2b5d0 | ||
|
3b93e92960 | ||
|
5ec7dec9f0 | ||
|
8a64b77e63 | ||
|
b23c831da5 | ||
|
eaaa7bb0e1 | ||
|
c49853d724 | ||
|
642155292a | ||
|
c9c6e7efc1 | ||
|
1ba1b756c9 | ||
|
f158d7f266 | ||
|
cef3a98b4e | ||
|
31f782e333 | ||
|
3e95a46bd2 | ||
|
52c0a0ebf3 | ||
|
b896c85bf0 | ||
|
7b72b24ee2 | ||
|
e771c9da81 | ||
|
9bd395007f | ||
|
2723e1cfb5 | ||
|
56df419bea | ||
|
9e3153453e | ||
|
26484130c3 | ||
|
495956d907 | ||
|
d95dab9f0c | ||
|
f99411f2f9 | ||
|
cdad0d6289 | ||
|
c5a7d7027c | ||
|
54e5e96ad2 | ||
|
fd349fb0fc | ||
|
0c8efd5331 | ||
|
5572833652 | ||
|
b7b7bad2fb | ||
|
44b1762b7d | ||
|
512fb63e1f | ||
|
5d4d68fe32 | ||
|
7647755e96 | ||
|
ef25c50e16 | ||
|
4aabb73847 | ||
|
cda07bf8d9 | ||
|
e19fab0615 | ||
|
e0980cf396 | ||
|
3d29b6b6a1 | ||
|
8faa3ae32d | ||
|
d15e683955 | ||
|
3ddfb4d594 | ||
|
ce64d7973b | ||
|
36dc01bf30 | ||
|
148d3fdb18 | ||
|
a6a4417eff | ||
|
849ed16d67 | ||
|
11e0e84dcf | ||
|
430182a0a5 | ||
|
48c9d9fa16 | ||
|
3cc3e387c5 | ||
|
ef6ed93ecd | ||
|
3b044e3044 | ||
|
b8c7a7c7e5 | ||
|
e2bb8cf0de | ||
|
3d3bd91700 | ||
|
e720430aa4 | ||
|
c76ee8cd4f | ||
|
10b604ef89 | ||
|
6b27126c37 | ||
|
d0f92113f4 | ||
|
fe018ee241 | ||
|
1c78a30535 | ||
|
921ebdcdd5 | ||
|
5ad5bac786 | ||
|
40a1a871cb | ||
|
8754837f15 | ||
|
7ccadebca0 | ||
|
a529ee5d06 | ||
|
0c9b6cf85f | ||
|
f686e2b9f0 | ||
|
7e6dd354cf | ||
|
7d04fb904a | ||
|
72170304ef | ||
|
74ae5f039b | ||
|
be05f96c26 | ||
|
6b096761e0 | ||
|
e257194d17 | ||
|
7974f30261 | ||
|
c500730ae6 | ||
|
7657bd7221 | ||
|
3055cca767 | ||
|
0b50ae1be0 | ||
|
530190df7a | ||
|
1390493a29 | ||
|
ace6b8004c | ||
|
a9c539821f | ||
|
5e87ff1ce6 | ||
|
e84bb603eb | ||
|
6fc252b2c7 | ||
|
104fa2caca | ||
|
17c7f4c648 | ||
|
c6815621df | ||
|
b38d765759 | ||
|
f99387b3e5 | ||
|
b66ce460b6 | ||
|
36db809588 | ||
|
305127137a | ||
|
e23909881a | ||
|
0e9ae8ee8a | ||
|
f13a0b5849 | ||
|
a6362a993c | ||
|
4c5d59a5bc | ||
|
192c05ce0d | ||
|
dd74b14d76 | ||
|
1f19bd9f1e | ||
|
202859cea1 | ||
|
eebadd188a | ||
|
002a39db2a | ||
|
1e7d682df5 | ||
|
e76762dd4d | ||
|
6369026925 | ||
|
b357f935d4 | ||
|
09bcfa2242 | ||
|
50c053cf56 | ||
|
dc95b4c098 | ||
|
eb0c694cc8 | ||
|
e116a95e34 | ||
|
f849805a73 | ||
|
7bacf4a5f0 | ||
|
1c66ac2da2 | ||
|
98863bcc23 | ||
|
1714d1eeef | ||
|
df151d4dbc | ||
|
6639546413 | ||
|
06e5b4baf6 | ||
|
c3ddd7f2bf | ||
|
a3f4f6b944 | ||
|
b9a6d029e2 | ||
|
b9cf470871 | ||
|
5a44385a54 | ||
|
0560963c63 | ||
|
1d222d67d5 | ||
|
4f79803885 | ||
|
b99cebcee6 | ||
|
2ac4bab4d5 | ||
|
f7c78f63a0 | ||
|
67682e7e93 | ||
|
e6c0a16342 | ||
|
021ec61a81 | ||
|
0e90342b02 | ||
|
487b0c44ae | ||
|
76fd132409 | ||
|
0d61e102c0 | ||
|
3df5c62b5e | ||
|
2244672e33 | ||
|
dc776b171a | ||
|
3f3bdbeeda | ||
|
115f790210 | ||
|
eca002ac29 | ||
|
6e28b0b4a1 | ||
|
fbb40b75f6 | ||
|
ea845a8408 | ||
|
ac0c49918d | ||
|
bd1c5c3f62 | ||
|
8a78c34917 | ||
|
ef563c807f | ||
|
a32070b08a | ||
|
9f386163a4 | ||
|
897943857d | ||
|
b535782621 | ||
|
ea7357ca26 | ||
|
f80f033d5d | ||
|
99d0198530 | ||
|
c06b5cf297 | ||
|
2e254d55fb | ||
|
b117c7a260 | ||
|
9e6cd8820f | ||
|
b6b6e7750e | ||
|
f0e8fa2060 | ||
|
18058c74e5 | ||
|
a6b828e892 | ||
|
5c0a2d4c4e | ||
|
61f8406412 | ||
|
dbd12fc500 | ||
|
08a0c2d11f | ||
|
6980ed1906 | ||
|
c155bafa84 | ||
|
e0c53c28bb | ||
|
f041402533 | ||
|
bddec64faa | ||
|
57de4f9ba4 | ||
|
9f1bef7fde | ||
|
e9fd5cdc0e | ||
|
c47c1e209e | ||
|
ada7393979 | ||
|
d4ca29ed2c | ||
|
31ada29a37 | ||
|
4d58bac123 | ||
|
7930d9750a | ||
|
d111b04c14 | ||
|
f8513d3859 | ||
|
3bce055c89 | ||
|
8b70497802 | ||
|
fc8eafa451 | ||
|
870f9aed17 | ||
|
9a4c3e41a6 | ||
|
37c5b0eb11 | ||
|
2f4ec7ca98 | ||
|
16e313ab70 | ||
|
b25ea7409a | ||
|
f999caa3a3 | ||
|
3fb9fe5e28 | ||
|
b0de760621 | ||
|
7cf977a3cb | ||
|
e1cbce8a08 | ||
|
68cf2d773d | ||
|
2e9e857b7b | ||
|
3dec22651e | ||
|
9fe56b9e10 | ||
|
80bd3f214a | ||
|
6d339f486e | ||
|
867397eccd | ||
|
4adbe5e29a | ||
|
b71b6a99f3 | ||
|
243ccd9e37 | ||
|
7d5d1e0ea9 | ||
|
12e39ffd61 | ||
|
2ac883abb6 | ||
|
e03021a94c | ||
|
e5fc51213b | ||
|
fbad9bf83e | ||
|
33b1636229 | ||
|
9122f09dae | ||
|
cb5bb2e190 | ||
|
eddf37a1b5 | ||
|
ae6041a010 | ||
|
b1f936e65c | ||
|
558d331d66 | ||
|
42c222a6c8 | ||
|
b6d77e4048 | ||
|
48cde1b473 | ||
|
bade28a0b0 | ||
|
6e5d43ca78 | ||
|
c3a8453e94 | ||
|
68e72958b8 | ||
|
45f051f51a | ||
|
4cad215560 | ||
|
e9d909a3ba | ||
|
4b2645cbae | ||
|
e3aa088fa7 | ||
|
6da3b6dc01 | ||
|
7f06e11d7a | ||
|
f07774e351 | ||
|
3ad9e37d31 | ||
|
b511461cfa | ||
|
046ebc7514 | ||
|
cfdd05358a | ||
|
336936651f | ||
|
09cd77e8dc | ||
|
d68b9e1ca1 | ||
|
142e6f597e | ||
|
514ee309b8 | ||
|
e23c4b78b5 | ||
|
8ec661b8a3 | ||
|
616e33d2b4 | ||
|
e75fa75e65 | ||
|
96de70704d | ||
|
4d97110183 | ||
|
a52f46949e | ||
|
c38c39efee | ||
|
7a465eabeb | ||
|
99555c41b5 | ||
|
b2fc1dcce8 | ||
|
f25b672a0e | ||
|
975e4ba7e2 | ||
|
57de3b7d81 | ||
|
b0b98d85fe | ||
|
9e72d10c4c | ||
|
66d03d133f | ||
|
5b029e6117 | ||
|
4ee4f388f4 | ||
|
748ad738e2 | ||
|
4de3606084 | ||
|
8c2de0e6d7 | ||
|
05d0a0cc83 | ||
|
93bcd9bdfe | ||
|
d916f66dbf | ||
|
b76a1c43da | ||
|
ebba342779 | ||
|
169e62f1b0 | ||
|
171ce3428d | ||
|
d20ce3d383 | ||
|
9ee4c21f6b | ||
|
12e01656f0 | ||
|
de6e31582f | ||
|
c93aa02036 | ||
|
ced8d251d9 | ||
|
07f41e8cfa | ||
|
c9f76e595e | ||
|
5cb8ea2886 | ||
|
29234ddc35 | ||
|
c381d56630 | ||
|
631e08a557 | ||
|
7c3abb2625 | ||
|
3c7dcbadbe | ||
|
6f71c98e13 | ||
|
40a7fcdbeb | ||
|
5eaf94a18f | ||
|
32429933f9 | ||
|
971deb387b | ||
|
5455158ea0 | ||
|
c64a17e97c | ||
|
2553c1244d | ||
|
6b1ac328fd | ||
|
bfd1cf5eb8 | ||
|
a54ed90259 | ||
|
ce07fedc06 | ||
|
3e22bf9292 | ||
|
4fb6263212 | ||
|
526867bcdd | ||
|
66e23d1444 | ||
|
626a18a6ec | ||
|
fb184c5f5e | ||
|
5922ca41ee | ||
|
2b2f24449f | ||
|
0e083ad600 | ||
|
64a31e301d | ||
|
0a74fe9cef | ||
|
888981c11e | ||
|
832b9229f3 | ||
|
b509af6798 | ||
|
b2187269d1 | ||
|
40a40af952 | ||
|
982aad0a16 | ||
|
99e2f7bab8 | ||
|
14bcb2c1af | ||
|
a11aa24c7e | ||
|
4c2f2861db | ||
|
6abee8e9d6 | ||
|
78aa2548ac | ||
|
0702e6f2b6 | ||
|
4ca6e3f95f | ||
|
686fc0cfdf | ||
|
c9fc298317 | ||
|
f7a49d715e | ||
|
89624c155b | ||
|
8d702fee9d | ||
|
e4f1453cc9 | ||
|
919ab7902d | ||
|
52a0ccb780 | ||
|
28093894ad | ||
|
4238ca57de | ||
|
be38cfa87a | ||
|
c1b93cf81b | ||
|
2a3fd820b9 | ||
|
d9951b54c0 | ||
|
9f9c0089c8 | ||
|
74724b2185 | ||
|
ca73c74a8e | ||
|
404760876f |
8
.build/allow_all_python_version.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import toml
|
||||||
|
|
||||||
|
pyproject = toml.load("pyproject.toml")
|
||||||
|
|
||||||
|
pyproject["tool"]["poetry"]["dependencies"]["python"] = "*"
|
||||||
|
|
||||||
|
with open("pyproject.toml", "w") as toml_file:
|
||||||
|
toml.dump(pyproject, toml_file)
|
|
@ -1,64 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
BRANCH=$TRAVIS_BRANCH
|
|
||||||
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
|
|
||||||
BRANCH='master'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if branch has been updated since this build started
|
|
||||||
# This tends to happen if multiple things have been merged in at the same time.
|
|
||||||
if [[ -z $TRAVIS_TAG ]]; then
|
|
||||||
git fetch origin
|
|
||||||
if [[ $(git rev-parse "origin/${BRANCH}") != $TRAVIS_COMMIT ]]; then
|
|
||||||
echo "${BRANCH} has been updated since build started. Aborting changelog."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
FILENAME='CHANGELOG.md'
|
|
||||||
|
|
||||||
# get the latest git tags
|
|
||||||
releases="$(git tag --sort=-creatordate | grep -Ev '(alpha|beta|rc)')"
|
|
||||||
release_latest=$(printf '%s' "$releases" | awk 'NR==1')
|
|
||||||
release_secondlatest=$(printf '%s' "$releases" | awk 'NR==2')
|
|
||||||
|
|
||||||
echo "release_latest: ${release_latest}"
|
|
||||||
echo "release_secondlatest: ${release_secondlatest}"
|
|
||||||
|
|
||||||
# delete generated line (or it will be added multiple times)
|
|
||||||
sed -i '/This Changelog was automatically generated by/d' "$FILENAME"
|
|
||||||
|
|
||||||
# delete trailing empty lines
|
|
||||||
sed -i -e :a -e '/^\n*$/{$d;N;};/\n$/ba' "$FILENAME"
|
|
||||||
|
|
||||||
# determine correct tag to go back to
|
|
||||||
if [[ $TRAVIS_TAG == $release_latest ]]; then
|
|
||||||
echo "release build"
|
|
||||||
gittag=${release_secondlatest}
|
|
||||||
elif [[ ! -z $TRAVIS_TAG ]]; then
|
|
||||||
echo "beta elease"
|
|
||||||
gittag=${release_latest}
|
|
||||||
else
|
|
||||||
echo "merge into master or develop"
|
|
||||||
gittag=${release_latest}
|
|
||||||
fi
|
|
||||||
echo "gittag: ${gittag}"
|
|
||||||
|
|
||||||
# find the line the tag starts on, and subtract 1
|
|
||||||
tagline=$(grep -n "^## \[\?$gittag\]\?" "$FILENAME" | awk '{print $1}' FS=':' | head -1)
|
|
||||||
echo "tagline: ${tagline}"
|
|
||||||
[[ ! -z $tagline ]] && sed -i "1,$(expr $tagline - 1)d" "$FILENAME"
|
|
||||||
|
|
||||||
# generate the changelog
|
|
||||||
docker run -it --rm -v "$(pwd)":/usr/local/src/your-app ferrarimarco/github-changelog-generator -t $GITHUB_TOKEN --since-tag $gittag
|
|
||||||
|
|
||||||
# Put back our link (instead of the broken one)
|
|
||||||
sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME"
|
|
||||||
|
|
||||||
git config --global user.email "jrnl.bot@gmail.com"
|
|
||||||
git config --global user.name "Jrnl Bot"
|
|
||||||
git checkout $BRANCH
|
|
||||||
git add "$FILENAME"
|
|
||||||
git commit -m "Update changelog [ci skip]"
|
|
||||||
git push https://${GITHUB_TOKEN}@github.com/jrnl-org/jrnl.git $BRANCH
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# This file is a template, and might need editing before it works on your project.
|
|
||||||
# Official language image. Look for the different tagged releases at:
|
|
||||||
# https://hub.docker.com/r/library/python/tags/
|
|
||||||
image: python:latest
|
|
||||||
|
|
||||||
# Change pip's cache directory to be inside the project directory since we can
|
|
||||||
# only cache local items.
|
|
||||||
variables:
|
|
||||||
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
|
||||||
|
|
||||||
# Pip's cache doesn't store the python packages
|
|
||||||
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
|
|
||||||
#
|
|
||||||
# If you want to also cache the installed packages, you have to install
|
|
||||||
# them in a virtualenv and cache it as well.
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- .cache/pip
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- python -V # Print out python version for debugging
|
|
||||||
- pip install poetry
|
|
||||||
|
|
||||||
release:
|
|
||||||
rules:
|
|
||||||
- if: $RELEASE != null
|
|
||||||
script:
|
|
||||||
- git config --global user.email "jrnl.bot@gmail.com"
|
|
||||||
- git config --global user.name "Jrnl Bot"
|
|
||||||
- git checkout "$CI_COMMIT_BRANCH"
|
|
||||||
- poetry version "$RELEASE"
|
|
||||||
- echo __version__ = \"$RELEASE\" > jrnl/__version__.py
|
|
||||||
- git add pyproject.toml jrnl/__version__.py
|
|
||||||
- git commit -m "Increment version to ${RELEASE}"
|
|
||||||
- git tag -a -m "$RELEASE" "$RELEASE"
|
|
||||||
- git push --follow-tags "https://${GITHUB_TOKEN}@github.com/jrnl-org/jrnl.git" "$CI_COMMIT_BRANCH"
|
|
2
.gitattributes
vendored
|
@ -1,2 +1,4 @@
|
||||||
*.journal text eol=lf
|
*.journal text eol=lf
|
||||||
*.feature text eol=lf
|
*.feature text eol=lf
|
||||||
|
poetry.lock text eol=lf
|
||||||
|
pyrpoject.toml text eol=lf
|
||||||
|
|
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,42 +0,0 @@
|
||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: ":new:, bug"
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Bug Report
|
|
||||||
<!--
|
|
||||||
Hello, and thank you for reporting an issue!
|
|
||||||
Please fill out the points below, as it will make our process much easier.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- Please tell us about your environment -->
|
|
||||||
### Environment
|
|
||||||
- Jrnl version: <!-- Run `jrnl -v` -->
|
|
||||||
- Install method: <!-- How did you install jrnl? (pipx, brew, etc) -->
|
|
||||||
- OS <!-- What is your operating system? (MacOS, Linux, Windows) -->
|
|
||||||
|
|
||||||
### Current Behavior
|
|
||||||
<!--
|
|
||||||
Please put a short description of what is currently happening.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Expected Behavior
|
|
||||||
<!--
|
|
||||||
Please write a short description of what you would expect to happen
|
|
||||||
(instead of what is currently happening).
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Repro Steps
|
|
||||||
<!--
|
|
||||||
Please provide the steps to reproduce the problem. It is important for you to
|
|
||||||
be as precise as possible here, since more info will let us help you faster.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Other Information
|
|
||||||
<!-- (e.g. more detailed explanation, stacktraces, related
|
|
||||||
issues, suggestions how to fix, links for us to have context, eg.
|
|
||||||
stackoverflow, gitter, etc) -->
|
|
74
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
name: Bug Report
|
||||||
|
description: Create a report to help us improve
|
||||||
|
title: "Bug Report"
|
||||||
|
labels: [ ":new:", "bug" ]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# Bug Report
|
||||||
|
Hello, and thank you for reporting an issue!
|
||||||
|
|
||||||
|
Please fill out the points below, as it will make our process much easier.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: diagnostic
|
||||||
|
attributes:
|
||||||
|
label: Diagnostic output
|
||||||
|
description: Run `jrnl --diagnostic` and paste the output below
|
||||||
|
placeholder: Paste output here
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: current-behavior
|
||||||
|
attributes:
|
||||||
|
label: Current Behavior
|
||||||
|
description: Please put a short description of what is currently happening.
|
||||||
|
placeholder: Tell us what is happening
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
attributes:
|
||||||
|
label: Expected Behavior
|
||||||
|
description: Please write a short description of what you would expect to happen
|
||||||
|
placeholder: Tell us what should be happening
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: repro-steps
|
||||||
|
attributes:
|
||||||
|
label: Repro Steps
|
||||||
|
description: |
|
||||||
|
Provide the steps to reproduce the problem.
|
||||||
|
|
||||||
|
Please be as precise as possible, since more info will let us help you faster.
|
||||||
|
placeholder: Repro steps
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: debug-output
|
||||||
|
attributes:
|
||||||
|
label: Debug output
|
||||||
|
description: |
|
||||||
|
Please provide the output of your command with the `--debug` flag on.
|
||||||
|
placeholder: "example: `jrnl --debug lorem ipsum`"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: other-info
|
||||||
|
attributes:
|
||||||
|
label: Other Information
|
||||||
|
description: >
|
||||||
|
Is there anything else we should know?
|
||||||
|
|
||||||
|
(e.g. more detailed explanation, stacktraces, related
|
||||||
|
issues, suggestions how to fix, links for us to have context, eg.
|
||||||
|
stackoverflow, gitter, etc)
|
||||||
|
validations:
|
||||||
|
required: false
|
41
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
name: Documentation Change
|
||||||
|
description: Request or report any updates to our documentation (https://jrnl.sh)
|
||||||
|
title: Documentation Change
|
||||||
|
labels: [ ":new:", "documentation" ]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# Documentation Change
|
||||||
|
Hello, and thank you for reporting an issue!
|
||||||
|
|
||||||
|
Please fill out the points below, as it will make our process much easier.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: affected-pages
|
||||||
|
attributes:
|
||||||
|
label: Affected Page(s)
|
||||||
|
description: >
|
||||||
|
Please tell us which page, or pages, from the documentation site
|
||||||
|
(https://jrnl.sh) are affected in this issue
|
||||||
|
placeholder: "example: https://jrnl.sh/en/stable/overview"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: what-could-be-better
|
||||||
|
attributes:
|
||||||
|
label: What Could Be Better?
|
||||||
|
description: >
|
||||||
|
Please write a short description of what you hope can be clarified or
|
||||||
|
further explained.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: other-info
|
||||||
|
attributes:
|
||||||
|
label: Other Information
|
||||||
|
description: Is there anything else we should know that might be helpful?
|
||||||
|
validations:
|
||||||
|
required: false
|
31
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for jrnl
|
|
||||||
title: ''
|
|
||||||
labels: ":new:, enhancement"
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Feature Request
|
|
||||||
<!--
|
|
||||||
Hello, and thank you for reporting an issue!
|
|
||||||
Please fill out the points below, as it will make our process much easier.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Use Case/Motivation
|
|
||||||
<!--
|
|
||||||
What is the motivation / use case for changing the behavior?
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Example Usage
|
|
||||||
<!--
|
|
||||||
Please provide examples of the usage you would like to see.
|
|
||||||
e.g `jrnl --new-flag="super cool new feature"`
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Other information
|
|
||||||
<!--
|
|
||||||
Please provide any other relevant info about this request (e.g. stacktraces,
|
|
||||||
related issues, suggestions how to fix, etc)
|
|
||||||
-->
|
|
43
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
name: Feature Request
|
||||||
|
description: Suggest an idea for jrnl
|
||||||
|
title: "Feature Report"
|
||||||
|
labels: [ ":new:", "enhancement" ]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# Feature Request
|
||||||
|
Hello, and thank you for reporting an issue!
|
||||||
|
|
||||||
|
Please fill out the points below, as it will make our process much easier.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: user-case
|
||||||
|
attributes:
|
||||||
|
label: Use Case/Motivation
|
||||||
|
description: What is the motivation / use case for changing the behavior?
|
||||||
|
placeholder: Tell us about your idea
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: example-usage
|
||||||
|
attributes:
|
||||||
|
label: Example Usage
|
||||||
|
description: Please provide examples of the usage you would like to see.
|
||||||
|
placeholder: e.g `jrnl --new-flag="super cool new feature"`
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: other-info
|
||||||
|
attributes:
|
||||||
|
label: Other Information
|
||||||
|
description: >
|
||||||
|
Is there anything else we should know?
|
||||||
|
|
||||||
|
(e.g. more detailed explanation, stacktraces, related
|
||||||
|
issues, suggestions how to fix, links for us to have context, eg.
|
||||||
|
stackoverflow, gitter, etc)
|
||||||
|
validations:
|
||||||
|
required: false
|
39
.github/ISSUE_TEMPLATE/support_request.md
vendored
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
name: Support Request
|
|
||||||
about: Get help with jrnl
|
|
||||||
title: ''
|
|
||||||
labels: ":new:, support"
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Support Request
|
|
||||||
<!--
|
|
||||||
Hello, and thank you for reporting an issue!
|
|
||||||
Please fill out the points below, as it will make our process much easier.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Environment
|
|
||||||
<!--
|
|
||||||
Please tell us about your environment
|
|
||||||
-->
|
|
||||||
- Jrnl version: <!-- Run `jrnl -v` -->
|
|
||||||
- Install method: <!-- How did you install jrnl? (pipx, brew, etc) -->
|
|
||||||
- OS <!-- What is your operating system? (MacOS, Linux, Windows) -->
|
|
||||||
|
|
||||||
### What are you trying to do?
|
|
||||||
<!--
|
|
||||||
Please write a short description of what is happening.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### What have you tried?
|
|
||||||
<!--
|
|
||||||
Have you tried anything to fix the problem? This can help give us more
|
|
||||||
information to help you with.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Other Information
|
|
||||||
<!--
|
|
||||||
Is there anything else we should know that might be helpful?
|
|
||||||
e.g. detailed explanation, stacktraces, related issues, suggestions how to fix
|
|
||||||
-->
|
|
54
.github/ISSUE_TEMPLATE/support_request.yaml
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
name: Support Request
|
||||||
|
description: Get help with jrnl
|
||||||
|
title: Support Request
|
||||||
|
labels: [ ":new:", "support" ]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# Support Request
|
||||||
|
Hello, and thank you for reporting an issue!
|
||||||
|
|
||||||
|
Please fill out the points below, as it will make our process much easier.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: diagnostic
|
||||||
|
attributes:
|
||||||
|
label: Diagnostic output
|
||||||
|
description: Run `jrnl --diagnostic` and paste the output below
|
||||||
|
placeholder: Paste output here
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: current-behavior
|
||||||
|
attributes:
|
||||||
|
label: What are you trying to do?
|
||||||
|
description: Please put a short description of what is happening.
|
||||||
|
placeholder: Tell us what is happening
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: tried
|
||||||
|
attributes:
|
||||||
|
label: What have you tried?
|
||||||
|
description: >
|
||||||
|
Have you tried anything to fix the problem? This can help give us more
|
||||||
|
information to help you with.
|
||||||
|
placeholder: Tell us what should be happening
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: other-info
|
||||||
|
attributes:
|
||||||
|
label: Other Information
|
||||||
|
description: >
|
||||||
|
Is there anything else we should know?
|
||||||
|
|
||||||
|
(e.g. more detailed explanation, stacktraces, related
|
||||||
|
issues, suggestions how to fix, links for us to have context, eg.
|
||||||
|
stackoverflow, gitter, etc)
|
||||||
|
validations:
|
||||||
|
required: false
|
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -12,15 +12,13 @@ Here are some key points to include in your description:
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
|
||||||
- [ ] I have read the [contributing doc](https://github.com/jrnl-org/jrnl/blob/develop/CONTRIBUTING.md).
|
- [ ] I have read the [contributing doc](https://github.com/jrnl-org/jrnl/blob/develop/docs/contributing.md).
|
||||||
- [ ] I have included a link to the relevant issue number.
|
- [ ] I have included a link to the relevant issue number.
|
||||||
- [ ] I have tested this code locally.
|
|
||||||
- [ ] I have checked to ensure there aren't other open [pull requests](../pulls)
|
- [ ] I have checked to ensure there aren't other open [pull requests](../pulls)
|
||||||
for the same issue.
|
for the same issue.
|
||||||
- [ ] I have you written new tests for these changes, as needed.
|
- [ ] I have written new tests for these changes, as needed.
|
||||||
- [ ] All tests pass.
|
|
||||||
<!--
|
<!--
|
||||||
NOTE: Your PR may not be reviewed if there are any failing tests. You can run
|
NOTE: Your PR may not be reviewed if there are any failing tests. You can run
|
||||||
tests locally with `make test` (see the contributing doc if you need help with
|
tests locally with `poe test` (see the contributing doc if you need help with
|
||||||
`make`), or use our automated tests after you submit your PR.
|
`poe`), or use our automated tests after you submit your PR.
|
||||||
-->
|
-->
|
||||||
|
|
17
.github/actionlint-matcher.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "actionlint",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"column": 3,
|
||||||
|
"message": 4,
|
||||||
|
"code": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
46
.github/actions/run_tests/action.yaml
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
name: run jrnl tests
|
||||||
|
description: Runs all jrnl tests on multiple platforms
|
||||||
|
inputs:
|
||||||
|
cache-string:
|
||||||
|
description: 'Cache string secret. Change to bust the cache'
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- run: git config --global core.autocrlf false
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
allow-prereleases: true
|
||||||
|
|
||||||
|
- name: Capture full Python version in env
|
||||||
|
run: echo "PYTHON_FULL_VERSION=$(python --version)" >> $GITHUB_ENV
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: poetry cache # Change CACHE_STRING secret to bust the cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .venv
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ env.PYTHON_FULL_VERSION }}-${{ inputs.cache-string }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
echo '::group::poetry'
|
||||||
|
pip --disable-pip-version-check install poetry
|
||||||
|
poetry config --local virtualenvs.in-project true
|
||||||
|
echo '::endgroup::'
|
||||||
|
|
||||||
|
echo '::group::Other dependencies'
|
||||||
|
poetry sync
|
||||||
|
echo '::endgroup::'
|
||||||
|
|
||||||
|
echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Linting & Testing
|
||||||
|
if: ${{ env.DEPS_INSTALLED == 'true' }}
|
||||||
|
run: poetry run poe test
|
||||||
|
shell: bash
|
14
.github/renovate.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
],
|
||||||
|
"schedule": [ "at any time" ],
|
||||||
|
"prConcurrentLimit": 10,
|
||||||
|
"prHourlyLimit": 10,
|
||||||
|
"reviewers": [
|
||||||
|
"wren",
|
||||||
|
"micahellison"
|
||||||
|
],
|
||||||
|
"labels": [ "packaging" ]
|
||||||
|
}
|
170
.github/workflows/changelog.yaml
vendored
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
name: Changelog
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
if: >
|
||||||
|
! contains(github.event.head_commit.message, '[ci skip]') &&
|
||||||
|
! (
|
||||||
|
startsWith(github.event.head_commit.message, 'Increment version to v') &&
|
||||||
|
startsWith(github.ref, 'refs/heads/')
|
||||||
|
)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Check branch for new commits, and env vars
|
||||||
|
run: |
|
||||||
|
echo "::group::git fetch origin --tags --force"
|
||||||
|
git fetch origin --tags --force
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
TAG_REGEX='include-all'
|
||||||
|
echo "::debug::GITHUB_REF: $GITHUB_REF"
|
||||||
|
BRANCH="${GITHUB_REF##*/}"
|
||||||
|
|
||||||
|
if [[ $GITHUB_REF =~ ^refs/tags/ ]]; then
|
||||||
|
# This is a tag build (i.e. a release)
|
||||||
|
echo '::debug::Release build'
|
||||||
|
if [[ ! $BRANCH =~ ^v[0-9]+(\.[0-9]+){1,2}(-(alpha|beta)([0-9]+)?)?$ ]]; then
|
||||||
|
echo "::error::Invalid tag format: ${BRANCH}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RELEASE=1
|
||||||
|
BRANCH=develop
|
||||||
|
git checkout $BRANCH
|
||||||
|
|
||||||
|
# if actual release (not pre), then changelog should exclude prereleases on update
|
||||||
|
prerelease_regex='(alpha|beta)'
|
||||||
|
if [[ ! ${GITHUB_REF##*/} =~ $prerelease_regex ]]; then
|
||||||
|
echo '::debug::Actual release (not a prerelease)'
|
||||||
|
TAG_REGEX="$prerelease_regex"
|
||||||
|
echo "FULL_RELEASE=true" >> "$GITHUB_ENV"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "::debug::TAG_REGEX: $TAG_REGEX"
|
||||||
|
|
||||||
|
if [[ "$(git rev-parse "origin/$BRANCH")" != "$GITHUB_SHA" ]]; then
|
||||||
|
# Normal build on a branch (no tag)
|
||||||
|
echo "::debug::BRANCH: $BRANCH $(git rev-parse "origin/$BRANCH")"
|
||||||
|
echo "::debug::GITHUB_SHA: $GITHUB_SHA"
|
||||||
|
echo "::error::$BRANCH has been updated since build started. Aborting changelog."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SINCE_TAG=$(git tag --sort=-creatordate | grep -Ev "$TAG_REGEX" | awk "NR==$(( 1 + ${RELEASE:-0} ))")
|
||||||
|
|
||||||
|
echo "::debug::BRANCH: $BRANCH"
|
||||||
|
echo "::debug::TAG_REGEX: $TAG_REGEX"
|
||||||
|
echo "::debug::FILENAME: CHANGELOG.md"
|
||||||
|
echo "::debug::SINCE_TAG: $SINCE_TAG"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "BRANCH=$BRANCH"
|
||||||
|
echo "TAG_REGEX=$TAG_REGEX"
|
||||||
|
echo "FILENAME=CHANGELOG.md"
|
||||||
|
echo "SINCE_TAG=$SINCE_TAG"
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Prep changelog file (clear out old lines)
|
||||||
|
run: |
|
||||||
|
# delete the top of the changelog up to the correct tag
|
||||||
|
tagline=$(grep -n "^## \[${SINCE_TAG}\]" "$FILENAME" | awk '{print $1}' FS=':' | head -1)
|
||||||
|
echo "tagline: ${tagline}"
|
||||||
|
|
||||||
|
if [[ -z $tagline ]]; then
|
||||||
|
echo "::error::Something is wrong. ${SINCE_TAG} isn't in the changelog."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $tagline == 1 ]]; then
|
||||||
|
echo "::error::Something is wrong."
|
||||||
|
echo "::error::The latest release ${SINCE_TAG} is the first line in the changelog,"
|
||||||
|
echo "::error::but the h1 '# Changelog' should always be the first line."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i "1,$(( tagline - 1 ))d" "$FILENAME"
|
||||||
|
# delete generated line (or it will be added multiple times)
|
||||||
|
sed -i '/This Changelog was automatically generated by/d' "$FILENAME"
|
||||||
|
# delete trailing empty lines
|
||||||
|
sed -i -e :a -e '/^\n*$/{$d;N;};/\n$/ba' "$FILENAME"
|
||||||
|
|
||||||
|
- name: Generate changelog
|
||||||
|
uses: heinrichreimer/action-github-changelog-generator@v2.1.1
|
||||||
|
with:
|
||||||
|
# see: https://github.com/heinrichreimer/action-github-changelog-generator
|
||||||
|
repo: jrnl-org/jrnl
|
||||||
|
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
||||||
|
base: CHANGELOG.md
|
||||||
|
addSections: '{"build":{"prefix":"**Build:**","labels":["build"]},"docs":{"prefix":"**Documentation:**","labels":["documentation"]},"packaging":{"prefix":"**Packaging:**","labels":["packaging"]}}'
|
||||||
|
issues: true
|
||||||
|
pullRequests: true
|
||||||
|
issuesWoLabels: false
|
||||||
|
unreleased: true
|
||||||
|
compareLink: true
|
||||||
|
includeLabels: bug,enhancement,documentation,build,packaging,deprecated
|
||||||
|
excludeLabels: stale,wontfix
|
||||||
|
excludeTagsRegex: ${{ env.TAG_REGEX }}
|
||||||
|
sinceTag: ${{ env.SINCE_TAG }}
|
||||||
|
maxIssues: 150
|
||||||
|
releaseUrl: https://pypi.org/project/jrnl/%s/
|
||||||
|
releaseBranch: develop
|
||||||
|
verbose: false
|
||||||
|
author: true
|
||||||
|
|
||||||
|
- name: Small fixes
|
||||||
|
run: |
|
||||||
|
# Change unreleased link to correct url
|
||||||
|
sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME"
|
||||||
|
|
||||||
|
- name: Diff and consistency check
|
||||||
|
run: |
|
||||||
|
git diff
|
||||||
|
if [[ $(grep -c '^# Changelog$' "$FILENAME") != 1 ]]; then
|
||||||
|
echo '::error::Something is wrong with the changelog.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SOMETHING_CHANGED=false
|
||||||
|
git diff --exit-code || SOMETHING_CHANGED=true
|
||||||
|
echo "::debug::SOMETHING_CHANGED: $SOMETHING_CHANGED"
|
||||||
|
echo "SOMETHING_CHANGED=$SOMETHING_CHANGED" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Commit
|
||||||
|
if: env.SOMETHING_CHANGED == 'true'
|
||||||
|
run: |
|
||||||
|
git config --global user.name "${{ secrets.JRNL_BOT_NAME }}"
|
||||||
|
git config --global user.email "${{ secrets.JRNL_BOT_EMAIL }}"
|
||||||
|
git add "$FILENAME"
|
||||||
|
git commit -m "Update changelog [ci skip]"
|
||||||
|
git push origin "$BRANCH"
|
||||||
|
|
||||||
|
- name: Update tag to include changelog
|
||||||
|
if: startsWith(env.GITHUB_REF, 'refs/tags/')
|
||||||
|
run: |
|
||||||
|
# This is a tag build (releases and prereleases)
|
||||||
|
# update the tag to include the changelog
|
||||||
|
git tag -fam "$GITHUB_REF_NAME" "$GITHUB_REF_NAME"
|
||||||
|
git push --tags --force
|
||||||
|
|
||||||
|
- name: Merge to Release branch
|
||||||
|
if: env.FULL_RELEASE == 'true'
|
||||||
|
run: |
|
||||||
|
git fetch --unshallow origin
|
||||||
|
git checkout release
|
||||||
|
git merge --ff-only "$BRANCH"
|
||||||
|
git push origin release
|
||||||
|
|
76
.github/workflows/docs.yaml
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
name: Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ develop, release ]
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'docs_theme/**'
|
||||||
|
- 'mkdocs.yml'
|
||||||
|
- 'readthedocs.yml'
|
||||||
|
- '.github/workflows/docs.yaml'
|
||||||
|
- 'tasks.py'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop ]
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'docs_theme/**'
|
||||||
|
- 'mkdocs.yml'
|
||||||
|
- 'readthedocs.yml'
|
||||||
|
- '.github/workflows/docs.yaml'
|
||||||
|
- 'tasks.py'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
accessibility:
|
||||||
|
if: contains(toJson(github.event.commits), '[ci skip]') == false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
python-version: [ '3.11' ]
|
||||||
|
os: [ ubuntu-latest ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: Setup Node.js environment
|
||||||
|
uses: actions/setup-node@main
|
||||||
|
|
||||||
|
- name: Capture full Python version in env
|
||||||
|
run: echo "PYTHON_FULL_VERSION=$(python --version)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: poetry cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .venv
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ env.PYTHON_FULL_VERSION }}-${{ secrets.CACHE_STRING }}
|
||||||
|
|
||||||
|
- name: npm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-pa11y-v3
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
pip install poetry
|
||||||
|
poetry config --local virtualenvs.in-project true
|
||||||
|
poetry sync --no-root
|
||||||
|
npm install
|
||||||
|
echo "node_modules/.bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
- name: Start docs server
|
||||||
|
run: poetry run poe docs-run &
|
||||||
|
|
||||||
|
- name: Accessibility testing (Pa11y)
|
||||||
|
run: poetry run poe docs-check
|
109
.github/workflows/release.yaml
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
name: Release
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version (e.g. v2.5, v2.5.1-beta, v2.6-beta2)'
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
include_repo_version:
|
||||||
|
description: 'Update version in repo?'
|
||||||
|
type: boolean
|
||||||
|
required: true
|
||||||
|
default: true
|
||||||
|
include_pypi:
|
||||||
|
description: 'Publish to PyPI?'
|
||||||
|
type: boolean
|
||||||
|
required: true
|
||||||
|
default: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
name: "Validate version string"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Validate version
|
||||||
|
run: |
|
||||||
|
JRNL_VERSION="${{ github.event.inputs.version }}"
|
||||||
|
echo "::debug::version: $JRNL_VERSION"
|
||||||
|
if [[ ! $JRNL_VERSION =~ ^v[0-9]+(\.[0-9]+){1,2}(-(alpha|beta)([0-9]+)?)?$ ]]; then
|
||||||
|
echo
|
||||||
|
echo "::error::Bad version"
|
||||||
|
echo
|
||||||
|
echo "Version string should match pattern above."
|
||||||
|
echo "Here are some examples of valid version numbers:"
|
||||||
|
echo
|
||||||
|
echo " v2.5"
|
||||||
|
echo " v2.5-alpha"
|
||||||
|
echo " v2.5-beta"
|
||||||
|
echo " v2.5.1"
|
||||||
|
echo " v2.5.1-alpha"
|
||||||
|
echo " v2.5.1-beta"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
release_pypi:
|
||||||
|
needs: validate
|
||||||
|
name: "Release to PyPI"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
pypi_version: ${{ steps.pypi-version-getter.outputs.pypi_version }}
|
||||||
|
env:
|
||||||
|
HOME_REPO: ${{ secrets.HOME_REPO }}
|
||||||
|
steps:
|
||||||
|
- name: Get version
|
||||||
|
run: |
|
||||||
|
JRNL_VERSION="${{ github.event.inputs.version }}"
|
||||||
|
echo "::debug::version: $JRNL_VERSION"
|
||||||
|
echo "JRNL_VERSION=$JRNL_VERSION" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.13'
|
||||||
|
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.JRNL_BOT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Config git user
|
||||||
|
run: |
|
||||||
|
git config --global user.name "${{ secrets.JRNL_BOT_NAME }}"
|
||||||
|
git config --global user.email "${{ secrets.JRNL_BOT_EMAIL }}"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pip install poetry
|
||||||
|
|
||||||
|
- name: Update version in files
|
||||||
|
if: ${{ github.event.inputs.include_repo_version == 'true' }}
|
||||||
|
run: |
|
||||||
|
poetry version "$JRNL_VERSION"
|
||||||
|
echo "__version__ = \"$JRNL_VERSION\"" > jrnl/__version__.py
|
||||||
|
|
||||||
|
- name: Commit updated files
|
||||||
|
if: ${{ github.event.inputs.include_repo_version == 'true' && github.repository == env.HOME_REPO }}
|
||||||
|
run: |
|
||||||
|
git add pyproject.toml jrnl/__version__.py
|
||||||
|
git commit -m "Increment version to ${JRNL_VERSION}"
|
||||||
|
git tag -a -m "$JRNL_VERSION" "$JRNL_VERSION"
|
||||||
|
git push
|
||||||
|
git push --tags
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: poetry build
|
||||||
|
|
||||||
|
- name: Deploy to PyPI
|
||||||
|
if: ${{ github.event.inputs.include_pypi == 'true' && github.repository == env.HOME_REPO }}
|
||||||
|
env:
|
||||||
|
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
|
||||||
|
run: poetry publish
|
||||||
|
|
||||||
|
- name: Get PyPI version
|
||||||
|
id: pypi-version-getter
|
||||||
|
run: |
|
||||||
|
pypi_version="$(find dist/jrnl-*.tar.gz | sed -r 's!dist/jrnl-(.*)\.tar\.gz!\1!')"
|
||||||
|
echo "pypi_version=$pypi_version" >> "$GITHUB_OUTPUT"
|
35
.github/workflows/testing_pipelines.yaml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
name: Testing Pipeline Files
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ develop, release ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/**'
|
||||||
|
- '.github/actions/**'
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/**'
|
||||||
|
- '.github/actions/**'
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * SAT'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
if: >
|
||||||
|
! contains(github.event.head_commit.message, '[ci skip]')
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-latest ]
|
||||||
|
steps:
|
||||||
|
- run: git config --global core.autocrlf false
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check workflow files
|
||||||
|
uses: docker://rhysd/actionlint:latest
|
||||||
|
with:
|
||||||
|
args: -color
|
48
.github/workflows/testing_prs.yaml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
name: Testing
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ develop, release ]
|
||||||
|
paths:
|
||||||
|
- 'jrnl/**'
|
||||||
|
- 'features/**'
|
||||||
|
- 'tests/**'
|
||||||
|
- 'poetry.lock'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- '.github/workflows/testing_prs.yaml'
|
||||||
|
- 'tasks.py'
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop ]
|
||||||
|
paths:
|
||||||
|
- 'jrnl/**'
|
||||||
|
- 'features/**'
|
||||||
|
- 'tests/**'
|
||||||
|
- 'poetry.lock'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- '.github/workflows/testing_prs.yaml'
|
||||||
|
- 'tasks.py'
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash # needed to prevent Windows from using PowerShell
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
if: >
|
||||||
|
! contains(github.event.head_commit.message, '[ci skip]')
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
|
||||||
|
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
||||||
|
steps:
|
||||||
|
- run: git config --global core.autocrlf false
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Run tests
|
||||||
|
uses: ./.github/actions/run_tests
|
||||||
|
with:
|
||||||
|
cache-string: ${{ secrets.CACHE_STRING }}
|
28
.github/workflows/testing_schedule.yaml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
name: Testing
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * SAT'
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash # needed to prevent Windows from using PowerShell
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test_all:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
|
||||||
|
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
||||||
|
steps:
|
||||||
|
- run: git config --global core.autocrlf false
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Run tests
|
||||||
|
uses: ./.github/actions/run_tests
|
||||||
|
with:
|
||||||
|
cache-string: ${{ secrets.CACHE_STRING }}
|
|
@ -1,11 +0,0 @@
|
||||||
project=jrnl
|
|
||||||
user=jrnl-org
|
|
||||||
base=CHANGELOG.md
|
|
||||||
issues=false
|
|
||||||
issues-wo-labels=false
|
|
||||||
include-labels=bug,enhancement,documentation,build,deprecated
|
|
||||||
release-url=https://pypi.org/project/jrnl/%s/
|
|
||||||
add-sections={ "build": { "prefix": "**Build:**", "labels": ["build"]}, "docs": { "prefix": "**Updated documentation:**", "labels": ["documentation"]}}
|
|
||||||
exclude-tags-regex=(alpha|beta|rc)
|
|
||||||
verbose=false
|
|
||||||
|
|
70
.gitignore
vendored
|
@ -1,55 +1,63 @@
|
||||||
|
# Byte-compiled DLL and Shared Library files
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
*.so
|
||||||
.python-version
|
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
*.egg
|
*.egg
|
||||||
*.egg-info
|
*.egg-info/
|
||||||
dist
|
|
||||||
build
|
|
||||||
eggs
|
|
||||||
parts
|
|
||||||
bin
|
|
||||||
var
|
|
||||||
sdist
|
|
||||||
develop-eggs
|
|
||||||
.installed.cfg
|
.installed.cfg
|
||||||
lib
|
bin/
|
||||||
lib64
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
eggs/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
.tox/
|
||||||
|
var/
|
||||||
|
node_modules/
|
||||||
|
__pycache__/
|
||||||
|
.pytest_cache/
|
||||||
|
.flakeheaven_cache/
|
||||||
|
|
||||||
|
# Versioning
|
||||||
.python-version
|
.python-version
|
||||||
|
.tool-versions
|
||||||
|
|
||||||
# Installer logs
|
# Installer logs
|
||||||
pip-log.txt
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.travis-solo
|
.travis-solo
|
||||||
Icon
|
Icon
|
||||||
|
pip-log.txt
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
_build
|
_build
|
||||||
_sources
|
_sources
|
||||||
_static
|
_static
|
||||||
|
coverage.xml
|
||||||
|
exp/
|
||||||
objects.inv
|
objects.inv
|
||||||
searchindex.js
|
searchindex.js
|
||||||
|
|
||||||
# MS Visual Studio (PyTools)
|
# virtualenv
|
||||||
obj
|
.venv*/
|
||||||
*.pyproj
|
|
||||||
*.sln
|
|
||||||
*.suo
|
|
||||||
|
|
||||||
# virtaulenv
|
|
||||||
env/
|
env/
|
||||||
env*/
|
env*/
|
||||||
venv*/
|
venv*/
|
||||||
|
|
||||||
# PyCharm Project files
|
# Editor and IDE specific files
|
||||||
.idea/
|
# Since contributors may want to user a variety of development tools it is
|
||||||
|
# recommended that editor specific file types be ignored globally by each
|
||||||
# export testing directories
|
# contributor via a global gitignore. Instructions for setting up a global
|
||||||
exp/
|
# ignore file can be found here:
|
||||||
|
# https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||||
_extras/
|
# (Configuring ignored files for all repositories on your computer)
|
||||||
*.sublime-*
|
# Examples of such files are:
|
||||||
site/
|
# MS Visual Studio (PyTools)
|
||||||
|
# obj
|
||||||
|
# *.suo
|
||||||
|
# PyCharm
|
||||||
|
# .idea/
|
||||||
|
# VS Code
|
||||||
|
# .vscode/settings.json
|
28
.readthedocs.yaml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# readthedocs.yml
|
||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Set the OS
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3"
|
||||||
|
|
||||||
|
|
||||||
|
# Build documentation in the docs/ directory
|
||||||
|
mkdocs:
|
||||||
|
configuration: mkdocs.yml
|
||||||
|
fail_on_warning: false
|
||||||
|
|
||||||
|
# Optionally build your docs in additional formats such as PDF
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
- epub
|
||||||
|
|
||||||
|
# Optionally set the version of Python and requirements required to build your docs
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: docs_theme/requirements.txt
|
152
.travis.yml
|
@ -1,152 +0,0 @@
|
||||||
dist: xenial # required for Python >= 3.7
|
|
||||||
os: linux
|
|
||||||
language: python
|
|
||||||
|
|
||||||
cache:
|
|
||||||
pip: true
|
|
||||||
directories:
|
|
||||||
- $HOME/virtualenv
|
|
||||||
|
|
||||||
git:
|
|
||||||
depth: false
|
|
||||||
autocrlf: false
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- date
|
|
||||||
|
|
||||||
install:
|
|
||||||
- pip install --upgrade poetry
|
|
||||||
- poetry install
|
|
||||||
- poetry run python --version
|
|
||||||
|
|
||||||
script:
|
|
||||||
- poetry run behave
|
|
||||||
|
|
||||||
aliases:
|
|
||||||
test_mac: &test_mac
|
|
||||||
os: osx
|
|
||||||
language: shell
|
|
||||||
osx_image: xcode11.2
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.pyenv/versions
|
|
||||||
- $HOME/Library/Caches/pypoetry
|
|
||||||
before_install:
|
|
||||||
- eval "$(pyenv init -)"
|
|
||||||
- pyenv install -s $JRNL_PYTHON_VERSION
|
|
||||||
- pyenv global $JRNL_PYTHON_VERSION
|
|
||||||
- pip install --upgrade pip
|
|
||||||
- pip --version
|
|
||||||
test_windows: &test_windows
|
|
||||||
os: windows
|
|
||||||
language: shell
|
|
||||||
env: &env_windows
|
|
||||||
PATH: /c/Python36:/c/Python36/Scripts:/c/Python37:/c/Python37/Scripts:/c/Python38:/c/Python38/Scripts:$PATH
|
|
||||||
PYTHONIOENCODING: UTF-8
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- /c/Python36
|
|
||||||
- /c/Python37
|
|
||||||
- /c/Python38
|
|
||||||
- /c/ProgramData/chocolatey/lib
|
|
||||||
- /c/ProgramData/chocolatey/bin
|
|
||||||
- /c/Users/travis/AppData/Local/pypoetry/Cache
|
|
||||||
before_install:
|
|
||||||
- choco install python --version $JRNL_PYTHON_VERSION
|
|
||||||
- python -m pip install --upgrade pip
|
|
||||||
- pip --version
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
fast_finish: true
|
|
||||||
allow_failures:
|
|
||||||
- python: nightly
|
|
||||||
|
|
||||||
include:
|
|
||||||
- name: Misc Linting
|
|
||||||
python: 3.8
|
|
||||||
script:
|
|
||||||
- poetry --version
|
|
||||||
- poetry check
|
|
||||||
- black --version
|
|
||||||
- black --check --diff .
|
|
||||||
- pyflakes --version
|
|
||||||
- pyflakes .
|
|
||||||
|
|
||||||
# Python 3.6 Tests
|
|
||||||
- name: Python 3.6 on Linux
|
|
||||||
python: 3.6
|
|
||||||
- <<: *test_mac
|
|
||||||
name: Python 3.6 on MacOS
|
|
||||||
python: 3.6
|
|
||||||
env:
|
|
||||||
JRNL_PYTHON_VERSION: 3.6.8
|
|
||||||
- <<: *test_windows
|
|
||||||
name: Python 3.6 on Windows
|
|
||||||
python: 3.6
|
|
||||||
env:
|
|
||||||
<<: *env_windows
|
|
||||||
JRNL_PYTHON_VERSION: 3.6.8
|
|
||||||
|
|
||||||
# Python 3.7 Tests
|
|
||||||
- name: Python 3.7 on Linux
|
|
||||||
python: 3.7
|
|
||||||
- <<: *test_mac
|
|
||||||
name: Python 3.7 on MacOS
|
|
||||||
python: 3.7
|
|
||||||
env:
|
|
||||||
JRNL_PYTHON_VERSION: 3.7.7
|
|
||||||
- <<: *test_windows
|
|
||||||
name: Python 3.7 on Windows
|
|
||||||
python: 3.7
|
|
||||||
env:
|
|
||||||
<<: *env_windows
|
|
||||||
JRNL_PYTHON_VERSION: 3.7.7
|
|
||||||
|
|
||||||
# Python 3.8 Tests
|
|
||||||
- name: Python 3.8 on Linux
|
|
||||||
python: 3.8
|
|
||||||
- <<: *test_mac
|
|
||||||
name: Python 3.8 on MacOS
|
|
||||||
python: 3.8
|
|
||||||
env:
|
|
||||||
JRNL_PYTHON_VERSION: 3.8.2
|
|
||||||
- <<: *test_windows
|
|
||||||
name: Python 3.8 on Windows
|
|
||||||
python: 3.8
|
|
||||||
env:
|
|
||||||
<<: *env_windows
|
|
||||||
JRNL_PYTHON_VERSION: 3.8.2
|
|
||||||
|
|
||||||
# ... and beyond!
|
|
||||||
- name: Python nightly on Linux
|
|
||||||
before_install:
|
|
||||||
- sed -i 's/^python = ">=3\.6\.0.*"$/python = "*"/' pyproject.toml
|
|
||||||
python: nightly
|
|
||||||
|
|
||||||
# Specialty tests
|
|
||||||
- name: Python 3.7 on Linux, not UTC
|
|
||||||
python: 3.7
|
|
||||||
env:
|
|
||||||
TZ: America/Edmonton
|
|
||||||
|
|
||||||
- stage: Deploy
|
|
||||||
if: tag IS present
|
|
||||||
before_deploy:
|
|
||||||
- poetry build
|
|
||||||
script:
|
|
||||||
- echo "Deployment starting..."
|
|
||||||
deploy:
|
|
||||||
- provider: script
|
|
||||||
script: poetry publish
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
all_branches: true
|
|
||||||
|
|
||||||
# Changelog for Unreleased changes
|
|
||||||
- stage: Update Changelog
|
|
||||||
if: (tag IS present) OR (branch = develop AND type NOT IN (pull_request))
|
|
||||||
install:
|
|
||||||
- echo 'Skipping installation step'
|
|
||||||
script:
|
|
||||||
- ./.build/generate_changelog.sh
|
|
||||||
|
|
713
CHANGELOG.md
|
@ -2,7 +2,716 @@
|
||||||
|
|
||||||
## [Unreleased](https://github.com/jrnl-org/jrnl/)
|
## [Unreleased](https://github.com/jrnl-org/jrnl/)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.2...HEAD)
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.2.1...HEAD)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- poetry warning - "poetry.dev-dependencies" section is deprecated [\#1975](https://github.com/jrnl-org/jrnl/issues/1975)
|
||||||
|
- Homebrew autobump error on jrnl release [\#1961](https://github.com/jrnl-org/jrnl/issues/1961)
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Remove release step to publish to Homebrew [\#1994](https://github.com/jrnl-org/jrnl/pull/1994) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update dependency rich to v14 [\#1989](https://github.com/jrnl-org/jrnl/pull/1989) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency python to 3.13 [\#1988](https://github.com/jrnl-org/jrnl/pull/1988) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.25.0 [\#1986](https://github.com/jrnl-org/jrnl/pull/1986) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5.3.1 [\#1984](https://github.com/jrnl-org/jrnl/pull/1984) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency jinja2 to v3.1.6 [\#1983](https://github.com/jrnl-org/jrnl/pull/1983) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.33.1 [\#1982](https://github.com/jrnl-org/jrnl/pull/1982) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest to v8.3.5 [\#1981](https://github.com/jrnl-org/jrnl/pull/1981) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v44.0.2 [\#1980](https://github.com/jrnl-org/jrnl/pull/1980) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.11.3 [\#1978](https://github.com/jrnl-org/jrnl/pull/1978) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.2.1](https://pypi.org/project/jrnl/v4.2.1/) (2025-02-25)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.2...v4.2.1)
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Typing animation in landing page is broken [\#1969](https://github.com/jrnl-org/jrnl/issues/1969)
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update dependency pytest to \>=8.1.1 [\#1974](https://github.com/jrnl-org/jrnl/pull/1974) ([wren](https://github.com/wren))
|
||||||
|
- Update dependency black to v25 [\#1973](https://github.com/jrnl-org/jrnl/pull/1973) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5.3 [\#1972](https://github.com/jrnl-org/jrnl/pull/1972) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.18.10 [\#1967](https://github.com/jrnl-org/jrnl/pull/1967) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency jinja2 to v3.1.5 [\#1966](https://github.com/jrnl-org/jrnl/pull/1966) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v44 [\#1962](https://github.com/jrnl-org/jrnl/pull/1962) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-bdd to v8.1.0 [\#1952](https://github.com/jrnl-org/jrnl/pull/1952) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.32.2 [\#1951](https://github.com/jrnl-org/jrnl/pull/1951) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency keyring to v25.6.0 [\#1948](https://github.com/jrnl-org/jrnl/pull/1948) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.9.7 [\#1947](https://github.com/jrnl-org/jrnl/pull/1947) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.9.4 [\#1946](https://github.com/jrnl-org/jrnl/pull/1946) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.24.1 [\#1945](https://github.com/jrnl-org/jrnl/pull/1945) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.2](https://pypi.org/project/jrnl/v4.2/) (2024-11-17)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.2-beta...v4.2)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add Python 3.13 support [\#1893](https://github.com/jrnl-org/jrnl/issues/1893)
|
||||||
|
- Add calendar heatmap display format [\#1759](https://github.com/jrnl-org/jrnl/pull/1759) ([alichtman](https://github.com/alichtman))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- -contains doesn't accept multiple search terms, doesn't work with -and [\#1877](https://github.com/jrnl-org/jrnl/issues/1877)
|
||||||
|
- Tests failing on develop branch starting with pytest-bdd 7.1.2 [\#1875](https://github.com/jrnl-org/jrnl/issues/1875)
|
||||||
|
- Ignore color when used in a pipeline [\#1839](https://github.com/jrnl-org/jrnl/issues/1839)
|
||||||
|
- Fix -contains to allow multiple terms with "OR" logic unless -and is added [\#1890](https://github.com/jrnl-org/jrnl/pull/1890) ([eigenric](https://github.com/eigenric))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Recommend pipx as default installation method [\#1888](https://github.com/jrnl-org/jrnl/issues/1888)
|
||||||
|
- Remove documentation recommendation to install pipx through brew or pip [\#1886](https://github.com/jrnl-org/jrnl/issues/1886)
|
||||||
|
- Document security risks of using a computer that someone else has admin access to [\#1793](https://github.com/jrnl-org/jrnl/issues/1793)
|
||||||
|
- Recommend pipx as easiest installation method for all OSes and remove warning about apt [\#1889](https://github.com/jrnl-org/jrnl/pull/1889) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Docs accessibility checker failure - contrast ratio [\#1934](https://github.com/jrnl-org/jrnl/issues/1934)
|
||||||
|
- Docs accessibility test runner failing [\#1932](https://github.com/jrnl-org/jrnl/issues/1932)
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update actions/cache action to v4 [\#1847](https://github.com/jrnl-org/jrnl/pull/1847) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update actions/setup-python action to v5 [\#1848](https://github.com/jrnl-org/jrnl/pull/1848) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency black to v24.8.0 [\#1923](https://github.com/jrnl-org/jrnl/pull/1923) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v43.0.3 [\#1942](https://github.com/jrnl-org/jrnl/pull/1942) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency jinja2 to v3.1.4 [\#1892](https://github.com/jrnl-org/jrnl/pull/1892) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency keyring to v25.4.1 [\#1924](https://github.com/jrnl-org/jrnl/pull/1924) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency mkdocs to v1.6.1 [\#1895](https://github.com/jrnl-org/jrnl/pull/1895) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pa11y-ci to v3.1.0 [\#1831](https://github.com/jrnl-org/jrnl/pull/1831) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency parse-type to v0.6.4 [\#1936](https://github.com/jrnl-org/jrnl/pull/1936) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update peter-evans/create-pull-request action to v7 [\#1929](https://github.com/jrnl-org/jrnl/pull/1929) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.29.0 [\#1925](https://github.com/jrnl-org/jrnl/pull/1925) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest to v7.4.4 [\#1845](https://github.com/jrnl-org/jrnl/pull/1845) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-bdd to v7.3.0 [\#1896](https://github.com/jrnl-org/jrnl/pull/1896) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-xdist to v3.6.1 [\#1897](https://github.com/jrnl-org/jrnl/pull/1897) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency python-dateutil to v2.9.0 [\#1898](https://github.com/jrnl-org/jrnl/pull/1898) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency requests to v2.32.3 [\#1899](https://github.com/jrnl-org/jrnl/pull/1899) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.9.2 [\#1937](https://github.com/jrnl-org/jrnl/pull/1937) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.18.6 [\#1855](https://github.com/jrnl-org/jrnl/pull/1855) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.7.0 [\#1938](https://github.com/jrnl-org/jrnl/pull/1938) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.23.0 [\#1935](https://github.com/jrnl-org/jrnl/pull/1935) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency typed.js to v2.1.0 [\#1861](https://github.com/jrnl-org/jrnl/pull/1861) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency xmltodict to v0.14.2 [\#1940](https://github.com/jrnl-org/jrnl/pull/1940) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update nick-invision/retry action to v3 [\#1851](https://github.com/jrnl-org/jrnl/pull/1851) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update peter-evans/create-pull-request action to v6 [\#1852](https://github.com/jrnl-org/jrnl/pull/1852) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.1](https://pypi.org/project/jrnl/v4.1/) (2023-11-04)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.1-beta2...v4.1)
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add Python 3.12 support [\#1761](https://github.com/jrnl-org/jrnl/pull/1761) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Set new required build fields in the ReadTheDocs config file [\#1803](https://github.com/jrnl-org/jrnl/pull/1803) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Replace flake8 and isort with ruff linter and add `black --check` to linting step [\#1763](https://github.com/jrnl-org/jrnl/pull/1763) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Add note about messages going to `stderr` and the implication for piping [\#1768](https://github.com/jrnl-org/jrnl/pull/1768) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Drop/replace ansiwrap dependency [\#1191](https://github.com/jrnl-org/jrnl/issues/1191)
|
||||||
|
- Use rich instead of ansiwrap to wrap text [\#1693](https://github.com/jrnl-org/jrnl/pull/1693) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Update actions/checkout action to v4 [\#1788](https://github.com/jrnl-org/jrnl/pull/1788) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency black to v23.10.1 [\#1811](https://github.com/jrnl-org/jrnl/pull/1811) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v41.0.5 [\#1815](https://github.com/jrnl-org/jrnl/pull/1815) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency keyring to v24.2.0 [\#1760](https://github.com/jrnl-org/jrnl/pull/1760) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency mkdocs to v1.5.3 [\#1795](https://github.com/jrnl-org/jrnl/pull/1795) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency parse-type to v0.6.2 [\#1762](https://github.com/jrnl-org/jrnl/pull/1762) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.24.1 [\#1806](https://github.com/jrnl-org/jrnl/pull/1806) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest to v7.4.3 [\#1816](https://github.com/jrnl-org/jrnl/pull/1816) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-bdd to v7 [\#1807](https://github.com/jrnl-org/jrnl/pull/1807) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.6.0 [\#1794](https://github.com/jrnl-org/jrnl/pull/1794) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.18.3 [\#1813](https://github.com/jrnl-org/jrnl/pull/1813) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruff to v0.1.3 [\#1810](https://github.com/jrnl-org/jrnl/pull/1810) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.11.3 [\#1782](https://github.com/jrnl-org/jrnl/pull/1782) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5.2 [\#1814](https://github.com/jrnl-org/jrnl/pull/1814) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
**Special thanks:**
|
||||||
|
- jrnl uses UTC instead of local time for entries in WSL/Ubuntu [\#1607](https://github.com/jrnl-org/jrnl/issues/1607) investigated and reported upstream by [giuseppedandrea](https://github.com/giuseppedandrea)
|
||||||
|
|
||||||
|
## [v4.0.1](https://pypi.org/project/jrnl/v4.0.1/) (2023-06-20)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0.1-beta...v4.0.1)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- jrnl crashes when running `jrnl --list --format json` and `jrnl --list --format yaml` [\#1737](https://github.com/jrnl-org/jrnl/issues/1737)
|
||||||
|
- Refactor --template code [\#1711](https://github.com/jrnl-org/jrnl/pull/1711) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Fix linting issue in CI pipeline [\#1743](https://github.com/jrnl-org/jrnl/pull/1743) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Update dependency ruamel.yaml to v0.17.28 [\#1749](https://github.com/jrnl-org/jrnl/pull/1749) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency requests to v2.31.0 [\#1748](https://github.com/jrnl-org/jrnl/pull/1748) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ruamel.yaml to v0.17.26 [\#1746](https://github.com/jrnl-org/jrnl/pull/1746) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v5 [\#1741](https://github.com/jrnl-org/jrnl/pull/1741) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-xdist to v3.3.1 [\#1740](https://github.com/jrnl-org/jrnl/pull/1740) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.20.0 [\#1735](https://github.com/jrnl-org/jrnl/pull/1735) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency mkdocs to v1.4.3 [\#1733](https://github.com/jrnl-org/jrnl/pull/1733) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.3.5 [\#1729](https://github.com/jrnl-org/jrnl/pull/1729) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency requests to v2.30.0 [\#1728](https://github.com/jrnl-org/jrnl/pull/1728) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.5.1 [\#1727](https://github.com/jrnl-org/jrnl/pull/1727) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update peter-evans/create-pull-request action to v5 [\#1719](https://github.com/jrnl-org/jrnl/pull/1719) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency flake8-simplify to v0.20.0 [\#1716](https://github.com/jrnl-org/jrnl/pull/1716) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v4.0](https://pypi.org/project/jrnl/v4.0/) (2023-05-20)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v4.0-beta3...v4.0)
|
||||||
|
|
||||||
|
🚨 **BREAKING CHANGES** 🚨
|
||||||
|
|
||||||
|
**Deprecated:**
|
||||||
|
|
||||||
|
- Drop Python 3.9 and use Python 3.11 official release [\#1611](https://github.com/jrnl-org/jrnl/pull/1611) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add message with config location and docs location when installation is complete [\#1695](https://github.com/jrnl-org/jrnl/pull/1695) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Prompt to include colors in config when first running jrnl [\#1687](https://github.com/jrnl-org/jrnl/pull/1687) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add ability to use template with `--template` [\#1667](https://github.com/jrnl-org/jrnl/pull/1667) ([alichtman](https://github.com/alichtman))
|
||||||
|
- Search for entries with no tags or stars with `-not -starred` and `-not -tagged` [\#1663](https://github.com/jrnl-org/jrnl/pull/1663) ([cjcon90](https://github.com/cjcon90))
|
||||||
|
- Refactor flow for easier access to some files \(avoid things like `jrnl.Journal.Journal` and `jrnl.jrnl` co-existing\) [\#1662](https://github.com/jrnl-org/jrnl/pull/1662) ([wren](https://github.com/wren))
|
||||||
|
- Add more type hints [\#1642](https://github.com/jrnl-org/jrnl/pull/1642) ([outa](https://github.com/outa))
|
||||||
|
- Add `rich` handler to debug logging [\#1627](https://github.com/jrnl-org/jrnl/pull/1627) ([wren](https://github.com/wren))
|
||||||
|
- Rework Encryption to enable future support of other encryption methods [\#1602](https://github.com/jrnl-org/jrnl/pull/1602) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Only read text files that look like entries when opening folder journal [\#1697](https://github.com/jrnl-org/jrnl/pull/1697) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Save empty journal on install instead of just creating a zero-length file [\#1690](https://github.com/jrnl-org/jrnl/pull/1690) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Allow combinations of `--change-time`, `--delete`, and `--edit` while correctly counting the number of entries affected [\#1669](https://github.com/jrnl-org/jrnl/pull/1669) ([wren](https://github.com/wren))
|
||||||
|
- Don't save templated journal entries if the received raw text is the same as the template itself [\#1653](https://github.com/jrnl-org/jrnl/pull/1653) ([Briscoooe](https://github.com/Briscoooe))
|
||||||
|
- Add tag to XML file when edited DayOne entry and is searchable afterward [\#1648](https://github.com/jrnl-org/jrnl/pull/1648) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- Update version key in config file after version changes [\#1646](https://github.com/jrnl-org/jrnl/pull/1646) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Update copyright notices for 2023 [\#1660](https://github.com/jrnl-org/jrnl/pull/1660) ([wren](https://github.com/wren))
|
||||||
|
- Fix bug where changelog is always slightly out of date on release tags [\#1631](https://github.com/jrnl-org/jrnl/pull/1631) ([wren](https://github.com/wren))
|
||||||
|
- Add `simplify` plugin to linting checks [\#1630](https://github.com/jrnl-org/jrnl/pull/1630) ([wren](https://github.com/wren))
|
||||||
|
- Add type hints [\#1614](https://github.com/jrnl-org/jrnl/pull/1614) ([outa](https://github.com/outa))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Update contributing.md links in documentation [\#1726](https://github.com/jrnl-org/jrnl/pull/1726) ([ahosking](https://github.com/ahosking))
|
||||||
|
- Fix various typos [\#1718](https://github.com/jrnl-org/jrnl/pull/1718) ([hezhizhen](https://github.com/hezhizhen))
|
||||||
|
- Update documentation front page text [\#1698](https://github.com/jrnl-org/jrnl/pull/1698) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Support mkdocs 1.4.2 and fix its missing breadcrumb [\#1691](https://github.com/jrnl-org/jrnl/pull/1691) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Document temporary file extension behavior when using template [\#1686](https://github.com/jrnl-org/jrnl/pull/1686) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Document `-tagged`, `-not -tagged`, and `-not -starred` [\#1684](https://github.com/jrnl-org/jrnl/pull/1684) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Update documentation about privacy and security in VSCode [\#1680](https://github.com/jrnl-org/jrnl/pull/1680) ([giuseppedandrea](https://github.com/giuseppedandrea))
|
||||||
|
- Update documentation on temporary files naming [\#1673](https://github.com/jrnl-org/jrnl/pull/1673) ([giuseppedandrea](https://github.com/giuseppedandrea))
|
||||||
|
- Update docs to include time and title in arguments with `--edit` [\#1657](https://github.com/jrnl-org/jrnl/pull/1657) ([pconrad-fb](https://github.com/pconrad-fb))
|
||||||
|
- Fix markup in "Advanced Usage" doc [\#1655](https://github.com/jrnl-org/jrnl/pull/1655) ([multani](https://github.com/multani))
|
||||||
|
- Remove Windows 7 known issue since Windows 7 is no longer supported [\#1636](https://github.com/jrnl-org/jrnl/pull/1636) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Lock ruamel.yaml version to v0.17.21 until bug is fixed [\#1738](https://github.com/jrnl-org/jrnl/pull/1738) ([wren](https://github.com/wren))
|
||||||
|
- Update dependency black to v23.3.0 [\#1715](https://github.com/jrnl-org/jrnl/pull/1715) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency cryptography to v40.0.2 [\#1723](https://github.com/jrnl-org/jrnl/pull/1723) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency flake8-type-checking to v2.4.0 [\#1714](https://github.com/jrnl-org/jrnl/pull/1714) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency flakeheaven to v3.3.0 [\#1722](https://github.com/jrnl-org/jrnl/pull/1722) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency ipdb to v0.13.13 [\#1703](https://github.com/jrnl-org/jrnl/pull/1703) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency poethepoet to v0.19.0 [\#1709](https://github.com/jrnl-org/jrnl/pull/1709) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest to v7.3.1 [\#1720](https://github.com/jrnl-org/jrnl/pull/1720) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency pytest-xdist to v3.2.1 [\#1705](https://github.com/jrnl-org/jrnl/pull/1705) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency rich to v13.3.4 [\#1713](https://github.com/jrnl-org/jrnl/pull/1713) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tox to v4.4.7 [\#1707](https://github.com/jrnl-org/jrnl/pull/1707) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency tzlocal to v4.3 [\#1708](https://github.com/jrnl-org/jrnl/pull/1708) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v3.3](https://pypi.org/project/jrnl/v3.3/) (2022-10-29)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.3-beta2...v3.3)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Change default config to use journal key [\#1594](https://github.com/jrnl-org/jrnl/pull/1594) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add machine readable --list output [\#1592](https://github.com/jrnl-org/jrnl/pull/1592) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Fix bug for new `--list --format` options when no default journal is specified [\#1621](https://github.com/jrnl-org/jrnl/pull/1621) ([wren](https://github.com/wren))
|
||||||
|
- Don't create empty file when attempting a YAML export to a non-existing folder [\#1600](https://github.com/jrnl-org/jrnl/pull/1600) ([outa](https://github.com/outa))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Update `.gitignore` [\#1604](https://github.com/jrnl-org/jrnl/pull/1604) ([wren](https://github.com/wren))
|
||||||
|
- Fix Docs Accessibility Testing [\#1588](https://github.com/jrnl-org/jrnl/pull/1588) ([wren](https://github.com/wren))
|
||||||
|
- Update to use renamed flag for `brew bump-formula-pr` [\#1587](https://github.com/jrnl-org/jrnl/pull/1587) ([wren](https://github.com/wren))
|
||||||
|
- Update peter-evans/create-pull-request action to v4 [\#1585](https://github.com/jrnl-org/jrnl/pull/1585) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update actions/setup-python action to v4 [\#1583](https://github.com/jrnl-org/jrnl/pull/1583) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update actions/checkout action to v3 [\#1582](https://github.com/jrnl-org/jrnl/pull/1582) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update actions/cache action to v3 [\#1581](https://github.com/jrnl-org/jrnl/pull/1581) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Replace Dependabot with Renovate [\#1575](https://github.com/jrnl-org/jrnl/pull/1575) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Add documentation about how the editor must be a blocking process [\#1456](https://github.com/jrnl-org/jrnl/issues/1456)
|
||||||
|
- Document that editors must be blocking processes [\#1624](https://github.com/jrnl-org/jrnl/pull/1624) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Remove wrong option in configuration file reference [\#1618](https://github.com/jrnl-org/jrnl/pull/1618) ([DSiekmeier](https://github.com/DSiekmeier))
|
||||||
|
- Update YAML export description in docs [\#1591](https://github.com/jrnl-org/jrnl/pull/1591) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Update dependency jinja2 to v3.1.2 [\#1579](https://github.com/jrnl-org/jrnl/pull/1579) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Update dependency typed.js to v2.0.12 [\#1578](https://github.com/jrnl-org/jrnl/pull/1578) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
- Add hint for how to get vi to go to end-of-file [\#1563](https://github.com/jrnl-org/jrnl/pull/1563) ([pjz](https://github.com/pjz))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Pin dependencies [\#1577](https://github.com/jrnl-org/jrnl/pull/1577) ([renovate[bot]](https://github.com/apps/renovate))
|
||||||
|
|
||||||
|
## [v3.2](https://pypi.org/project/jrnl/v3.2/) (2022-09-03)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.2-beta...v3.2)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Update issue & PR templates to use forms [\#1559](https://github.com/jrnl-org/jrnl/issues/1559)
|
||||||
|
- Suppress "Entry added" message if using default journal [\#1561](https://github.com/jrnl-org/jrnl/pull/1561) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add message showing the number of search results [\#1524](https://github.com/jrnl-org/jrnl/pull/1524) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Quick fix follow up for actionlint [\#1565](https://github.com/jrnl-org/jrnl/pull/1565) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Remove note in contributing docs about gh-pages branch that we no longer use [\#1566](https://github.com/jrnl-org/jrnl/pull/1566) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
## [v3.1](https://pypi.org/project/jrnl/v3.1/) (2022-08-21)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.1-beta2...v3.1)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Update tzlocal to v4.x and remove pytz dependency [\#1528](https://github.com/jrnl-org/jrnl/pull/1528) ([outa](https://github.com/outa))
|
||||||
|
- Add linewrap option 'auto' [\#1507](https://github.com/jrnl-org/jrnl/pull/1507) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Update formatting function to better account for indentation [\#1541](https://github.com/jrnl-org/jrnl/pull/1541) ([wren](https://github.com/wren))
|
||||||
|
- Export to file\(s\) when first line/title of an entry is very long [\#1527](https://github.com/jrnl-org/jrnl/pull/1527) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- Fixed index out of range error in fancy exporter [\#1522](https://github.com/jrnl-org/jrnl/pull/1522) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add actionlint to testing pipelines [\#1555](https://github.com/jrnl-org/jrnl/pull/1555) ([wren](https://github.com/wren))
|
||||||
|
- Fix docs pipeline, make docs tests easier to run locally and on different OSes [\#1554](https://github.com/jrnl-org/jrnl/pull/1554) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Reformat contributor appreciation on `--help` screen [\#1556](https://github.com/jrnl-org/jrnl/pull/1556) ([xeruf](https://github.com/xeruf))
|
||||||
|
- Clean up copyright notices and version screen [\#1553](https://github.com/jrnl-org/jrnl/pull/1553) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump pyproject-flake8 from 0.0.1a4 to 0.0.1a5 [\#1552](https://github.com/jrnl-org/jrnl/pull/1552) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.7.0 to 23.8.2 [\#1551](https://github.com/jrnl-org/jrnl/pull/1551) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump yq from 3.0.2 to 3.1.0 [\#1546](https://github.com/jrnl-org/jrnl/pull/1546) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump poethepoet from 0.15.0 to 0.16.0 [\#1542](https://github.com/jrnl-org/jrnl/pull/1542) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.6.0 to 23.7.0 [\#1539](https://github.com/jrnl-org/jrnl/pull/1539) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump rich from 12.4.4 to 12.5.1 [\#1538](https://github.com/jrnl-org/jrnl/pull/1538) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v3.0](https://pypi.org/project/jrnl/v3.0/) (2022-07-09)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.0-beta2...v3.0)
|
||||||
|
|
||||||
|
🚨 **BREAKING CHANGES** 🚨
|
||||||
|
|
||||||
|
**Deprecated:**
|
||||||
|
|
||||||
|
- Drop support for Python 3.7 and 3.8 [\#1412](https://github.com/jrnl-org/jrnl/pull/1412) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Show name of journal when creating a password/encrypting [\#1478](https://github.com/jrnl-org/jrnl/pull/1478) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- Rework how all output and messaging works in jrnl [\#1475](https://github.com/jrnl-org/jrnl/pull/1475) ([wren](https://github.com/wren))
|
||||||
|
- Implement --change-time flag [\#1452](https://github.com/jrnl-org/jrnl/pull/1452) ([richardjs](https://github.com/richardjs))
|
||||||
|
- Reformat additional messages and finish centralizing exception handling [\#1424](https://github.com/jrnl-org/jrnl/pull/1424) ([wren](https://github.com/wren))
|
||||||
|
- Reformat messages and add new centralized exception handling [\#1417](https://github.com/jrnl-org/jrnl/pull/1417) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Display message when no edits take place [\#1510](https://github.com/jrnl-org/jrnl/pull/1510) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Fixed error related to display\_format in config file for some values [\#1495](https://github.com/jrnl-org/jrnl/pull/1495) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Create folder if config ends with \(back\)slash [\#1492](https://github.com/jrnl-org/jrnl/pull/1492) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- `-not` search parameter no longer opens editor [\#1490](https://github.com/jrnl-org/jrnl/pull/1490) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Fix TypeError when using debug flag [\#1484](https://github.com/jrnl-org/jrnl/pull/1484) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- Prompt for password change when using 'jrnl --encrypt' on already encrypted journal [\#1477](https://github.com/jrnl-org/jrnl/pull/1477) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- Always expand all paths \(journals, templates, etc\) [\#1468](https://github.com/jrnl-org/jrnl/pull/1468) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- The `-not` option with no arguments now outputs error instead of stack trace [\#1466](https://github.com/jrnl-org/jrnl/pull/1466) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Give a proper message when trying to use an empty config file [\#1461](https://github.com/jrnl-org/jrnl/pull/1461) ([jonakeys](https://github.com/jonakeys))
|
||||||
|
- Display "No entry to save, because no text was received" after empty entry on cmdline [\#1459](https://github.com/jrnl-org/jrnl/pull/1459) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Yaml export errors now don't show stack trace [\#1449](https://github.com/jrnl-org/jrnl/pull/1449) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Pin `pytest-bdd` to \<6.0 to temporarily avoid breaking changes [\#1536](https://github.com/jrnl-org/jrnl/pull/1536) ([wren](https://github.com/wren))
|
||||||
|
- Reduce difference between local and CI environments [\#1518](https://github.com/jrnl-org/jrnl/pull/1518) ([wren](https://github.com/wren))
|
||||||
|
- Add bdd tests for jrnl installation [\#1513](https://github.com/jrnl-org/jrnl/pull/1513) ([apainintheneck](https://github.com/apainintheneck))
|
||||||
|
- Stop hardcoding bot info in changelog pipeline [\#1506](https://github.com/jrnl-org/jrnl/pull/1506) ([wren](https://github.com/wren))
|
||||||
|
- Fix Poetry caching for accessibility tests [\#1505](https://github.com/jrnl-org/jrnl/pull/1505) ([wren](https://github.com/wren))
|
||||||
|
- Implement Tox for testing [\#1504](https://github.com/jrnl-org/jrnl/pull/1504) ([wren](https://github.com/wren))
|
||||||
|
- Replace `make` with python alternative \(`poe`\) [\#1503](https://github.com/jrnl-org/jrnl/pull/1503) ([wren](https://github.com/wren))
|
||||||
|
- Update copyright year [\#1502](https://github.com/jrnl-org/jrnl/pull/1502) ([wren](https://github.com/wren))
|
||||||
|
- Add Python 3.11 to PR tests [\#1500](https://github.com/jrnl-org/jrnl/pull/1500) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Pin jinja2 in docs requirements to keep readthedocs builds from failing [\#1439](https://github.com/jrnl-org/jrnl/pull/1439) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Tidy up git ignore [\#1414](https://github.com/jrnl-org/jrnl/pull/1414) ([nelnog](https://github.com/nelnog))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Document --change-time in web-based docs' command line reference [\#1471](https://github.com/jrnl-org/jrnl/pull/1471) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump cryptography from 37.0.2 to 37.0.3 [\#1516](https://github.com/jrnl-org/jrnl/pull/1516) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump poethepoet from 0.13.1 to 0.14.0 [\#1514](https://github.com/jrnl-org/jrnl/pull/1514) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.5.1 to 23.6.0 [\#1499](https://github.com/jrnl-org/jrnl/pull/1499) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pyxdg from 0.27 to 0.28 [\#1497](https://github.com/jrnl-org/jrnl/pull/1497) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.5.0 to 23.5.1 [\#1487](https://github.com/jrnl-org/jrnl/pull/1487) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump cryptography from 37.0.1 to 37.0.2 [\#1467](https://github.com/jrnl-org/jrnl/pull/1467) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump cryptography from 36.0.2 to 37.0.1 [\#1462](https://github.com/jrnl-org/jrnl/pull/1462) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytest from 7.1.1 to 7.1.2 [\#1458](https://github.com/jrnl-org/jrnl/pull/1458) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pyproject-flake8 from 0.0.1a3 to 0.0.1a4 [\#1447](https://github.com/jrnl-org/jrnl/pull/1447) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump black from 22.1.0 to 22.3.0 [\#1442](https://github.com/jrnl-org/jrnl/pull/1442) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump mkdocs from 1.2.3 to 1.3.0 [\#1441](https://github.com/jrnl-org/jrnl/pull/1441) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pyproject-flake8 from 0.0.1a2 to 0.0.1a3 [\#1440](https://github.com/jrnl-org/jrnl/pull/1440) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytz from 2021.3 to 2022.1 [\#1438](https://github.com/jrnl-org/jrnl/pull/1438) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytest from 7.0.1 to 7.1.1 [\#1430](https://github.com/jrnl-org/jrnl/pull/1430) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump cryptography from 36.0.1 to 36.0.2 [\#1427](https://github.com/jrnl-org/jrnl/pull/1427) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump yq from 2.13.0 to 2.14.0 [\#1418](https://github.com/jrnl-org/jrnl/pull/1418) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Replace PyYAML with ruamel.yaml [\#1416](https://github.com/jrnl-org/jrnl/pull/1416) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Bump pytest from 6.2.5 to 7.0.0 [\#1407](https://github.com/jrnl-org/jrnl/pull/1407) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.8.4](https://pypi.org/project/jrnl/v2.8.4/) (2022-02-12)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.4-beta2...v2.8.4)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add hash as a default tag symbol for new jrnl config file [\#1398](https://github.com/jrnl-org/jrnl/pull/1398) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add --config-file argument to use alternate config file at runtime [\#1290](https://github.com/jrnl-org/jrnl/pull/1290) ([samuelgregorovic](https://github.com/samuelgregorovic))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Certs broken on website [\#1408](https://github.com/jrnl-org/jrnl/issues/1408)
|
||||||
|
- Add added option to \_print\_edited\_summary [\#1366](https://github.com/jrnl-org/jrnl/pull/1366) ([piero-vic](https://github.com/piero-vic))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Improve handling of mocking logic in pytest [\#1382](https://github.com/jrnl-org/jrnl/pull/1382) ([wren](https://github.com/wren))
|
||||||
|
- Use full Python version for GitHub Actions cache key [\#1373](https://github.com/jrnl-org/jrnl/pull/1373) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Use Python 3.10 stable in CI [\#1362](https://github.com/jrnl-org/jrnl/pull/1362) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Switch from poetry to poetry-core [\#1359](https://github.com/jrnl-org/jrnl/pull/1359) ([fabaff](https://github.com/fabaff))
|
||||||
|
- Add more steps to `pytest`, fully remove `behave` [\#1347](https://github.com/jrnl-org/jrnl/pull/1347) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Fix styling on documentation sidebar [\#1395](https://github.com/jrnl-org/jrnl/pull/1395) ([wren](https://github.com/wren))
|
||||||
|
- Added Recipe for visualizing Markdown in the CLI [\#1354](https://github.com/jrnl-org/jrnl/pull/1354) ([viegasfh](https://github.com/viegasfh))
|
||||||
|
- Fix recipe 'Launch a terminal for rapid logging' [\#1351](https://github.com/jrnl-org/jrnl/pull/1351) ([zapateo](https://github.com/zapateo))
|
||||||
|
- Fix readme splash and add changelog link to readme [\#1339](https://github.com/jrnl-org/jrnl/pull/1339) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add reference documentation to docs site and separate out "Tips and Tricks" and "External Editors" from "Recipes" [\#1332](https://github.com/jrnl-org/jrnl/pull/1332) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Document journal types [\#1331](https://github.com/jrnl-org/jrnl/pull/1331) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump asteval from 0.9.25 to 0.9.26 [\#1400](https://github.com/jrnl-org/jrnl/pull/1400) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump black from 21.7b0 to 22.1.0 [\#1404](https://github.com/jrnl-org/jrnl/pull/1404) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump cryptography from 3.4.8 to 36.0.1 [\#1389](https://github.com/jrnl-org/jrnl/pull/1389) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump ipython from 7.28.0 to 7.31.1 [\#1401](https://github.com/jrnl-org/jrnl/pull/1401) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.1.0 to 23.5.0 [\#1392](https://github.com/jrnl-org/jrnl/pull/1392) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump mkdocs from 1.2.2 to 1.2.3 [\#1355](https://github.com/jrnl-org/jrnl/pull/1355) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytest from 6.2.4 to 6.2.5 [\#1334](https://github.com/jrnl-org/jrnl/pull/1334) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytest-bdd from 4.1.0 to 5.0.0 [\#1368](https://github.com/jrnl-org/jrnl/pull/1368) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytz from 2021.1 to 2021.3 [\#1348](https://github.com/jrnl-org/jrnl/pull/1348) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump yq from 2.12.2 to 2.13.0 [\#1385](https://github.com/jrnl-org/jrnl/pull/1385) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.8.3](https://pypi.org/project/jrnl/v2.8.3/) (2021-09-06)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.3-beta...v2.8.3)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Fix deletion of entries on folder journal through `--delete` flag [\#1328](https://github.com/jrnl-org/jrnl/pull/1328) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Warn when DayOne/directory journals have encrypt: true in config [\#1325](https://github.com/jrnl-org/jrnl/pull/1325) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Fix failure to import into directory journal [\#1314](https://github.com/jrnl-org/jrnl/pull/1314) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Allow emoji in config file in Windows by always opening it as unicode [\#1313](https://github.com/jrnl-org/jrnl/pull/1313) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Set bash as default shell [\#1324](https://github.com/jrnl-org/jrnl/pull/1324) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump cryptography from 3.4.7 to 3.4.8 [\#1329](https://github.com/jrnl-org/jrnl/pull/1329) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.0.1 to 23.1.0 [\#1318](https://github.com/jrnl-org/jrnl/pull/1318) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.8.2](https://pypi.org/project/jrnl/v2.8.2/) (2021-07-31)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.2-beta...v2.8.2)
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add CI tests for latest dev Python build [\#1273](https://github.com/jrnl-org/jrnl/issues/1273)
|
||||||
|
- Fix lock file from stable Poetry version [\#1298](https://github.com/jrnl-org/jrnl/pull/1298) ([wren](https://github.com/wren))
|
||||||
|
- Change all YAML FullLoader calls to SafeLoader [\#1285](https://github.com/jrnl-org/jrnl/pull/1285) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Remove useless shebangs and executable permissions [\#1283](https://github.com/jrnl-org/jrnl/pull/1283) ([musicinmybrain](https://github.com/musicinmybrain))
|
||||||
|
- Add Python 3.10 support [\#1271](https://github.com/jrnl-org/jrnl/pull/1271) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Ensure that line endings in all py files are Linux style instead of Windows [\#1250](https://github.com/jrnl-org/jrnl/pull/1250) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Remove `--version` from brew release workflow [\#1233](https://github.com/jrnl-org/jrnl/pull/1233) ([wren](https://github.com/wren))
|
||||||
|
- Move test suite to Pytest \(replace Behave\) [\#1193](https://github.com/jrnl-org/jrnl/pull/1193) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Add documentation about saved passwords in Windows [\#1301](https://github.com/jrnl-org/jrnl/pull/1301) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add security.md [\#1299](https://github.com/jrnl-org/jrnl/pull/1299) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump mkdocs from 1.2.1 to 1.2.2 [\#1307](https://github.com/jrnl-org/jrnl/pull/1307) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump python-dateutil from 2.8.1 to 2.8.2 [\#1302](https://github.com/jrnl-org/jrnl/pull/1302) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump black from 21.5b1 to 21.5b2 [\#1254](https://github.com/jrnl-org/jrnl/pull/1254) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump black from 21.5b0 to 21.5b1 [\#1244](https://github.com/jrnl-org/jrnl/pull/1244) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump black from 20.8b1 to 21.5b0 [\#1241](https://github.com/jrnl-org/jrnl/pull/1241) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytest from 6.2.3 to 6.2.4 [\#1240](https://github.com/jrnl-org/jrnl/pull/1240) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.8.1](https://pypi.org/project/jrnl/v2.8.1/) (2021-04-24)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.1-beta...v2.8.1)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- More graceful handling of low linewrap values [\#1219](https://github.com/jrnl-org/jrnl/pull/1219) ([sriniv27](https://github.com/sriniv27))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Update absolute URLs to preview images in metatags [\#1229](https://github.com/jrnl-org/jrnl/pull/1229) ([maebert](https://github.com/maebert))
|
||||||
|
- Docs: Add emacs as external editor to recipes [\#1220](https://github.com/jrnl-org/jrnl/pull/1220) ([mandarvaze](https://github.com/mandarvaze))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump pytest from 6.2.2 to 6.2.3 [\#1228](https://github.com/jrnl-org/jrnl/pull/1228) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump cryptography from 3.4.6 to 3.4.7 [\#1223](https://github.com/jrnl-org/jrnl/pull/1223) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 23.0.0 to 23.0.1 [\#1222](https://github.com/jrnl-org/jrnl/pull/1222) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pyflakes from 2.3.0 to 2.3.1 [\#1221](https://github.com/jrnl-org/jrnl/pull/1221) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.8](https://pypi.org/project/jrnl/v2.8/) (2021-03-27)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8-beta...v2.8)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add `--config-override` feature [\#1169](https://github.com/jrnl-org/jrnl/pull/1169) ([sriniv27](https://github.com/sriniv27))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Fix bug that prevented --format pretty and --format short from working [\#1177](https://github.com/jrnl-org/jrnl/pull/1177) ([sriniv27](https://github.com/sriniv27))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Fix broken brew release process [\#1211](https://github.com/jrnl-org/jrnl/pull/1211) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump pyflakes from 2.2.0 to 2.3.0 [\#1215](https://github.com/jrnl-org/jrnl/pull/1215) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 22.3.0 to 23.0.0 [\#1213](https://github.com/jrnl-org/jrnl/pull/1213) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 22.0.1 to 22.3.0 [\#1210](https://github.com/jrnl-org/jrnl/pull/1210) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump asteval from 0.9.22 to 0.9.23 [\#1209](https://github.com/jrnl-org/jrnl/pull/1209) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.7.1](https://pypi.org/project/jrnl/v2.7.1/) (2021-02-27)
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.7...v2.7.1)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Make journal selection behavior more consistent when there's a colon with no date [\#1164](https://github.com/jrnl-org/jrnl/pull/1164) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Update documentation about journal-level config values [\#1196](https://github.com/jrnl-org/jrnl/issues/1196)
|
||||||
|
- update per-journal config documentation [\#1199](https://github.com/jrnl-org/jrnl/pull/1199) ([sriniv27](https://github.com/sriniv27))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump cryptography from 3.4.4 to 3.4.6 [\#1195](https://github.com/jrnl-org/jrnl/pull/1195) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump asteval from 0.9.21 to 0.9.22 [\#1189](https://github.com/jrnl-org/jrnl/pull/1189) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump cryptography from 3.3.1 to 3.4.4 [\#1188](https://github.com/jrnl-org/jrnl/pull/1188) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump yq from 2.11.1 to 2.12.0 [\#1186](https://github.com/jrnl-org/jrnl/pull/1186) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytz from 2020.5 to 2021.1 [\#1174](https://github.com/jrnl-org/jrnl/pull/1174) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 21.8.0 to 22.0.1 [\#1168](https://github.com/jrnl-org/jrnl/pull/1168) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytest from 6.2.1 to 6.2.2 [\#1167](https://github.com/jrnl-org/jrnl/pull/1167) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
|
## [v2.7](https://pypi.org/project/jrnl/v2.7/) (2021-01-23)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.7-beta...v2.7)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add new date format \(`--format date`\) for heatmapping [\#1146](https://github.com/jrnl-org/jrnl/pull/1146) ([KarimPwnz](https://github.com/KarimPwnz))
|
||||||
|
- Add new `-today-in-history`, `-month`, `-day`, and `-year` search filters [\#1145](https://github.com/jrnl-org/jrnl/pull/1145) ([KarimPwnz](https://github.com/KarimPwnz))
|
||||||
|
- Allow custom extensions when editing \(for easier syntax highlighting\) [\#1139](https://github.com/jrnl-org/jrnl/pull/1139) ([KarimPwnz](https://github.com/KarimPwnz))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Editor can't be launched on Windows when using full path to editor executable [\#1096](https://github.com/jrnl-org/jrnl/issues/1096)
|
||||||
|
- Fix OS compatibility issues for editors with spaces, slashes, and quotes [\#1153](https://github.com/jrnl-org/jrnl/pull/1153) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add delimiters in YAML format [\#1150](https://github.com/jrnl-org/jrnl/pull/1150) ([Seopril](https://github.com/Seopril))
|
||||||
|
- Fix keyring error handling [\#1138](https://github.com/jrnl-org/jrnl/pull/1138) ([KarimPwnz](https://github.com/KarimPwnz))
|
||||||
|
- Notify user when config directory can't be created because there is already a file with the same name [\#1134](https://github.com/jrnl-org/jrnl/pull/1134) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Fix homebrew release, add options for release pipeline [\#1154](https://github.com/jrnl-org/jrnl/pull/1154) ([wren](https://github.com/wren))
|
||||||
|
- Fix changelog generator [\#1127](https://github.com/jrnl-org/jrnl/pull/1127) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- add instructions to add VSCode as an external editor for Windows [\#1155](https://github.com/jrnl-org/jrnl/issues/1155)
|
||||||
|
- Clarify editor documentation for PATH variable and VS Code [\#1160](https://github.com/jrnl-org/jrnl/pull/1160) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Emphasize installing dependencies before testing [\#1148](https://github.com/jrnl-org/jrnl/pull/1148) ([gumatias](https://github.com/gumatias))
|
||||||
|
- Clarify installation documentation \(\#1097\) [\#1137](https://github.com/jrnl-org/jrnl/pull/1137) ([Seopril](https://github.com/Seopril))
|
||||||
|
- Fix broken search bar in docs site [\#1135](https://github.com/jrnl-org/jrnl/pull/1135) ([wren](https://github.com/wren))
|
||||||
|
- Fix search on docs site [\#1133](https://github.com/jrnl-org/jrnl/pull/1133) ([wren](https://github.com/wren))
|
||||||
|
- Add packaging label to changelog generator config [\#1132](https://github.com/jrnl-org/jrnl/pull/1132) ([wren](https://github.com/wren))
|
||||||
|
- Fix failing contrast test in accessibility tools on docs site [\#1126](https://github.com/jrnl-org/jrnl/pull/1126) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Packaging:**
|
||||||
|
|
||||||
|
- Bump pyyaml from 5.3.1 to 5.4.1 [\#1158](https://github.com/jrnl-org/jrnl/pull/1158) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump keyring from 21.7.0 to 21.8.0 [\#1136](https://github.com/jrnl-org/jrnl/pull/1136) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump pytz from 2020.4 to 2020.5 [\#1130](https://github.com/jrnl-org/jrnl/pull/1130) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
|
||||||
|
- Bump pytest from 6.2.0 to 6.2.1 [\#1129](https://github.com/jrnl-org/jrnl/pull/1129) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
|
||||||
|
- Bump keyring from 21.5.0 to 21.7.0 [\#1128](https://github.com/jrnl-org/jrnl/pull/1128) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
|
||||||
|
|
||||||
|
## [v2.6](https://pypi.org/project/jrnl/v2.6/) (2020-12-20)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.5...v2.6)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add ability to put --edit partly through a cli entry to move it to the editor [\#1091](https://github.com/jrnl-org/jrnl/pull/1091) ([wren](https://github.com/wren))
|
||||||
|
- Allow --edit flag partway through an entry [\#906](https://github.com/jrnl-org/jrnl/issues/906)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Check for readline module instead of Windows when initializing autocomplete in install [\#1104](https://github.com/jrnl-org/jrnl/pull/1104) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Directory export crashes in Windows with certain characters - UnicodeEncodeError: 'locale' codec can't encode character [\#1089](https://github.com/jrnl-org/jrnl/issues/1089)
|
||||||
|
- Fix Unicode encoding failure in directory export when creating filenames from journal titles with certain characters [\#1090](https://github.com/jrnl-org/jrnl/pull/1090) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Typo fix in output.py: "us" -\> "use" [\#1117](https://github.com/jrnl-org/jrnl/pull/1117) ([signal-9](https://github.com/signal-9))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add a release workflow for PyPI in CI \(Github Actions\) [\#1095](https://github.com/jrnl-org/jrnl/pull/1095) ([wren](https://github.com/wren))
|
||||||
|
- Add automatic deployment for homebrew releases \(and prereleases\) [\#1111](https://github.com/jrnl-org/jrnl/pull/1111) ([wren](https://github.com/wren))
|
||||||
|
- Add changelog generation workflow to github actions [\#1086](https://github.com/jrnl-org/jrnl/pull/1086) ([wren](https://github.com/wren))
|
||||||
|
- Add fix for changelog conditional always returning false [\#1101](https://github.com/jrnl-org/jrnl/pull/1101) ([wren](https://github.com/wren))
|
||||||
|
- Change approach for docs workflow to use pa11y-ci [\#1116](https://github.com/jrnl-org/jrnl/pull/1116) ([wren](https://github.com/wren))
|
||||||
|
- Changelog fixes [\#1088](https://github.com/jrnl-org/jrnl/pull/1088) ([wren](https://github.com/wren))
|
||||||
|
- Fix trigger for changelog [\#1114](https://github.com/jrnl-org/jrnl/pull/1114) ([wren](https://github.com/wren))
|
||||||
|
- Make changelog auto exclude stale and wontfix issues [\#1081](https://github.com/jrnl-org/jrnl/pull/1081) ([wren](https://github.com/wren))
|
||||||
|
- Migrate to Github Actions from Travis CI [\#1060](https://github.com/jrnl-org/jrnl/issues/1060)
|
||||||
|
- More changelog fixes [\#1092](https://github.com/jrnl-org/jrnl/pull/1092) ([wren](https://github.com/wren))
|
||||||
|
- Standardize version regex in release pipeline [\#1124](https://github.com/jrnl-org/jrnl/pull/1124) ([wren](https://github.com/wren))
|
||||||
|
- Udpate build badge in readme to point at github instead of travis [\#1094](https://github.com/jrnl-org/jrnl/pull/1094) ([wren](https://github.com/wren))
|
||||||
|
- Update all dependencies and lock file [\#1110](https://github.com/jrnl-org/jrnl/pull/1110) ([wren](https://github.com/wren))
|
||||||
|
- get rid of travis and circle configs \(in favor of github actions\) [\#1082](https://github.com/jrnl-org/jrnl/pull/1082) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
|
||||||
|
- Add visual header to readme [\#1085](https://github.com/jrnl-org/jrnl/pull/1085) ([wren](https://github.com/wren))
|
||||||
|
- Comply with GPL by acknowledging all authors and including license info in each source file [\#1121](https://github.com/jrnl-org/jrnl/pull/1121) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Fix lone closing parenthesis [\#1118](https://github.com/jrnl-org/jrnl/pull/1118) ([maebert](https://github.com/maebert))
|
||||||
|
- Make docs site \(jrnl.sh\) fully meet Web Content Accessibility Guidelines \(WCAG\) 2.1 [\#1105](https://github.com/jrnl-org/jrnl/pull/1105) ([wren](https://github.com/wren))
|
||||||
|
- Small accessibility fixes for docs site [\#1122](https://github.com/jrnl-org/jrnl/pull/1122) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
## [v2.5](https://pypi.org/project/jrnl/v2.5/) (2020-11-07)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.5...v2.5)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- 🚨 Deprecate Python 3.6 🚨 [\#992](https://github.com/jrnl-org/jrnl/issues/992)
|
||||||
|
- Add support for Python 3.9 [\#1017](https://github.com/jrnl-org/jrnl/issues/1017)
|
||||||
|
- Implement arg parsing library [\#866](https://github.com/jrnl-org/jrnl/issues/866)
|
||||||
|
- Rename `--export` to `--format` and `--export -o` to `--format --file` [\#814](https://github.com/jrnl-org/jrnl/issues/814)
|
||||||
|
- Pull functionality out of util.py [\#737](https://github.com/jrnl-org/jrnl/issues/737)
|
||||||
|
- Support -not for individual @tag in the command line [\#374](https://github.com/jrnl-org/jrnl/issues/374)
|
||||||
|
- Add punctuation more commonly used in Asian languages \(ellipsis\) to sentence parsing [\#1044](https://github.com/jrnl-org/jrnl/pull/1044) ([felixonmars](https://github.com/felixonmars))
|
||||||
|
- Clean up help screen, get rid of util.py [\#1027](https://github.com/jrnl-org/jrnl/pull/1027) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Extra error when writing empty entry [\#1048](https://github.com/jrnl-org/jrnl/issues/1048)
|
||||||
|
- 'Edit on Github' Button in Documentation not working [\#1039](https://github.com/jrnl-org/jrnl/issues/1039)
|
||||||
|
- Decrypt jrnl file in dropbox on another machine fails [\#1019](https://github.com/jrnl-org/jrnl/issues/1019)
|
||||||
|
- Listing jrnl entries by tag for non default journal seem to not work as expected. [\#875](https://github.com/jrnl-org/jrnl/issues/875)
|
||||||
|
- -and parameter seems to only work for the default journal [\#520](https://github.com/jrnl-org/jrnl/issues/520)
|
||||||
|
- Disable logging by default [\#1053](https://github.com/jrnl-org/jrnl/pull/1053) ([wren](https://github.com/wren))
|
||||||
|
- Partial refactor of cli.py \(mainly help screen and arg parsing\) [\#991](https://github.com/jrnl-org/jrnl/pull/991) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add accessibility testing for docs site \(https://jrnl.sh) [\#1067](https://github.com/jrnl-org/jrnl/pull/1067) ([wren](https://github.com/wren))
|
||||||
|
- Add circle ci config file for linux tests [\#1063](https://github.com/jrnl-org/jrnl/pull/1063) ([wren](https://github.com/wren))
|
||||||
|
- Lots of test refactoring [\#1042](https://github.com/jrnl-org/jrnl/pull/1042) ([wren](https://github.com/wren))
|
||||||
|
- Add support for Python 3.9 build testing [\#1018](https://github.com/jrnl-org/jrnl/pull/1018) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Resolve Travis/Windows/pip issues with upgrade to cryptography 3.0 [\#1016](https://github.com/jrnl-org/jrnl/pull/1016) ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
**Updated documentation:**
|
||||||
|
|
||||||
|
- Clarify usage output between export and reading sections [\#344](https://github.com/jrnl-org/jrnl/issues/344)
|
||||||
|
- Fix "Edit on GitHub" button on docs site [\#1043](https://github.com/jrnl-org/jrnl/pull/1043) ([matildepark](https://github.com/matildepark))
|
||||||
|
- Correct typos in CONTRIBUTING.md [\#1040](https://github.com/jrnl-org/jrnl/pull/1040) ([felixonmars](https://github.com/felixonmars))
|
||||||
|
- Change styling of terminal on docs site, small copy changes [\#1038](https://github.com/jrnl-org/jrnl/pull/1038) ([wren](https://github.com/wren))
|
||||||
|
- Documentation updates [\#1032](https://github.com/jrnl-org/jrnl/pull/1032) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Updated advanced.md in docs to reflect all four subkeys under colors … [\#1023](https://github.com/jrnl-org/jrnl/pull/1023) ([DacodaNelson](https://github.com/DacodaNelson))
|
||||||
|
- Update github issue templates to use new diagnostic command [\#1022](https://github.com/jrnl-org/jrnl/pull/1022) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
## [v2.4.5](https://pypi.org/project/jrnl/v2.4.5/) (2020-07-31)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.4...v2.4.5)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Add missing dependency \(packaging\) [\#1011](https://github.com/jrnl-org/jrnl/pull/1011) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
## [v2.4.4](https://pypi.org/project/jrnl/v2.4.4/) (2020-07-25)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.4...v2.4.3)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add --diagnostic argument [\#984](https://github.com/jrnl-org/jrnl/pull/984) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Add tags to json and xml exporters [\#975](https://github.com/jrnl-org/jrnl/pull/975) ([eshrh](https://github.com/eshrh))
|
||||||
|
- Add extended metadata support for DayOne Classic [\#928](https://github.com/jrnl-org/jrnl/pull/928) ([MinchinWeb](https://github.com/MinchinWeb))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Allow editing of DayOne entries [\#1001](https://github.com/jrnl-org/jrnl/pull/1001) ([minchinweb](https://github.com/minchinweb), [micahellison](https://github.com/micahellison), [wren](https://github.com/wren))
|
||||||
|
- Create journal with absolute path when no path is specified [\#972](https://github.com/jrnl-org/jrnl/pull/972) ([eshrh](https://github.com/eshrh))
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
|
||||||
|
- Add unit testing via pytest [\#987](https://github.com/jrnl-org/jrnl/pull/987) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Rename master branch to release [\#985](https://github.com/jrnl-org/jrnl/pull/985) ([wren](https://github.com/wren))
|
||||||
|
|
||||||
|
**Updated documentation:**
|
||||||
|
|
||||||
|
- Fix readme link to submit an issue [\#1002](https://github.com/jrnl-org/jrnl/pull/1002) ([wren](https://github.com/wren))
|
||||||
|
- Extensive modifications to overview.md [\#957](https://github.com/jrnl-org/jrnl/pull/957) ([guydebros](https://github.com/guydebros))
|
||||||
|
|
||||||
|
## [v2.4.3](https://pypi.org/project/jrnl/v2.4.3/) (2020-06-13)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.2...v2.4.3)
|
||||||
|
|
||||||
**Implemented enhancements:**
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
@ -10,6 +719,7 @@
|
||||||
|
|
||||||
**Fixed bugs:**
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Fix set\_keychain errors [\#964](https://github.com/jrnl-org/jrnl/pull/964) ([eshrh](https://github.com/eshrh))
|
||||||
- Fix title splitting logic to account for both newlines and periods [\#958](https://github.com/jrnl-org/jrnl/pull/958) ([eshrh](https://github.com/eshrh))
|
- Fix title splitting logic to account for both newlines and periods [\#958](https://github.com/jrnl-org/jrnl/pull/958) ([eshrh](https://github.com/eshrh))
|
||||||
- Fix editor config when an argument with a space is used [\#953](https://github.com/jrnl-org/jrnl/pull/953) ([wren](https://github.com/wren))
|
- Fix editor config when an argument with a space is used [\#953](https://github.com/jrnl-org/jrnl/pull/953) ([wren](https://github.com/wren))
|
||||||
- Ask for password before adding entry instead of after [\#951](https://github.com/jrnl-org/jrnl/pull/951) ([ollybritton](https://github.com/ollybritton))
|
- Ask for password before adding entry instead of after [\#951](https://github.com/jrnl-org/jrnl/pull/951) ([ollybritton](https://github.com/ollybritton))
|
||||||
|
@ -19,6 +729,7 @@
|
||||||
|
|
||||||
- Fix for hanging Windows tests on Travis [\#969](https://github.com/jrnl-org/jrnl/pull/969) ([wren](https://github.com/wren))
|
- Fix for hanging Windows tests on Travis [\#969](https://github.com/jrnl-org/jrnl/pull/969) ([wren](https://github.com/wren))
|
||||||
- Ensure test data is always checked out with LF line endings [\#965](https://github.com/jrnl-org/jrnl/pull/965) ([micahellison](https://github.com/micahellison))
|
- Ensure test data is always checked out with LF line endings [\#965](https://github.com/jrnl-org/jrnl/pull/965) ([micahellison](https://github.com/micahellison))
|
||||||
|
- Clean up templates and issues [\#954](https://github.com/jrnl-org/jrnl/pull/954) ([wren](https://github.com/wren))
|
||||||
- Update lockbot comment to encourage linking to issue [\#941](https://github.com/jrnl-org/jrnl/pull/941) ([MinchinWeb](https://github.com/MinchinWeb))
|
- Update lockbot comment to encourage linking to issue [\#941](https://github.com/jrnl-org/jrnl/pull/941) ([MinchinWeb](https://github.com/MinchinWeb))
|
||||||
|
|
||||||
**Updated documentation:**
|
**Updated documentation:**
|
||||||
|
|
|
@ -59,7 +59,7 @@ representative at an online or offline event.
|
||||||
## Enforcement
|
## Enforcement
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported by [emailing the maintainers](mailto:jrnl-sh@googlegroups.com).
|
reported by [emailing the maintainers](mailto:maintainers@jrnl.sh).
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
|
126
CONTRIBUTING.md
|
@ -1,122 +1,8 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
We welcome contributions to jrnl, whether it's through reporting bugs, improving the documentation, testing releases, engaging in discussion on features and bugs, or writing code.
|
See "[Contributing](docs/contributing.md)" in the `docs` directory.
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
* [Code of Conduct](#code-of-conduct)
|
|
||||||
* [Reporting Bugs](#reporting-bugs)
|
|
||||||
* [Editing Documentation](#editing-documentation)
|
|
||||||
* [Testing](#testing)
|
|
||||||
* [Submitting feature requests and ideas](#submitting-feature-requests-and-ideas)
|
|
||||||
* [Developing](#developing)
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
Before starting, please read the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
||||||
|
|
||||||
## Reporting Bugs
|
|
||||||
|
|
||||||
Please report bugs by [opening a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) and describing it as well as possible. Many bugs are specific to a particular operating system and Python version, so please include that information!
|
|
||||||
|
|
||||||
## Editing Documentation
|
|
||||||
|
|
||||||
If you find a typo or a mistake in the docs, please fix it right away and send a pull request.
|
|
||||||
|
|
||||||
To edit the documentation, edit the `docs/*.md` files on the **develop** branch. You can see the result if you run `make html` (or `poetry run mkdocs serve` if on Windows) inside the project's root directory, then navigating your browser to [locahost:8000](http://localhost:8000).
|
|
||||||
|
|
||||||
The `gh-pages` branch is automatically maintained and generated after your changes are merged. You should never have to edit that branch.
|
|
||||||
|
|
||||||
### Recipes and external editors
|
|
||||||
|
|
||||||
If you'd like to share a jrnl command line trick that you find useful, or advice on how to integrate a particular external editor, you may find it worthwile to add it to the ["Recipes" section](docs/recipes.md).
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
Much of the work of maintaining jrnl involves testing rather than coding.
|
|
||||||
|
|
||||||
The nature of jrnl means we deal with extremely sensitive data, and can't risk data loss. While jrnl does have a comprehensive automated testing suite, user testing is crucial to mitigating this risk.
|
|
||||||
|
|
||||||
### Prereleases
|
|
||||||
|
|
||||||
[Prereleases are deployed through PyPi much like normal releases](https://pypi.org/project/jrnl/#history). You can use [pipx](https://pypi.org/project/pipx/) to fetch them and test them. See the [changelog](CHANGELOG.md) for information on what has changed with each release.
|
|
||||||
|
|
||||||
### Pull requests
|
|
||||||
|
|
||||||
If you are comfortable enough with git, feel free to fetch particular [pull requests](https://github.com/jrnl-org/jrnl/pulls), test them yourself, and report back your findings. Bonus points if you can add a screencast of how the new feature works.
|
|
||||||
|
|
||||||
### Confirm bug reports
|
|
||||||
|
|
||||||
There are always [open bugs among our GitHub issues](https://github.com/jrnl-org/jrnl/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and many are specific to a particular OS, Python version, or jrnl version. A simple comment like "Confirmed on jrnl v2.2, MacOS 10.15, Python 3.8.1" would be extremely helpful in tracking down bugs.
|
|
||||||
|
|
||||||
### Automate tests
|
|
||||||
|
|
||||||
See the develop section below for information on how to contribute new automated tests.
|
|
||||||
|
|
||||||
## Submitting feature requests and ideas
|
|
||||||
|
|
||||||
If you have a feature request or idea for jrnl, please [open a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) and describe the goal of the feature, and any relevant use cases. We'll discuss the issue with you, and decide if it's a good fit for the project.
|
|
||||||
|
|
||||||
When discussing new features, please keep in mind our design goals. jrnl strives to do one thing well. To us, that means:
|
|
||||||
|
|
||||||
* be _slim_
|
|
||||||
* have a simple interface
|
|
||||||
* avoid duplicating functionality
|
|
||||||
|
|
||||||
## Developing
|
|
||||||
|
|
||||||
### Getting your environment set up
|
|
||||||
|
|
||||||
You will need to install [poetry](https://poetry.eustace.io/) to develop jrnl. It will take care of all of the project's other dependencies.
|
|
||||||
|
|
||||||
### Understanding the branches
|
|
||||||
|
|
||||||
jrnl uses two primary branches:
|
|
||||||
|
|
||||||
* `develop` - for ongoing development
|
|
||||||
* `master` - for releases
|
|
||||||
|
|
||||||
In general, pull requests should be made on the `develop` branch.
|
|
||||||
|
|
||||||
### Common development commands
|
|
||||||
|
|
||||||
You can find an inventory of commands in the `makefile`. \*nix users can run the commands by typing `make` followed by the name of the command; however, Windows users will need to type out the commands directly, or install a third-party make tool such as [GNU Make for Windows](http://gnuwin32.sourceforge.net/packages/make.htm).
|
|
||||||
|
|
||||||
A typical development workflow includes:
|
|
||||||
|
|
||||||
* Running tests: `make test`
|
|
||||||
* Running the source in a virtual environment:
|
|
||||||
* `poetry install`
|
|
||||||
* `poetry shell`
|
|
||||||
* `jrnl` (with or without arguments as necessary)
|
|
||||||
* Linting the code to standardize its style: `make lint`
|
|
||||||
|
|
||||||
### Updating automated tests
|
|
||||||
|
|
||||||
When resolving bugs or adding new functionality, please add tests to prevent that functionality from breaking in the future. If you notice any functionality that isn't covered in the tests, feel free to submit a test-only pull request as well.
|
|
||||||
|
|
||||||
For testing, jrnl uses [behave](https://behave.readthedocs.io/) tests, which are all in the `features` folder.
|
|
||||||
|
|
||||||
Many tests can be created by only editing `feature` files with the same format as other tests. For more complicated functionality, you may need to implement steps in `features/steps` which are then executed by your tests in the `feature` files.
|
|
||||||
|
|
||||||
### Submitting pull requests
|
|
||||||
|
|
||||||
When you're ready, feel free to submit a pull request (PR). The jrnl maintainers generally review the pull requests every two weeks, but the continuous integration pipeline will run on automated tests on it within a matter of minutes and will report back any issues it has found with your code across a variety of environments.
|
|
||||||
|
|
||||||
The pull request template contains a checklist full of housekeeping items. Please fill them out as necessary when you submit.
|
|
||||||
|
|
||||||
If a pull request contains failing tests, it probably will not be reviewed, and it definitely will not be approved. However, if you need help resolving a failing test, please mention that in your PR.
|
|
||||||
|
|
||||||
### Finding things to work on
|
|
||||||
|
|
||||||
You can search the [jrnl GitHub issues](https://github.com/jrnl-org/jrnl/issues) by [label](https://github.com/jrnl-org/jrnl/labels) for things to work on. Here are some labels worth searching:
|
|
||||||
|
|
||||||
* [critical](https://github.com/jrnl-org/jrnl/labels/critical)
|
|
||||||
* [help wanted](https://github.com/jrnl-org/jrnl/labels/help%20wanted)
|
|
||||||
* [bug](https://github.com/jrnl-org/jrnl/labels/bug)
|
|
||||||
* [enhancement](https://github.com/jrnl-org/jrnl/labels/enhancement)
|
|
||||||
|
|
||||||
### A note for new programmers and programmers new to python
|
|
||||||
|
|
||||||
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!
|
|
||||||
|
|
31
Makefile
|
@ -1,31 +0,0 @@
|
||||||
# A Makefile for commands I run frequently:
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf dist
|
|
||||||
rm -rf _static
|
|
||||||
rm -rf jrnl.egg-info
|
|
||||||
rm -rf _build
|
|
||||||
rm -rf _sources
|
|
||||||
rm -rf _static
|
|
||||||
rm -rf site/
|
|
||||||
rm -f *.html
|
|
||||||
|
|
||||||
html:
|
|
||||||
poetry run mkdocs serve
|
|
||||||
|
|
||||||
format: ## Format files to match style
|
|
||||||
poetry run black .
|
|
||||||
|
|
||||||
lint: ## Check style with various tools
|
|
||||||
poetry check
|
|
||||||
poetry run pyflakes .
|
|
||||||
poetry run black --check --diff .
|
|
||||||
|
|
||||||
test: lint ## Run behave tests
|
|
||||||
poetry run behave
|
|
||||||
|
|
||||||
build:
|
|
||||||
poetry build
|
|
||||||
|
|
||||||
install: clean ## install the package to the active Python's site-packages
|
|
||||||
poetry install
|
|
83
README.md
|
@ -1,71 +1,82 @@
|
||||||
jrnl [](https://travis-ci.com/jrnl-org/jrnl) [](https://pepy.tech/project/jrnl) [](https://pypi.python.org/pypi/jrnl/)
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://jrnl.sh">
|
||||||
|
<img align="center" src="https://raw.githubusercontent.com/jrnl-org/jrnl/develop/docs_theme/assets/readme-header.png"/>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
jrnl
|
||||||
|
[](https://github.com/jrnl-org/jrnl/actions?query=workflow%3ATesting)
|
||||||
|
[](https://pepy.tech/project/jrnl)
|
||||||
|
[](https://pypi.python.org/pypi/jrnl/)
|
||||||
|
[](https://formulae.brew.sh/formula/jrnl)
|
||||||
|
[](https://gitter.im/jrnl-org/jrnl)
|
||||||
|
[](https://github.com/jrnl-org/jrnl/blob/develop/CHANGELOG.md)
|
||||||
====
|
====
|
||||||
|
|
||||||
_To get help, [submit an issue](https://github.com/jrnl-org/jrnl/issues/new) on
|
_To get help, [submit an issue](https://github.com/jrnl-org/jrnl/issues/new/choose) on
|
||||||
Github._
|
GitHub._
|
||||||
|
|
||||||
*jrnl* is a simple journal application for your command line. Journals are
|
`jrnl` is a simple journal application for the command line.
|
||||||
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.
|
|
||||||
|
|
||||||
Optionally, your journal can be encrypted using the [256-bit
|
You can use it to easily create, search, and view journal entries. Journals are
|
||||||
AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard).
|
stored as human-readable plain text, and can also be encrypted using [AES
|
||||||
|
encryption](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard).
|
||||||
|
|
||||||
### Why keep a journal?
|
## In a Nutshell
|
||||||
|
|
||||||
Journals aren't just for people who have too much time on their summer
|
To make a new entry, just enter
|
||||||
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, or 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
|
``` sh
|
||||||
-------------
|
jrnl yesterday: Called in sick. Used the time to clean the house and write my
|
||||||
|
book.
|
||||||
|
```
|
||||||
|
|
||||||
To make a new entry, just type
|
`yesterday:` is interpreted by `jrnl` as a timestamp. Everything until the
|
||||||
|
first sentence ending (either `.`, `?`, or `!`) is interpreted as the title, and
|
||||||
jrnl yesterday: Called in sick. Used the time cleaning the house and writing my book.
|
the rest as the body. In your journal file, the result will look like this:
|
||||||
|
|
||||||
and hit return. `yesterday:` will be interpreted as a timestamp. 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:
|
|
||||||
|
|
||||||
[2012-03-29 09:00] Called in sick.
|
[2012-03-29 09:00] Called in sick.
|
||||||
Used the time cleaning the house and writing my book.
|
Used the time to clean the house and write my book.
|
||||||
|
|
||||||
If you just call `jrnl`, you will be prompted to compose your entry - but you
|
If you just call `jrnl`, you will be prompted to compose your entry - but you
|
||||||
can also configure _jrnl_ to use your external editor.
|
can also configure _jrnl_ to use your external editor.
|
||||||
|
|
||||||
For more information, please read our [documentation](https://jrnl.sh/overview/).
|
For more information, please read the
|
||||||
|
[documentation](https://jrnl.sh).
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
### Maintainers
|
### Maintainers
|
||||||
Our maintainers help keep the lights on for the project. Please thank them if
|
|
||||||
you like jrnl.
|
Our maintainers help keep the lights on for the project:
|
||||||
|
|
||||||
* Jonathan Wren ([wren](https://github.com/wren))
|
* Jonathan Wren ([wren](https://github.com/wren))
|
||||||
* Micah Ellison ([micahellison](https://github.com/micahellison))
|
* Micah Ellison ([micahellison](https://github.com/micahellison))
|
||||||
|
|
||||||
|
Please thank them if you like `jrnl`!
|
||||||
|
|
||||||
### Code Contributors
|
### Code Contributors
|
||||||
This project is made with love by the many fabulous people who have
|
|
||||||
contributed. Jrnl couldn't exist without each and every one of you!
|
This project is made with love by the many fabulous people who have contributed.
|
||||||
|
`jrnl` couldn't exist without each and every one of you!
|
||||||
|
|
||||||
<a href="https://github.com/jrnl-org/jrnl/graphs/contributors"><img
|
<a href="https://github.com/jrnl-org/jrnl/graphs/contributors"><img
|
||||||
src="https://opencollective.com/jrnl/contributors.svg?width=890&button=false"
|
src="https://opencollective.com/jrnl/contributors.svg?width=890&button=false"
|
||||||
/></a>
|
/></a>
|
||||||
|
|
||||||
If you'd also like to help make jrnl better, please see our [contributing
|
If you'd also like to help make `jrnl` better, please see our [contributing
|
||||||
documentation](CONTRIBUTING.md).
|
documentation](docs/contributing.md).
|
||||||
|
|
||||||
### Financial Backers
|
### Financial Backers
|
||||||
|
|
||||||
Another way show support is through direct financial contributions. These funds
|
Another way show support is through direct financial contributions. These funds
|
||||||
go to covering our costs, and are a quick way to show your appreciation for
|
go to covering our costs, and are a quick way to show your appreciation for
|
||||||
jrnl.
|
`jrnl`.
|
||||||
|
|
||||||
[Become a financial contributor](https://opencollective.com/jrnl/contribute)
|
[Become a financial contributor](https://opencollective.com/jrnl/contribute)
|
||||||
and help us sustain our community.
|
and help us sustain our community.
|
||||||
|
|
7
SECURITY.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Security
|
||||||
|
|
||||||
|
If you've discovered a potential security issue in jrnl, please contact the maintainers at [maintainers@jrnl.sh](mailto:maintainers@jrnl.sh).
|
||||||
|
|
||||||
|
You can also feel free to [open an issue](https://github.com/jrnl-org/jrnl/issues/new/choose) (but please don't disclose the vulnerability) in case the email goes to spam.
|
||||||
|
|
||||||
|
You can find [known privacy and security issues in our documentation](https://jrnl.sh/en/stable/privacy-and-security/).
|
|
@ -1,2 +0,0 @@
|
||||||
jrnl.sh
|
|
||||||
|
|
147
docs/advanced.md
|
@ -1,71 +1,27 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
# Advanced Usage
|
# Advanced Usage
|
||||||
|
|
||||||
## Configuration File
|
## Configuration File
|
||||||
|
|
||||||
You can configure the way jrnl behaves in a configuration file. By
|
`jrnl` has a wide variety of options that can be customized through the config file,
|
||||||
default, this is `~/.config/jrnl/jrnl.yaml`. If you have the `XDG_CONFIG_HOME`
|
including templates, formats, multiple journals, and more. See
|
||||||
variable set, the configuration file will be saved as
|
the [configuration file reference](./reference-config-file.md) for details
|
||||||
`$XDG_CONFIG_HOME/jrnl/jrnl.yaml`.
|
or read on for some common use cases.
|
||||||
|
|
||||||
!!! note
|
### Multiple journal files
|
||||||
On Windows, the configuration file is typically found at `%USERPROFILE%\.config\jrnl\jrnl.yaml`.
|
|
||||||
|
|
||||||
The configuration file is a YAML file with the following options
|
|
||||||
and can be edited with a plain text editor.
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
Backup your journal and config file before editing. Changes to the config file
|
|
||||||
can have destructive effects on your journal!
|
|
||||||
|
|
||||||
- `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 <recipes>` 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.
|
|
||||||
- `colors`
|
|
||||||
dictionary that controls the colors used to display journal entries. It has two subkeys, which are: `date` and `title`. Current valid values are: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, and `WHITE`. `colorama.Fore` is used for colorization, and you can find the [docs here](https://github.com/tartley/colorama#colored-output). To disable colored output, set the value to `NONE`. If you set the value of any color subkey to an invalid color, no color will be used.
|
|
||||||
|
|
||||||
!!! 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.
|
|
||||||
|
|
||||||
## Multiple journal files
|
|
||||||
|
|
||||||
You can configure `jrnl`to use with multiple journals (eg.
|
You can configure `jrnl`to use with multiple journals (eg.
|
||||||
`private` and `work`) by defining more journals in your `jrnl.yaml`,
|
`private` and `work`) by defining more journals in your [config file](./reference-config-file.md),
|
||||||
for example:
|
for example:
|
||||||
|
|
||||||
``` yaml
|
``` yaml
|
||||||
journals:
|
journals:
|
||||||
default: ~\journal.txt
|
default: ~/journal.txt
|
||||||
work: ~\work.txt
|
work: ~/work.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
The `default` journal gets created the first time you start `jrnl`
|
The `default` journal gets created the first time you start `jrnl`
|
||||||
|
@ -86,31 +42,76 @@ If your `jrnl.yaml` looks like this:
|
||||||
``` yaml
|
``` yaml
|
||||||
encrypt: false
|
encrypt: false
|
||||||
journals:
|
journals:
|
||||||
default: ~/journal.txt
|
default: ~/journal.txt
|
||||||
work:
|
work:
|
||||||
journal: ~/work.txt
|
journal: ~/work.txt
|
||||||
encrypt: true
|
encrypt: true
|
||||||
food: ~/my_recipes.txt
|
food: ~/my_recipes.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
Your `default` and your `food` journals won't be encrypted, however your
|
Your `default` and your `food` journals won't be encrypted, however your
|
||||||
`work` journal will! You can override all options that are present at
|
`work` journal will!
|
||||||
|
|
||||||
|
You can override all options that are present at
|
||||||
the top level of `jrnl.yaml`, just make sure that at the very least
|
the top level of `jrnl.yaml`, just make sure that at the very least
|
||||||
you specify a `journal: ...` key that points to the journal file of
|
you specify a `journal: ...` key that points to the journal file of
|
||||||
that journal.
|
that journal.
|
||||||
|
|
||||||
|
Consider the following example configuration
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
editor: vi -c startinsert
|
||||||
|
journals:
|
||||||
|
default: ~/journal.txt
|
||||||
|
work:
|
||||||
|
journal: ~/work.txt
|
||||||
|
encrypt: true
|
||||||
|
display_format: json
|
||||||
|
editor: code -rw
|
||||||
|
food:
|
||||||
|
display_format: markdown
|
||||||
|
journal: ~/recipes.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
The `work` journal is encrypted, prints to `json` by default, and is edited using an existing window of VSCode. Similarly, the `food` journal prints to markdown by default, but uses all the other defaults.
|
||||||
|
|
||||||
|
### Modifying Configurations from the Command line
|
||||||
|
|
||||||
|
You can override a configuration field for the current instance of `jrnl` using `--config-override CONFIG_KEY CONFIG_VALUE` where `CONFIG_KEY` is a valid configuration field, specified in dot notation and `CONFIG_VALUE` is the (valid) desired override value. The dot notation can be used to change config keys within other keys, such as `colors.title` for the `title` key within the `colors` key.
|
||||||
|
|
||||||
|
You can specify multiple overrides as multiple calls to `--config-override`.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Changing `encrypt` to a different value will not encrypt or decrypt your
|
These overrides allow you to modify ***any*** field of your jrnl configuration. We trust that you know what you are doing.
|
||||||
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
|
#### Examples:
|
||||||
|
|
||||||
### Unicode on Windows
|
``` sh
|
||||||
|
# Create an entry using the `stdin` prompt, for rapid logging
|
||||||
|
jrnl --config-override editor ""
|
||||||
|
|
||||||
The Windows shell prior to Windows 7 has issues with unicode encoding.
|
# Populate a project's log
|
||||||
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`.
|
jrnl --config-override journals.todo "$(git rev-parse --show-toplevel)/todo.txt" todo find my towel
|
||||||
|
|
||||||
(Related issue: [#486](https://github.com/jrnl-org/jrnl/issues/486))
|
# Pass multiple overrides
|
||||||
|
jrnl --config-override display_format fancy --config-override linewrap 20 \
|
||||||
|
--config-override colors.title green
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using an alternate config
|
||||||
|
|
||||||
|
You can specify an alternate configuration file for the current instance of `jrnl` using `--config-file CONFIG_FILE_PATH` where
|
||||||
|
`CONFIG_FILE_PATH` is a path to an alternate `jrnl` configuration file.
|
||||||
|
|
||||||
|
#### Examples:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
# Use personalised configuration file for personal journal entries
|
||||||
|
jrnl --config-file ~/foo/jrnl/personal-config.yaml
|
||||||
|
|
||||||
|
# Use alternate configuration file for work-related entries
|
||||||
|
jrnl --config-file ~/foo/jrnl/work-config.yaml
|
||||||
|
|
||||||
|
# Use default configuration file (created on first run)
|
||||||
|
jrnl
|
||||||
|
```
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,204 +0,0 @@
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* 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-menu-vertical li.current {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
.wy-nav-top {
|
|
||||||
background-image: linear-gradient(-211deg, #95699C 0%, #604385 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wy-nav-top .fa-bars {
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
132
docs/contributing.md
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Contributing to jrnl
|
||||||
|
|
||||||
|
We welcome contributions to jrnl, whether it's through reporting bugs, improving the documentation, testing releases, engaging in discussion on features and bugs, or writing code.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
* [Code of Conduct](#code-of-conduct)
|
||||||
|
* [Reporting Bugs](#reporting-bugs)
|
||||||
|
* [Editing Documentation](#editing-documentation)
|
||||||
|
* [Testing](#testing)
|
||||||
|
* [Submitting feature requests and ideas](#submitting-feature-requests-and-ideas)
|
||||||
|
* [Developing jrnl](#developing)
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
Before starting, please read the [Code of Conduct](https://github.com/jrnl-org/jrnl/blob/develop/CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
|
## Reporting Bugs
|
||||||
|
|
||||||
|
Please report bugs by [opening a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) and describing it as well as possible. Many bugs are specific to a particular operating system and Python version, so please include that information!
|
||||||
|
|
||||||
|
## Editing Documentation
|
||||||
|
|
||||||
|
If you find a typo or a mistake in the docs, please fix it right away and send a pull request. If you're unsure what to change but still see a problem, you can [open a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) with the "Documentation change" type.
|
||||||
|
|
||||||
|
To edit the documentation, edit the `docs/*.md` files on the **develop** branch. You can see the result by running `poe docs-run` inside the project's root directory, then navigating your browser to [localhost:8000](http://localhost:8000).
|
||||||
|
|
||||||
|
### External editors and tips and tricks
|
||||||
|
|
||||||
|
If you'd like to share a jrnl command line trick that you find useful, you may find it worthwhile to add it to the ["Tips and Tricks" section](tips-and-tricks.md). For advice on how to integrate a particular external editor, you can add to the ["External Editors" section](external-editors.md).
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Much of the work of maintaining jrnl involves testing rather than coding.
|
||||||
|
|
||||||
|
The nature of jrnl means we deal with extremely sensitive data, and can't risk data loss. While jrnl does have a comprehensive automated testing suite, user testing is crucial to mitigating this risk.
|
||||||
|
|
||||||
|
### Prereleases
|
||||||
|
|
||||||
|
[Prereleases are deployed through PyPi much like normal releases](https://pypi.org/project/jrnl/#history). You can use [pipx](https://pypi.org/project/pipx/) to fetch them and test them. See the [changelog](https://github.com/jrnl-org/jrnl/blob/develop/CHANGELOG.md) for information on what has changed with each release.
|
||||||
|
|
||||||
|
### Pull requests
|
||||||
|
|
||||||
|
If you are comfortable enough with git, feel free to fetch particular [pull requests](https://github.com/jrnl-org/jrnl/pulls), test them yourself, and report back your findings. Bonus points if you can add a screencast of how the new feature works.
|
||||||
|
|
||||||
|
### Confirm bug reports
|
||||||
|
|
||||||
|
There are always [open bugs among our GitHub issues](https://github.com/jrnl-org/jrnl/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and many are specific to a particular OS, Python version, or jrnl version. A simple comment like "Confirmed on jrnl v2.2, MacOS 10.15, Python 3.8.1" would be extremely helpful in tracking down bugs.
|
||||||
|
|
||||||
|
### Automate tests
|
||||||
|
|
||||||
|
See the develop section below for information on how to contribute new automated tests.
|
||||||
|
|
||||||
|
## Submitting feature requests and ideas
|
||||||
|
|
||||||
|
If you have a feature request or idea for jrnl, please [open a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) and describe the goal of the feature, and any relevant use cases. We'll discuss the issue with you, and decide if it's a good fit for the project.
|
||||||
|
|
||||||
|
When discussing new features, please keep in mind our design goals. jrnl strives to
|
||||||
|
[do one thing well](https://en.wikipedia.org/wiki/Unix_philosophy). To us, that means:
|
||||||
|
|
||||||
|
* being _nimble_
|
||||||
|
* having a simple interface
|
||||||
|
* avoiding duplicating functionality
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
### Getting your environment set up
|
||||||
|
|
||||||
|
You will need to install [poetry](https://python-poetry.org/) to develop jrnl. It will take care of all of the project's other dependencies.
|
||||||
|
|
||||||
|
### Understanding the branches
|
||||||
|
|
||||||
|
jrnl uses two primary branches:
|
||||||
|
|
||||||
|
* `develop` - for ongoing development
|
||||||
|
* `release` - for releases
|
||||||
|
|
||||||
|
In general, pull requests should be made on the `develop` branch.
|
||||||
|
|
||||||
|
### Common development commands
|
||||||
|
|
||||||
|
You can find an inventory of commands in the `pyproject.toml`. Users can run the commands by typing `poe` followed by the name of the command ([Poe the Poet](https://github.com/nat-n/poethepoet) can be installed on its own, or as part of `poetry install`).
|
||||||
|
|
||||||
|
A typical development workflow includes:
|
||||||
|
|
||||||
|
* Installing dependencies:
|
||||||
|
* `poetry install`
|
||||||
|
* Activate virtual environment:
|
||||||
|
* `poetry shell`
|
||||||
|
* Running the source in a virtual environment:
|
||||||
|
* `jrnl` (with or without arguments as necessary)
|
||||||
|
* Running tests:
|
||||||
|
* `poe test`
|
||||||
|
* Formatting the code to standardize its style:
|
||||||
|
* `poe format`
|
||||||
|
|
||||||
|
### Updating automated tests
|
||||||
|
|
||||||
|
When resolving bugs or adding new functionality, please add tests to prevent that functionality from breaking in the future. If you notice any functionality that isn't covered in the tests, feel free to submit a test-only pull request as well.
|
||||||
|
|
||||||
|
For testing, jrnl uses [pytest](https://docs.pytest.org) for unit tests, and [pytest-bdd](https://pytest-bdd.readthedocs.io/) for integration testing. All tests are in the `tests` folder.
|
||||||
|
|
||||||
|
Many tests can be created by only editing `*.feature` files with the same format as other tests. For more complicated functionality, you may need to implement steps in `tests/lib/` which are then executed by your tests in the `feature` files.
|
||||||
|
|
||||||
|
### Submitting pull requests
|
||||||
|
|
||||||
|
When you're ready, feel free to submit a pull request (PR). The jrnl maintainers generally review the pull requests every two weeks, but the continuous integration pipeline will run on automated tests on it within a matter of minutes and will report back any issues it has found with your code across a variety of environments.
|
||||||
|
|
||||||
|
The pull request template contains a checklist full of housekeeping items. Please fill them out as necessary when you submit.
|
||||||
|
|
||||||
|
If a pull request contains failing tests, it probably will not be reviewed, and it definitely will not be approved. However, if you need help resolving a failing test, please mention that in your PR.
|
||||||
|
|
||||||
|
### Finding things to work on
|
||||||
|
|
||||||
|
You can search the [jrnl GitHub issues](https://github.com/jrnl-org/jrnl/issues) by [label](https://github.com/jrnl-org/jrnl/labels) for things to work on. Here are some labels worth searching:
|
||||||
|
|
||||||
|
* [critical](https://github.com/jrnl-org/jrnl/labels/critical)
|
||||||
|
* [help wanted](https://github.com/jrnl-org/jrnl/labels/help%20wanted)
|
||||||
|
* [bug](https://github.com/jrnl-org/jrnl/labels/bug)
|
||||||
|
* [enhancement](https://github.com/jrnl-org/jrnl/labels/enhancement)
|
||||||
|
|
||||||
|
You can also get a feel for the project's priorities by reviewing the [milestones](https://github.com/jrnl-org/jrnl/milestones).
|
||||||
|
|
||||||
|
### A note for new programmers and programmers new to python
|
||||||
|
|
||||||
|
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!
|
|
@ -1,78 +1,155 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
# Encryption
|
# Encryption
|
||||||
|
|
||||||
## Encrypting and decrypting
|
## A Note on Security
|
||||||
|
|
||||||
If you don’t choose to encrypt your file when you run
|
While `jrnl` follows best practices, total security is never possible in the
|
||||||
`jrnl` for the first time, you can encrypt
|
real world. There are a number of ways that people can at least partially
|
||||||
your existing journal file or change its password using this:
|
compromise your `jrnl` data. See the [Privacy and Security](./privacy-and-security.md) page
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
## Encrypting and Decrypting
|
||||||
|
|
||||||
|
Existing plain text journal files can be encrypted using the `--encrypt`
|
||||||
|
command:
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
jrnl --encrypt
|
jrnl --encrypt [FILENAME]
|
||||||
```
|
```
|
||||||
|
|
||||||
If it is already encrypted, you will first be asked for the current
|
You can then enter a new password, and the unencrypted file will replaced with
|
||||||
password. You can then enter a new password and your plain journal will
|
the new encrypted file.
|
||||||
replaced by the encrypted file. Conversely,
|
|
||||||
|
This command also works to change the password for a journal file that is
|
||||||
|
already encrypted. `jrnl` will prompt you for the current password and then new
|
||||||
|
password.
|
||||||
|
|
||||||
|
Conversely,
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
jrnl --decrypt
|
jrnl --decrypt [FILENAME]
|
||||||
```
|
```
|
||||||
|
|
||||||
will replace your encrypted journal file with a journal in plain text. You
|
replaces the encrypted journal file with a plain text file. You can also specify
|
||||||
can also specify a filename, i.e. `jrnl --decrypt plain_text_copy.txt`,
|
a filename, e.g., `jrnl --decrypt plain_text_copy.txt`, to leave the original
|
||||||
to leave your original file untouched.
|
encrypted file untouched and create a new plain text file next to it.
|
||||||
|
|
||||||
## Storing passwords in your keychain
|
!!! note
|
||||||
|
Changing `encrypt` in your [config file](./reference-config-file.md) 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. This is why the above commands are necessary.
|
||||||
|
|
||||||
Whenever you encrypt your journal, you are asked whether you want to
|
## Storing Passwords in Your Keychain
|
||||||
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
|
Nobody can recover or reset your `jrnl` password. If you lose it,
|
||||||
do so at a later point – or maybe want to store it on one computer but
|
your data will be inaccessible forever.
|
||||||
not on another – you can run `jrnl --encrypt` on an encrypted
|
|
||||||
journal and use the same password again.
|
|
||||||
|
|
||||||
## A note on security
|
For this reason, when encrypting a journal, `jrnl` asks whether you would like
|
||||||
|
to store the password in your system's keychain. An added benefit is that you
|
||||||
|
will not need to enter the password when interacting with the journal file.
|
||||||
|
|
||||||
While `jrnl` follows best practices, total security is an illusion.
|
If you don't initially store the password in your keychain but decide to do so
|
||||||
There are a number of ways that people can at least partially
|
later---or if you want to store it in one computer's keychain but not in another
|
||||||
compromise your `jrnl` data. See the [Privacy and Security](./security.md)
|
computer's---you can run `jrnl --encrypt` on an encrypted journal and use the
|
||||||
documentation for more information.
|
same password again. This will trigger the keychain storage prompt.
|
||||||
|
|
||||||
## No password recovery
|
## Manual Decryption
|
||||||
|
|
||||||
There is no method to recover or reset your `jrnl` password. If you lose it,
|
The easiest way to decrypt your journal is with `jrnl --decrypt`, but you could
|
||||||
your data is inaccessible.
|
also decrypt your journal manually if needed. To do this, you can use any
|
||||||
|
program that supports the AES algorithm (specifically AES-CBC), and you'll need
|
||||||
|
the following relevant information for decryption:
|
||||||
|
|
||||||
## Manual decryption
|
- **Key:** The key used for encryption is the
|
||||||
|
[SHA-256](https://en.wikipedia.org/wiki/SHA-2) hash of your password.
|
||||||
|
- **Initialization vector (IV):** The IV is stored in the first 16 bytes of
|
||||||
|
your encrypted journal file.
|
||||||
|
- **The actual text of the journal** (everything after the first 16 bytes in
|
||||||
|
the encrypted journal file) is encoded in
|
||||||
|
[UTF-8](https://en.wikipedia.org/wiki/UTF-8) and padded according to
|
||||||
|
[PKCS\#7](https://en.wikipedia.org/wiki/PKCS_7) before being encrypted.
|
||||||
|
|
||||||
Should you ever want to decrypt your journal manually, you can do so
|
If you'd like an example of what this might look like in script form, please
|
||||||
with any program that supports the AES algorithm in CBC. The key used
|
see below for some examples of Python scripts that you could use to manually
|
||||||
for encryption is the SHA-256-hash of your password, the IV
|
decrypt your journal.
|
||||||
(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:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
These are only examples, and are only here to illustrate that your journal files
|
||||||
|
will still be recoverable even if `jrnl` isn't around anymore. Please use
|
||||||
|
`jrnl --decrypt` if available.
|
||||||
|
|
||||||
|
**Example for jrnl v2 files**:
|
||||||
``` python
|
``` python
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Decrypt a jrnl v2 encrypted journal.
|
||||||
|
|
||||||
|
Note: the `cryptography` module must be installed (you can do this with
|
||||||
|
something like `pip3 install crytography`)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import getpass
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||||
|
|
||||||
|
filepath = input("journal file path: ")
|
||||||
|
password = getpass.getpass("Password: ")
|
||||||
|
|
||||||
|
with open(Path(filepath), "rb") as f:
|
||||||
|
ciphertext = f.read()
|
||||||
|
|
||||||
|
password = password.encode("utf-8")
|
||||||
|
kdf = PBKDF2HMAC(
|
||||||
|
algorithm=hashes.SHA256(),
|
||||||
|
length=32,
|
||||||
|
salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8",
|
||||||
|
iterations=100_000,
|
||||||
|
backend=default_backend(),
|
||||||
|
)
|
||||||
|
|
||||||
|
key = base64.urlsafe_b64encode(kdf.derive(password))
|
||||||
|
|
||||||
|
print(Fernet(key).decrypt(ciphertext).decode("utf-8"))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example for jrnl v1 files**:
|
||||||
|
``` python
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Decrypt a jrnl v1 encrypted journal.
|
||||||
|
|
||||||
|
Note: the `pycrypto` module must be installed (you can do this with something
|
||||||
|
like `pip3 install pycrypto`)
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from Crypto.Cipher import AES
|
|
||||||
import getpass
|
import getpass
|
||||||
import hashlib
|
import hashlib
|
||||||
import sys
|
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("filepath", help="journal file to decrypt")
|
parser.add_argument("filepath", help="journal file to decrypt")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
pwd = getpass.getpass()
|
pwd = getpass.getpass()
|
||||||
key = hashlib.sha256(pwd.encode('utf-8')).digest()
|
key = hashlib.sha256(pwd.encode("utf-8")).digest()
|
||||||
|
|
||||||
with open(args.filepath, 'rb') as f:
|
with open(args.filepath, "rb") as f:
|
||||||
ciphertext = f.read()
|
ciphertext = f.read()
|
||||||
|
|
||||||
crypto = AES.new(key, AES.MODE_CBC, ciphertext[:16])
|
crypto = AES.new(key, AES.MODE_CBC, ciphertext[:16])
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
# 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.knightlab.com/) 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
|
|
||||||
|- ...
|
|
||||||
```
|
|
137
docs/external-editors.md
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# External editors
|
||||||
|
|
||||||
|
Configure your preferred external editor by updating the `editor` option
|
||||||
|
in your [configuration file](./reference-config-file.md#editor). If your editor is not
|
||||||
|
in your operating system's `PATH` environment variable, then you will have to
|
||||||
|
enter the full path of your editor.
|
||||||
|
|
||||||
|
Once it's configured, you can create an entry as a new document in your editor using the `jrnl`
|
||||||
|
command by itself:
|
||||||
|
|
||||||
|
``` text
|
||||||
|
jrnl
|
||||||
|
```
|
||||||
|
|
||||||
|
You can specify the time and title of the entry as usual on the first line of the document.
|
||||||
|
|
||||||
|
If you want, you can skip the editor by including a quick entry with the `jrnl` command:
|
||||||
|
|
||||||
|
``` text
|
||||||
|
jrnl yesterday: All my troubles seemed so far away.
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to start the entry on the command line and continue writing in your chosen editor,
|
||||||
|
use the `--edit` flag. For example:
|
||||||
|
|
||||||
|
``` text
|
||||||
|
jrnl yesterday: All my troubles seemed so far away. --edit
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
To save and log any entry edits, save and close the file.
|
||||||
|
|
||||||
|
All editors must be [blocking processes](https://en.wikipedia.org/wiki/Blocking_(computing)) to work with jrnl. Some editors, such as [micro](https://micro-editor.github.io/), are blocking by default, though others can be made to block with additional arguments, such as many of those documented below. If jrnl opens your editor but finishes running immediately, then your editor is not a blocking process, and you may be able to correct that with one of the suggestions below.
|
||||||
|
|
||||||
|
Please see [this section](./privacy-and-security.md#editor-history) about how
|
||||||
|
your editor might leak sensitive information and how to mitigate that risk.
|
||||||
|
|
||||||
|
## Sublime Text
|
||||||
|
|
||||||
|
To use [Sublime Text](https://www.sublimetext.com/), install the command line
|
||||||
|
tools for Sublime Text and configure your `jrnl.yaml` like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
editor: "subl -w"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the `-w` flag to make sure `jrnl` waits for Sublime Text to close the
|
||||||
|
file before writing into the journal.
|
||||||
|
|
||||||
|
## Visual Studio Code
|
||||||
|
|
||||||
|
[Visual Studio Code](https://code.visualstudio.com) also requires a flag
|
||||||
|
that tells the process to wait until the file is closed before exiting:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
editor: "code --wait"
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows, `code` is not added to the path by default, so you'll need to
|
||||||
|
enter the full path to your `code.exe` file, or add it to the `PATH` variable.
|
||||||
|
|
||||||
|
## MacVim
|
||||||
|
|
||||||
|
Also 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`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
editor: "mvim -f"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vim/Neovim
|
||||||
|
|
||||||
|
To use any of the Vim derivatives as editor in Linux, simply set the `editor`
|
||||||
|
to the executable:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
editor: "vim"
|
||||||
|
# or
|
||||||
|
editor: "nvim"
|
||||||
|
```
|
||||||
|
|
||||||
|
## iA Writer
|
||||||
|
|
||||||
|
On OS X, you can use the fabulous [iA
|
||||||
|
Writer](http://www.iawriter.com/mac) to write entries. Configure your
|
||||||
|
`jrnl.yaml` like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
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.yaml`) like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
## emacs
|
||||||
|
|
||||||
|
To use `emacs` as your editor, edit the `jrnl` config file (`jrnl.yaml`) like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
editor: emacsclient -a "" -c
|
||||||
|
```
|
||||||
|
|
||||||
|
When you're done editing the message, save and `C-x #` to close the buffer and stop the emacsclient process.
|
||||||
|
|
||||||
|
## Other editors
|
||||||
|
|
||||||
|
If you're using another editor and would like to share, feel free to [contribute documentation](./contributing.md#editing-documentation) on it.
|
354
docs/formats.md
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Formats
|
||||||
|
|
||||||
|
`jrnl` supports a variety of alternate formats. These can be used to display your
|
||||||
|
journal in a different manner than the `jrnl` default, and can even be used to pipe data
|
||||||
|
from your journal for use in another program to create reports, or do whatever you want
|
||||||
|
with your `jrnl` data.
|
||||||
|
|
||||||
|
Any of these formats can be used with a search (e.g. `jrnl -contains "lorem ipsum"
|
||||||
|
--format json`) to display the results of that search in the given format, or can be
|
||||||
|
used alone (e.g. `jrnl --format json`) to display all entries from the selected journal.
|
||||||
|
|
||||||
|
This page shows examples of all the built-in formats, but since `jrnl` supports adding
|
||||||
|
more formats through plugins, you may have more available on your system. Please see
|
||||||
|
`jrnl --help` for a list of which formats are available on your system.
|
||||||
|
|
||||||
|
Any of these formats can be used interchangeably, and are only grouped into "display",
|
||||||
|
"data", and "report" formats below for convenience.
|
||||||
|
|
||||||
|
## Display Formats
|
||||||
|
These formats are mainly intended for displaying your journal in the terminal. Even so,
|
||||||
|
they can still be used in the same way as any other format (like written to a file, if
|
||||||
|
you choose).
|
||||||
|
|
||||||
|
### Pretty
|
||||||
|
``` sh
|
||||||
|
jrnl --format pretty
|
||||||
|
# or
|
||||||
|
jrnl -1 # any search
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the default format in `jrnl`. If no `--format` is given, `pretty` will be used.
|
||||||
|
|
||||||
|
It displays the timestamp of each entry formatted to by the user config followed by the
|
||||||
|
title on the same line. Then the body of the entry is shown below.
|
||||||
|
|
||||||
|
This format is configurable through these values from your config file (see
|
||||||
|
[Advanced Usage](./advanced.md) for more details):
|
||||||
|
|
||||||
|
- `colors`
|
||||||
|
- `body`
|
||||||
|
- `date`
|
||||||
|
- `tags`
|
||||||
|
- `title`
|
||||||
|
- `indent_character`
|
||||||
|
- `linewrap`
|
||||||
|
- `timeformat`
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` sh
|
||||||
|
2020-06-28 18:22 This is the first sample entry
|
||||||
|
| This is the sample body text of the first sample entry.
|
||||||
|
|
||||||
|
2020-07-01 20:00 This is the second sample entry
|
||||||
|
| This is the sample body text of the second sample entry, but
|
||||||
|
| this one has a @tag.
|
||||||
|
|
||||||
|
2020-07-02 09:00 This is the third sample entry
|
||||||
|
| This is the sample body text of the third sample entry.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Short
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format short
|
||||||
|
# or
|
||||||
|
jrnl --short
|
||||||
|
```
|
||||||
|
|
||||||
|
This will shorten entries to display only the date and title. It is essentially the
|
||||||
|
`pretty` format but without the body of each entry. This can be useful if you have long
|
||||||
|
journal entries and only want to see a list of entries that match your search.
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` sh
|
||||||
|
2020-06-28 18:22 This is the first sample entry
|
||||||
|
2020-07-01 20:00 This is the second sample entry
|
||||||
|
2020-07-02 09:00 This is the third sample entry
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fancy (or Boxed)
|
||||||
|
``` sh
|
||||||
|
jrnl --format fancy
|
||||||
|
# or
|
||||||
|
jrnl --format boxed
|
||||||
|
```
|
||||||
|
|
||||||
|
This format outlines each entry with a border. This makes it much easier to tell where
|
||||||
|
each entry starts and ends. It's an example of how free-form the formats can be, and also
|
||||||
|
just looks kinda ~*~fancy~*~, if you're into that kind of thing.
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` sh
|
||||||
|
┎──────────────────────────────────────────────────────────────────────╮2020-06-28 18:22
|
||||||
|
┃ This is the first sample entry ╘═══════════════╕
|
||||||
|
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
||||||
|
┃ This is the sample body text of the first sample entry. │
|
||||||
|
┖──────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
┎──────────────────────────────────────────────────────────────────────╮2020-07-01 20:00
|
||||||
|
┃ This is the second sample entry ╘═══════════════╕
|
||||||
|
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
||||||
|
┃ This is the sample body text of the second sample entry, but this one has a @tag. │
|
||||||
|
┖──────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
┎──────────────────────────────────────────────────────────────────────╮2020-07-02 09:00
|
||||||
|
┃ This is the third sample entry ╘═══════════════╕
|
||||||
|
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
||||||
|
┃ This is the sample body text of the third sample entry. │
|
||||||
|
┖──────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Formats
|
||||||
|
These formats are mainly intended for piping or exporting your journal to other
|
||||||
|
programs. Even so, they can still be used in the same way as any other format (like
|
||||||
|
written to a file, or displayed in your terminal, if you want).
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
You may see boxed messages like "2 entries found" when using these formats, but
|
||||||
|
those messages are written to `stderr` instead of `stdout`, and won't be piped when
|
||||||
|
using the `|` operator.
|
||||||
|
|
||||||
|
### JSON
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format json
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON is a very handy format used by many programs and has support in nearly every
|
||||||
|
programming language. There are many things you could do with JSON data. Maybe you could
|
||||||
|
use `jq` ([project page](https://github.com/stedolan/jq)) to filter through the fields in your journal.
|
||||||
|
Like this:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
$ j -3 --format json | jq '.entries[].date' jrnl-GFqVlfgP-py3.8
|
||||||
|
"2020-06-28"
|
||||||
|
"2020-07-01"
|
||||||
|
"2020-07-02"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or why not create a [beautiful timeline](http://timeline.knightlab.com/) of your journal?
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"tags": {
|
||||||
|
"@tag": 1
|
||||||
|
},
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"title": "This is the first sample entry",
|
||||||
|
"body": "This is the sample body text of the first sample entry.",
|
||||||
|
"date": "2020-06-28",
|
||||||
|
"time": "18:22",
|
||||||
|
"tags": [],
|
||||||
|
"starred": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "This is the second sample entry",
|
||||||
|
"body": "This is the sample body text of the second sample entry, but this one has a @tag.",
|
||||||
|
"date": "2020-07-01",
|
||||||
|
"time": "20:00",
|
||||||
|
"tags": [
|
||||||
|
"@tag"
|
||||||
|
],
|
||||||
|
"starred": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "This is the third sample entry",
|
||||||
|
"body": "This is the sample body text of the third sample entry.",
|
||||||
|
"date": "2020-07-02",
|
||||||
|
"time": "09:00",
|
||||||
|
"tags": [],
|
||||||
|
"starred": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Markdown
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format markdown
|
||||||
|
# or
|
||||||
|
jrnl --format md
|
||||||
|
```
|
||||||
|
|
||||||
|
Markdown is a simple markup language that is human readable and can be used to be
|
||||||
|
rendered to other formats (html, pdf). `jrnl`'s
|
||||||
|
[README](https://github.com/jrnl-org/jrnl/blob/develop/README.md) for example is
|
||||||
|
formatted in markdown, then Github adds some formatting to make it look nice.
|
||||||
|
|
||||||
|
The markdown format groups entries by date (first by year, then by month), and adds
|
||||||
|
header markings as needed (e.g. `#`, `##`, etc). If you already have markdown header
|
||||||
|
markings in your journal, they will be incremented as necessary to make them fit under
|
||||||
|
these new headers (i.e. `#` will become `##`).
|
||||||
|
|
||||||
|
This format can be very useful, for example, to export a journal to a program that
|
||||||
|
converts markdown to html to make a website or a blog from your journal.
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` markdown
|
||||||
|
# 2020
|
||||||
|
|
||||||
|
## June
|
||||||
|
|
||||||
|
### 2020-06-28 18:22 This is the first sample entry
|
||||||
|
|
||||||
|
This is the sample body text of the first sample entry.
|
||||||
|
|
||||||
|
## July
|
||||||
|
|
||||||
|
### 2020-07-01 20:00 This is the second sample entry
|
||||||
|
|
||||||
|
This is the sample body text of the second sample entry, but this one has a @tag.
|
||||||
|
|
||||||
|
### 2020-07-02 09:00 This is the third sample entry
|
||||||
|
|
||||||
|
This is the sample body text of the third sample entry.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Plain Text
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format text
|
||||||
|
# or
|
||||||
|
jrnl --format txt
|
||||||
|
```
|
||||||
|
|
||||||
|
This outputs your journal in the same plain-text format that `jrnl` uses to store your
|
||||||
|
journal on disk. This format is particularly useful for importing and exporting journals
|
||||||
|
within `jrnl`.
|
||||||
|
|
||||||
|
You can use it, for example, to move entries from one journal to another, or to create a
|
||||||
|
new journal with search results from another journal.
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` sh
|
||||||
|
[2020-06-28 18:22] This is the first sample entry
|
||||||
|
This is the sample body text of the first sample entry.
|
||||||
|
|
||||||
|
[2020-07-01 20:00] This is the second sample entry
|
||||||
|
This is the sample body text of the second sample entry, but this one has a @tag.
|
||||||
|
|
||||||
|
[2020-07-02 09:00] This is the third sample entry
|
||||||
|
This is the sample body text of the third sample entry.
|
||||||
|
```
|
||||||
|
|
||||||
|
### XML
|
||||||
|
``` sh
|
||||||
|
jrnl --format xml
|
||||||
|
```
|
||||||
|
|
||||||
|
This outputs your journal into XML format. XML is a commonly used data format and is
|
||||||
|
supported by many programs and programming languages.
|
||||||
|
|
||||||
|
**Example output**:
|
||||||
|
``` xml
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
<journal>
|
||||||
|
<entries>
|
||||||
|
<entry date="2020-06-28T18:22:00" starred="">This is the first sample entry This is the sample body text of the first sample entry.</entry>
|
||||||
|
<entry date="2020-07-01T20:00:00" starred="">
|
||||||
|
<tag name="@tag"/>
|
||||||
|
This is the second sample entry This is the sample body text of the second sample entry, but this one has a @tag.
|
||||||
|
</entry>
|
||||||
|
<entry date="2020-07-02T09:00:00" starred="">*This is the third sample entry, and is starred This is the sample body text of the third sample entry.</entry>
|
||||||
|
</entries>
|
||||||
|
<tags>
|
||||||
|
<tag name="@tag">1</tag>
|
||||||
|
</tags>
|
||||||
|
</journal>
|
||||||
|
```
|
||||||
|
|
||||||
|
### YAML
|
||||||
|
``` sh
|
||||||
|
jrnl --format yaml --file 'my_directory/'
|
||||||
|
```
|
||||||
|
|
||||||
|
This outputs your journal into YAML format. YAML is a commonly used data format and is
|
||||||
|
supported by many programs and programming languages. [Exporting to directories](#exporting-to-directories) is the
|
||||||
|
only supported YAML export option and each entry will be written to a separate file.
|
||||||
|
|
||||||
|
**Example file**:
|
||||||
|
``` yaml
|
||||||
|
title: This is the second sample entry
|
||||||
|
date: 2020-07-01 20:00
|
||||||
|
starred: False
|
||||||
|
tags: tag
|
||||||
|
|
||||||
|
This is the sample body text of the second sample entry, but this one has a @tag.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Report formats
|
||||||
|
Since formats use your journal data and display it in different ways, they can also be
|
||||||
|
used to create reports.
|
||||||
|
|
||||||
|
### Tags
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format tags
|
||||||
|
# or
|
||||||
|
jrnl --tags
|
||||||
|
```
|
||||||
|
|
||||||
|
This format is a simple example of how formats can be used to create reports. It
|
||||||
|
displays each tag, and a count of how many entries in which tag appears in your journal
|
||||||
|
(or in the search results), sorted by most frequent.
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
``` sh
|
||||||
|
@one : 32
|
||||||
|
@two : 17
|
||||||
|
@three : 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### Exporting with `--file`
|
||||||
|
|
||||||
|
Example: `jrnl --format json --file /some/path/to/a/file.txt`
|
||||||
|
|
||||||
|
By default, `jrnl` will output entries to your terminal. But if you provide `--file`
|
||||||
|
along with a filename, the same output that would have been to your terminal will be
|
||||||
|
written to the file instead. This is the same as piping the output to a file.
|
||||||
|
|
||||||
|
So, in bash for example, the following two statements are equivalent:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format json --file myjournal.json
|
||||||
|
```
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format json > myjournal.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Exporting to directories
|
||||||
|
|
||||||
|
If the `--file` argument is a directory, jrnl will export each entry into an individual file:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
jrnl --format yaml --file my_entries/
|
||||||
|
```
|
||||||
|
|
||||||
|
The contents of `my_entries/` will then look like this:
|
||||||
|
|
||||||
|
``` output
|
||||||
|
my_entries/
|
||||||
|
|- 2013_06_03_a-beautiful-day.yaml
|
||||||
|
|- 2013_06_07_dinner-with-gabriel.yaml
|
||||||
|
|- ...
|
||||||
|
```
|
|
@ -1,20 +1,23 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
On OS X, the easiest way to install *jrnl* is using
|
The easiest way to install `jrnl` is using
|
||||||
[Homebrew](http://brew.sh/):
|
[pipx](https://pipx.pypa.io/stable/installation/)
|
||||||
|
with [Python](https://www.python.org/) 3.10+:
|
||||||
``` sh
|
|
||||||
brew install jrnl
|
|
||||||
```
|
|
||||||
|
|
||||||
On other platforms, install *jrnl* using [Python](https://www.python.org/) 3.6+ and [pipx](https://pipxproject.github.io/pipx/):
|
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
pipx install jrnl
|
pipx install jrnl
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Do not use `sudo` while installing `jrnl`. This may lead to path issues.
|
||||||
|
|
||||||
The first time you run `jrnl` you will be asked where your journal file
|
The first time you run `jrnl` you will be asked where your journal file
|
||||||
should be created and whether you wish to encrypt it.
|
should be created and whether you wish to encrypt it.
|
||||||
|
|
||||||
|
@ -22,8 +25,8 @@ should be created and whether you wish to encrypt it.
|
||||||
|
|
||||||
To make a new entry, just type
|
To make a new entry, just type
|
||||||
|
|
||||||
``` sh
|
``` text
|
||||||
jrnl yesterday: Called in sick. Used the time to clean the house and spent 4h on writing my book.
|
jrnl yesterday: Called in sick. Used the time to clean, and spent 4h on writing my book.
|
||||||
```
|
```
|
||||||
|
|
||||||
and hit return. `yesterday:` will be interpreted as a time stamp.
|
and hit return. `yesterday:` will be interpreted as a time stamp.
|
||||||
|
@ -37,4 +40,4 @@ 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 -
|
If you just call `jrnl`, you will be prompted to compose your entry -
|
||||||
but you can also configure *jrnl* to use your external editor.
|
but you can also [configure](advanced.md) *jrnl* to use your external editor.
|
||||||
|
|
65
docs/journal-types.md
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Journal Types
|
||||||
|
`jrnl` can store your journal in a few different ways:
|
||||||
|
|
||||||
|
- a single text file (encrypted or otherwise)
|
||||||
|
- a folder structure organized by date containing unencrypted text files
|
||||||
|
- the DayOne Classic format
|
||||||
|
|
||||||
|
There is no need to specify what type of journal you'd like to use. Instead,
|
||||||
|
`jrnl` will automatically detect the journal type based on whether you're
|
||||||
|
referencing a file or a folder in your [config file](advanced.md),
|
||||||
|
and if it's a folder, whether or not DayOne Classic content exists in it.
|
||||||
|
|
||||||
|
## Single File
|
||||||
|
The single file format is the most flexible, as it can be [encrypted](encryption.md).
|
||||||
|
To use it, enter any path that is a file or does not already exist. You can
|
||||||
|
use any extension. `jrnl` will automatically create the file when you save
|
||||||
|
your first entry.
|
||||||
|
|
||||||
|
## Folder
|
||||||
|
The folder journal format organizes your entries into subfolders for the year
|
||||||
|
and month and `.txt` files for each day. If there are multiple entries in a day,
|
||||||
|
they all appear in the same `.txt` file.
|
||||||
|
|
||||||
|
The directory tree structure is in this format: `YYYY/MM/DD.txt`. For instance, if
|
||||||
|
you have an entry on May 5th, 2021 in a folder journal at `~/folderjournal`, it will
|
||||||
|
be located in: `~/folderjournal/2021/05/05.txt`
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Creating a new folder journal can be done in two ways:
|
||||||
|
|
||||||
|
* Create a folder with the name of the journal before running `jrnl`. Otherwise, when you run `jrnl` for the first time, it will assume that you are creating a single file journal instead, and it will create a file at that path.
|
||||||
|
* Create a new journal in your [config_file](advanced.md) and end the path with a ``/`` (on a POSIX system like Linux or MacOSX) or a ``\`` (on a Windows system). The folder will be created automatically if it doesn't exist.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Folder journals can't be encrypted.
|
||||||
|
|
||||||
|
## Day One Classic
|
||||||
|
`jrnl` supports the original data format used by DayOne. It's similar to the folder
|
||||||
|
journal format, except it's identified by either of these characteristics:
|
||||||
|
|
||||||
|
* the folder has a `.dayone` extension
|
||||||
|
* the folder has a subfolder named `entries`
|
||||||
|
|
||||||
|
This is not to be confused with the DayOne 2.0 format, [which is very different](https://help.dayoneapp.com/en/articles/1187337-day-one-classic-is-retired).
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
DayOne Classic journals can't be encrypted.
|
||||||
|
|
||||||
|
## Changing your journal type
|
||||||
|
You can't simply modify a journal's configuration to change its type. Instead,
|
||||||
|
define a new journal as the type you'd like, and use
|
||||||
|
[piping](https://en.wikipedia.org/wiki/Redirection_(computing)#Piping)
|
||||||
|
to export your old journal as `txt` to an import command on your new journal.
|
||||||
|
|
||||||
|
For instance, if you have a `projects` journal you would like to import into
|
||||||
|
a `new` journal, you would run the following after setting up the configuration
|
||||||
|
for your `new` journal:
|
||||||
|
```
|
||||||
|
jrnl projects --format txt | jrnl new --import
|
||||||
|
```
|
|
@ -1,27 +1,64 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
## What is jrnl?
|
`jrnl` is a simple journal application for the command line.
|
||||||
|
|
||||||
`jrnl` is a simple journal application for
|
You can use it to easily create, search, and view journal entries. Journals are
|
||||||
your command line. Journals are stored as human readable plain text
|
stored as human-readable plain text, and can also be encrypted using [AES
|
||||||
files - you can put them into a Dropbox folder for instant syncing and
|
encryption](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard).
|
||||||
you can be assured that your journal will still be readable in 2050,
|
|
||||||
when all your fancy iPad journal applications will long be forgotten.
|
|
||||||
|
|
||||||
Optionally, your journal can be encrypted using the [256-bit
|
`jrnl` has most of the features you need, and few of the ones you don't.
|
||||||
AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard).
|
|
||||||
|
|
||||||
## Why keep a journal?
|
## Plain Text
|
||||||
|
|
||||||
Journals aren't just for people who have too much
|
`jrnl` stores each journal in plain text. You can store `jrnl` files anywhere,
|
||||||
time on their summer vacation. A journal helps you to keep track of the
|
including in shared folders to keep them synchronized between devices. Journal
|
||||||
things you get done and how you did them. Your imagination may be
|
files are compact (thousands of entries take up less than 1 MiB) and can be read
|
||||||
limitless, but your memory isn't.
|
by almost any electronic device, now and for the foreseeable future.
|
||||||
|
|
||||||
For personal use, make it a good habit to write at least 20 words a day.
|
## Tags
|
||||||
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
|
To make it easier to find entries later, `jrnl` includes support for inline tags
|
||||||
complement to your GTD todo list - a documentation of what and how
|
(the default tag symbol is `@`). You can find and filter entries by using tags
|
||||||
you've done it. Or use it as a quick way to keep a change log. Or use it
|
along with other search criteria.
|
||||||
to keep a lab book.
|
|
||||||
|
## Support for Multiple Journals
|
||||||
|
|
||||||
|
`jrnl` includes support for the creation of multiple journals, each of which
|
||||||
|
can be stored as a single file or as a set of files. Entries are automatically
|
||||||
|
timestamped in a human-readable format that makes it easy to view multiple
|
||||||
|
entries at a time. `jrnl` can easily find the entries you want so that you can
|
||||||
|
read them or edit them.
|
||||||
|
|
||||||
|
## Support for External Editors
|
||||||
|
|
||||||
|
`jrnl` plays nicely with your favorite text editor. You may prefer to write
|
||||||
|
journal entries in an editor. Or you may want to make changes that require a
|
||||||
|
more comprehensive application. `jrnl` can filter specific entries and pass them
|
||||||
|
to the [external editor](./external-editors.md) of your choice.
|
||||||
|
|
||||||
|
## Encryption
|
||||||
|
|
||||||
|
`jrnl` includes support for [AES
|
||||||
|
encryption](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). See the
|
||||||
|
[encryption page](./encryption.md) for more information.
|
||||||
|
|
||||||
|
## Import and Export
|
||||||
|
|
||||||
|
`jrnl` makes it easy to import entries from other sources. Existing entries can
|
||||||
|
be exported in a variety of [formats](./formats.md).
|
||||||
|
|
||||||
|
## Multi-Platform Support
|
||||||
|
|
||||||
|
`jrnl` is compatible with most operating systems. You can [download](./installation.md) it using one
|
||||||
|
of a variety of package managers, or you can build from source.
|
||||||
|
|
||||||
|
## Open-Source
|
||||||
|
|
||||||
|
`jrnl` is written in [Python](https://www.python.org) and maintained by a
|
||||||
|
[friendly community](https://github.com/jrnl-org/jrnl) of open-source software
|
||||||
|
enthusiasts.
|
||||||
|
|
232
docs/privacy-and-security.md
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Privacy and Security
|
||||||
|
|
||||||
|
`jrnl` is designed with privacy and security in mind, but like any other
|
||||||
|
program there are some limitations to be aware of.
|
||||||
|
|
||||||
|
## Password strength
|
||||||
|
|
||||||
|
`jrnl` doesn't enforce password strength requirements. Short or commonly-used
|
||||||
|
passwords can be easily circumvented by someone with basic security skills
|
||||||
|
to access to your encrypted `jrnl` file.
|
||||||
|
|
||||||
|
## Plausible deniability
|
||||||
|
|
||||||
|
You may be able to hide the contents of your journal behind a layer of encryption,
|
||||||
|
but if someone has access to your configuration file, then they can figure out that
|
||||||
|
you have a journal, where that journal file is, and when you last edited it.
|
||||||
|
With a sufficient power imbalance, someone may be able to force you to unencrypt
|
||||||
|
it through non-technical means.
|
||||||
|
|
||||||
|
## Spying
|
||||||
|
|
||||||
|
While `jrnl` can protect against unauthorized access to your journal entries while
|
||||||
|
it isn't open, it cannot protect you against an unsafe computer/location.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
- Someone installs a keylogger, tracking what you type into your journal.
|
||||||
|
- Someone watches your screen while you write your entry.
|
||||||
|
- Someone installs a backdoor into `jrnl` or poisons your journal into revealing your entries.
|
||||||
|
|
||||||
|
## Saved Passwords
|
||||||
|
|
||||||
|
When creating an encrypted journal, you'll be prompted as to whether or not you
|
||||||
|
want to "store the password in your keychain." This keychain is accessed using
|
||||||
|
the [Python keyring library](https://pypi.org/project/keyring/), which has different
|
||||||
|
behavior depending on your operating system.
|
||||||
|
|
||||||
|
In Windows, the keychain is the Windows Credential Manager (WCM), which can't be locked
|
||||||
|
and can be accessed by any other application running under your username. If this is
|
||||||
|
a concern for you, you may not want to store your password.
|
||||||
|
|
||||||
|
## Shell history
|
||||||
|
|
||||||
|
Since you can enter entries from the command line, any tool that logs command
|
||||||
|
line actions is a potential security risk. See below for how to deal with this
|
||||||
|
problem in various shells.
|
||||||
|
|
||||||
|
### bash
|
||||||
|
|
||||||
|
You can disable history logging for jrnl by adding this line into your
|
||||||
|
`~/.bashrc` file:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
HISTIGNORE="$HISTIGNORE:jrnl *"
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete existing `jrnl` commands from `bash` history, simply delete them from
|
||||||
|
your bash history file. The default location of this file is `~/.bash_history`,
|
||||||
|
but you can run `echo "$HISTFILE"` to find it if needed. Also, you can run
|
||||||
|
`history -c` to delete all commands from your history.
|
||||||
|
|
||||||
|
### zsh
|
||||||
|
|
||||||
|
You can disable history logging for jrnl by adding this to your `~/.zshrc`
|
||||||
|
file:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
setopt HIST_IGNORE_SPACE
|
||||||
|
alias jrnl=" jrnl"
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete existing `jrnl` commands from `zsh` history, simply remove them from
|
||||||
|
your zsh history file. The default location of this file is `~/.zsh_history`,
|
||||||
|
but you can run `echo "$HISTFILE"` to find it if needed. Also, you can run
|
||||||
|
`history -c` to delete all commands from your history.
|
||||||
|
|
||||||
|
### fish
|
||||||
|
|
||||||
|
By default `fish` will not log any command that starts with a space. If you
|
||||||
|
want to always run jrnl with a space before it, then you can add this to your
|
||||||
|
`~/.config/fish/config.fish` file:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
abbr --add jrnl " jrnl"
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete existing jrnl commands from `fish` history, run `history delete --prefix 'jrnl '`.
|
||||||
|
|
||||||
|
### Windows Command Prompt
|
||||||
|
|
||||||
|
Windows doesn't log history to disk, but it does keep it in your command prompt
|
||||||
|
session. Close the command prompt or press `Alt`+`F7` to clear your history
|
||||||
|
after journaling.
|
||||||
|
|
||||||
|
## Files in transit from editor to jrnl
|
||||||
|
|
||||||
|
When creating or editing an entry, `jrnl` uses a unencrypted temporary file on
|
||||||
|
disk in order to give your editor access to your journal. After you close your
|
||||||
|
editor, `jrnl` then deletes this temporary file.
|
||||||
|
|
||||||
|
So, if you have saved a journal entry but haven't closed your editor yet, the
|
||||||
|
unencrypted temporary remains on your disk. If your computer were to shut off
|
||||||
|
during this time, or the `jrnl` process were killed unexpectedly, then the
|
||||||
|
unencrypted temporary file will remain on your disk. You can mitigate this
|
||||||
|
issue by only saving with your editor right before closing it. You can also
|
||||||
|
manually delete these files from your temporary folder. By default, they
|
||||||
|
are named `jrnl*.jrnl`, but if you use a
|
||||||
|
[template](reference-config-file.md#template), they will have the same
|
||||||
|
extension as the template.
|
||||||
|
|
||||||
|
## Editor history
|
||||||
|
|
||||||
|
Some editors keep usage history stored on disk for future use. This can be a
|
||||||
|
security risk in the sense that sensitive information can leak via recent
|
||||||
|
search patterns or editor commands.
|
||||||
|
|
||||||
|
### Visual Studio Code
|
||||||
|
|
||||||
|
Visual Studio Code stores the contents of saved files to allow you to restore or
|
||||||
|
review the contents later. You can disable this feature for all files by unchecking
|
||||||
|
the `workbench.localHistory.enabled` setting in the
|
||||||
|
[Settings editor](https://code.visualstudio.com/docs/getstarted/settings#_settings-editor).
|
||||||
|
|
||||||
|
Alternatively, you can disable this feature for specific files by configuring a
|
||||||
|
[pattern](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)
|
||||||
|
in the `workbench.localHistory.exclude` setting. To exclude unencrypted temporary files generated
|
||||||
|
by `jrnl`, you can set the `**/jrnl*.jrnl` (unless you are using a
|
||||||
|
[template](reference-config-file.md#template)) pattern for the `workbench.localHistory.exclude` setting
|
||||||
|
in the [Settings editor](https://code.visualstudio.com/docs/getstarted/settings#_settings-editor).
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
On Windows, the history location is typically found at
|
||||||
|
`%APPDATA%\Code\User\History`.
|
||||||
|
|
||||||
|
Visual Studio Code also creates a copy of all unsaved files that are open.
|
||||||
|
It stores these copies in a backup location that's automatically cleaned when
|
||||||
|
you save the file. However, if your computer shuts off before you save the file,
|
||||||
|
or the Visual Studio Code process stops unexpectedly, then an unencrypted
|
||||||
|
temporary file may remain on your disk. You can manually delete these files
|
||||||
|
from the backup location.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
On Windows, the backup location is typically found at
|
||||||
|
`%APPDATA%\Code\Backups`.
|
||||||
|
|
||||||
|
### Vim
|
||||||
|
|
||||||
|
Vim stores progress data in a so called Viminfo file located at `~/.viminfo`
|
||||||
|
which contains all sorts of user data including command line history, search
|
||||||
|
string history, search/substitute patterns, contents of register etc. Also to
|
||||||
|
be able to recover opened files after an unexpected application close Vim uses
|
||||||
|
swap files.
|
||||||
|
|
||||||
|
These options as well as other leaky features can be disabled by setting the
|
||||||
|
`editor` key in the Jrnl settings like this:
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
editor: "vim -c 'set viminfo= noswapfile noundofile nobackup nowritebackup noshelltemp history=0 nomodeline secure'"
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable all plugins and custom configurations and start Vim with the default
|
||||||
|
configuration `-u NONE` can be passed on the command line as well. This will
|
||||||
|
ensure that any rogue plugins or other difficult to catch information leaks are
|
||||||
|
eliminated. The downside to this is that the editor experience will decrease
|
||||||
|
quite a bit.
|
||||||
|
|
||||||
|
To instead let Vim automatically detect when a Jrnl file is being edited an
|
||||||
|
autocommand can be used. Place this in your `~/.vimrc`:
|
||||||
|
|
||||||
|
``` vim
|
||||||
|
autocmd BufNewFile,BufReadPre *.jrnl setlocal viminfo= noswapfile noundofile nobackup nowritebackup noshelltemp history=0 nomodeline secure
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
If you're using a [template](reference-config-file.md#template), you will
|
||||||
|
have to use the template's file extension instead of `.jrnl`.
|
||||||
|
|
||||||
|
See `:h <option>` in Vim for more information about the options mentioned.
|
||||||
|
|
||||||
|
### Neovim
|
||||||
|
|
||||||
|
Neovim strives to be mostly compatible with Vim and has therefore similar
|
||||||
|
functionality as Vim. One difference in Neovim is that the Viminfo file is
|
||||||
|
instead called the ShaDa ("shared data") file which resides in
|
||||||
|
`~/.local/state/nvim` (`~/.local/share/nvim` pre Neovim v0.8.0). The ShaDa file
|
||||||
|
can be disabled in the same way as for Vim.
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
editor: "nvim -c 'set shada= noswapfile noundofile nobackup nowritebackup noshelltemp history=0 nomodeline secure'"
|
||||||
|
```
|
||||||
|
|
||||||
|
`-u NONE` can be passed here as well to start a session with the default configs.
|
||||||
|
|
||||||
|
As for Vim above we can create an autocommand in Vimscript:
|
||||||
|
|
||||||
|
``` vim
|
||||||
|
autocmd BufNewFile,BufReadPre *.jrnl setlocal shada= noswapfile noundofile nobackup nowritebackup noshelltemp history=0 nomodeline secure
|
||||||
|
```
|
||||||
|
|
||||||
|
or the same but in Lua:
|
||||||
|
|
||||||
|
``` lua
|
||||||
|
vim.api.nvim_create_autocmd( {"BufNewFile","BufReadPre" }, {
|
||||||
|
group = vim.api.nvim_create_augroup("PrivateJrnl", {}),
|
||||||
|
pattern = "*.jrnl",
|
||||||
|
callback = function()
|
||||||
|
vim.o.shada = ""
|
||||||
|
vim.o.swapfile = false
|
||||||
|
vim.o.undofile = false
|
||||||
|
vim.o.backup = false
|
||||||
|
vim.o.writebackup = false
|
||||||
|
vim.o.shelltemp = false
|
||||||
|
vim.o.history = 0
|
||||||
|
vim.o.modeline = false
|
||||||
|
vim.o.secure = true
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
If you're using a [template](reference-config-file.md#template), you will
|
||||||
|
have to use the template's file extension instead of `.jrnl`.
|
||||||
|
|
||||||
|
Please see `:h <option>` in Neovim for more information about the options mentioned.
|
||||||
|
|
||||||
|
## Notice any other risks?
|
||||||
|
|
||||||
|
Please let the maintainers know by [filing an issue on GitHub](https://github.com/jrnl-org/jrnl/issues).
|
245
docs/recipes.md
|
@ -1,245 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
Templates require an [external editor](./advanced.md) be configured.
|
|
||||||
|
|
||||||
A template is a code snippet that makes it easier to use repeated text
|
|
||||||
each time a new journal entry is started. There are two ways you can utilize
|
|
||||||
templates in your entries.
|
|
||||||
|
|
||||||
#### 1. Command line arguments
|
|
||||||
|
|
||||||
If you had a `template.txt` file with the following contents:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
My Personal Journal
|
|
||||||
Title:
|
|
||||||
|
|
||||||
Body:
|
|
||||||
```
|
|
||||||
|
|
||||||
The `template.txt` file could be used to create a new entry with these
|
|
||||||
command line arguements:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
jrnl < template.txt # Imports template.txt as the most recent entry
|
|
||||||
jrnl -1 --edit # Opens the most recent entry in the editor
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Include the template file in `jrnl.yaml`
|
|
||||||
|
|
||||||
A more efficient way to work with a template file is to declare the file
|
|
||||||
in your config file by changing the `template` setting from `false` to the
|
|
||||||
template file's path in double quotes:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
...
|
|
||||||
template: "/path/to/template.txt"
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
Changes can be saved as you continue writing the journal entry and will be
|
|
||||||
logged as a new entry in the journal you specified in the original argument.
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
To read your journal entry or to verify the entry saved, you can use this
|
|
||||||
command: `jrnl -n 1` (Check out [Import and Export](./export.md) for more export options).
|
|
||||||
|
|
||||||
```sh
|
|
||||||
jrnl -n 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Prompts on shell reload
|
|
||||||
|
|
||||||
If you'd like to be prompted each time you refresh your shell, you can include
|
|
||||||
this in your `.bash_profile`:
|
|
||||||
|
|
||||||
```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?'
|
|
||||||
```
|
|
||||||
|
|
||||||
Whenever your shell is reloaded, you will be prompted to answer each of the
|
|
||||||
questions in the example above. Each answer will be logged as a separate
|
|
||||||
journal entry at the `default_hour` and `default_minute` listed in your
|
|
||||||
`jrnl.yaml` [config file](../advanced/#configuration-file).
|
|
||||||
|
|
||||||
### Display random entry
|
|
||||||
|
|
||||||
You can use this to select one title at random and then display the whole
|
|
||||||
entry. The invocation of `cut` needs to match the format of the timestamp.
|
|
||||||
For timestamps that have a space between data and time components, select
|
|
||||||
fields 1 and 2 as shown. For timestamps that have no whitespace, select
|
|
||||||
only field 1.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
jrnl -on "$(jrnl --short | shuf -n 1 | cut -d' ' -f1,2)"
|
|
||||||
```
|
|
||||||
|
|
||||||
## External editors
|
|
||||||
|
|
||||||
Configure your preferred external editor by updating the `editor` option
|
|
||||||
in your `jrnl.yaml` file. (See [advanced usage](./advanced.md) for details).
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
To save and log any entry edits, save and close the file.
|
|
||||||
|
|
||||||
### Sublime Text
|
|
||||||
|
|
||||||
To use Sublime Text, install the command line tools for Sublime Text and
|
|
||||||
configure your `jrnl.yaml` like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
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`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
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.yaml` like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
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.yaml`) like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
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.yaml` like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
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:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
editor: "code --wait"
|
|
||||||
```
|
|
||||||
|
|
||||||
to `jrnl.yaml`. See also the [Visual Studio Code documentation](https://code.visualstudio.com/docs/setup/mac)
|
|
141
docs/reference-command-line.md
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Command Line Reference
|
||||||
|
|
||||||
|
## Synopsis
|
||||||
|
```
|
||||||
|
usage: jrnl [--debug] [--help] [--version] [--list] [--encrypt] [--decrypt]
|
||||||
|
[--import] [-on DATE] [-today-in-history] [-month DATE]
|
||||||
|
[-day DATE] [-year DATE] [-from DATE] [-to DATE] [-contains TEXT]
|
||||||
|
[-and] [-starred] [-n [NUMBER]] [-not [TAG]] [--edit] [--delete]
|
||||||
|
[--format TYPE] [--tags] [--short]
|
||||||
|
[--config-override CONFIG_KEY CONFIG_VALUE]
|
||||||
|
[--config-file CONFIG_FILE_PATH]
|
||||||
|
[[...]]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standalone Commands
|
||||||
|
|
||||||
|
These commands will exit after they complete. You may only run one at a time.
|
||||||
|
|
||||||
|
### --help
|
||||||
|
Show a help message.
|
||||||
|
|
||||||
|
### --version
|
||||||
|
Print version and license information.
|
||||||
|
|
||||||
|
### --list
|
||||||
|
List the config file location, all configured journals, and their locations.
|
||||||
|
|
||||||
|
### ---encrypt
|
||||||
|
Encrypt a journal. See [encryption](encryption.md) for more information.
|
||||||
|
|
||||||
|
### --decrypt
|
||||||
|
Decrypt a journal. See [encryption](encryption.md) for more information.
|
||||||
|
|
||||||
|
|
||||||
|
### --import
|
||||||
|
Import entries from another journal. If any entries have the exact same content
|
||||||
|
and timestamp, they will be deduplicated.
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
```sh
|
||||||
|
--file FILENAME
|
||||||
|
```
|
||||||
|
Specify a file to import. If not provided, `jrnl` will use STDIN as the data source.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
--format TYPE
|
||||||
|
```
|
||||||
|
Specify the format of the file that is being imported. Defaults to the same data
|
||||||
|
storage method that jrnl uses. See [formats](formats.md) for more information.
|
||||||
|
|
||||||
|
## Writing new entries
|
||||||
|
See [Basic Usage](usage.md).
|
||||||
|
|
||||||
|
## Searching
|
||||||
|
|
||||||
|
To find entries from your journal, use any combination of the below filters.
|
||||||
|
Only entries that match all the filters will be displayed.
|
||||||
|
|
||||||
|
When specifying dates, you can use the same kinds of dates you use for new
|
||||||
|
entries, such as `yesterday`, `today`, `Tuesday`, or `2021-08-01`.
|
||||||
|
|
||||||
|
| Search Argument | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| -on DATE | Show entries on this date |
|
||||||
|
| -today-in-history | Show entries of today over the years |
|
||||||
|
| -month DATE | Show entries on this month of any year |
|
||||||
|
| -day DATE | Show entries on this day of any month |
|
||||||
|
| -year DATE | Show entries of a specific year |
|
||||||
|
| -from DATE | Show entries after, or on, this date |
|
||||||
|
| -to DATE | Show entries before, or on, this date (alias: -until) |
|
||||||
|
| -contains TEXT | Show entries containing specific text (put quotes around text with spaces) |
|
||||||
|
| -and | Show only entries that match all conditions, like saying "x AND y" (default: OR) |
|
||||||
|
| -starred | Show only starred entries (marked with *) |
|
||||||
|
| -tagged | Show only tagged entries (marked with the [configured tagsymbols](reference-config-file.md#tagsymbols)) |
|
||||||
|
| -n [NUMBER] | Show a maximum of NUMBER entries (note: '-n 3' and '-3' have the same effect) |
|
||||||
|
| -not [TAG] | Exclude entries with this tag |
|
||||||
|
| -not -starred | Exclude entries that are starred |
|
||||||
|
| -not -tagged | Exclude entries that are tagged |
|
||||||
|
|
||||||
|
## Searching Options
|
||||||
|
These help you do various tasks with the selected entries from your search.
|
||||||
|
If used on their own (with no search), they will act on your entire journal.
|
||||||
|
|
||||||
|
### --edit
|
||||||
|
Opens the selected entries in your configured editor. It will fail if the
|
||||||
|
`editor` key is not set in your config file.
|
||||||
|
|
||||||
|
Once you begin editing, you can add multiple entries and delete entries
|
||||||
|
by modifying the text in your editor. When your editor closes, jrnl reads
|
||||||
|
the temporary file you were editing and makes the changes to your journal.
|
||||||
|
|
||||||
|
### --delete
|
||||||
|
Interactively deletes selected entries. You'll be asked to confirm deletion of
|
||||||
|
each entry.
|
||||||
|
|
||||||
|
### --change-time DATE
|
||||||
|
Interactively changes the time of the selected entries to the date specified,
|
||||||
|
or to right now if no date is specified. You'll be asked to confirm each entry,
|
||||||
|
unless you are using this with `--edit` on a single entry.
|
||||||
|
|
||||||
|
### --format TYPE
|
||||||
|
Display selected entries in an alternate format. See [formats](formats.md).
|
||||||
|
|
||||||
|
#### Optional parameters
|
||||||
|
```sh
|
||||||
|
--file FILENAME
|
||||||
|
```
|
||||||
|
Write output to file instead of STDOUT. In most shells, the
|
||||||
|
same effect can be achieved using `>`.
|
||||||
|
|
||||||
|
### --tags
|
||||||
|
|
||||||
|
Alias for '--format tags'. Returns a list of all tags and the number of times
|
||||||
|
they occur within the searched entries. If there are no tags found, `jrnl` will output a message saying so.
|
||||||
|
|
||||||
|
### --short
|
||||||
|
Only shows the date and titles of the searched entries.
|
||||||
|
|
||||||
|
## Configuration arguments
|
||||||
|
|
||||||
|
### --config-override CONFIG_KEY CONFIG_VALUE
|
||||||
|
|
||||||
|
Override configured key-value pair with CONFIG_KV_PAIR for this command invocation only. To access config keys that aren't at the top level, separate the keys with a dot, such as `colors.title` to access the `title` key within the `colors` key. Read [advanced usage](./advanced.md) for examples.
|
||||||
|
|
||||||
|
### --config-file CONFIG_FILE_PATH
|
||||||
|
|
||||||
|
Use the config file at CONFIG_FILE_PATH for this command invocation only.
|
||||||
|
Read [advanced usage](./advanced.md) for examples.
|
||||||
|
|
||||||
|
## Other Arguments
|
||||||
|
|
||||||
|
### --debug
|
||||||
|
Prints information useful for troubleshooting while `jrnl` executes.
|
||||||
|
|
||||||
|
### --diagnostic
|
||||||
|
Prints diagnostic information useful for [reporting issues](https://github.com/jrnl-org/jrnl/issues).
|
123
docs/reference-config-file.md
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Configuration File Reference
|
||||||
|
|
||||||
|
`jrnl` stores its information in a YAML configuration file.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Backup your journal and config file before editing. Changes to the config file
|
||||||
|
can have destructive effects on your journal!
|
||||||
|
|
||||||
|
## Config location
|
||||||
|
You can find your configuration file location by running:
|
||||||
|
`jrnl --list`
|
||||||
|
|
||||||
|
By default, the configuration file is `~/.config/jrnl/jrnl.yaml`.
|
||||||
|
If you have the `XDG_CONFIG_HOME` variable set, the configuration
|
||||||
|
file will be saved as `$XDG_CONFIG_HOME/jrnl/jrnl.yaml`.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
On Windows, the configuration file is typically found at
|
||||||
|
`%USERPROFILE%\.config\jrnl\jrnl.yaml`.
|
||||||
|
|
||||||
|
|
||||||
|
## Config format
|
||||||
|
The configuration file is a [YAML](https://yaml.org/) file and can be edited with
|
||||||
|
a text editor.
|
||||||
|
|
||||||
|
## Config keys
|
||||||
|
|
||||||
|
### journals
|
||||||
|
|
||||||
|
Describes each journal used by `jrnl`. Each indented key after this key is
|
||||||
|
the name of a journal.
|
||||||
|
|
||||||
|
If a journal key has a value, that value will be interpreted as the path
|
||||||
|
to the journal. Otherwise, the journal needs the additional indented key
|
||||||
|
`journal` to specify its path.
|
||||||
|
|
||||||
|
All keys below can be specified for each journal at the same level as the
|
||||||
|
`journal` key. If a key conflicts with a top-level key, the journal-specific
|
||||||
|
key will be used instead.
|
||||||
|
|
||||||
|
### editor
|
||||||
|
If set, executes this command to launch an external editor for
|
||||||
|
writing and editing your entries. The path to a temporary file
|
||||||
|
is passed after it, and `jrnl` processes the file once
|
||||||
|
the editor returns control to `jrnl`.
|
||||||
|
|
||||||
|
Some editors require special options to work properly, since they must be
|
||||||
|
blocking processes to work with `jrnl`. See [External Editors](external-editors.md)
|
||||||
|
for details.
|
||||||
|
|
||||||
|
### encrypt
|
||||||
|
If `true`, encrypts your journal using AES. Do not change this
|
||||||
|
value for journals that already have data in them.
|
||||||
|
|
||||||
|
### template
|
||||||
|
The path to a text file to use as a template for new entries. Only works when you
|
||||||
|
have the `editor` field configured. If you use a template, the editor's
|
||||||
|
[temporary files](privacy-and-security.md#files-in-transit-from-editor-to-jrnl)
|
||||||
|
will have the same extension as the template.
|
||||||
|
|
||||||
|
### tagsymbols
|
||||||
|
Symbols to be interpreted as tags.
|
||||||
|
|
||||||
|
!!! 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.
|
||||||
|
|
||||||
|
### default_hour and default_minute
|
||||||
|
Entries will be created at this time if you supply a date but no specific time (for example, `last thursday`).
|
||||||
|
|
||||||
|
### timeformat
|
||||||
|
Defines how to format the timestamps as they are stored in your journal.
|
||||||
|
See the [python docs](http://docs.python.org/library/time.html#time.strftime) for reference.
|
||||||
|
|
||||||
|
Do not change this for an existing journal, since that might lead
|
||||||
|
to data loss.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
`jrnl` doesn't support the `%z` or `%Z` time zone identifiers.
|
||||||
|
|
||||||
|
### 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. Set to `auto` to let `jrnl` automatically determine
|
||||||
|
the terminal width.
|
||||||
|
|
||||||
|
### colors
|
||||||
|
A dictionary that controls the colors used to display journal entries.
|
||||||
|
It has four subkeys, which are: `body`, `date`, `tags`, and `title`.
|
||||||
|
|
||||||
|
Current valid values are: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`,
|
||||||
|
`MAGENTA`, `CYAN`, `WHITE`, and `NONE`.
|
||||||
|
|
||||||
|
`colorama.Fore` is used for colorization, and you can find the [docs here](https://github.com/tartley/colorama#colored-output).
|
||||||
|
|
||||||
|
To disable colored output, set the value to `NONE`.
|
||||||
|
|
||||||
|
### display_format
|
||||||
|
Specifies formatter to use by default. See [formats](formats.md).
|
||||||
|
|
||||||
|
### version
|
||||||
|
`jrnl` automatically updates this field to the version that it is running.
|
||||||
|
There is no need to change this field manually.
|
|
@ -1,74 +0,0 @@
|
||||||
# Privacy and Security
|
|
||||||
|
|
||||||
`jrnl` is designed with privacy and security in mind, but there are some
|
|
||||||
limitations to be aware of.
|
|
||||||
|
|
||||||
## Password strength
|
|
||||||
|
|
||||||
`jrnl` doesn't enforce password strength requirements. Short or commonly-used
|
|
||||||
passwords can easily be circumvented by someone with basic security skills
|
|
||||||
and access to your encrypted `jrnl` file.
|
|
||||||
|
|
||||||
## Shell history
|
|
||||||
|
|
||||||
Since you can enter entries from the command line, any tool
|
|
||||||
that logs command line actions is a potential security risk. See
|
|
||||||
below for how to deal with this problem in various shells.
|
|
||||||
|
|
||||||
### bash
|
|
||||||
|
|
||||||
You can disable history logging for jrnl in your `.bashrc`:
|
|
||||||
|
|
||||||
``` sh
|
|
||||||
HISTIGNORE="$HISTIGNORE:jrnl *"
|
|
||||||
```
|
|
||||||
|
|
||||||
### zsh
|
|
||||||
|
|
||||||
Disable history logging by adding this to your `zshrc`:
|
|
||||||
|
|
||||||
``` sh
|
|
||||||
setopt HIST_IGNORE_SPACE
|
|
||||||
alias jrnl=" jrnl"
|
|
||||||
```
|
|
||||||
|
|
||||||
### fish
|
|
||||||
|
|
||||||
Add this abbreviation to your `fish` configuration to run jrnl with
|
|
||||||
a space before it, which prevents `fish` from logging it:
|
|
||||||
|
|
||||||
``` sh
|
|
||||||
abbr --add jrnl " jrnl"
|
|
||||||
```
|
|
||||||
|
|
||||||
To delete existing `jrnl` commands from `fish`’s history, run
|
|
||||||
`history delete --prefix 'jrnl '`.
|
|
||||||
|
|
||||||
### Windows Command Prompt
|
|
||||||
|
|
||||||
Windows doesn't log history to disk, but it does keep it in your command
|
|
||||||
prompt session. Close the command prompt or press Alt+F7 to clear its
|
|
||||||
history after journaling.
|
|
||||||
|
|
||||||
## Files in transit from editor to jrnl
|
|
||||||
|
|
||||||
When creating or editing an entry, `jrnl` uses a plain text temporary file on disk
|
|
||||||
to give your editor access to it. `jrnl` deletes the temporary file when it
|
|
||||||
saves the entry back to your journal.
|
|
||||||
|
|
||||||
If you save an entry but haven't closed your editor yet, and your computer shuts
|
|
||||||
off or the `jrnl` process is killed, the entry remains on your disk as a
|
|
||||||
temporary file. You can mitigate this issue by only saving with your editor
|
|
||||||
right before closing it.
|
|
||||||
|
|
||||||
## Plausible deniability
|
|
||||||
|
|
||||||
You may be able to hide the contents of your journal behind a layer of encryption,
|
|
||||||
but if someone has access to your configuration file, then they can figure out that
|
|
||||||
you have a journal, where that journal file is, and when you last edited it.
|
|
||||||
With a sufficient power imbalance, someone may be able to force you to unencrypt
|
|
||||||
it through non-technical means.
|
|
||||||
|
|
||||||
## Notice any other risks?
|
|
||||||
|
|
||||||
Please let the maintainers know by [filing an issue on GitHub](https://github.com/jrnl-org/jrnl/issues).
|
|
18
docs/theme/img/sprites.svg
vendored
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg width="400px" height="160px" viewBox="0 0 400 160" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<!-- Generator: Sketch 55 (78076) - https://sketchapp.com -->
|
|
||||||
<title>sprites</title>
|
|
||||||
<desc>Created with Sketch.</desc>
|
|
||||||
<g id="sprites" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
||||||
<path d="M200.001666,7.10542736e-15 C186.746448,7.10542736e-15 176.000667,10.745781 176.000667,24.0009999 C176.000667,28.0531687 177.014042,31.8666609 178.791449,35.2174671 L162.102754,51.9021622 L162.117422,51.9141627 C160.812034,53.1968828 160,54.9729568 160,56.9463723 C160,60.8452014 163.160132,64.0039997 167.057627,64.0039997 C169.028376,64.0039997 170.805783,63.1919658 172.08717,61.8865781 L172.08317,61.882578 L188.765198,45.2018831 C192.117338,46.984624 195.937497,48.0019997 199.999,48.0019997 C213.254219,48.0019997 224,37.2562187 224,24.0009999 C224.002666,10.7471144 213.256885,7.10542736e-15 200.001666,7.10542736e-15 Z M169.589733,59.386474 C168.945706,60.0545018 168.053669,60.4731859 167.057627,60.4731859 C165.108213,60.4731859 163.528147,58.8957869 163.528147,56.9450389 C163.528147,55.9489974 163.948164,55.0596271 164.614859,54.4129335 L164.597525,54.3969328 L180.730197,38.2642607 C182.139589,40.1656733 183.819659,41.8457432 185.718405,43.2604689 L169.589733,59.386474 Z M200.001666,44.0044998 C188.957206,44.0044998 180.000833,35.04546 180.000833,24.0036666 C180.000833,12.9592065 188.957206,4.00283342 200.001666,4.00283342 C211.04346,4.00283342 220.0025,12.9592065 220.0025,24.0036666 C220.0025,35.0467933 211.044793,44.0044998 200.001666,44.0044998 Z M200.001666,10.00175 C200.551023,10.00175 201.001708,10.4497687 201.001708,11.0017917 C201.001708,11.5524813 200.551023,12.0018333 200.001666,12.0018333 C193.37339,12.0018333 188.001166,17.3753905 188.001166,24.0023332 C188.001166,24.5543562 187.553148,25.0023749 187.001125,25.0023749 C186.449102,25.0023749 186.001083,24.5543562 186.001083,24.0023332 C186.001083,16.2686777 192.268011,10.00175 200.001666,10.00175 Z" id="path10" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M42,26 L42,18 C42,8.05733333 33.9426667,0 24,0 C14.0573333,0 6,8.05733333 6,18 L6,26 C2.68533333,26 0,28.6853333 0,32 L0,38 L0,40 L0,44 L0,46 C0,55.9426667 8.05733333,64 18,64 L30,64 C39.9426667,64 48,55.9426667 48,46 L48,44 L48,40 L48,38 L48,32 C48,28.684 45.312,26 42,26 Z M10,18 C10,10.268 16.268,4 24,4 C31.732,4 38,10.268 38,18 L38,26 L34,26 L34,18.004 C34,12.48 29.524,8.004 24,8.004 C18.476,8.004 14,12.48 14,18.004 L14,26 L10,26 L10,18 Z M32,18 L32,18.0066667 L32,26 L16,26 L16,18.004 L16,18 C16,13.5813333 19.5813333,10 24,10 C28.4173333,10 32,13.5826667 32,18 Z M44,38 L44,40 L44,44 L44,46 C44,53.7173333 37.7173333,60 30,60 L18,60 C10.2826667,60 4,53.7173333 4,46 L4,44 L4,40 L4,38 L4,32 C4,30.896 4.896,30 6,30 C7.33466667,30 8.66533333,30 10,30 L38,30 C39.332,30 40.664,30 42,30 C43.1026667,30 44,30.896 44,32 L44,38 Z M24,38 C26.208,38 28,39.7906667 28,42 C28,43.2173333 27.344,45.536 26.668,47.364 C26.1213333,48.84 25.564,49.996 24,49.996 C22.5626667,49.996 21.8786667,48.828 21.3333333,47.344 C20.6666667,45.52 20,43.2133333 20,42 C20,39.7906667 21.792,38 24,38 Z" id="path12" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M56,110.174879 L37.4495142,102.225364 L44.8646072,96.9285223 C41.0009854,92.8572051 35.5547484,90.2992712 29.5,90.2992712 C19.2306123,90.2992712 10.6738014,97.6001925 8.72073517,107.291434 L3.77369603,105.243629 C6.58790907,93.6333303 17.023696,85 29.5,85 C37.336557,85 44.3508342,88.4239389 49.2055642,93.8300944 L56,88.9753644 L56,110.174879 Z M14.1353928,126.072692 C17.9965854,130.142795 23.4452516,132.700729 29.5,132.700729 C39.8082547,132.700729 48.3893574,125.343936 50.2974837,115.594395 L55.2396645,117.709002 C52.4412412,129.342378 41.9945229,138 29.5,138 C21.663443,138 14.6467366,134.576061 9.79443579,129.169906 L3,134.024636 L3,112.823907 L21.5504858,120.773421 L14.1353928,126.072692 Z" id="path6" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M110.666667,136 L110.666667,88 L114.666667,88 L114.666667,136 L124,136 C129.154658,136 133.333333,131.821324 133.333333,126.666667 L133.333333,97.3333333 C133.333333,94.1616732 131.751312,91.3595139 129.333333,89.672919 L129.333333,109.333333 L124,105.333333 L118.666667,109.333333 L118.666667,88 L121.333333,88 L100,88 C94.8453423,88 90.6666667,92.1786757 90.6666667,97.3333333 L90.6666667,126.666667 C90.6666667,131.821324 94.8453423,136 100,136 L110.666667,136 Z M134.130346,88.6638236 C136.127154,90.9949079 137.333333,94.0232615 137.333333,97.3333333 L137.333333,126.666667 C137.333333,129.976739 136.127154,133.005092 134.130346,135.336176 C137.570042,133.9607 140,130.597457 140,126.666667 L140,97.3333333 C140,93.4025432 137.570042,90.0393001 134.130346,88.6638236 Z M89.8696538,135.336176 C87.872846,133.005092 86.6666667,129.976739 86.6666667,126.666667 L86.6666667,97.3333333 C86.6666667,94.0232615 87.872846,90.9949079 89.8696538,88.6638236 C86.4299578,90.0393001 84,93.4025432 84,97.3333333 L84,126.666667 C84,130.597457 86.4299578,133.9607 89.8696538,135.336176 Z M93.3333333,84 L130.666667,84 C138.030463,84 144,89.9695367 144,97.3333333 L144,126.666667 C144,134.030463 138.030463,140 130.666667,140 L93.3333333,140 C85.9695367,140 80,134.030463 80,126.666667 L80,97.3333333 C80,89.9695367 85.9695367,84 93.3333333,84 Z" id="Combined-Shape" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M363.625,2 L363.625,13.625 C363.625,13.625 332.463,13.711 331.708333,47.375 C332.168333,42.2843333 335.715667,22.375 363.625,22.375 L363.625,31.0833333 L384,16.5416667 L363.625,2 Z M328,8.54166667 C323.568,8.54166667 320,12.1096667 320,16.5416667 L320,52.5416667 C320,56.9736667 323.568,60.5416667 328,60.5416667 L369.333333,60.5416667 C373.765333,60.5416667 377.333333,56.9736667 377.333333,52.5416667 L377.333333,29.875 L373.333333,32.5416667 L373.333333,52.5416667 C373.333333,54.7576667 371.549333,56.5416667 369.333333,56.5416667 L328,56.5416667 C325.784,56.5416667 324,54.7576667 324,52.5416667 L324,16.5416667 C324,14.3256667 325.784,12.5416667 328,12.5416667 L344,12.5416667 L353.333333,8.54166667 L328,8.54166667 Z" id="path8" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M272,13 C272.552,13 273,13.448 273,14 C273,14.552 272.549333,15 272,15 C261.345333,15 252,20.608 252,27 C252,27.552 251.552,28 251,28 C250.448,28 250,27.552 250,27 C250,19.412 260.074667,13 272,13 Z M272,3 C254.326667,3 240,13.7453333 240,27 C240,35.2546667 245.557333,42.532 254.016,46.852 C254.016,46.9053333 254,46.9413333 254,47 C254,50.5853333 251.322667,54.4466667 250.144,56.472 C250.146667,56.472 250.148,56.472 250.148,56.472 C250.053333,56.692 250,56.9333333 250,57.188 C250,58.188 250.809333,59 251.812,59 C252,59 252.330667,58.9506667 252.321333,58.972 C258.572,57.948 264.46,52.2053333 265.828,50.5426667 C267.826667,50.836 269.886667,51 272,51 C289.670667,51 304,40.2546667 304,27 C304,13.7453333 289.672,3 272,3 Z M272,47 C270.165333,47 268.284,46.86 266.408,46.5866667 C266.213333,46.5546667 266.02,46.544 265.828,46.544 C264.64,46.544 263.502667,47.072 262.736,48.004 C261.88,49.0466667 259.444,51.372 256.566667,53.0826667 C257.346667,51.292 257.956,49.2866667 257.998667,47.2186667 C258.010667,47.0906667 258.016,46.96 258.016,46.8506667 C258.016,45.3466667 257.174667,43.972 255.836,43.2893333 C248.424,39.504 244,33.4146667 244,27 C244,15.972 256.56,7 272,7 C287.436,7 300,15.972 300,27 C300,38.028 287.438667,47 272,47 Z" id="path16" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M192,80 C174.326667,80 160,94.3266667 160,112 C160,129.673333 174.326667,144 192,144 C209.673333,144 224,129.673333 224,112 C224,94.3266667 209.673333,80 192,80 Z M192,84 C207.463973,84 220,96.536024 220,112 C220,124.684311 211.56628,135.391332 200,138.833333 L200,137.666667 L200,135.375 L200,132.875 C200,130.353667 199.104333,128.479667 197.375,127.291667 C198.459,127.187667 199.469667,127.061667 200.375,126.875 C201.280333,126.688333 202.239333,126.436667 203.25,126.083333 C204.260667,125.73 205.155667,125.281 205.958333,124.791667 C206.761,124.302333 207.553,123.656333 208.291667,122.875 C209.030333,122.093667 209.625,121.239333 210.125,120.25 C210.625,119.260667 211.041333,118.052 211.333333,116.666667 C211.625333,115.281333 211.75,113.75 211.75,112.083333 C211.75,108.854 210.729,106.105333 208.625,103.833333 C209.583667,101.333333 209.458333,98.604 208.291667,95.6666667 L207.5,95.5833333 C206.958667,95.5206667 205.988667,95.7703333 204.583333,96.2916667 C203.178,96.813 201.625667,97.6453333 199.875,98.8333333 C197.396333,98.1453333 194.791667,97.8333333 192.125,97.8333333 C189.437,97.8333333 186.895667,98.1466667 184.458333,98.8333333 C183.354333,98.0826667 182.322667,97.4906667 181.333333,97 C180.344,96.5106667 179.551667,96.1773333 178.958333,96 C178.365,95.8226667 177.802333,95.708 177.291667,95.6666667 C176.781,95.6253333 176.437,95.6036667 176.291667,95.625 C176.146333,95.6463333 176.061333,95.687 176,95.7083333 C174.833333,98.667 174.708,101.354667 175.666667,103.833333 C173.562667,106.104 172.5,108.854 172.5,112.083333 C172.5,113.75 172.666333,115.281333 172.958333,116.666667 C173.250333,118.052 173.625,119.260667 174.125,120.25 C174.625,121.239333 175.26,122.093667 176,122.875 C176.74,123.656333 177.532,124.301 178.333333,124.791667 C179.134667,125.282333 180.031,125.73 181.041667,126.083333 C182.052333,126.436667 182.678,126.688333 183.583333,126.875 C184.488667,127.061667 185.500667,127.229333 186.583333,127.333333 C184.875333,128.5 184,130.333667 184,132.875 L184,135.125 L184,137.75 L184,138.833333 C172.433733,135.391332 164,124.684311 164,112 C164,96.536024 176.53604,84 192,84 Z" id="path22" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M100,1.0658141e-14 C99.0049467,1.0658141e-14 98.0752267,0.350804013 97.3333333,0.958333333 C96.59144,1.56586265 96,2.50111463 96,3.625 L96,5.33333333 L94.6666667,5.33333333 L94.6666667,6.66666667 L87.3333333,6.66666667 C87.264,6.66305333 87.1943867,6.66305333 87.125,6.66666667 C86.1491067,6.76895307 85.32808,7.6854408 85.3333333,8.66666667 L85.3333333,9.33333333 L83.3333333,9.33333333 C82.28616,9.333438 81.33344,10.2861644 81.3333333,11.3333333 L81.3333333,12.125 C80.5629867,12.3974076 80.0044,13.1829169 80,14 L80,18 C80.0001067,19.0471693 80.9528267,19.9998947 82,20 L85.3333333,20 L85.3333333,53.3333333 L83.6666667,54.9166667 C83.05688,55.268736 82.6604,55.962572 82.6666667,56.6666667 L82.6666667,60.6666667 C82.6667733,61.713836 83.6194933,62.6665613 84.6666667,62.6666667 L95.2083333,62.6666667 L104.666667,62.6666667 L104.875,62.6666667 L115.333333,62.6666667 C116.380507,62.6665613 117.333227,61.713836 117.333333,60.6666667 L117.333333,56.6666667 C117.34,55.962572 116.94312,55.268736 116.333333,54.9166667 L114.666667,53.3333333 L114.666667,20 L118,20 C119.047173,19.9998947 119.999893,19.0471693 120,18 L120,14 C119.996,13.1829169 119.437013,12.3974076 118.666667,12.125 L118.666667,11.3333333 C118.66656,10.2861644 117.71384,9.333438 116.666667,9.33333333 L114.666667,9.33333333 L114.666667,8.66666667 C114.66656,7.61949773 113.71384,6.66677133 112.666667,6.66666667 L105.333333,6.66666667 L105.333333,5.33333333 L104,5.33333333 L104,3.625 C104,2.50111463 103.40856,1.56586269 102.666667,0.958333333 C101.924773,0.350803973 100.995053,1.0658141e-14 100,1.0658141e-14 Z M100,2.66666667 C100.274467,2.66666667 100.684267,2.8172396 100.958333,3.04166667 C101.2324,3.26609373 101.333333,3.4793628 101.333333,3.625 L101.333333,5.33333333 L98.6666667,5.33333333 L98.6666667,3.625 C98.6666667,3.4793628 98.7676,3.2660936 99.0416667,3.04166667 C99.3157333,2.81723973 99.7255333,2.66666667 100,2.66666667 Z M88,10.6666667 L112,10.6666667 L112,12 L114.666667,12 C114.596267,12.9827864 114.819853,13.6843969 116,13.4166667 L116,17.3333333 L110.666667,17.3333333 L89.3333333,17.3333333 L84,17.3333333 L84,13.5416667 C85.09188,13.6062785 85.25424,12.8356391 85.3333333,12 L88,12 L88,10.6666667 Z M89.3333333,20 L110.666667,20 L110.666667,56 L113.333333,57.8333333 L113.333333,58.6666667 L86.6666667,58.6666667 L86.6666667,57.8333333 L89.3333333,56 L89.3333333,20 Z M92,22.6666667 L92,28 L94.6666667,28 L94.6666667,22.6666667 L92,22.6666667 Z M96,22.6666667 L96,28 L98.6666667,28 L98.6666667,22.6666667 L96,22.6666667 Z M101.333333,22.6666667 L101.333333,28 L104,28 L104,22.6666667 L101.333333,22.6666667 Z M105.333333,22.6666667 L105.333333,28 L108,28 L108,22.6666667 L105.333333,22.6666667 Z M92,29.3333333 L92,34.6666667 L94.6666667,34.6666667 L94.6666667,29.3333333 L92,29.3333333 Z M96,29.3333333 L96,34.6666667 L98.6666667,34.6666667 L98.6666667,29.3333333 L96,29.3333333 Z M101.333333,29.3333333 L101.333333,34.6666667 L104,34.6666667 L104,29.3333333 L101.333333,29.3333333 Z M105.333333,29.3333333 L105.333333,34.6666667 L108,34.6666667 L108,29.3333333 L105.333333,29.3333333 Z M103.166667,40.8333333 C102.15268,40.8333333 101.333333,41.6526813 101.333333,42.6666667 C101.333333,43.680652 102.15268,44.5 103.166667,44.5 C104.180653,44.5 105,43.680652 105,42.6666667 C105,41.6526813 104.180653,40.8333333 103.166667,40.8333333 Z" id="path3858" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M247.471598,80 L243.471598,115.791667 L247.429931,116.208333 L251.013264,84 L291.929931,84 L295.513264,116.208333 L299.471598,115.791667 L295.471598,80 L247.471598,80 Z M255.471598,88 L255.471598,92 L287.471598,92 L287.471598,88 L255.471598,88 Z M255.471598,96 L255.471598,100 L287.471598,100 L287.471598,96 L255.471598,96 Z M255.471598,104 L255.471598,108 L287.471598,108 L287.471598,104 L255.471598,104 Z M255.471598,112 L255.471598,116 L287.471598,116 L287.471598,112 L255.471598,112 Z M241.471598,120 C240.371598,120 239.748598,120.872667 240.096598,121.916667 L246.846598,142.083333 C247.194598,143.127333 248.371598,144 249.471598,144 L293.471598,144 C294.571598,144 295.748598,143.127333 296.096598,142.083333 L302.846598,121.916667 C303.195931,120.872667 302.571598,120 301.471598,120 L241.471598,120 Z M263.471598,124 L279.471598,124 L279.471598,128 L263.471598,128 L263.471598,124 Z" id="path20" fill="#684688" fill-rule="nonzero"></path>
|
|
||||||
<path d="M384,92.1508074 C381.644441,93.1945738 379.116959,93.9024443 376.461373,94.2184709 C379.172907,92.5947297 381.248518,90.0192484 382.232259,86.9597924 C379.688777,88.4634811 376.881243,89.5553522 373.889761,90.1472486 C371.494254,87.5917412 368.086876,86 364.307523,86 C357.056897,86 351.177986,91.8789116 351.177986,99.1255639 C351.177986,100.15333 351.29396,101.157149 351.51796,102.117046 C340.608034,101.569071 330.933874,96.3420823 324.459092,88.399481 C323.327273,90.3351705 322.683403,92.5906513 322.683403,94.9982892 C322.683403,99.5534862 325.002989,103.572735 328.522367,105.924216 C326.370729,105.852268 324.347092,105.260371 322.575481,104.276527 L322.575481,104.440501 C322.575481,110.799308 327.102652,116.106298 333.105485,117.314143 C332.005667,117.610091 330.845926,117.774065 329.646133,117.774065 C328.798341,117.774065 327.978471,117.690091 327.1746,117.530091 C328.846237,122.749132 333.693408,126.54438 339.436372,126.648432 C334.945175,130.167811 329.282211,132.259422 323.131404,132.259422 C322.071637,132.259422 321.027766,132.195422 320,132.079448 C325.810938,135.8108 332.709668,137.986386 340.124268,137.986386 C364.275732,137.986386 377.477323,117.982065 377.477323,100.633331 L377.433296,98.9336682 C380.012752,97.0938743 382.244285,94.7823411 384,92.1508074 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 15 KiB |
307
docs/theme/index.css
vendored
|
@ -1,307 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
224
docs/tips-and-tricks.md
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Tips and Tricks
|
||||||
|
|
||||||
|
This page contains tips and tricks for using `jrnl`, often in conjunction
|
||||||
|
with other tools, including external editors.
|
||||||
|
|
||||||
|
## 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 -to "jan 2013" --short
|
||||||
|
```
|
||||||
|
|
||||||
|
To get a short summary of the 10 most recent, favourite entries before
|
||||||
|
January 1, 2013 that are tagged with `@fixed`.
|
||||||
|
|
||||||
|
## Statistics
|
||||||
|
|
||||||
|
How much did I write last year?
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl -from "jan 1 2013" -to "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
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Templates require an [external editor](./advanced.md) be configured.
|
||||||
|
|
||||||
|
Templates are text files that are used for creating structured journals.
|
||||||
|
There are three ways you can use templates:
|
||||||
|
|
||||||
|
### 1. Use the `--template` command line argument and the default $XDG_DATA_HOME/jrnl/templates directory
|
||||||
|
|
||||||
|
`$XDG_DATA_HOME/jrnl/templates` is created by default to store your templates! Create a template (like `default.md`) in this directory and pass `--template FILE_IN_DIR`.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl --template default.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Use the `--template` command line argument with a local / absolute path
|
||||||
|
|
||||||
|
You can create a template file with any text. Here is an example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# /tmp/template.txt
|
||||||
|
My Personal Journal
|
||||||
|
Title:
|
||||||
|
|
||||||
|
Body:
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, pass the absolute or relative path to the template file as an argument, and your external
|
||||||
|
editor will open and have your template pre-populated.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl --template /tmp/template.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Set a default template file in `jrnl.yaml`
|
||||||
|
|
||||||
|
If you want a template by default, change the value of `template` in the [config file](./reference-config-file.md)
|
||||||
|
from `false` to the template file's path, wrapped in double quotes:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
...
|
||||||
|
template: "/path/to/template.txt"
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
To read your journal entry or to verify the entry saved, you can use this
|
||||||
|
command: `jrnl -n 1` (Check out [Formats](./formats.md) for more options).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl -n 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prompts on shell reload
|
||||||
|
|
||||||
|
If you'd like to be prompted each time you refresh your shell, you can include
|
||||||
|
this in your `.bash_profile`:
|
||||||
|
|
||||||
|
```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?'
|
||||||
|
```
|
||||||
|
|
||||||
|
Whenever your shell is reloaded, you will be prompted to answer each of the
|
||||||
|
questions in the example above. Each answer will be logged as a separate
|
||||||
|
journal entry at the `default_hour` and `default_minute` listed in your
|
||||||
|
`jrnl.yaml` [config file](../advanced/#configuration-file).
|
||||||
|
|
||||||
|
## Display random entry
|
||||||
|
|
||||||
|
You can use this to select one title at random and then display the whole
|
||||||
|
entry. The invocation of `cut` needs to match the format of the timestamp.
|
||||||
|
For timestamps that have a space between data and time components, select
|
||||||
|
fields 1 and 2 as shown. For timestamps that have no whitespace, select
|
||||||
|
only field 1.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl -on "$(jrnl --short | shuf -n 1 | cut -d' ' -f1,2)"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Launch a terminal for rapid logging
|
||||||
|
You can use this to launch a terminal that is the `jrnl` stdin prompt so you can start typing away immediately.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jrnl --config-override editor ""
|
||||||
|
```
|
||||||
|
|
||||||
|
Bind this to a keyboard shortcut.
|
||||||
|
|
||||||
|
Map `Super+Alt+J` to launch the terminal with `jrnl` prompt
|
||||||
|
|
||||||
|
- **xbindkeys**
|
||||||
|
In your `.xbindkeysrc`
|
||||||
|
|
||||||
|
```ini
|
||||||
|
Mod4+Mod1+j
|
||||||
|
alacritty -t floating-jrnl -e jrnl --config-override editor "",
|
||||||
|
```
|
||||||
|
|
||||||
|
- **I3 WM** Launch a floating terminal with the `jrnl` prompt
|
||||||
|
|
||||||
|
```ini
|
||||||
|
bindsym Mod4+Mod1+j exec --no-startup-id alacritty -t floating-jrnl -e jrnl --config-override editor ""
|
||||||
|
for_window[title="floating *"] floating enable
|
||||||
|
```
|
||||||
|
## Visualize Formatted Markdown in the CLI
|
||||||
|
|
||||||
|
Out of the box, `jrnl` can output journal entries in Markdown. To visualize it, you can pipe to [mdless](https://github.com/ttscoff/mdless), which is a [less](https://en.wikipedia.org/wiki/Less_(Unix))-like tool that allows you to visualize your Markdown text with formatting and syntax highlighting from the CLI. You can use this in any shell that supports piping.
|
||||||
|
|
||||||
|
The simplest way to visualize your Markdown output with `mdless` is as follows:
|
||||||
|
```sh
|
||||||
|
jrnl --export md | mdless
|
||||||
|
```
|
||||||
|
|
||||||
|
This will render your Markdown output in the whole screen.
|
||||||
|
|
||||||
|
Fortunately, `mdless` has an option that allows you to adjust the screen width by using the `-w` option as follows:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl --export md | mdless -w 70
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want Markdown to be your default display format, you can define this in your config file as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
display_format: md
|
||||||
|
# or
|
||||||
|
display_format: markdown
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on how `jrnl` outputs your entries in Markdown, please visit the [Formats](./formats.md) section.
|
||||||
|
|
||||||
|
|
||||||
|
## Jump to end of buffer (with vi)
|
||||||
|
|
||||||
|
To cause vi to jump to the end of the last line of the entry you edit, in your config file set:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
editor: vi + -c "call cursor('.',strwidth(getline('.')))"
|
||||||
|
```
|
|
@ -1,3 +1,8 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
# Basic Usage #
|
# Basic Usage #
|
||||||
|
|
||||||
`jrnl` has two modes: **composing** and **viewing**. Whenever you don't enter
|
`jrnl` has two modes: **composing** and **viewing**. Whenever you don't enter
|
||||||
|
@ -11,13 +16,15 @@ it. Filter arguments can be combined arbitrarily. Arguments with a _double dash_
|
||||||
arguments are mutually exclusive (i.e., you can only specify one way to display
|
arguments are mutually exclusive (i.e., you can only specify one way to display
|
||||||
or export your journal at a time).
|
or export your journal at a time).
|
||||||
|
|
||||||
|
For a list of commands, enter `jrnl --help`.
|
||||||
|
|
||||||
## Composing Entries ##
|
## Composing Entries ##
|
||||||
|
|
||||||
Composing mode is entered by either starting `jrnl` without any arguments --
|
Composing mode is entered by either starting `jrnl` without any arguments --
|
||||||
which will launch an external editor -- or by just writing an entry on the
|
which will launch an external editor -- or by just writing an entry on the
|
||||||
command line:
|
command line:
|
||||||
|
|
||||||
```sh
|
```text
|
||||||
jrnl today at 3am: I just met Steve Buscemi in a bar! What a nice guy.
|
jrnl today at 3am: I just met Steve Buscemi in a bar! What a nice guy.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -28,7 +35,7 @@ jrnl today at 3am: I just met Steve Buscemi in a bar! What a nice guy.
|
||||||
reserved characters can be escaped using `\`, this is not ideal for
|
reserved characters can be escaped using `\`, this is not ideal for
|
||||||
long-form writing. The solution: first enter `jrnl` and hit `return`. You
|
long-form writing. The solution: first enter `jrnl` and hit `return`. You
|
||||||
can then enter the text of your journal entry. Alternatively, you can [use
|
can then enter the text of your journal entry. Alternatively, you can [use
|
||||||
an external editor](./advanced.md)).
|
an external editor](./advanced.md).
|
||||||
|
|
||||||
You can also import an entry directly from a file:
|
You can also import an entry directly from a file:
|
||||||
|
|
||||||
|
@ -51,15 +58,15 @@ If you don't specify a date and time (e.g., `jrnl finished writing letter to bro
|
||||||
|
|
||||||
If you don't use a timestamp, `jrnl` will create an entry using the current
|
If you don't use a timestamp, `jrnl` will create an entry using the current
|
||||||
time. If you use a date only (no time), `jrnl` will use the default time
|
time. If you use a date only (no time), `jrnl` will use the default time
|
||||||
specified in your configuration file (see [advanced usage](./advanced.md)).
|
specified in your [configuration file](./reference-config-file.md#default_hour-and-default_minute).
|
||||||
Behind the scenes, `jrnl` reorganizes entries in chronological order.
|
Behind the scenes, `jrnl` reorganizes entries in chronological order.
|
||||||
|
|
||||||
### Using Tags ###
|
### Using Tags ###
|
||||||
|
|
||||||
`jrnl` supports tags. Note that because `#` is a reserved character, the default
|
`jrnl` supports tags. The default tag symbol is `@` (largely because `#` is a
|
||||||
tag symbol is `@`. You can specify your own tag symbol in the configuration
|
reserved character). You can specify your own tag symbol in the
|
||||||
file. There is no limit to how many tags you can use in an entry. To use tags,
|
[configuration file](./reference-config-file.md#tagsymbols). To use tags, preface the
|
||||||
simply preface the desired tag with the symbol:
|
desired tag with the symbol:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
jrnl Had a wonderful day at the @beach with @Tom and @Anna.
|
jrnl Had a wonderful day at the @beach with @Tom and @Anna.
|
||||||
|
@ -68,6 +75,8 @@ jrnl Had a wonderful day at the @beach with @Tom and @Anna.
|
||||||
Although you can use capitals while tagging an entry, searches by tag are
|
Although you can use capitals while tagging an entry, searches by tag are
|
||||||
case-insensitive.
|
case-insensitive.
|
||||||
|
|
||||||
|
There is no limit to how many tags you can use in an entry.
|
||||||
|
|
||||||
### Starring Entries ###
|
### Starring Entries ###
|
||||||
|
|
||||||
To mark an entry as a favorite, simply "star" it using an asterisk (`*`):
|
To mark an entry as a favorite, simply "star" it using an asterisk (`*`):
|
||||||
|
@ -83,20 +92,22 @@ _now_), the following options are equivalent:
|
||||||
- `jrnl *Best day of my life.`
|
- `jrnl *Best day of my life.`
|
||||||
- `jrnl Best day of my life.*`
|
- `jrnl Best day of my life.*`
|
||||||
|
|
||||||
!!! note Make sure that the asterisk (`*`) is **not** surrounded by whitespaces.
|
!!! note
|
||||||
`jrnl Best day of my life! *` will not work because the `*` character has a
|
Make sure that the asterisk (`*`) is **not** surrounded by whitespaces.
|
||||||
special meaning in most shells.
|
`jrnl Best day of my life! *` will not work because the `*` character has a
|
||||||
|
special meaning in most shells.
|
||||||
|
|
||||||
## Viewing Entries ##
|
## Viewing and Searching Entries ##
|
||||||
|
|
||||||
`jrnl` can display entries in a variety of ways. Entries are filtered using commands preceded by a single dash (`-`). Type `jrnl -h` for a list of
|
`jrnl` can display entries in a variety of ways.
|
||||||
commands.
|
|
||||||
|
|
||||||
It is possible to see all entries by entering `jrnl -until today`. However, in
|
To view all entries, enter:
|
||||||
most cases you will likely want to use a filter to see specific entries that
|
```sh
|
||||||
meet certain criteria. `jrnl` provides several filtering commands, prefaced by a
|
jrnl -to today
|
||||||
single dash (`-`), that allow you to find exactly what you're looking for. For
|
```
|
||||||
example,
|
|
||||||
|
`jrnl` provides several filtering commands, prefaced by a single dash (`-`), that
|
||||||
|
allow you to find a more specific range of entries. For example,
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
jrnl -n 10
|
jrnl -n 10
|
||||||
|
@ -107,15 +118,20 @@ same way. If you want to see all of the entries you wrote from the beginning of
|
||||||
last year until the end of this past March, you would enter
|
last year until the end of this past March, you would enter
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
jrnl -from "last year" -until march
|
jrnl -from "last year" -to march
|
||||||
```
|
```
|
||||||
|
|
||||||
Filter criteria that use more than one word require surrounding quotes (`""`).
|
Filter criteria that use more than one word require surrounding quotes (`""`).
|
||||||
|
|
||||||
|
To see entries on a particular date, use `-on`:
|
||||||
|
```sh
|
||||||
|
jrnl -on yesterday
|
||||||
|
```
|
||||||
|
|
||||||
### Text Search ###
|
### Text Search ###
|
||||||
|
|
||||||
The `-contains` command displays all entries containing a specific string. This
|
The `-contains` command displays all entries containing the text you enter after it.
|
||||||
may be helpful when you're searching for entries and you can't remember if you
|
This may be helpful when you're searching for entries and you can't remember if you
|
||||||
tagged any words when you wrote them.
|
tagged any words when you wrote them.
|
||||||
|
|
||||||
You may realize that you use a word a lot and want to turn it into a tag in all
|
You may realize that you use a word a lot and want to turn it into a tag in all
|
||||||
|
@ -145,7 +161,7 @@ jrnl -n 5 @pinkie -and @WorldDomination
|
||||||
|
|
||||||
displays the last five entries containing _both_ `@pinkie` _and_
|
displays the last five entries containing _both_ `@pinkie` _and_
|
||||||
`@worldDomination`. You can change which symbols you'd like to use for tagging
|
`@worldDomination`. You can change which symbols you'd like to use for tagging
|
||||||
in the configuration.
|
in the [configuration file](./reference-config-file.md#tagsymbols).
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Entering `jrnl @pinkie @WorldDomination` will display entries in which both
|
Entering `jrnl @pinkie @WorldDomination` will display entries in which both
|
||||||
|
@ -153,6 +169,12 @@ in the configuration.
|
||||||
of the input strings look like tags. `jrnl` will assume you want to filter
|
of the input strings look like tags. `jrnl` will assume you want to filter
|
||||||
by tag, rather than create a new entry that consists only of tags.
|
by tag, rather than create a new entry that consists only of tags.
|
||||||
|
|
||||||
|
To view a list of all tags in the journal, enter:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
jrnl --tags
|
||||||
|
```
|
||||||
|
|
||||||
### Viewing Starred Entries ###
|
### Viewing Starred Entries ###
|
||||||
|
|
||||||
To display only your favorite (starred) entries, enter
|
To display only your favorite (starred) entries, enter
|
||||||
|
@ -165,11 +187,11 @@ jrnl -starred
|
||||||
|
|
||||||
You can edit entries after writing them. This is particularly useful when your
|
You can edit entries after writing them. This is particularly useful when your
|
||||||
journal file is encrypted. To use this feature, you need to have an external
|
journal file is encrypted. To use this feature, you need to have an external
|
||||||
editor configured in your configuration file. You can also edit only the entries
|
editor configured in your [configuration file](./reference-config-file.md#editor). You
|
||||||
that match specific search criteria. For example,
|
can also edit only the entries that match specific search criteria. For example,
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
jrnl -until 1950 @texas -and @history --edit
|
jrnl -to 1950 @texas -and @history --edit
|
||||||
```
|
```
|
||||||
|
|
||||||
opens your external editor displaying all entries tagged with `@texas` and
|
opens your external editor displaying all entries tagged with `@texas` and
|
||||||
|
@ -227,8 +249,8 @@ removed from the journal.
|
||||||
To list all of your journals:
|
To list all of your journals:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
jrnl -ls
|
jrnl --list
|
||||||
```
|
```
|
||||||
|
|
||||||
The journals displayed correspond to those specified in the `jrnl` configuration
|
The journals displayed correspond to those specified in the `jrnl`
|
||||||
file.
|
[configuration file](./reference-config-file.md#journals).
|
||||||
|
|
34
docs_theme/assets/colors.css
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* For dark bg */
|
||||||
|
--white: #fcfcfc;
|
||||||
|
--off-white: #f4f0ff;
|
||||||
|
--purple: #7e57c2;
|
||||||
|
--light-purple: #cf93e6;
|
||||||
|
--blue: #61aeee;
|
||||||
|
--green: #a6e22e;
|
||||||
|
--orange: #fd971f;
|
||||||
|
--red: #eb5567;
|
||||||
|
--pink: #d57699;
|
||||||
|
--yellow: #e2b93d;
|
||||||
|
|
||||||
|
/* For light bg */
|
||||||
|
--black: #404040;
|
||||||
|
--teal: #2a8068;
|
||||||
|
--dark-blue: #356eb7;
|
||||||
|
--mid-purple: #846392;
|
||||||
|
--bright-purple: #af27ad;
|
||||||
|
--dark-purple: #604385;
|
||||||
|
--darkest-purple: #251A32;
|
||||||
|
--grey: #3b3b4a;
|
||||||
|
|
||||||
|
--black-shadow: #0000001A;
|
||||||
|
--blacker-shadow: #00000059;
|
||||||
|
|
||||||
|
/* Special cases */
|
||||||
|
--terminal: #1b1c2e;
|
||||||
|
}
|
147
docs_theme/assets/highlight.css
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
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: var(--off-white);
|
||||||
|
background: #383e49;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.3rem;
|
||||||
|
}
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-operator {
|
||||||
|
color: var(--pink);
|
||||||
|
}
|
||||||
|
.hljs-pattern-match {
|
||||||
|
color: var(--pink);
|
||||||
|
}
|
||||||
|
.hljs-pattern-match .hljs-constructor {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
.hljs-function {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
.hljs-function .hljs-params {
|
||||||
|
color: var(--green);
|
||||||
|
}
|
||||||
|
.hljs-function .hljs-params .hljs-typing {
|
||||||
|
color: var(--orange);
|
||||||
|
}
|
||||||
|
.hljs-module-access .hljs-module {
|
||||||
|
color: var(--purple);
|
||||||
|
}
|
||||||
|
.hljs-constructor {
|
||||||
|
color: var(--yellow);
|
||||||
|
}
|
||||||
|
.hljs-constructor .hljs-string {
|
||||||
|
color: var(--green);
|
||||||
|
}
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote {
|
||||||
|
color: var(--light-purple);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.hljs-doctag,
|
||||||
|
.hljs-formula {
|
||||||
|
color: var(--purple);
|
||||||
|
}
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-deletion,
|
||||||
|
.hljs-subst {
|
||||||
|
color: var(--yellow);
|
||||||
|
}
|
||||||
|
.hljs-literal {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-addition,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-meta-string {
|
||||||
|
color: var(--green);
|
||||||
|
}
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-class .hljs-title {
|
||||||
|
color: var(--orange);
|
||||||
|
}
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-pseudo,
|
||||||
|
.hljs-number {
|
||||||
|
color: var(--orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content a tt,
|
||||||
|
.rst-content a tt,
|
||||||
|
.rst-content a code {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-tag .hljs-attr {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: var(--pink)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-link,
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-title {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.hljs-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .note .admonition-title {
|
||||||
|
background: var(--dark-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .note.admonition {
|
||||||
|
background: var(--light-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .tip .admonition-title {
|
||||||
|
background: var(--teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .tip .admonition {
|
||||||
|
background: var(--light-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hack to bypass a11y issue with conflicting highlight.css files */
|
||||||
|
code.language-xml span.hljs-meta span.hljs-string {
|
||||||
|
color: var(--green) !important;
|
||||||
|
}
|
||||||
|
|
325
docs_theme/assets/index.css
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* reset */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: var(--white);
|
||||||
|
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: 0 -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon.dayone {
|
||||||
|
background-position: -1em -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon.github {
|
||||||
|
background-position: -2em -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon.search {
|
||||||
|
background-position: -2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon.folders {
|
||||||
|
background-position: -3em -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon.twitter {
|
||||||
|
background-position: -4em -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: var(--mid-purple);
|
||||||
|
background-image: linear-gradient(211deg, var(--mid-purple) 0%, var(--dark-purple) 100%);
|
||||||
|
color: var(--white);
|
||||||
|
border: 0px solid transparent;
|
||||||
|
display: relative;
|
||||||
|
padding-top: 150px;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal {
|
||||||
|
background: var(--terminal);
|
||||||
|
max-width: 520px;
|
||||||
|
box-shadow: 0 -2px 16px 0 var(--black-shadow);
|
||||||
|
border-radius: 6px;
|
||||||
|
min-height: 120px;
|
||||||
|
margin: 0px auto;
|
||||||
|
position: relative;
|
||||||
|
transform: translateY(75px);
|
||||||
|
color: var(--off-white);
|
||||||
|
font-family: "Monaco", "Courier New";
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 45px 20px 0px 20px;
|
||||||
|
line-height: 165%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal b {
|
||||||
|
font-weight: normal;
|
||||||
|
color: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal i {
|
||||||
|
font-style: normal;
|
||||||
|
color: var(--light-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
left: 15px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--grey);
|
||||||
|
box-shadow: 25px 0 0 var(--grey), 50px 0 0 var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#typed:before {
|
||||||
|
content: "$ ";
|
||||||
|
color: var(--mid-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
#twitter {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
text-decoration: none;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
border: 1px solid var(--white);
|
||||||
|
padding: 5px 10px;
|
||||||
|
color: var(--white);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#twitter .icon {
|
||||||
|
transform: scale(0.5);
|
||||||
|
vertical-align: -18%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#twitter:hover,
|
||||||
|
#twitter:active {
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 2px 25px 0 var(--blacker-shadow);
|
||||||
|
transition: all .5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
max-width: 630px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prompt {
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 25px auto 100px auto;
|
||||||
|
padding: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header img {
|
||||||
|
float: left;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: var(--white);
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
a:visited {
|
||||||
|
color: var(--dark-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--bright-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a#twitter-nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a, nav a:visited {
|
||||||
|
color: var(--dark-purple);
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 2.5em;
|
||||||
|
margin: 0 40px;
|
||||||
|
font-weight: 400;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:hover,
|
||||||
|
nav a:visited:hover {
|
||||||
|
color: var(--bright-purple);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nav a.cta {
|
||||||
|
display: inline-block;
|
||||||
|
color: var(--white);
|
||||||
|
background-color: var(--mid-purple);
|
||||||
|
background-image: linear-gradient(259deg, var(--mid-purple) 0%, var(--dark-purple) 100%);
|
||||||
|
box-shadow: 0 2px 8px 0 var(--blacker-shadow);
|
||||||
|
border-radius: 50px;
|
||||||
|
padding: 0 2em;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: all 0.1s ease;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a.cta:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: var(--mid-purple);
|
||||||
|
background-image: linear-gradient(259deg, var(--bright-purple) 0%, var(--dark-purple) 100%);
|
||||||
|
box-shadow: 0 4px 16px 0 var(--black-shadow);
|
||||||
|
color: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
padding: 60px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 920px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 20px 20px;
|
||||||
|
padding-top: 30px;
|
||||||
|
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: 18px;
|
||||||
|
color: var(--dark-purple);
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
font-weight: 300;
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex section p {
|
||||||
|
padding-left: 40px;
|
||||||
|
color: var(--grey);
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
color: var(--grey);
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 70px auto 20px;
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
BIN
docs_theme/assets/readme-header.png
Normal file
After Width: | Height: | Size: 43 KiB |
378
docs_theme/assets/theme.css
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* Overrides for jrnl theme */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
body.wy-body-for-nav,
|
||||||
|
section.wy-nav-content-wrap {
|
||||||
|
background-color: var(--white);
|
||||||
|
color: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content pre {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
margin: 1em -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content code {
|
||||||
|
color: var(--darkest-purple);
|
||||||
|
background-color: var(--off-white);
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content pre code {
|
||||||
|
color: var(--off-white);
|
||||||
|
background: var(--darkest-purple);
|
||||||
|
padding: 1em 1.5em;
|
||||||
|
border-radius: 15px;
|
||||||
|
border: none;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-weight: 200 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-family: "Open Sans", "Helvetica Neue", Helvetica, sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
td,
|
||||||
|
tr,
|
||||||
|
div,
|
||||||
|
li {
|
||||||
|
font-family: "Open Sans", "Helvetica Neue", Helvetica, sans-serif;
|
||||||
|
font-weight: 00;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No-one likes lines that are 400 characters long. */
|
||||||
|
div.rst-content {
|
||||||
|
max-width: 54em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.wy-side-nav-search,
|
||||||
|
.wy-menu-vertical li.current,
|
||||||
|
.wy-menu-vertical li.toctree-l1.current > a,
|
||||||
|
.wy-menu-vertical li.toctree-l2.current > a,
|
||||||
|
.wy-menu-vertical li.toctree-l3.current > a {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3,
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l4,
|
||||||
|
.wy-menu-vertical li.toctree-l5,
|
||||||
|
.wy-menu-vertical li.toctree-l6,
|
||||||
|
.wy-menu-vertical li.toctree-l7 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-nav-top {
|
||||||
|
background-color: var(--mid-purple);
|
||||||
|
background-image: linear-gradient(-211deg, var(--mid-purple) 0%, var(--dark-purple) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-nav-top .fa-bars {
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search a.icon-home {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 250px;
|
||||||
|
background-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search 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 {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--white);
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical a:hover,
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover,
|
||||||
|
.wy-menu-vertical li.current a:hover {
|
||||||
|
background-color: var(--black-shadow);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.on a {
|
||||||
|
transition: all .25s ease;
|
||||||
|
background: var(--dark-purple);
|
||||||
|
color: var(--white);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l1.current > a {
|
||||||
|
background: var(--darkest-purple);
|
||||||
|
border: none !important;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 > a.current:after {
|
||||||
|
position: absolute;
|
||||||
|
right: 0em;
|
||||||
|
z-index: 999;
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 1em solid transparent;
|
||||||
|
border-bottom: 1em solid transparent;
|
||||||
|
border-right: 1em solid var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toctree-expand:before {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-versions,
|
||||||
|
.rst-versions .rst-current-version {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical p.caption {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical span {
|
||||||
|
color: var(--white);
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li a {
|
||||||
|
color: var(--white) !important;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.wy-nav-side {
|
||||||
|
background-color: var(--mid-purple);
|
||||||
|
font-weight: 300;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search input[type=text],
|
||||||
|
.mkdocs-search input[type=text],
|
||||||
|
form .search-query {
|
||||||
|
background-color: var(--off-white);
|
||||||
|
border: none;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
color: var(--black);
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search input[type=text]::placeholder,
|
||||||
|
.mkdocs-search input[type=text]::placeholder,
|
||||||
|
form .search-query::placeholder {
|
||||||
|
color: var(--dark-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search > a:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current ul {
|
||||||
|
background-color: var(--mid-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* 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(--dark-purple);
|
||||||
|
text-align: center;
|
||||||
|
line-height: 2em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* Accessibility-related changes */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
.rst-content div[role="main"] a,
|
||||||
|
.rst-content div[role="main"] a:visited {
|
||||||
|
color: var(--mid-purple);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content div[role="main"] a:hover {
|
||||||
|
color: var(--bright-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content div[role="navigation"] a,
|
||||||
|
.rst-content div[role="navigation"] a:visited {
|
||||||
|
color: var(--mid-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mkdocs-search {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search input[type="text"],
|
||||||
|
.mkdocs-search input[type=text] {
|
||||||
|
border-radius: 50px 0 0 50px;
|
||||||
|
height: 32px;
|
||||||
|
border-right: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mkdocs-search button {
|
||||||
|
background-color: var(--off-white);
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
color: var(--mid-purple);
|
||||||
|
border-radius: 0 50px 50px 0;
|
||||||
|
height: 32px;
|
||||||
|
width: 2.5em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mkdocs-search {
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mkdocs-search:focus-within {
|
||||||
|
box-shadow: 0 2px 25px 0 var(--blacker-shadow);
|
||||||
|
transition: all .5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content div[role="main"] .mkdocs-search input[type="text"] {
|
||||||
|
border-right: none;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 48px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content div[role="main"] .mkdocs-search button {
|
||||||
|
border-left: none;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content div[role="main"] .mkdocs-search button:before {
|
||||||
|
font-size: 140%;
|
||||||
|
position: relative;
|
||||||
|
left: -7px;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
49
docs_theme/breadcrumbs.html
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<!--
|
||||||
|
Copied from https://github.com/mkdocs/mkdocs/blob/master/mkdocs/themes/readthedocs/breadcrumbs.html
|
||||||
|
Then lightly modified for accessibility
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
<ul class="wy-breadcrumbs">
|
||||||
|
<li><a href="{{ nav.homepage.url|url }}" class="icon icon-home" aria-label="{% trans %}Docs{% endtrans %}"></a> »</li>
|
||||||
|
{%- if page %}
|
||||||
|
{%- for doc in page.ancestors[::-1] %}
|
||||||
|
{%- if doc.link %}
|
||||||
|
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> »</li>
|
||||||
|
{%- else %}
|
||||||
|
<li>{{ doc.title }} »</li>
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
<li>{{ page.title }}</li>
|
||||||
|
{%- endif %}
|
||||||
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
{%- block repo %}
|
||||||
|
{%- if page and page.edit_url %}
|
||||||
|
{%- if config.repo_name|lower == 'github' %}
|
||||||
|
<a href="{{ page.edit_url }}" class="icon icon-github"> {% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}</a>
|
||||||
|
{%- elif config.repo_name|lower == 'bitbucket' %}
|
||||||
|
<a href="{{ page.edit_url }}" class="icon icon-bitbucket"> {% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}</a>
|
||||||
|
{%- elif config.repo_name|lower == 'gitlab' %}
|
||||||
|
<a href="{{ page.edit_url }}" class="icon icon-gitlab"> {% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}</a>
|
||||||
|
{%- elif config.repo_name %}
|
||||||
|
<a href="{{ page.edit_url }}">{% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}</a>
|
||||||
|
{%- else %}
|
||||||
|
<a href="{{ page.edit_url }}">{% trans %}Edit{% endtrans %}</a>
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endblock %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{%- if config.theme.prev_next_buttons_location|lower in ['top', 'both']
|
||||||
|
and page and (page.next_page or page.previous_page) %}
|
||||||
|
<div class="rst-breadcrumbs-buttons" role="navigation" aria-label="{% trans %}Breadcrumb Navigation{% endtrans %}">
|
||||||
|
{%- if page.previous_page %}
|
||||||
|
<a href="{{ page.previous_page.url|url }}" class="btn btn-neutral float-left" title="{{ page.previous_page.title }}"><span class="icon icon-circle-arrow-left" aria-hidden="true"></span> {% trans %}Previous{% endtrans %}</a>
|
||||||
|
{%- endif %}
|
||||||
|
{%- if page.next_page %}
|
||||||
|
<a href="{{ page.next_page.url|url }}" class="btn btn-neutral float-right" title="{{ page.next_page.title }}">{% trans %}Next{% endtrans %} <span class="icon icon-circle-arrow-right" aria-hidden="true"></span></a>
|
||||||
|
{%- endif %}
|
||||||
|
</div>
|
||||||
|
{%- endif %}
|
||||||
|
<hr/>
|
||||||
|
</div>
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 224 KiB |
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
14
docs_theme/img/sprites.svg
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<svg width="400" height="160" viewBox="0 0 400 160" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="sprites">
|
||||||
|
<path id="path10" fill-rule="evenodd" clip-rule="evenodd" d="M176.001 24.001C176.001 10.7458 186.746 0 200.002 0C213.257 0 224.003 10.7471 224 24.001C224 37.2562 213.254 48.002 199.999 48.002C195.938 48.002 192.117 46.9846 188.765 45.2019L172.083 61.8826L172.087 61.8866C170.806 63.192 169.028 64.004 167.058 64.004C163.16 64.004 160 60.8452 160 56.9464C160 54.973 160.812 53.1969 162.117 51.9142L162.103 51.9022L178.791 35.2175C177.014 31.8667 176.001 28.0532 176.001 24.001ZM167.058 60.4732C168.054 60.4732 168.946 60.0545 169.59 59.3865L185.718 43.2605C183.82 41.8457 182.14 40.1657 180.73 38.2643L164.598 54.3969L164.615 54.4129C163.948 55.0596 163.528 55.949 163.528 56.945C163.528 58.8958 165.108 60.4732 167.058 60.4732ZM200.002 44.0045C188.957 44.0045 180.001 35.0455 180.001 24.0037C180.001 12.9592 188.957 4.00283 200.002 4.00283C211.043 4.00283 220.003 12.9592 220.003 24.0037C220.003 35.0468 211.045 44.0045 200.002 44.0045ZM201.002 11.0018C201.002 10.4498 200.551 10.0017 200.002 10.0017C192.268 10.0017 186.001 16.2687 186.001 24.0023C186.001 24.5544 186.449 25.0024 187.001 25.0024C187.553 25.0024 188.001 24.5544 188.001 24.0023C188.001 17.3754 193.373 12.0018 200.002 12.0018C200.551 12.0018 201.002 11.5525 201.002 11.0018Z" fill="#684688"/>
|
||||||
|
<path id="path12" fill-rule="evenodd" clip-rule="evenodd" d="M42 26V18C42 8.05733 33.9427 0 24 0C14.0573 0 6 8.05733 6 18V26C2.68533 26 0 28.6853 0 32V38V40V44V46C0 55.9427 8.05733 64 18 64H30C39.9427 64 48 55.9427 48 46V44V40V38V32C48 28.684 45.312 26 42 26ZM10 18C10 10.268 16.268 4 24 4C31.732 4 38 10.268 38 18V26H34V18.004C34 12.48 29.524 8.004 24 8.004C18.476 8.004 14 12.48 14 18.004V26H10V18ZM32 18.0067V18C32 13.5827 28.4173 10 24 10C19.5813 10 16 13.5813 16 18V18.004V26H32V18.0067ZM44 38V40V44V46C44 53.7173 37.7173 60 30 60H18C10.2827 60 4 53.7173 4 46V44V40V38V32C4 30.896 4.896 30 6 30H10H38H42C43.1027 30 44 30.896 44 32V38ZM28 42C28 39.7907 26.208 38 24 38C21.792 38 20 39.7907 20 42C20 43.2133 20.6667 45.52 21.3333 47.344C21.8787 48.828 22.5627 49.996 24 49.996C25.564 49.996 26.1213 48.84 26.668 47.364C27.344 45.536 28 43.2173 28 42Z" fill="#684688"/>
|
||||||
|
<path id="path6" fill-rule="evenodd" clip-rule="evenodd" d="M37.4495 102.225L56 110.175V88.9754L49.2056 93.8301C44.3508 88.4239 37.3366 85 29.5 85C17.0237 85 6.58791 93.6333 3.7737 105.244L8.72074 107.291C10.6738 97.6002 19.2306 90.2993 29.5 90.2993C35.5547 90.2993 41.001 92.8572 44.8646 96.9285L37.4495 102.225ZM29.5 132.701C23.4453 132.701 17.9966 130.143 14.1354 126.073L21.5505 120.773L3 112.824V134.025L9.79444 129.17C14.6467 134.576 21.6634 138 29.5 138C41.9945 138 52.4412 129.342 55.2397 117.709L50.2975 115.594C48.3894 125.344 39.8083 132.701 29.5 132.701Z" fill="#684688"/>
|
||||||
|
<path id="Combined Shape" fill-rule="evenodd" clip-rule="evenodd" d="M124 84H130.667C138.03 84 144 89.9695 144 97.3333V126.667C144 134.03 138.03 140 130.667 140H124H100H93.3333C85.9695 140 80 134.03 80 126.667V97.3333C80 89.9695 85.9695 84 93.3333 84H100H124ZM110.667 88H100C94.8453 88 90.6667 92.1787 90.6667 97.3333V126.667C90.6667 131.821 94.8453 136 100 136H110.667V88ZM114.667 88V136H124C129.155 136 133.333 131.821 133.333 126.667V97.3333C133.333 94.1617 131.751 91.3595 129.333 89.6729V109.333L124 105.333L118.667 109.333V88H114.667ZM134.13 135.336C136.127 133.005 137.333 129.977 137.333 126.667V97.3333C137.333 94.0233 136.127 90.9949 134.13 88.6638C137.57 90.0393 140 93.4025 140 97.3333V126.667C140 130.597 137.57 133.961 134.13 135.336ZM89.8697 135.336C87.8729 133.005 86.6667 129.977 86.6667 126.667V97.3333C86.6667 94.0233 87.8728 90.9949 89.8697 88.6638C86.43 90.0393 84 93.4025 84 97.3333V126.667C84 130.597 86.43 133.961 89.8697 135.336Z" fill="#684688"/>
|
||||||
|
<path id="path8" fill-rule="evenodd" clip-rule="evenodd" d="M363.625 13.625V2L384 16.5417L363.625 31.0833V22.375C335.716 22.375 332.168 42.2843 331.708 47.375C332.463 13.711 363.625 13.625 363.625 13.625ZM320 16.5417C320 12.1097 323.568 8.54167 328 8.54167H353.333L344 12.5417H328C325.784 12.5417 324 14.3257 324 16.5417V52.5417C324 54.7577 325.784 56.5417 328 56.5417H369.333C371.549 56.5417 373.333 54.7577 373.333 52.5417V32.5417L377.333 29.875V52.5417C377.333 56.9737 373.765 60.5417 369.333 60.5417H328C323.568 60.5417 320 56.9737 320 52.5417V16.5417Z" fill="#684688"/>
|
||||||
|
<path id="path16" fill-rule="evenodd" clip-rule="evenodd" d="M272 3C254.327 3 240 13.7453 240 27C240 35.2547 245.557 42.532 254.016 46.852C254.016 46.878 254.012 46.8999 254.008 46.9224C254.004 46.9459 254 46.97 254 47C254 50.1096 251.986 53.4268 250.683 55.5737L250.683 55.5739C250.483 55.9023 250.3 56.2033 250.144 56.472H250.148C250.053 56.692 250 56.9333 250 57.188C250 58.188 250.809 59 251.812 59C251.902 59 252.025 58.9887 252.127 58.9792C252.239 58.9689 252.326 58.9609 252.321 58.972C258.572 57.948 264.46 52.2053 265.828 50.5427C267.827 50.836 269.887 51 272 51C289.671 51 304 40.2547 304 27C304 13.7453 289.672 3 272 3ZM272 13C272.552 13 273 13.448 273 14C273 14.552 272.549 15 272 15C261.345 15 252 20.608 252 27C252 27.552 251.552 28 251 28C250.448 28 250 27.552 250 27C250 19.412 260.075 13 272 13ZM266.408 46.5867C268.284 46.86 270.165 47 272 47C287.439 47 300 38.028 300 27C300 15.972 287.436 7 272 7C256.56 7 244 15.972 244 27C244 33.4147 248.424 39.504 255.836 43.2893C257.175 43.972 258.016 45.3467 258.016 46.8507C258.016 46.96 258.011 47.0907 257.999 47.2187C257.956 49.2867 257.347 51.292 256.567 53.0827C259.444 51.372 261.88 49.0467 262.736 48.004C263.503 47.072 264.64 46.544 265.828 46.544C266.02 46.544 266.213 46.5547 266.408 46.5867Z" fill="#684688"/>
|
||||||
|
<path id="path22" fill-rule="evenodd" clip-rule="evenodd" d="M160 112C160 94.3267 174.327 80 192 80C209.673 80 224 94.3267 224 112C224 129.673 209.673 144 192 144C174.327 144 160 129.673 160 112ZM220 112C220 96.536 207.464 84 192 84C176.536 84 164 96.536 164 112C164 124.684 172.434 135.391 184 138.833V137.75V135.125V132.875C184 130.334 184.875 128.5 186.583 127.333C185.501 127.229 184.489 127.062 183.583 126.875C182.838 126.721 182.282 126.524 181.545 126.261C181.387 126.205 181.22 126.146 181.042 126.083C180.031 125.73 179.135 125.282 178.333 124.792C177.532 124.301 176.74 123.656 176 122.875C175.26 122.094 174.625 121.239 174.125 120.25C173.625 119.261 173.25 118.052 172.958 116.667C172.666 115.281 172.5 113.75 172.5 112.083C172.5 108.854 173.563 106.104 175.667 103.833C174.708 101.355 174.833 98.667 176 95.7083C176.012 95.7042 176.025 95.6992 176.039 95.6938C176.097 95.6718 176.175 95.6422 176.292 95.625C176.437 95.6037 176.781 95.6253 177.292 95.6667C177.802 95.708 178.365 95.8227 178.958 96C179.552 96.1773 180.344 96.5107 181.333 97C182.323 97.4907 183.354 98.0827 184.458 98.8333C186.896 98.1467 189.437 97.8333 192.125 97.8333C194.792 97.8333 197.396 98.1453 199.875 98.8333C201.626 97.6453 203.178 96.813 204.583 96.2917C205.989 95.7703 206.959 95.5207 207.5 95.5833L208.292 95.6667C209.458 98.604 209.584 101.333 208.625 103.833C210.729 106.105 211.75 108.854 211.75 112.083C211.75 113.75 211.625 115.281 211.333 116.667C211.041 118.052 210.625 119.261 210.125 120.25C209.625 121.239 209.03 122.094 208.292 122.875C207.553 123.656 206.761 124.302 205.958 124.792C205.156 125.281 204.261 125.73 203.25 126.083C202.239 126.437 201.28 126.688 200.375 126.875C199.47 127.062 198.459 127.188 197.375 127.292C199.104 128.48 200 130.354 200 132.875V135.375V137.667V138.833C211.566 135.391 220 124.684 220 112Z" fill="#684688"/>
|
||||||
|
<path id="path3858" fill-rule="evenodd" clip-rule="evenodd" d="M100 0C99.0049 0 98.0752 0.350804 97.3333 0.958333C96.5914 1.56586 96 2.50111 96 3.625V5.33333H94.6667V6.66667H87.3333C87.264 6.66305 87.1944 6.66305 87.125 6.66667C86.1491 6.76895 85.3281 7.68544 85.3333 8.66667V9.33333H83.3333C82.2862 9.33344 81.3334 10.2862 81.3333 11.3333V12.125C80.563 12.3974 80.0044 13.1829 80 14V18C80.0001 19.0472 80.9528 19.9999 82 20H85.3333V53.3333L83.6667 54.9167C83.0569 55.2687 82.6604 55.9626 82.6667 56.6667V60.6667C82.6668 61.7138 83.6195 62.6666 84.6667 62.6667H95.2083H104.667H104.875H115.333C116.381 62.6666 117.333 61.7138 117.333 60.6667V56.6667C117.34 55.9626 116.943 55.2687 116.333 54.9167L114.667 53.3333V20H118C119.047 19.9999 120 19.0472 120 18V14C119.996 13.1829 119.437 12.3974 118.667 12.125V11.3333C118.667 10.2862 117.714 9.33344 116.667 9.33333H114.667V8.66667C114.667 7.6195 113.714 6.66677 112.667 6.66667H105.333V5.33333H104V3.625C104 2.50111 103.409 1.56586 102.667 0.958333C101.925 0.350804 100.995 0 100 0ZM100 2.66667C100.274 2.66667 100.684 2.81724 100.958 3.04167C101.232 3.26609 101.333 3.47936 101.333 3.625V5.33333H98.6667V3.625C98.6667 3.47936 98.7676 3.26609 99.0417 3.04167C99.3157 2.81724 99.7255 2.66667 100 2.66667ZM112 12V10.6667H88V12H85.3333C85.2542 12.8356 85.0919 13.6063 84 13.5417V17.3333H89.3333H110.667H116V13.4167C114.82 13.6844 114.596 12.9828 114.667 12H112ZM110.667 20V56L113.333 57.8333V58.6667H86.6667V57.8333L89.3333 56V20H110.667ZM92 28V22.6667H94.6667V28H92ZM96 22.6667V28H98.6667V22.6667H96ZM101.333 28V22.6667H104V28H101.333ZM105.333 22.6667V28H108V22.6667H105.333ZM92 34.6667V29.3333H94.6667V34.6667H92ZM96 29.3333V34.6667H98.6667V29.3333H96ZM101.333 34.6667V29.3333H104V34.6667H101.333ZM105.333 29.3333V34.6667H108V29.3333H105.333ZM101.333 42.6667C101.333 41.6527 102.153 40.8333 103.167 40.8333C104.181 40.8333 105 41.6527 105 42.6667C105 43.6806 104.181 44.5 103.167 44.5C102.153 44.5 101.333 43.6806 101.333 42.6667Z" fill="#684688"/>
|
||||||
|
<path id="path20" fill-rule="evenodd" clip-rule="evenodd" d="M247.472 80L243.472 115.792L247.43 116.208L251.013 84H291.93L295.513 116.208L299.472 115.792L295.472 80H247.472ZM255.472 88V92H287.472V88H255.472ZM255.472 100V96H287.472V100H255.472ZM255.472 104V108H287.472V104H255.472ZM255.472 116V112H287.472V116H255.472ZM241.472 120C240.372 120 239.749 120.873 240.097 121.917L246.847 142.083C247.195 143.127 248.372 144 249.472 144H293.472C294.572 144 295.749 143.127 296.097 142.083L302.847 121.917C303.196 120.873 302.572 120 301.472 120H241.472ZM279.472 124H263.472V128H279.472V124Z" fill="#684688"/>
|
||||||
|
<path id="Vector" d="M370.378 82H380.145L358.811 107.042L384 141H364.209L348.787 120.416L331.052 141H321.285L344.161 114.253L320 82H340.305L354.313 100.88L370.378 82ZM366.908 134.969H372.305L337.349 87.6378H331.438L366.908 134.969Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 10 KiB |
60
docs/theme/index.html → docs_theme/index.html
Executable file → Normal file
|
@ -1,28 +1,34 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>jrnl - The Command Line Journal</title>
|
<title>jrnl - The Command Line Journal</title>
|
||||||
<meta name="description" content="Collect your thoughts and notes without leaving the command line.">
|
<meta name="description" content="Collect your thoughts and notes without leaving the command line.">
|
||||||
<meta name="image" content="https://jrnl.sh/img/banner.png">
|
<meta name="image" content="https://jrnl.sh/en/stable/img/banner_og.png">
|
||||||
<meta itemprop="name" content="jrnl - The Command Line Journal">
|
<meta itemprop="name" content="jrnl - The Command Line Journal">
|
||||||
<meta itemprop="description" content="Collect your thoughts and notes without leaving the command line.">
|
<meta itemprop="description" content="Collect your thoughts and notes without leaving the command line.">
|
||||||
<meta itemprop="image" content="https://jrnl.sh/img/banner_og.png">
|
<meta itemprop="image" content="https://jrnl.sh/en/stable/img/banner_og.png">
|
||||||
<meta name="twitter:card" content="summary">
|
<meta name="twitter:card" content="summary">
|
||||||
<meta name="twitter:title" content="jrnl - The Command Line Journal">
|
<meta name="twitter:title" content="jrnl - The Command Line Journal">
|
||||||
<meta name="twitter:description" content="Collect your thoughts and notes without leaving the command line.">
|
<meta name="twitter:description" content="Collect your thoughts and notes without leaving the command line.">
|
||||||
<meta name="twitter:creator" content="jrnl">
|
<meta name="twitter:creator" content="jrnl">
|
||||||
<meta name="twitter:image:src" content="https://jrnl.sh/img/banner_twitter.png">
|
<meta name="twitter:image:src" content="https://jrnl.sh/en/stable/img/banner_twitter.png">
|
||||||
<meta name="og:title" content="jrnl - The Command Line Journal">
|
<meta name="og:title" content="jrnl - The Command Line Journal">
|
||||||
<meta name="og:description" content="Collect your thoughts and notes without leaving the command line.">
|
<meta name="og:description" content="Collect your thoughts and notes without leaving the command line.">
|
||||||
<meta name="og:image" content="https://jrnl.sh/img/banner_og.png">
|
<meta name="og:image" content="https://jrnl.sh/en/stable/img/banner_og.png">
|
||||||
<meta name="og:url" content="https://jrnl.sh">
|
<meta name="og:url" content="https://jrnl.sh">
|
||||||
<meta name="og:site_name" content="jrnl - The Command Line Journal">
|
<meta name="og:site_name" content="jrnl - The Command Line Journal">
|
||||||
<meta name="og:type" content="website">
|
<meta name="og:type" content="website">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300,400' rel='stylesheet' type='text/css'>
|
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300,400' rel='stylesheet' type='text/css'>
|
||||||
<link rel="stylesheet" href="index.css">
|
<link rel="stylesheet" href="assets/colors.css">
|
||||||
|
<link rel="stylesheet" href="assets/index.css">
|
||||||
<link rel="shortcut icon" href="img/favicon.ico">
|
<link rel="shortcut icon" href="img/favicon.ico">
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
|
@ -32,9 +38,9 @@
|
||||||
"name": "jrnl",
|
"name": "jrnl",
|
||||||
"description": "Collect your thoughts and notes without leaving the command line.",
|
"description": "Collect your thoughts and notes without leaving the command line.",
|
||||||
"operatingSystem": ["macOS", "Windows", "Linux"],
|
"operatingSystem": ["macOS", "Windows", "Linux"],
|
||||||
"thumbnailUrl": "https://jrnl.sh/img/banner_og.png",
|
"thumbnailUrl": "https://jrnl.sh/en/stable/img/banner_og.png",
|
||||||
"installUrl": "https://jrnl.sh/installation",
|
"installUrl": "https://jrnl.sh/en/stable/installation",
|
||||||
"softwareVersion": "2.2"
|
"softwareVersion": "2.5"
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -45,7 +51,7 @@
|
||||||
<a id="twitter" href="https://twitter.com/intent/tweet?text=Collect+your+thoughts+and+notes+without+leaving+the+command+line.+https%3A%2F%2Fjrnl.sh+via+@JrnlSh"><i class="icon twitter"></i>Tell your friends</a>
|
<a id="twitter" href="https://twitter.com/intent/tweet?text=Collect+your+thoughts+and+notes+without+leaving+the+command+line.+https%3A%2F%2Fjrnl.sh+via+@JrnlSh"><i class="icon twitter"></i>Tell your friends</a>
|
||||||
</aside>
|
</aside>
|
||||||
<div id="title">
|
<div id="title">
|
||||||
<img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" />
|
<img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" alt="jrnl logo" />
|
||||||
<h1>Collect your thoughts and notes <br />without leaving the command line.</h1>
|
<h1>Collect your thoughts and notes <br />without leaving the command line.</h1>
|
||||||
</div>
|
</div>
|
||||||
<div id="prompt">
|
<div id="prompt">
|
||||||
|
@ -57,9 +63,9 @@
|
||||||
<main>
|
<main>
|
||||||
<nav>
|
<nav>
|
||||||
<a href="overview">Documentation</a>
|
<a href="overview">Documentation</a>
|
||||||
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork me on GitHub</a>
|
<a href="installation" class="cta">Get Started</a>
|
||||||
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Collect+your+thoughts+and+notes+without+leaving+the+command+line.+https%3A%2F%2Fjrnl.sh+via+@JrnlSh"><i class="icon twitter"></i>Tell your friends on Twitter</a>
|
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork on GitHub</a>
|
||||||
<a href="installation" class="cta">Download</a>
|
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Collect+your+thoughts+and+notes+without+leaving+the+command+line.+https%3A%2F%2Fjrnl.sh+via+@JrnlSh">Tell your friends on X</a>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<section>
|
<section>
|
||||||
|
@ -70,22 +76,22 @@
|
||||||
<section>
|
<section>
|
||||||
<i class="icon future"></i>
|
<i class="icon future"></i>
|
||||||
<h3>Future-proof.</h3>
|
<h3>Future-proof.</h3>
|
||||||
<p>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.</p>
|
<p>Your journals are stored in plain-text files that will still be readable in 50 years when your fancy proprietary apps will have gone the way of the dodo.</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<i class="icon secure"></i>
|
<i class="icon secure"></i>
|
||||||
<h3>Secure.</h3>
|
<h3>Secure.</h3>
|
||||||
<p>Encrypt your journals with the industry-strength AES encryption. The NSA won't be able to read your dirty secrets.</p>
|
<p>Encrypt your journals with industry-strength AES encryption. Nobody will be able to read your dirty secrets—not even you, if you lose your password!</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<i class="icon sync"></i>
|
<i class="icon sync"></i>
|
||||||
<h3>Accessible anywhere.</h3>
|
<h3>Accessible anywhere.</h3>
|
||||||
<p>Sync your journals with Dropbox and capture your thoughts where ever you are</p>
|
<p>Sync your journal files with other tools like Dropbox to capture your thoughts wherever you are.</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<i class="icon github"></i>
|
<i class="icon github"></i>
|
||||||
<h3>Free & Open Source.</h3>
|
<h3>Free & Open Source.</h3>
|
||||||
<p>jrnl is made by a bunch of really friendly and remarkably attractive people. Maybe even <a href="https://www.github.com/jrnl-org/jrnl" title="Fork jrnl on GitHub">you</a>?</p>
|
<p>jrnl is made by a bunch of really friendly and remarkably amazing people. Maybe even <a href="https://www.github.com/jrnl-org/jrnl" title="Fork jrnl on GitHub">you</a>?</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<i class="icon folders"></i>
|
<i class="icon folders"></i>
|
||||||
|
@ -97,21 +103,21 @@
|
||||||
<footer>
|
<footer>
|
||||||
jrnl is made with love by <a href="https://github.com/jrnl-org/jrnl/graphs/contributors" title="Contributors">many fabulous people</a>. If you need help, <a href="https://github.com/jrnl-org/jrnl/issues/new/choose" title="Open a new issue on Github">submit an issue</a> on Github.
|
jrnl is made with love by <a href="https://github.com/jrnl-org/jrnl/graphs/contributors" title="Contributors">many fabulous people</a>. If you need help, <a href="https://github.com/jrnl-org/jrnl/issues/new/choose" title="Open a new issue on Github">submit an issue</a> on Github.
|
||||||
</footer>
|
</footer>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.10/typed.min.js"></script>
|
<script src="https://unpkg.com/typed.js@2.1.0/dist/typed.umd.js"></script>
|
||||||
<script>
|
<script>
|
||||||
new Typed("#typed", {
|
new Typed("#typed", {
|
||||||
strings: [
|
strings: [
|
||||||
"jrnl today: Started writing my memoirs. On the command line. Like a boss.",
|
"jrnl Started writing my memoirs on the command line. 🎉🔥💻🔥🎉",
|
||||||
"jrnl yesterday 2pm: used jrnl to keep track of accomplished tasks. The done.txt for my todo.txt",
|
"jrnl yesterday 2pm: used jrnl to keep track of accomplished tasks. The done.txt for my todo.txt",
|
||||||
"jrnl <b>-from</b> 2009 <b>-until</b> may<br /><i>`(Displays all entries from January 2009 to last may)`</i>",
|
"jrnl <b>-from</b> 2019 <b>-until</b> may<br /><i>`(displays all entries from January 2019 to last May)`</i>",
|
||||||
"jrnl A day on the beach with @beth and @frank. Taggidy-tag-tag.",
|
"jrnl A day on the beach with @beth and @frank. Tagging them so I can easily look this up later.",
|
||||||
"jrnl <b>--tags</b><br /><i>`@idea 7<br />@beth 5</i>`",
|
"jrnl <b>--tags</b><br /><i>`@frank 7<br />@beth 5</i>`",
|
||||||
"jrnl <b>--export</b> json<br /><i>`(Exports your entire journal to json)</i>`",
|
"jrnl <b>--format</b> json<br /><i>`(Outputs your entire journal as json)</i>`",
|
||||||
"jrnl <b>--encrypt</b><br /><i>`(256 bit AES encryption. Crack this, NSA)</i>`"
|
"jrnl <b>--encrypt</b><br /><i>`(AES encryption. Don't lose your password!)</i>`"
|
||||||
],
|
],
|
||||||
typeSpeed: 35,
|
typeSpeed: 20, // less is faster
|
||||||
backSpeed: 15,
|
backSpeed: 10,
|
||||||
backDelay: 2000,
|
backDelay: 2500,
|
||||||
loop: true,
|
loop: true,
|
||||||
showCursor: false
|
showCursor: false
|
||||||
});
|
});
|
17
docs_theme/main.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{%- block search_button %}
|
||||||
|
{% if 'search' in config['plugins'] %}
|
||||||
|
<div role="search">
|
||||||
|
<form id ="rtd-search-form" class="wy-form mkdocs-search" action="{{ base_url }}/search.html" method="get">
|
||||||
|
<input type="text" name="q" placeholder="Search docs" title="Type search term here" />
|
||||||
|
<button class="icon icon-search" aria-label="submit"></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{%- endblock %}
|
2
docs_theme/requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
mkdocs>=1.4
|
||||||
|
jinja2==3.1.6
|
34
docs_theme/search.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<!--
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
{% extends "main.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div role="search">
|
||||||
|
<form id ="content_search" class="wy-form mkdocs-search" action="{{ base_url }}/search.html" method="get">
|
||||||
|
|
||||||
|
<span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span>
|
||||||
|
<input
|
||||||
|
name="q"
|
||||||
|
id="mkdocs-search-query"
|
||||||
|
type="text"
|
||||||
|
class="search_input search-query ui-autocomplete-input"
|
||||||
|
placeholder="Search the Docs"
|
||||||
|
autocomplete="off"
|
||||||
|
autofocus
|
||||||
|
title="Type search term here"
|
||||||
|
>
|
||||||
|
<button class="icon icon-search" aria-label="submit"></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 id="search">Results</h1>
|
||||||
|
|
||||||
|
<div id="mkdocs-search-results" class="search-results">
|
||||||
|
Searching...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -1,29 +0,0 @@
|
||||||
Feature: Contains
|
|
||||||
|
|
||||||
Scenario: Searching for a string
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -contains life"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
2013-06-10 15:40 Life is good.
|
|
||||||
| But I'm better.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Searching for a string within tag results
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl @idea -contains software"
|
|
||||||
Then we should get no error
|
|
||||||
And the output should contain "software"
|
|
||||||
|
|
||||||
Scenario: Searching for a string within AND tag results
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl -and @journal @idea -contains software"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should contain "software"
|
|
||||||
|
|
||||||
Scenario: Searching for a string within NOT tag results
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl -not @dan -contains software"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should contain "software"
|
|
|
@ -1,115 +0,0 @@
|
||||||
Feature: Basic reading and writing to a journal
|
|
||||||
|
|
||||||
Scenario: Loading a sample journal
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -n 2"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
2013-06-09 15:39 My first entry.
|
|
||||||
| Everything is alright
|
|
||||||
|
|
||||||
2013-06-10 15:40 Life is good.
|
|
||||||
| But I'm better.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Printing a journal that has multiline entries
|
|
||||||
Given we use the config "multiline.yaml"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
2013-06-09 15:39 Multiple line entry.
|
|
||||||
| This is the first line.
|
|
||||||
| This line doesn't have any ending punctuation
|
|
||||||
|
|
|
||||||
| There is a blank line above this.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Multiline entry with punctuation
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl This is. the title\\n This is the second line"
|
|
||||||
and we run "jrnl -n 1"
|
|
||||||
Then the output should contain "This is. the title"
|
|
||||||
|
|
||||||
Scenario: Single line entry with punctuation
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl This is. the title"
|
|
||||||
and we run "jrnl -n 1"
|
|
||||||
Then the output should contain "| the title"
|
|
||||||
|
|
||||||
Scenario: Writing an entry from command line
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should contain "2013-07-23 09:00 A cold and stormy day."
|
|
||||||
|
|
||||||
Scenario: Writing an empty entry from the editor
|
|
||||||
Given we use the config "editor.yaml"
|
|
||||||
When we open the editor and enter nothing
|
|
||||||
Then we should see the message "[Nothing saved to file]"
|
|
||||||
|
|
||||||
Scenario: Sending an argument with spaces to the editor should work
|
|
||||||
Given we use the config "editor-args.yaml"
|
|
||||||
When we open the editor and enter "lorem ipsum"
|
|
||||||
Then the editor should have been called with 5 arguments
|
|
||||||
And one editor argument should be "vim"
|
|
||||||
And one editor argument should be "-f"
|
|
||||||
And one editor argument should be "-c"
|
|
||||||
And one editor argument should match "'?setf markdown'?"
|
|
||||||
|
|
||||||
Scenario: Writing an empty entry from the command line
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl" and enter nothing
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Filtering for dates
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -on 2013-06-10 --short"
|
|
||||||
Then the output should be "2013-06-10 15:40 Life is good."
|
|
||||||
When we run "jrnl -on 'june 6 2013' --short"
|
|
||||||
Then the output should be "2013-06-10 15:40 Life is good."
|
|
||||||
|
|
||||||
Scenario: Emoji support
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 23 july 2013: 🌞 sunny day. Saw an 🐘"
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should contain "🌞"
|
|
||||||
and the output should contain "🐘"
|
|
||||||
|
|
||||||
Scenario: Writing an entry at the prompt
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive."
|
|
||||||
Then we should get no error
|
|
||||||
and the journal should contain "[2013-07-25 09:00] I saw Elvis."
|
|
||||||
and the journal should contain "He's alive."
|
|
||||||
|
|
||||||
Scenario: Displaying the version number
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -v"
|
|
||||||
Then we should get no error
|
|
||||||
Then the output should contain "version"
|
|
||||||
|
|
||||||
Scenario: --short displays the short version of entries (only the title)
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -on 2013-06-10 --short"
|
|
||||||
Then the output should be "2013-06-10 15:40 Life is good."
|
|
||||||
|
|
||||||
Scenario: -s displays the short version of entries (only the title)
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -on 2013-06-10 -s"
|
|
||||||
Then the output should be "2013-06-10 15:40 Life is good."
|
|
||||||
|
|
||||||
Scenario: Invalid color configuration
|
|
||||||
Given we use the config "invalid_color.yaml"
|
|
||||||
When we run "jrnl -on 2013-06-10 -s"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2013-06-10 15:40 Life is good.
|
|
||||||
"""
|
|
||||||
And we should get no error
|
|
|
@ -1,35 +0,0 @@
|
||||||
Feature: Reading and writing to journal with custom date formats
|
|
||||||
|
|
||||||
Scenario: Loading a sample journal
|
|
||||||
Given we use the config "little_endian_dates.yaml"
|
|
||||||
When we run "jrnl -n 2"
|
|
||||||
Then we should get no error
|
|
||||||
And the output should be
|
|
||||||
"""
|
|
||||||
09.06.2013 15:39 My first entry.
|
|
||||||
| Everything is alright
|
|
||||||
|
|
||||||
10.06.2013 15:40 Life is good.
|
|
||||||
| But I'm better.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Writing an entry from command line
|
|
||||||
Given we use the config "little_endian_dates.yaml"
|
|
||||||
When we run "jrnl 2013-07-12: A cold and stormy day. I ate crisps on the sofa."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should contain "12.07.2013 09:00 A cold and stormy day."
|
|
||||||
|
|
||||||
Scenario: Filtering for dates
|
|
||||||
Given we use the config "little_endian_dates.yaml"
|
|
||||||
When we run "jrnl -on 2013-06-10 --short"
|
|
||||||
Then the output should be "10.06.2013 15:40 Life is good."
|
|
||||||
When we run "jrnl -on 'june 6 2013' --short"
|
|
||||||
Then the output should be "10.06.2013 15:40 Life is good."
|
|
||||||
|
|
||||||
Scenario: Writing an entry at the prompt
|
|
||||||
Given we use the config "little_endian_dates.yaml"
|
|
||||||
When we run "jrnl" and enter "2013-05-10: I saw Elvis. He's alive."
|
|
||||||
Then we should get no error
|
|
||||||
And the journal should contain "[10.05.2013 09:00] I saw Elvis."
|
|
||||||
And the journal should contain "He's alive."
|
|
|
@ -1,65 +0,0 @@
|
||||||
Feature: Dayone specific implementation details.
|
|
||||||
|
|
||||||
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!
|
|
||||||
"""
|
|
||||||
|
|
||||||
# broken still
|
|
||||||
@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!
|
|
||||||
"""
|
|
||||||
|
|
||||||
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"
|
|
|
@ -1,25 +0,0 @@
|
||||||
Feature: Zapped Dayone bugs stay dead!
|
|
||||||
|
|
||||||
# fails when system time is UTC (as on Travis-CI)
|
|
||||||
@skip
|
|
||||||
Scenario: DayOne tag searching should work with tags containing a mixture of upper and lower case.
|
|
||||||
# https://github.com/jrnl-org/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!
|
|
||||||
"""
|
|
||||||
|
|
||||||
# fails when system time is UTC (as on Travis-CI)
|
|
||||||
@skip
|
|
||||||
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.
|
|
||||||
"""
|
|
|
@ -1,149 +0,0 @@
|
||||||
Feature: Delete entries from journal
|
|
||||||
Scenario: --delete flag allows deletion of single entry
|
|
||||||
Given we use the config "deletion.yaml"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should contain
|
|
||||||
"""
|
|
||||||
2019-10-29 11:13 Third entry.
|
|
||||||
"""
|
|
||||||
When we run "jrnl --delete" and enter
|
|
||||||
"""
|
|
||||||
N
|
|
||||||
N
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should contain
|
|
||||||
"""
|
|
||||||
2019-10-29 11:11 Second entry.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Backing out of interactive delete does not change journal
|
|
||||||
Given we use the config "deletion.yaml"
|
|
||||||
When we run "jrnl --delete -n 1" and enter
|
|
||||||
"""
|
|
||||||
N
|
|
||||||
"""
|
|
||||||
Then the journal should have 3 entries
|
|
||||||
And the journal should contain "[2019-10-29 11:11] First entry."
|
|
||||||
And the journal should contain "[2019-10-29 11:11] Second entry."
|
|
||||||
And the journal should contain "[2019-10-29 11:13] Third entry."
|
|
||||||
|
|
||||||
Scenario: --delete flag with nonsense input deletes nothing (issue #932)
|
|
||||||
Given we use the config "deletion.yaml"
|
|
||||||
When we run "jrnl --delete asdfasdf"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should contain
|
|
||||||
"""
|
|
||||||
2019-10-29 11:13 Third entry.
|
|
||||||
"""
|
|
||||||
And the journal should have 3 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with tag only deletes tagged entries
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete @holidays" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should have 3 entries
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should contain "[2020-05-02 12:10] Writing tests."
|
|
||||||
|
|
||||||
Scenario: --delete flag with multiple tags deletes all entries matching any of the tags
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete @holidays @springtime" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should not contain "[2020-05-02 12:10] Writing tests. *"
|
|
||||||
and the journal should have 2 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with -and and tags only deletes boolean AND of tagged entries
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete -and @holidays @springtime" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should contain "[2020-05-02 12:10] Writing tests. *"
|
|
||||||
and the journal should have 4 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with -not does not delete entries with -not tag
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete @holidays -not @springtime" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should contain "[2020-05-02 12:10] Writing tests. *"
|
|
||||||
and the journal should have 4 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with -from only deletes entries since a specified date
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete -from 2020-01-02" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should not contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should not contain "[2020-05-02 12:10] Writing tests."
|
|
||||||
and the journal should have 2 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with -to only deletes entries up to specified date
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete -to 2020-01-02" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should not contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should contain "[2020-05-02 12:10] Writing tests."
|
|
||||||
and the journal should have 3 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with -starred only deletes starred entries
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete -starred" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should not contain "[2020-05-02 12:10] Writing tests. *"
|
|
||||||
and the journal should have 4 entries
|
|
||||||
|
|
||||||
Scenario: --delete flag with -contains only entries containing expression
|
|
||||||
Given we use the config "deletion_filters.yaml"
|
|
||||||
When we run "jrnl --delete -contains happy" and enter
|
|
||||||
"""
|
|
||||||
Y
|
|
||||||
Y
|
|
||||||
"""
|
|
||||||
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
|
|
||||||
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
|
|
||||||
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
|
|
||||||
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
|
|
||||||
and the journal should contain "[2020-05-02 12:10] Writing tests. *"
|
|
||||||
and the journal should have 3 entries
|
|
|
@ -1,81 +0,0 @@
|
||||||
Feature: Encrypted journals
|
|
||||||
Scenario: Loading an encrypted journal
|
|
||||||
Given we use the config "encrypted.yaml"
|
|
||||||
When we run "jrnl -n 1" and enter "bad doggie no biscuit"
|
|
||||||
Then the output should contain "Password"
|
|
||||||
And the output should contain "2013-06-10 15:40 Life is good"
|
|
||||||
|
|
||||||
Scenario: Decrypting a journal
|
|
||||||
Given we use the config "encrypted.yaml"
|
|
||||||
When we run "jrnl --decrypt" and enter "bad doggie no biscuit"
|
|
||||||
Then the config for journal "default" should have "encrypt" set to "bool:False"
|
|
||||||
Then we should see the message "Journal decrypted"
|
|
||||||
And the journal should have 2 entries
|
|
||||||
|
|
||||||
Scenario: Encrypting a journal
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl --encrypt" and enter
|
|
||||||
"""
|
|
||||||
swordfish
|
|
||||||
swordfish
|
|
||||||
n
|
|
||||||
"""
|
|
||||||
Then we should see the message "Journal encrypted"
|
|
||||||
And the config for journal "default" should have "encrypt" set to "bool:True"
|
|
||||||
When we run "jrnl -n 1" and enter "swordfish"
|
|
||||||
Then the output should contain "Password"
|
|
||||||
And the output should contain "2013-06-10 15:40 Life is good"
|
|
||||||
|
|
||||||
Scenario: Mistyping your password
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl --encrypt" and enter
|
|
||||||
"""
|
|
||||||
swordfish
|
|
||||||
sordfish
|
|
||||||
swordfish
|
|
||||||
swordfish
|
|
||||||
n
|
|
||||||
"""
|
|
||||||
Then we should see the message "Passwords did not match"
|
|
||||||
And we should see the message "Journal encrypted"
|
|
||||||
And the config for journal "default" should have "encrypt" set to "bool:True"
|
|
||||||
When we run "jrnl -n 1" and enter "swordfish"
|
|
||||||
Then the output should contain "Password"
|
|
||||||
And the output should contain "2013-06-10 15:40 Life is good"
|
|
||||||
|
|
||||||
Scenario: Storing a password in Keychain
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
When we run "jrnl simple --encrypt" and enter
|
|
||||||
"""
|
|
||||||
sabertooth
|
|
||||||
sabertooth
|
|
||||||
y
|
|
||||||
"""
|
|
||||||
When we set the keychain password of "simple" to "sabertooth"
|
|
||||||
Then the config for journal "simple" should have "encrypt" set to "bool:True"
|
|
||||||
When we run "jrnl simple -n 1"
|
|
||||||
Then the output should contain "2013-06-10 15:40 Life is good"
|
|
||||||
|
|
||||||
Scenario: Encrypt journal with no keyring backend and do not store in keyring
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we disable the keychain
|
|
||||||
and we run "jrnl test entry"
|
|
||||||
and we run "jrnl --encrypt" and enter
|
|
||||||
"""
|
|
||||||
password
|
|
||||||
password
|
|
||||||
n
|
|
||||||
"""
|
|
||||||
Then we should get no error
|
|
||||||
|
|
||||||
Scenario: Encrypt journal with no keyring backend and do store in keyring
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we disable the keychain
|
|
||||||
and we run "jrnl test entry"
|
|
||||||
and we run "jrnl --encrypt" and enter
|
|
||||||
"""
|
|
||||||
password
|
|
||||||
password
|
|
||||||
y
|
|
||||||
"""
|
|
||||||
Then we should get no error
|
|
|
@ -1,55 +0,0 @@
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def clean_all_working_dirs():
|
|
||||||
for folder in ("configs", "journals", "cache"):
|
|
||||||
working_dir = os.path.join("features", folder)
|
|
||||||
if os.path.exists(working_dir):
|
|
||||||
shutil.rmtree(working_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def before_feature(context, feature):
|
|
||||||
# add "skip" tag
|
|
||||||
# https://stackoverflow.com/a/42721605/4276230
|
|
||||||
if "skip" in feature.tags:
|
|
||||||
feature.skip("Marked with @skip")
|
|
||||||
return
|
|
||||||
|
|
||||||
if "skip_win" in feature.tags and "win32" in sys.platform:
|
|
||||||
feature.skip("Skipping on Windows")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def before_scenario(context, scenario):
|
|
||||||
"""Before each scenario, backup all config and journal test data."""
|
|
||||||
# Clean up in case something went wrong
|
|
||||||
clean_all_working_dirs()
|
|
||||||
|
|
||||||
for folder in ("configs", "journals"):
|
|
||||||
original = os.path.join("features", "data", folder)
|
|
||||||
working_dir = os.path.join("features", folder)
|
|
||||||
if not os.path.exists(working_dir):
|
|
||||||
os.mkdir(working_dir)
|
|
||||||
for filename in os.listdir(original):
|
|
||||||
source = os.path.join(original, filename)
|
|
||||||
if os.path.isdir(source):
|
|
||||||
shutil.copytree(source, os.path.join(working_dir, filename))
|
|
||||||
else:
|
|
||||||
shutil.copy2(source, working_dir)
|
|
||||||
|
|
||||||
# add "skip" tag
|
|
||||||
# https://stackoverflow.com/a/42721605/4276230
|
|
||||||
if "skip" in scenario.effective_tags:
|
|
||||||
scenario.skip("Marked with @skip")
|
|
||||||
return
|
|
||||||
|
|
||||||
if "skip_win" in scenario.effective_tags and "win32" in sys.platform:
|
|
||||||
scenario.skip("Skipping on Windows")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def after_scenario(context, scenario):
|
|
||||||
"""After each scenario, restore all test data and remove working_dirs."""
|
|
||||||
clean_all_working_dirs()
|
|
|
@ -1,144 +0,0 @@
|
||||||
Feature: Exporting a Journal
|
|
||||||
|
|
||||||
Scenario: Exporting to json
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl --export json"
|
|
||||||
Then we should get no error
|
|
||||||
And the output should be parsable as json
|
|
||||||
And "entries" in the json output should have 2 elements
|
|
||||||
And "tags" in the json output should contain "@idea"
|
|
||||||
And "tags" in the json output should contain "@journal"
|
|
||||||
And "tags" in the json output should contain "@dan"
|
|
||||||
|
|
||||||
Scenario: Exporting using filters should only export parts of the journal
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl -until 'may 2013' --export json"
|
|
||||||
Then the output should be parsable as json
|
|
||||||
And "entries" in the json output should have 1 element
|
|
||||||
And "tags" in the json output should contain "@idea"
|
|
||||||
And "tags" in the json output should contain "@journal"
|
|
||||||
And "tags" in the json output should not contain "@dan"
|
|
||||||
|
|
||||||
Scenario: Exporting using custom templates
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
Given we load template "sample.template"
|
|
||||||
When we run "jrnl --export sample"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
My first entry.
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Everything is alright
|
|
||||||
|
|
||||||
Life is good.
|
|
||||||
-------------
|
|
||||||
|
|
||||||
But I'm better.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Increasing Headings on Markdown export
|
|
||||||
Given we use the config "markdown-headings-335.yaml"
|
|
||||||
When we run "jrnl --export markdown"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
# 2015
|
|
||||||
|
|
||||||
## April
|
|
||||||
|
|
||||||
### 2015-04-14 13:23 Heading Test
|
|
||||||
|
|
||||||
#### H1-1
|
|
||||||
|
|
||||||
#### H1-2
|
|
||||||
|
|
||||||
#### H1-3
|
|
||||||
|
|
||||||
##### H2-1
|
|
||||||
|
|
||||||
##### H2-2
|
|
||||||
|
|
||||||
##### H2-3
|
|
||||||
|
|
||||||
Horizontal Rules (ignore)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
===
|
|
||||||
|
|
||||||
#### ATX H1
|
|
||||||
|
|
||||||
##### ATX H2
|
|
||||||
|
|
||||||
###### ATX H3
|
|
||||||
|
|
||||||
####### ATX H4
|
|
||||||
|
|
||||||
######## ATX H5
|
|
||||||
|
|
||||||
######### ATX H6
|
|
||||||
|
|
||||||
Stuff
|
|
||||||
|
|
||||||
More stuff
|
|
||||||
more stuff again
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Exporting to XML
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl --export xml"
|
|
||||||
Then the output should be a valid XML string
|
|
||||||
And "entries" node in the xml output should have 2 elements
|
|
||||||
And "tags" in the xml output should contain ["@idea", "@journal", "@dan"]
|
|
||||||
|
|
||||||
Scenario: Exporting tags
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl --export tags"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
@idea : 2
|
|
||||||
@journal : 1
|
|
||||||
@dan : 1
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Exporting fancy
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl --export fancy"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
┎──────────────────────────────────────────────────────────────╮2013-04-09 15:39
|
|
||||||
┃ I have an @idea: ╘═══════════════╕
|
|
||||||
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
|
||||||
┃ (1) write a command line @journal software │
|
|
||||||
┃ (2) ??? │
|
|
||||||
┃ (3) PROFIT! │
|
|
||||||
┖──────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
┎──────────────────────────────────────────────────────────────╮2013-06-10 15:40
|
|
||||||
┃ I met with @dan. ╘═══════════════╕
|
|
||||||
┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
|
|
||||||
┃ As alway's he shared his latest @idea on how to rule the world with me. │
|
|
||||||
┃ inst │
|
|
||||||
┖──────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Export to yaml
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
And we create cache directory "exported_journal"
|
|
||||||
When we run "jrnl --export yaml -o {cache_dir}" with cache directory "exported_journal"
|
|
||||||
Then cache directory "exported_journal" should contain the files
|
|
||||||
"""
|
|
||||||
[
|
|
||||||
"2013-04-09_i-have-an-idea.md",
|
|
||||||
"2013-06-10_i-met-with-dan.md"
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
And the content of file "2013-04-09_i-have-an-idea.md" in cache directory "exported_journal" should be
|
|
||||||
"""
|
|
||||||
title: I have an @idea:
|
|
||||||
date: 2013-04-09 15:39
|
|
||||||
starred: False
|
|
||||||
tags: idea, journal
|
|
||||||
|
|
||||||
(1) write a command line @journal software
|
|
||||||
(2) ???
|
|
||||||
(3) PROFIT!
|
|
||||||
"""
|
|
|
@ -1,42 +0,0 @@
|
||||||
Feature: Testing a journal with a root directory and multiple files in the format of yyyy/mm/dd.txt
|
|
||||||
|
|
||||||
Scenario: Opening an folder that's not a DayOne folder should treat as folder journal
|
|
||||||
Given we use the config "empty_folder.yaml"
|
|
||||||
When we run "jrnl 23 july 2013: Testing folder journal."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -1"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2013-07-23 09:00 Testing folder journal.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Adding entries to a Folder journal should generate date files
|
|
||||||
Given we use the config "empty_folder.yaml"
|
|
||||||
When we run "jrnl 23 July 2013: Testing folder journal."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When the journal directory is listed
|
|
||||||
Then the output should contain "2013/07/23.txt" or "2013\07\23.txt"
|
|
||||||
|
|
||||||
|
|
||||||
Scenario: Adding multiple entries to a Folder journal should generate multiple date files
|
|
||||||
Given we use the config "empty_folder.yaml"
|
|
||||||
When we run "jrnl 23 July 2013: Testing folder journal."
|
|
||||||
And we run "jrnl 3/7/2014: Second entry of journal."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When the journal directory is listed
|
|
||||||
Then the output should contain "2013/07/23.txt" or "2013\07\23.txt"
|
|
||||||
Then the output should contain "2014/03/07.txt" or "2014\03\07.txt"
|
|
||||||
|
|
||||||
Scenario: Out of order entries to a Folder journal should be listed in date order
|
|
||||||
Given we use the config "empty_folder.yaml"
|
|
||||||
When we run "jrnl 3/7/2014 4:37pm: Second entry of journal."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl 23 July 2013: Testing folder journal."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -2"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2013-07-23 09:00 Testing folder journal.
|
|
||||||
|
|
||||||
2014-03-07 16:37 Second entry of journal.
|
|
||||||
"""
|
|
|
@ -1,51 +0,0 @@
|
||||||
Feature: Multiple journals
|
|
||||||
|
|
||||||
Scenario: Loading a config with two journals
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
Then journal "default" should have 2 entries
|
|
||||||
and journal "work" should have 0 entries
|
|
||||||
|
|
||||||
Scenario: Write to default config by default
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
When we run "jrnl this goes to default"
|
|
||||||
Then journal "default" should have 3 entries
|
|
||||||
and journal "work" should have 0 entries
|
|
||||||
|
|
||||||
Scenario: Write to specified journal
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
When we run "jrnl work a long day in the office"
|
|
||||||
Then journal "default" should have 2 entries
|
|
||||||
and journal "work" should have 1 entry
|
|
||||||
|
|
||||||
Scenario: Tell user which journal was used
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
When we run "jrnl work a long day in the office"
|
|
||||||
Then we should see the message "Entry added to work journal"
|
|
||||||
|
|
||||||
Scenario: Write to specified journal with a timestamp
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
When we run "jrnl work 23 july 2012: a long day in the office"
|
|
||||||
Then journal "default" should have 2 entries
|
|
||||||
and journal "work" should have 1 entry
|
|
||||||
and journal "work" should contain "2012-07-23"
|
|
||||||
|
|
||||||
Scenario: Create new journals as required
|
|
||||||
Given we use the config "multiple.yaml"
|
|
||||||
Then journal "ideas" should not exist
|
|
||||||
When we run "jrnl ideas 23 july 2012: sell my junk on ebay and make lots of money"
|
|
||||||
Then journal "ideas" should have 1 entry
|
|
||||||
|
|
||||||
Scenario: Don't crash if no default journal is specified
|
|
||||||
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
|
|
||||||
these three eyes
|
|
||||||
n
|
|
||||||
"""
|
|
||||||
Then we should see the message "Encrypted journal 'new_encrypted' created"
|
|
|
@ -1,175 +0,0 @@
|
||||||
Feature: Zapped bugs should stay dead.
|
|
||||||
|
|
||||||
Scenario: Writing an entry does not print the entire journal
|
|
||||||
# https://github.com/jrnl-org/jrnl/issues/87
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then the output should not contain "Life is good"
|
|
||||||
|
|
||||||
Scenario: Date with time should be parsed correctly
|
|
||||||
# https://github.com/jrnl-org/jrnl/issues/117
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 2013-11-30 15:42: Project Started."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
and the journal should contain "[2013-11-30 15:42] Project Started."
|
|
||||||
|
|
||||||
Scenario: Loading entry with ambiguous time stamp
|
|
||||||
#https://github.com/jrnl-org/jrnl/issues/153
|
|
||||||
Given we use the config "bug153.yaml"
|
|
||||||
When we run "jrnl -1"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
2013-10-27 03:27 Some text.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Date in the future should be parsed correctly
|
|
||||||
# https://github.com/jrnl-org/jrnl/issues/185
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
and the journal should contain "[2019-06-26 09:00] Planet?"
|
|
||||||
|
|
||||||
Scenario: Empty DayOne entry bodies should not error
|
|
||||||
# https://github.com/jrnl-org/jrnl/issues/780
|
|
||||||
Given we use the config "bug780.yaml"
|
|
||||||
When we run "jrnl --short"
|
|
||||||
Then we should get no error
|
|
||||||
|
|
||||||
Scenario: Title with an embedded period.
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -1"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2014-04-24 09:00 Created a new website - empty.com.
|
|
||||||
| Hope to get a lot of traffic.
|
|
||||||
"""
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
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: 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: Viewing today's entries does not print the entire journal
|
|
||||||
# https://github.com/jrnl-org/jrnl/issues/741
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -on today"
|
|
||||||
Then the output should not contain "Life is good"
|
|
||||||
Then the output should not contain "But I'm better."
|
|
||||||
|
|
||||||
Scenario: Create entry using day of the week as entry date.
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl monday: This is an entry on a Monday."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -1"
|
|
||||||
Then the output should contain "monday at 9am" in the local time
|
|
||||||
Then the output should contain "This is an entry on a Monday."
|
|
||||||
|
|
||||||
Scenario: Create entry using day of the week abbreviations as entry date.
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl fri: This is an entry on a Friday."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -1"
|
|
||||||
Then the output should contain "friday at 9am" in the local time
|
|
||||||
|
|
||||||
Scenario: Displaying entries using -on today should display entries created today.
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl today: Adding an entry right now."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -on today"
|
|
||||||
Then the output should contain "Adding an entry right now."
|
|
||||||
|
|
||||||
Scenario: Displaying entries using -from day should display correct entries
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl yesterday: This thing happened yesterday"
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl today at 11:59pm: Adding an entry right now."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl tomorrow: A future entry."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -from today"
|
|
||||||
Then the output should contain "Adding an entry right now."
|
|
||||||
Then the output should contain "A future entry."
|
|
||||||
Then the output should not contain "This thing happened yesterday"
|
|
||||||
|
|
||||||
Scenario: Displaying entries using -from and -to day should display correct entries
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl yesterday: This thing happened yesterday"
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl today at 11:59pm: Adding an entry right now."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl tomorrow: A future entry."
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
When we run "jrnl -from yesterday -to today"
|
|
||||||
Then the output should contain "This thing happened yesterday"
|
|
||||||
Then the output should contain "Adding an entry right now."
|
|
||||||
Then the output should not contain "A future entry."
|
|
||||||
|
|
||||||
# See issues #768 and #881
|
|
||||||
# the "deletion" journal is used because it doesn't have a newline at the
|
|
||||||
# end of the last entry
|
|
||||||
Scenario: Add a blank line to Markdown export is there isn't one already
|
|
||||||
Given we use the config "deletion.yaml"
|
|
||||||
When we run "jrnl --export markdown"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
# 2019
|
|
||||||
|
|
||||||
## October
|
|
||||||
|
|
||||||
### 2019-10-29 11:11 First entry.
|
|
||||||
|
|
||||||
|
|
||||||
### 2019-10-29 11:11 Second entry.
|
|
||||||
|
|
||||||
|
|
||||||
### 2019-10-29 11:13 Third entry.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# See issues #768 and #881
|
|
||||||
Scenario: Add a blank line to YAML export is there isn't one already
|
|
||||||
Given we use the config "deletion.yaml"
|
|
||||||
And we create cache directory "bug768"
|
|
||||||
When we run "jrnl --export yaml -o {cache_dir}" with cache directory "bug768"
|
|
||||||
Then cache directory "bug768" should contain the files
|
|
||||||
"""
|
|
||||||
[
|
|
||||||
"2019-10-29_first-entry.md",
|
|
||||||
"2019-10-29_second-entry.md",
|
|
||||||
"2019-10-29_third-entry.md"
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
And the content of file "2019-10-29_third-entry.md" in cache directory "bug768" should be
|
|
||||||
"""
|
|
||||||
title: Third entry.
|
|
||||||
date: 2019-10-29 11:13
|
|
||||||
starred: False
|
|
||||||
tags:
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
@deployment_tests
|
|
||||||
Scenario: Version numbers should stay in sync
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl --version"
|
|
||||||
Then we should get no error
|
|
||||||
Then the output should contain pyproject.toml version
|
|
|
@ -1,20 +0,0 @@
|
||||||
Feature: Starring entries
|
|
||||||
|
|
||||||
Scenario: Starring an entry will mark it in the journal file
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl 20 july 2013 *: Best day of my life!"
|
|
||||||
Then we should see the message "Entry added"
|
|
||||||
and the journal should contain "[2013-07-20 09:00] Best day of my life! *"
|
|
||||||
|
|
||||||
Scenario: Filtering by starred entries
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl -starred"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
When we run "jrnl 20 july 2013 *: Best day of my life!"
|
|
||||||
When we run "jrnl -starred"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2013-07-20 09:00 Best day of my life!
|
|
||||||
"""
|
|
|
@ -1,372 +0,0 @@
|
||||||
import ast
|
|
||||||
from collections import defaultdict
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
import re
|
|
||||||
import shlex
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
import keyring
|
|
||||||
import toml
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from behave import given, then, when
|
|
||||||
from jrnl import Journal, __version__, cli, install, plugins, util
|
|
||||||
|
|
||||||
try:
|
|
||||||
import parsedatetime.parsedatetime_consts as pdt
|
|
||||||
except ImportError:
|
|
||||||
import parsedatetime as pdt
|
|
||||||
|
|
||||||
consts = pdt.Constants(usePyICU=False)
|
|
||||||
consts.DOWParseStyle = -1 # Prefers past weekdays
|
|
||||||
CALENDAR = pdt.Calendar(consts)
|
|
||||||
|
|
||||||
|
|
||||||
class TestKeyring(keyring.backend.KeyringBackend):
|
|
||||||
"""A test keyring that just stores its values in a hash"""
|
|
||||||
|
|
||||||
priority = 1
|
|
||||||
keys = defaultdict(dict)
|
|
||||||
|
|
||||||
def set_password(self, servicename, username, password):
|
|
||||||
self.keys[servicename][username] = password
|
|
||||||
|
|
||||||
def get_password(self, servicename, username):
|
|
||||||
return self.keys[servicename].get(username)
|
|
||||||
|
|
||||||
def delete_password(self, servicename, username):
|
|
||||||
self.keys[servicename][username] = None
|
|
||||||
|
|
||||||
|
|
||||||
class NoKeyring(keyring.backend.KeyringBackend):
|
|
||||||
"""A keyring that simulated an environment with no keyring backend."""
|
|
||||||
|
|
||||||
priority = 2
|
|
||||||
keys = defaultdict(dict)
|
|
||||||
|
|
||||||
def set_password(self, servicename, username, password):
|
|
||||||
raise keyring.errors.NoKeyringError
|
|
||||||
|
|
||||||
def get_password(self, servicename, username):
|
|
||||||
raise keyring.errors.NoKeyringError
|
|
||||||
|
|
||||||
def delete_password(self, servicename, username):
|
|
||||||
raise keyring.errors.NoKeyringError
|
|
||||||
|
|
||||||
|
|
||||||
# set the keyring for keyring lib
|
|
||||||
keyring.set_keyring(TestKeyring())
|
|
||||||
|
|
||||||
|
|
||||||
def ushlex(command):
|
|
||||||
return shlex.split(command, posix="win32" not in sys.platform)
|
|
||||||
|
|
||||||
|
|
||||||
def read_journal(journal_name="default"):
|
|
||||||
config = util.load_config(install.CONFIG_FILE_PATH)
|
|
||||||
with open(config["journals"][journal_name]) as journal_file:
|
|
||||||
journal = journal_file.read()
|
|
||||||
return journal
|
|
||||||
|
|
||||||
|
|
||||||
def open_journal(journal_name="default"):
|
|
||||||
config = util.load_config(install.CONFIG_FILE_PATH)
|
|
||||||
journal_conf = config["journals"][journal_name]
|
|
||||||
|
|
||||||
# We can override the default config on a by-journal basis
|
|
||||||
if type(journal_conf) is dict:
|
|
||||||
config.update(journal_conf)
|
|
||||||
# But also just give them a string to point to the journal file
|
|
||||||
else:
|
|
||||||
config["journal"] = journal_conf
|
|
||||||
|
|
||||||
return Journal.open_journal(journal_name, config)
|
|
||||||
|
|
||||||
|
|
||||||
@given('we use the config "{config_file}"')
|
|
||||||
def set_config(context, config_file):
|
|
||||||
full_path = os.path.join("features/configs", config_file)
|
|
||||||
install.CONFIG_FILE_PATH = os.path.abspath(full_path)
|
|
||||||
if config_file.endswith("yaml"):
|
|
||||||
# Add jrnl version to file for 2.x journals
|
|
||||||
with open(install.CONFIG_FILE_PATH, "a") as cf:
|
|
||||||
cf.write("version: {}".format(__version__))
|
|
||||||
|
|
||||||
|
|
||||||
@when('we open the editor and enter "{text}"')
|
|
||||||
@when("we open the editor and enter nothing")
|
|
||||||
def open_editor_and_enter(context, text=""):
|
|
||||||
text = text or context.text or ""
|
|
||||||
|
|
||||||
def _mock_editor_function(command):
|
|
||||||
context.editor_command = command
|
|
||||||
tmpfile = command[-1]
|
|
||||||
with open(tmpfile, "w+") as f:
|
|
||||||
f.write(text)
|
|
||||||
|
|
||||||
return tmpfile
|
|
||||||
|
|
||||||
# fmt: off
|
|
||||||
# see: https://github.com/psf/black/issues/664
|
|
||||||
with \
|
|
||||||
patch("subprocess.call", side_effect=_mock_editor_function), \
|
|
||||||
patch("sys.stdin.isatty", return_value=True) \
|
|
||||||
:
|
|
||||||
context.execute_steps('when we run "jrnl"')
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
|
|
||||||
@then("the editor should have been called with {num} arguments")
|
|
||||||
def count_editor_args(context, num):
|
|
||||||
assert len(context.editor_command) == int(num)
|
|
||||||
|
|
||||||
|
|
||||||
@then('one editor argument should be "{arg}"')
|
|
||||||
def contains_editor_arg(context, arg):
|
|
||||||
args = context.editor_command
|
|
||||||
assert (
|
|
||||||
arg in args and args.count(arg) == 1
|
|
||||||
), f"\narg not in args exactly 1 time:\n{arg}\n{str(args)}"
|
|
||||||
|
|
||||||
|
|
||||||
@then('one editor argument should match "{regex}"')
|
|
||||||
def matches_editor_arg(context, regex):
|
|
||||||
args = context.editor_command
|
|
||||||
matches = list(filter(lambda x: re.match(regex, x), args))
|
|
||||||
assert (
|
|
||||||
len(matches) == 1
|
|
||||||
), f"\nRegex didn't match exactly 1 time:\n{regex}\n{str(args)}"
|
|
||||||
|
|
||||||
|
|
||||||
def _mock_getpass(inputs):
|
|
||||||
def prompt_return(prompt="Password: "):
|
|
||||||
print(prompt)
|
|
||||||
return next(inputs)
|
|
||||||
|
|
||||||
return prompt_return
|
|
||||||
|
|
||||||
|
|
||||||
def _mock_input(inputs):
|
|
||||||
def prompt_return(prompt=""):
|
|
||||||
val = next(inputs)
|
|
||||||
print(prompt, val)
|
|
||||||
return val
|
|
||||||
|
|
||||||
return prompt_return
|
|
||||||
|
|
||||||
|
|
||||||
@when('we run "{command}" and enter')
|
|
||||||
@when('we run "{command}" and enter nothing')
|
|
||||||
@when('we run "{command}" and enter "{inputs}"')
|
|
||||||
def run_with_input(context, command, inputs=""):
|
|
||||||
# create an iterator through all inputs. These inputs will be fed one by one
|
|
||||||
# to the mocked calls for 'input()', 'util.getpass()' and 'sys.stdin.read()'
|
|
||||||
if context.text:
|
|
||||||
text = iter(context.text.split("\n"))
|
|
||||||
else:
|
|
||||||
text = iter([inputs])
|
|
||||||
|
|
||||||
args = ushlex(command)[1:]
|
|
||||||
|
|
||||||
# fmt: off
|
|
||||||
# see: https://github.com/psf/black/issues/664
|
|
||||||
with \
|
|
||||||
patch("builtins.input", side_effect=_mock_input(text)) as mock_input, \
|
|
||||||
patch("getpass.getpass", side_effect=_mock_getpass(text)) as mock_getpass, \
|
|
||||||
patch("sys.stdin.read", side_effect=text) as mock_read \
|
|
||||||
:
|
|
||||||
try:
|
|
||||||
cli.run(args or [])
|
|
||||||
context.exit_status = 0
|
|
||||||
except SystemExit as e:
|
|
||||||
context.exit_status = e.code
|
|
||||||
|
|
||||||
# at least one of the mocked input methods got called
|
|
||||||
assert mock_input.called or mock_getpass.called or mock_read.called
|
|
||||||
# all inputs were used
|
|
||||||
try:
|
|
||||||
next(text)
|
|
||||||
assert False, "Not all inputs were consumed"
|
|
||||||
except StopIteration:
|
|
||||||
pass
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
|
|
||||||
@when('we run "{command}"')
|
|
||||||
@when('we run "{command}" with cache directory "{cache_dir}"')
|
|
||||||
def run(context, command, cache_dir=None):
|
|
||||||
if cache_dir is not None:
|
|
||||||
cache_dir = os.path.join("features", "cache", cache_dir)
|
|
||||||
command = command.format(cache_dir=cache_dir)
|
|
||||||
|
|
||||||
args = ushlex(command)
|
|
||||||
|
|
||||||
try:
|
|
||||||
with patch("sys.argv", args):
|
|
||||||
cli.run(args[1:])
|
|
||||||
context.exit_status = 0
|
|
||||||
except SystemExit as e:
|
|
||||||
context.exit_status = e.code
|
|
||||||
|
|
||||||
|
|
||||||
@given('we load template "{filename}"')
|
|
||||||
def load_template(context, filename):
|
|
||||||
full_path = os.path.join("features/data/templates", filename)
|
|
||||||
exporter = plugins.template_exporter.__exporter_from_file(full_path)
|
|
||||||
plugins.__exporter_types[exporter.names[0]] = exporter
|
|
||||||
|
|
||||||
|
|
||||||
@when('we set the keychain password of "{journal}" to "{password}"')
|
|
||||||
def set_keychain(context, journal, password):
|
|
||||||
keyring.set_password("jrnl", journal, password)
|
|
||||||
|
|
||||||
|
|
||||||
@when("we disable the keychain")
|
|
||||||
def disable_keychain(context):
|
|
||||||
keyring.core.set_keyring(NoKeyring())
|
|
||||||
|
|
||||||
|
|
||||||
@then("we should get an error")
|
|
||||||
def has_error(context):
|
|
||||||
assert context.exit_status != 0, context.exit_status
|
|
||||||
|
|
||||||
|
|
||||||
@then("we should get no error")
|
|
||||||
def no_error(context):
|
|
||||||
assert context.exit_status == 0, context.exit_status
|
|
||||||
|
|
||||||
|
|
||||||
@then("the output should be")
|
|
||||||
@then('the output should be "{text}"')
|
|
||||||
def check_output(context, text=None):
|
|
||||||
text = (text or context.text).strip().splitlines()
|
|
||||||
out = context.stdout_capture.getvalue().strip().splitlines()
|
|
||||||
assert len(text) == len(out), "Output has {} lines (expected: {})".format(
|
|
||||||
len(out), len(text)
|
|
||||||
)
|
|
||||||
for line_text, line_out in zip(text, out):
|
|
||||||
assert line_text.strip() == line_out.strip(), [
|
|
||||||
line_text.strip(),
|
|
||||||
line_out.strip(),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@then('the output should contain "{text}" in the local time')
|
|
||||||
def check_output_time_inline(context, text):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
date, flag = CALENDAR.parse(text)
|
|
||||||
output_date = time.strftime("%Y-%m-%d %H:%M", date)
|
|
||||||
assert output_date in out, output_date
|
|
||||||
|
|
||||||
|
|
||||||
@then("the output should contain pyproject.toml version")
|
|
||||||
def check_output_version_inline(context):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
pyproject = (Path(__file__) / ".." / ".." / ".." / "pyproject.toml").resolve()
|
|
||||||
pyproject_contents = toml.load(pyproject)
|
|
||||||
pyproject_version = pyproject_contents["tool"]["poetry"]["version"]
|
|
||||||
assert pyproject_version in out, pyproject_version
|
|
||||||
|
|
||||||
|
|
||||||
@then("the output should contain")
|
|
||||||
@then('the output should contain "{text}"')
|
|
||||||
@then('the output should contain "{text}" or "{text2}"')
|
|
||||||
def check_output_inline(context, text=None, text2=None):
|
|
||||||
text = text or context.text
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
assert text in out or text2 in out, text or text2
|
|
||||||
|
|
||||||
|
|
||||||
@then("the error output should contain")
|
|
||||||
@then('the error output should contain "{text}"')
|
|
||||||
@then('the error output should contain "{text}" or "{text2}"')
|
|
||||||
def check_error_output_inline(context, text=None, text2=None):
|
|
||||||
text = text or context.text
|
|
||||||
out = context.stderr_capture.getvalue()
|
|
||||||
assert text in out or text2 in out, text or text2
|
|
||||||
|
|
||||||
|
|
||||||
@then('the output should not contain "{text}"')
|
|
||||||
def check_output_not_inline(context, text):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
assert text not in out
|
|
||||||
|
|
||||||
|
|
||||||
@then('we should see the message "{text}"')
|
|
||||||
def check_message(context, text):
|
|
||||||
out = context.stderr_capture.getvalue()
|
|
||||||
assert text in out, [text, out]
|
|
||||||
|
|
||||||
|
|
||||||
@then('we should not see the message "{text}"')
|
|
||||||
def check_not_message(context, text):
|
|
||||||
out = context.stderr_capture.getvalue()
|
|
||||||
assert text not in out, [text, out]
|
|
||||||
|
|
||||||
|
|
||||||
@then('the journal should contain "{text}"')
|
|
||||||
@then('journal "{journal_name}" should contain "{text}"')
|
|
||||||
def check_journal_content(context, text, journal_name="default"):
|
|
||||||
journal = read_journal(journal_name)
|
|
||||||
assert text in journal, journal
|
|
||||||
|
|
||||||
|
|
||||||
@then('the journal should not contain "{text}"')
|
|
||||||
@then('journal "{journal_name}" should not contain "{text}"')
|
|
||||||
def check_not_journal_content(context, text, journal_name="default"):
|
|
||||||
journal = read_journal(journal_name)
|
|
||||||
assert text not in journal, journal
|
|
||||||
|
|
||||||
|
|
||||||
@then('journal "{journal_name}" should not exist')
|
|
||||||
def journal_doesnt_exist(context, journal_name="default"):
|
|
||||||
with open(install.CONFIG_FILE_PATH) as config_file:
|
|
||||||
config = yaml.load(config_file, Loader=yaml.FullLoader)
|
|
||||||
journal_path = config["journals"][journal_name]
|
|
||||||
assert not os.path.exists(journal_path)
|
|
||||||
|
|
||||||
|
|
||||||
@then('the config should have "{key}" set to "{value}"')
|
|
||||||
@then('the config for journal "{journal}" should have "{key}" set to "{value}"')
|
|
||||||
def config_var(context, key, value, journal=None):
|
|
||||||
if not value[0] == "{":
|
|
||||||
t, value = value.split(":")
|
|
||||||
value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](
|
|
||||||
value
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# Handle value being a dictionary
|
|
||||||
value = ast.literal_eval(value)
|
|
||||||
|
|
||||||
config = util.load_config(install.CONFIG_FILE_PATH)
|
|
||||||
if journal:
|
|
||||||
config = config["journals"][journal]
|
|
||||||
assert key in config
|
|
||||||
assert config[key] == value
|
|
||||||
|
|
||||||
|
|
||||||
@then("the journal should have {number:d} entries")
|
|
||||||
@then("the journal should have {number:d} entry")
|
|
||||||
@then('journal "{journal_name}" should have {number:d} entries')
|
|
||||||
@then('journal "{journal_name}" should have {number:d} entry')
|
|
||||||
def check_journal_entries(context, number, journal_name="default"):
|
|
||||||
journal = open_journal(journal_name)
|
|
||||||
assert len(journal.entries) == number
|
|
||||||
|
|
||||||
|
|
||||||
@when("the journal directory is listed")
|
|
||||||
def list_journal_directory(context, journal="default"):
|
|
||||||
with open(install.CONFIG_FILE_PATH) as config_file:
|
|
||||||
config = yaml.load(config_file, Loader=yaml.FullLoader)
|
|
||||||
journal_path = config["journals"][journal]
|
|
||||||
for root, dirnames, f in os.walk(journal_path):
|
|
||||||
for file in f:
|
|
||||||
print(os.path.join(root, file))
|
|
||||||
|
|
||||||
|
|
||||||
@then("fail")
|
|
||||||
def debug_fail(context):
|
|
||||||
assert False
|
|
|
@ -1,137 +0,0 @@
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
from xml.etree import ElementTree
|
|
||||||
|
|
||||||
from behave import given, then
|
|
||||||
|
|
||||||
|
|
||||||
@then("the output should be parsable as json")
|
|
||||||
def check_output_json(context):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
assert json.loads(out), out
|
|
||||||
|
|
||||||
|
|
||||||
@then('"{field}" in the json output should have {number:d} elements')
|
|
||||||
@then('"{field}" in the json output should have 1 element')
|
|
||||||
def check_output_field(context, field, number=1):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
out_json = json.loads(out)
|
|
||||||
assert field in out_json, [field, out_json]
|
|
||||||
assert len(out_json[field]) == number, len(out_json[field])
|
|
||||||
|
|
||||||
|
|
||||||
@then('"{field}" in the json output should not contain "{key}"')
|
|
||||||
def check_output_field_not_key(context, field, key):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
out_json = json.loads(out)
|
|
||||||
assert field in out_json
|
|
||||||
assert key not in out_json[field]
|
|
||||||
|
|
||||||
|
|
||||||
@then('"{field}" in the json output should contain "{key}"')
|
|
||||||
def check_output_field_key(context, field, key):
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
out_json = json.loads(out)
|
|
||||||
assert field in out_json
|
|
||||||
assert key in out_json[field]
|
|
||||||
|
|
||||||
|
|
||||||
@then('the json output should contain {path} = "{value}"')
|
|
||||||
def check_json_output_path(context, path, value):
|
|
||||||
""" E.g.
|
|
||||||
the json output should contain entries.0.title = "hello"
|
|
||||||
"""
|
|
||||||
out = context.stdout_capture.getvalue()
|
|
||||||
struct = json.loads(out)
|
|
||||||
|
|
||||||
for node in path.split("."):
|
|
||||||
try:
|
|
||||||
struct = struct[int(node)]
|
|
||||||
except ValueError:
|
|
||||||
struct = struct[node]
|
|
||||||
assert struct == value, struct
|
|
||||||
|
|
||||||
|
|
||||||
@then("the output should be a valid XML string")
|
|
||||||
def assert_valid_xml_string(context):
|
|
||||||
output = context.stdout_capture.getvalue()
|
|
||||||
xml_tree = ElementTree.fromstring(output)
|
|
||||||
assert xml_tree, output
|
|
||||||
|
|
||||||
|
|
||||||
@then('"entries" node in the xml output should have {number:d} elements')
|
|
||||||
def assert_xml_output_entries_count(context, number):
|
|
||||||
output = context.stdout_capture.getvalue()
|
|
||||||
xml_tree = ElementTree.fromstring(output)
|
|
||||||
|
|
||||||
xml_tags = (node.tag for node in xml_tree)
|
|
||||||
assert "entries" in xml_tags, str(list(xml_tags))
|
|
||||||
|
|
||||||
actual_entry_count = len(xml_tree.find("entries"))
|
|
||||||
assert actual_entry_count == number, actual_entry_count
|
|
||||||
|
|
||||||
|
|
||||||
@then('"tags" in the xml output should contain {expected_tags_json_list}')
|
|
||||||
def assert_xml_output_tags(context, expected_tags_json_list):
|
|
||||||
output = context.stdout_capture.getvalue()
|
|
||||||
xml_tree = ElementTree.fromstring(output)
|
|
||||||
|
|
||||||
xml_tags = (node.tag for node in xml_tree)
|
|
||||||
assert "tags" in xml_tags, str(list(xml_tags))
|
|
||||||
|
|
||||||
expected_tags = json.loads(expected_tags_json_list)
|
|
||||||
actual_tags = set(t.attrib["name"] for t in xml_tree.find("tags"))
|
|
||||||
assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)]
|
|
||||||
|
|
||||||
|
|
||||||
@given('we create cache directory "{dir_name}"')
|
|
||||||
def create_directory(context, dir_name):
|
|
||||||
working_dir = os.path.join("features", "cache", dir_name)
|
|
||||||
if os.path.exists(working_dir):
|
|
||||||
shutil.rmtree(working_dir)
|
|
||||||
os.makedirs(working_dir)
|
|
||||||
|
|
||||||
|
|
||||||
@then('cache directory "{dir_name}" should contain the files')
|
|
||||||
@then(
|
|
||||||
'cache directory "{dir_name}" should contain the files {expected_files_json_list}'
|
|
||||||
)
|
|
||||||
def assert_dir_contains_files(context, dir_name, expected_files_json_list="[]"):
|
|
||||||
working_dir = os.path.join("features", "cache", dir_name)
|
|
||||||
actual_files = os.listdir(working_dir)
|
|
||||||
|
|
||||||
expected_files = context.text or expected_files_json_list
|
|
||||||
expected_files = json.loads(expected_files)
|
|
||||||
|
|
||||||
# sort to deal with inconsistent default file ordering on different OS's
|
|
||||||
actual_files.sort()
|
|
||||||
expected_files.sort()
|
|
||||||
|
|
||||||
assert actual_files == expected_files, [actual_files, expected_files]
|
|
||||||
|
|
||||||
|
|
||||||
@then('the content of file "{file_path}" in cache directory "{cache_dir}" should be')
|
|
||||||
def assert_exported_yaml_file_content(context, file_path, cache_dir):
|
|
||||||
expected_content = context.text.strip().splitlines()
|
|
||||||
full_file_path = os.path.join("features", "cache", cache_dir, file_path)
|
|
||||||
|
|
||||||
with open(full_file_path, "r") as f:
|
|
||||||
actual_content = f.read().strip().splitlines()
|
|
||||||
|
|
||||||
for actual_line, expected_line in zip(actual_content, expected_content):
|
|
||||||
if actual_line.startswith("tags: ") and expected_line.startswith("tags: "):
|
|
||||||
assert_equal_tags_ignoring_order(actual_line, expected_line)
|
|
||||||
else:
|
|
||||||
assert actual_line.strip() == expected_line.strip(), [
|
|
||||||
actual_line.strip(),
|
|
||||||
expected_line.strip(),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def assert_equal_tags_ignoring_order(actual_line, expected_line):
|
|
||||||
actual_tags = set(tag.strip() for tag in actual_line[len("tags: ") :].split(","))
|
|
||||||
expected_tags = set(
|
|
||||||
tag.strip() for tag in expected_line[len("tags: ") :].split(",")
|
|
||||||
)
|
|
||||||
assert actual_tags == expected_tags, [actual_tags, expected_tags]
|
|
|
@ -1,121 +0,0 @@
|
||||||
Feature: Tagging
|
|
||||||
|
|
||||||
Scenario: Displaying tags
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl --tags"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
@idea : 2
|
|
||||||
@journal : 1
|
|
||||||
@dan : 1
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Filtering journals should also filter tags
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl -from 'may 2013' --tags"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
@idea : 1
|
|
||||||
@dan : 1
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Tags should allow certain special characters
|
|
||||||
Given we use the config "tags-216.yaml"
|
|
||||||
When we run "jrnl --tags"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
@os/2 : 1
|
|
||||||
@c++ : 1
|
|
||||||
@c# : 1
|
|
||||||
"""
|
|
||||||
Scenario: An email should not be a tag
|
|
||||||
Given we use the config "tags-237.yaml"
|
|
||||||
When we run "jrnl --tags"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
@newline : 1
|
|
||||||
@email : 1
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Entry cans start and end with tags
|
|
||||||
Given we use the config "basic.yaml"
|
|
||||||
When we run "jrnl today: @foo came over, we went to a @bar"
|
|
||||||
When we run "jrnl --tags"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
@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
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
Scenario: Printing a journal that has multiline entries with tags
|
|
||||||
Given we use the config "multiline-tags.yaml"
|
|
||||||
When we run "jrnl -n 1"
|
|
||||||
Then we should get no error
|
|
||||||
and the output should be
|
|
||||||
"""
|
|
||||||
2013-06-09 15:39 Multiple @line entry with @tags.
|
|
||||||
| Tag with @punctuation. afterwards
|
|
||||||
| @TagOnLineAloneWithOutPunctuation
|
|
||||||
| @TagOnLineAloneWithPunctuation.
|
|
||||||
| Text before @tag. And After.
|
|
||||||
| @hi. Hello
|
|
||||||
| hi Hello
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Searching a journal for tags should display entries with that tag.
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl @dan"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2013-06-10 15:40 I met with @dan.
|
|
||||||
| As alway's he shared his latest @idea on how to rule the world with me.
|
|
||||||
| inst
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Searching a journal for multiple tags with -and should display entries with those tags.
|
|
||||||
Given we use the config "tags.yaml"
|
|
||||||
When we run "jrnl -and @idea @journal"
|
|
||||||
Then the output should be
|
|
||||||
"""
|
|
||||||
2013-04-09 15:39 I have an @idea:
|
|
||||||
| (1) write a command line @journal software
|
|
||||||
| (2) ???
|
|
||||||
| (3) PROFIT!
|
|
||||||
"""
|
|
|
@ -1,178 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import fnmatch
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
import plistlib
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
import uuid
|
|
||||||
from xml.parsers.expat import ExpatError
|
|
||||||
|
|
||||||
import pytz
|
|
||||||
import tzlocal
|
|
||||||
|
|
||||||
from . import Entry, Journal
|
|
||||||
from . import time as jrnl_time
|
|
||||||
|
|
||||||
|
|
||||||
class DayOne(Journal.Journal):
|
|
||||||
"""A special Journal handling DayOne files"""
|
|
||||||
|
|
||||||
# InvalidFileException was added to plistlib in Python3.4
|
|
||||||
PLIST_EXCEPTIONS = (
|
|
||||||
(ExpatError, plistlib.InvalidFileException)
|
|
||||||
if hasattr(plistlib, "InvalidFileException")
|
|
||||||
else ExpatError
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.entries = []
|
|
||||||
self._deleted_entries = []
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
filenames = [
|
|
||||||
os.path.join(self.config["journal"], "entries", f)
|
|
||||||
for f in os.listdir(os.path.join(self.config["journal"], "entries"))
|
|
||||||
]
|
|
||||||
filenames = []
|
|
||||||
for root, dirnames, f in os.walk(self.config["journal"]):
|
|
||||||
for filename in fnmatch.filter(f, "*.doentry"):
|
|
||||||
filenames.append(os.path.join(root, filename))
|
|
||||||
self.entries = []
|
|
||||||
for filename in filenames:
|
|
||||||
with open(filename, "rb") as plist_entry:
|
|
||||||
try:
|
|
||||||
dict_entry = plistlib.load(plist_entry, fmt=plistlib.FMT_XML)
|
|
||||||
except self.PLIST_EXCEPTIONS:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
timezone = pytz.timezone(dict_entry["Time Zone"])
|
|
||||||
except (KeyError, pytz.exceptions.UnknownTimeZoneError):
|
|
||||||
timezone = tzlocal.get_localzone()
|
|
||||||
date = dict_entry["Creation Date"]
|
|
||||||
# convert the date to UTC rather than keep messing with
|
|
||||||
# timezones
|
|
||||||
if timezone.zone != "UTC":
|
|
||||||
date = date + timezone.utcoffset(date, is_dst=False)
|
|
||||||
|
|
||||||
entry = Entry.Entry(
|
|
||||||
self,
|
|
||||||
date,
|
|
||||||
text=dict_entry["Entry Text"],
|
|
||||||
starred=dict_entry["Starred"],
|
|
||||||
)
|
|
||||||
entry.uuid = dict_entry["UUID"]
|
|
||||||
entry._tags = [
|
|
||||||
self.config["tagsymbols"][0] + tag.lower()
|
|
||||||
for tag in dict_entry.get("Tags", [])
|
|
||||||
]
|
|
||||||
|
|
||||||
self.entries.append(entry)
|
|
||||||
self.sort()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def write(self):
|
|
||||||
"""Writes only the entries that have been modified into plist files."""
|
|
||||||
for entry in self.entries:
|
|
||||||
if entry.modified:
|
|
||||||
utc_time = datetime.utcfromtimestamp(
|
|
||||||
time.mktime(entry.date.timetuple())
|
|
||||||
)
|
|
||||||
|
|
||||||
if not hasattr(entry, "uuid"):
|
|
||||||
entry.uuid = uuid.uuid1().hex
|
|
||||||
|
|
||||||
fn = (
|
|
||||||
Path(self.config["journal"])
|
|
||||||
/ "entries"
|
|
||||||
/ (entry.uuid.upper() + ".doentry")
|
|
||||||
)
|
|
||||||
|
|
||||||
entry_plist = {
|
|
||||||
"Creation Date": utc_time,
|
|
||||||
"Starred": entry.starred if hasattr(entry, "starred") else False,
|
|
||||||
"Entry Text": entry.title + "\n" + entry.body,
|
|
||||||
"Time Zone": str(tzlocal.get_localzone()),
|
|
||||||
"UUID": entry.uuid.upper(),
|
|
||||||
"Tags": [
|
|
||||||
tag.strip(self.config["tagsymbols"]).replace("_", " ")
|
|
||||||
for tag in entry.tags
|
|
||||||
],
|
|
||||||
}
|
|
||||||
# plistlib expects a binary object
|
|
||||||
with fn.open(mode="wb") as f:
|
|
||||||
plistlib.dump(entry_plist, f, fmt=plistlib.FMT_XML, sort_keys=False)
|
|
||||||
for entry in self._deleted_entries:
|
|
||||||
filename = os.path.join(
|
|
||||||
self.config["journal"], "entries", entry.uuid + ".doentry"
|
|
||||||
)
|
|
||||||
os.remove(filename)
|
|
||||||
|
|
||||||
def editable_str(self):
|
|
||||||
"""Turns the journal into a string of entries that can be edited
|
|
||||||
manually and later be parsed with eslf.parse_editable_str."""
|
|
||||||
return "\n".join([f"# {e.uuid}\n{str(e)}" for e in self.entries])
|
|
||||||
|
|
||||||
def parse_editable_str(self, edited):
|
|
||||||
"""Parses the output of self.editable_str and updates its entries."""
|
|
||||||
# Method: create a new list of entries from the edited text, then match
|
|
||||||
# UUIDs of the new entries against self.entries, updating the entries
|
|
||||||
# if the edited entries differ, and deleting entries from self.entries
|
|
||||||
# if they don't show up in the edited entries anymore.
|
|
||||||
|
|
||||||
# Initialise our current entry
|
|
||||||
entries = []
|
|
||||||
current_entry = None
|
|
||||||
|
|
||||||
for line in edited.splitlines():
|
|
||||||
# try to parse line as UUID => new entry begins
|
|
||||||
line = line.rstrip()
|
|
||||||
m = re.match("# *([a-f0-9]+) *$", line.lower())
|
|
||||||
if m:
|
|
||||||
if current_entry:
|
|
||||||
entries.append(current_entry)
|
|
||||||
current_entry = Entry.Entry(self)
|
|
||||||
current_entry.modified = False
|
|
||||||
current_entry.uuid = m.group(1).lower()
|
|
||||||
else:
|
|
||||||
date_blob_re = re.compile("^\\[[^\\]]+\\] ")
|
|
||||||
date_blob = date_blob_re.findall(line)
|
|
||||||
if date_blob:
|
|
||||||
date_blob = date_blob[0]
|
|
||||||
new_date = jrnl_time.parse(date_blob.strip(" []"))
|
|
||||||
if line.endswith("*"):
|
|
||||||
current_entry.starred = True
|
|
||||||
line = line[:-1]
|
|
||||||
current_entry.title = line[len(date_blob) - 1 :]
|
|
||||||
current_entry.date = new_date
|
|
||||||
elif current_entry:
|
|
||||||
current_entry.body += line + "\n"
|
|
||||||
|
|
||||||
# Append last entry
|
|
||||||
if current_entry:
|
|
||||||
entries.append(current_entry)
|
|
||||||
|
|
||||||
# Now, update our current entries if they changed
|
|
||||||
for entry in entries:
|
|
||||||
entry._parse_text()
|
|
||||||
matched_entries = [e for e in self.entries if e.uuid.lower() == entry.uuid]
|
|
||||||
if matched_entries:
|
|
||||||
# This entry is an existing entry
|
|
||||||
match = matched_entries[0]
|
|
||||||
if match != entry:
|
|
||||||
self.entries.remove(match)
|
|
||||||
entry.modified = True
|
|
||||||
self.entries.append(entry)
|
|
||||||
else:
|
|
||||||
# This entry seems to be new... save it.
|
|
||||||
entry.modified = True
|
|
||||||
self.entries.append(entry)
|
|
||||||
# Remove deleted entries
|
|
||||||
edited_uuids = [e.uuid for e in entries]
|
|
||||||
self._deleted_entries = [e for e in self.entries if e.uuid not in edited_uuids]
|
|
||||||
self.entries[:] = [e for e in self.entries if e.uuid in edited_uuids]
|
|
||||||
return entries
|
|
|
@ -1,132 +0,0 @@
|
||||||
import base64
|
|
||||||
import hashlib
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from cryptography.fernet import Fernet, InvalidToken
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
from cryptography.hazmat.primitives import hashes, padding
|
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
||||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
||||||
|
|
||||||
from . import util
|
|
||||||
from .Journal import Journal, LegacyJournal
|
|
||||||
|
|
||||||
log = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
def make_key(password):
|
|
||||||
password = password.encode("utf-8")
|
|
||||||
kdf = PBKDF2HMAC(
|
|
||||||
algorithm=hashes.SHA256(),
|
|
||||||
length=32,
|
|
||||||
# Salt is hard-coded
|
|
||||||
salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8",
|
|
||||||
iterations=100_000,
|
|
||||||
backend=default_backend(),
|
|
||||||
)
|
|
||||||
key = kdf.derive(password)
|
|
||||||
return base64.urlsafe_b64encode(key)
|
|
||||||
|
|
||||||
|
|
||||||
class EncryptedJournal(Journal):
|
|
||||||
def __init__(self, name="default", **kwargs):
|
|
||||||
super().__init__(name, **kwargs)
|
|
||||||
self.config["encrypt"] = True
|
|
||||||
self.password = None
|
|
||||||
|
|
||||||
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):
|
|
||||||
self.create_file(filename)
|
|
||||||
self.password = util.create_password(self.name)
|
|
||||||
print(
|
|
||||||
f"Encrypted journal '{self.name}' created at {filename}",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
|
|
||||||
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):
|
|
||||||
"""Loads an encrypted journal from a file and tries to decrypt it.
|
|
||||||
If password is not provided, will look for password in the keychain
|
|
||||||
and otherwise ask the user to enter a password up to three times.
|
|
||||||
If the password is provided but wrong (or corrupt), this will simply
|
|
||||||
return None."""
|
|
||||||
with open(filename, "rb") as f:
|
|
||||||
journal_encrypted = f.read()
|
|
||||||
|
|
||||||
def decrypt_journal(password):
|
|
||||||
key = make_key(password)
|
|
||||||
try:
|
|
||||||
plain = Fernet(key).decrypt(journal_encrypted).decode("utf-8")
|
|
||||||
self.password = password
|
|
||||||
return plain
|
|
||||||
except (InvalidToken, IndexError):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self.password:
|
|
||||||
return decrypt_journal(self.password)
|
|
||||||
|
|
||||||
return util.decrypt_content(keychain=self.name, decrypt_func=decrypt_journal)
|
|
||||||
|
|
||||||
def _store(self, filename, text):
|
|
||||||
key = make_key(self.password)
|
|
||||||
journal = Fernet(key).encrypt(text.encode("utf-8"))
|
|
||||||
with open(filename, "wb") as f:
|
|
||||||
f.write(journal)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_journal(cls, other: Journal):
|
|
||||||
new_journal = super().from_journal(other)
|
|
||||||
new_journal.password = (
|
|
||||||
other.password
|
|
||||||
if hasattr(other, "password")
|
|
||||||
else util.create_password(other.name)
|
|
||||||
)
|
|
||||||
return new_journal
|
|
||||||
|
|
||||||
|
|
||||||
class LegacyEncryptedJournal(LegacyJournal):
|
|
||||||
"""Legacy class to support opening journals encrypted with the jrnl 1.x
|
|
||||||
standard. You'll not be able to save these journals anymore."""
|
|
||||||
|
|
||||||
def __init__(self, name="default", **kwargs):
|
|
||||||
super().__init__(name, **kwargs)
|
|
||||||
self.config["encrypt"] = True
|
|
||||||
self.password = None
|
|
||||||
|
|
||||||
def _load(self, filename):
|
|
||||||
with open(filename, "rb") as f:
|
|
||||||
journal_encrypted = f.read()
|
|
||||||
iv, cipher = journal_encrypted[:16], journal_encrypted[16:]
|
|
||||||
|
|
||||||
def decrypt_journal(password):
|
|
||||||
decryption_key = hashlib.sha256(password.encode("utf-8")).digest()
|
|
||||||
decryptor = Cipher(
|
|
||||||
algorithms.AES(decryption_key), modes.CBC(iv), default_backend()
|
|
||||||
).decryptor()
|
|
||||||
try:
|
|
||||||
plain_padded = decryptor.update(cipher) + decryptor.finalize()
|
|
||||||
self.password = password
|
|
||||||
if plain_padded[-1] in (" ", 32):
|
|
||||||
# Ancient versions of jrnl. Do not judge me.
|
|
||||||
return plain_padded.decode("utf-8").rstrip(" ")
|
|
||||||
else:
|
|
||||||
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
|
|
||||||
plain = unpadder.update(plain_padded) + unpadder.finalize()
|
|
||||||
return plain.decode("utf-8")
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self.password:
|
|
||||||
return decrypt_journal(self.password)
|
|
||||||
return util.decrypt_content(keychain=self.name, decrypt_func=decrypt_journal)
|
|
|
@ -1,92 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
import codecs
|
|
||||||
import fnmatch
|
|
||||||
import os
|
|
||||||
|
|
||||||
from . import Journal
|
|
||||||
|
|
||||||
|
|
||||||
def get_files(journal_config):
|
|
||||||
"""Searches through sub directories starting with journal_config and find all text files"""
|
|
||||||
filenames = []
|
|
||||||
for root, dirnames, f in os.walk(journal_config):
|
|
||||||
for filename in fnmatch.filter(f, "*.txt"):
|
|
||||||
filenames.append(os.path.join(root, filename))
|
|
||||||
return filenames
|
|
||||||
|
|
||||||
|
|
||||||
class Folder(Journal.Journal):
|
|
||||||
"""A Journal handling multiple files in a folder"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.entries = []
|
|
||||||
self._diff_entry_dates = []
|
|
||||||
super(Folder, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
filenames = []
|
|
||||||
self.entries = []
|
|
||||||
filenames = get_files(self.config["journal"])
|
|
||||||
for filename in filenames:
|
|
||||||
with codecs.open(filename, "r", "utf-8") as f:
|
|
||||||
journal = f.read()
|
|
||||||
self.entries.extend(self._parse(journal))
|
|
||||||
self.sort()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def write(self):
|
|
||||||
"""Writes only the entries that have been modified into proper files."""
|
|
||||||
# Create a list of dates of modified entries. Start with diff_entry_dates
|
|
||||||
modified_dates = self._diff_entry_dates
|
|
||||||
seen_dates = set(self._diff_entry_dates)
|
|
||||||
for e in self.entries:
|
|
||||||
if e.modified:
|
|
||||||
if e.date not in seen_dates:
|
|
||||||
modified_dates.append(e.date)
|
|
||||||
seen_dates.add(e.date)
|
|
||||||
|
|
||||||
# For every date that had a modified entry, write to a file
|
|
||||||
for d in modified_dates:
|
|
||||||
write_entries = []
|
|
||||||
filename = os.path.join(
|
|
||||||
self.config["journal"],
|
|
||||||
d.strftime("%Y"),
|
|
||||||
d.strftime("%m"),
|
|
||||||
d.strftime("%d") + ".txt",
|
|
||||||
)
|
|
||||||
dirname = os.path.dirname(filename)
|
|
||||||
# create directory if it doesn't exist
|
|
||||||
if not os.path.exists(dirname):
|
|
||||||
os.makedirs(dirname)
|
|
||||||
for e in self.entries:
|
|
||||||
if (
|
|
||||||
e.date.year == d.year
|
|
||||||
and e.date.month == d.month
|
|
||||||
and e.date.day == d.day
|
|
||||||
):
|
|
||||||
write_entries.append(e)
|
|
||||||
journal = "\n".join([e.__str__() for e in write_entries])
|
|
||||||
with codecs.open(filename, "w", "utf-8") as journal_file:
|
|
||||||
journal_file.write(journal)
|
|
||||||
# look for and delete empty files
|
|
||||||
filenames = []
|
|
||||||
filenames = get_files(self.config["journal"])
|
|
||||||
for filename in filenames:
|
|
||||||
if os.stat(filename).st_size <= 0:
|
|
||||||
# print("empty file: {}".format(filename))
|
|
||||||
os.remove(filename)
|
|
||||||
|
|
||||||
def parse_editable_str(self, edited):
|
|
||||||
"""Parses the output of self.editable_str and updates it's entries."""
|
|
||||||
mod_entries = self._parse(edited)
|
|
||||||
diff_entries = set(self.entries) - set(mod_entries)
|
|
||||||
for e in diff_entries:
|
|
||||||
self._diff_entry_dates.append(e.date)
|
|
||||||
# Match those entries that can be found in self.entries and set
|
|
||||||
# these to modified, so we can get a count of how many entries got
|
|
||||||
# modified and how many got deleted later.
|
|
||||||
for entry in mod_entries:
|
|
||||||
entry.modified = not any(entry == old_entry for old_entry in self.entries)
|
|
||||||
self.entries = mod_entries
|
|
|
@ -1,7 +1,8 @@
|
||||||
#!/usr/bin/env python
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .__version__ import __version__
|
from jrnl.__version__ import __version__
|
||||||
except ImportError:
|
except ImportError:
|
||||||
__version__ = "source"
|
__version__ = "source"
|
||||||
__title__ = "jrnl"
|
__title__ = "jrnl"
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#!/usr/bin/env python
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
from . import cli
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from jrnl.main import run
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli.run()
|
sys.exit(run())
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "v2.4.3-beta"
|
__version__ = "v4.2.1"
|
||||||
|
|
456
jrnl/args.py
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from jrnl.commands import postconfig_decrypt
|
||||||
|
from jrnl.commands import postconfig_encrypt
|
||||||
|
from jrnl.commands import postconfig_import
|
||||||
|
from jrnl.commands import postconfig_list
|
||||||
|
from jrnl.commands import preconfig_diagnostic
|
||||||
|
from jrnl.commands import preconfig_version
|
||||||
|
from jrnl.output import deprecated_cmd
|
||||||
|
from jrnl.plugins import EXPORT_FORMATS
|
||||||
|
from jrnl.plugins import IMPORT_FORMATS
|
||||||
|
from jrnl.plugins import util
|
||||||
|
|
||||||
|
|
||||||
|
class WrappingFormatter(argparse.RawTextHelpFormatter):
|
||||||
|
"""Used in help screen"""
|
||||||
|
|
||||||
|
def _split_lines(self, text: str, width: int) -> list[str]:
|
||||||
|
text = text.split("\n\n")
|
||||||
|
text = map(lambda t: self._whitespace_matcher.sub(" ", t).strip(), text)
|
||||||
|
text = map(lambda t: textwrap.wrap(t, width=56), text)
|
||||||
|
text = [item for sublist in text for item in sublist]
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class IgnoreNoneAppendAction(argparse._AppendAction):
|
||||||
|
"""
|
||||||
|
Pass -not without a following string and avoid appending
|
||||||
|
a None value to the excluded list
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
if values is not None:
|
||||||
|
super().__call__(parser, namespace, values, option_string)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_not_arg(
|
||||||
|
args: list[str], parsed_args: argparse.Namespace, parser: argparse.ArgumentParser
|
||||||
|
) -> argparse.Namespace:
|
||||||
|
"""
|
||||||
|
It's possible to use -not as a precursor to -starred and -tagged
|
||||||
|
to reverse their behaviour, however this requires some extra logic
|
||||||
|
to parse, and to ensure we still do not allow passing an empty -not
|
||||||
|
"""
|
||||||
|
|
||||||
|
parsed_args.exclude_starred = False
|
||||||
|
parsed_args.exclude_tagged = False
|
||||||
|
|
||||||
|
if "-not-starred" in "".join(args):
|
||||||
|
parsed_args.starred = False
|
||||||
|
parsed_args.exclude_starred = True
|
||||||
|
if "-not-tagged" in "".join(args):
|
||||||
|
parsed_args.tagged = False
|
||||||
|
parsed_args.exclude_tagged = True
|
||||||
|
if "-not" in args and not any(
|
||||||
|
[parsed_args.exclude_starred, parsed_args.exclude_tagged, parsed_args.excluded]
|
||||||
|
):
|
||||||
|
parser.error("argument -not: expected 1 argument")
|
||||||
|
|
||||||
|
return parsed_args
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args(args: list[str] = []) -> argparse.Namespace:
|
||||||
|
"""
|
||||||
|
Argument parsing that is doable before the config is available.
|
||||||
|
Everything else goes into "text" for later parsing.
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
formatter_class=WrappingFormatter,
|
||||||
|
add_help=False,
|
||||||
|
description="Collect your thoughts and notes without leaving the command line",
|
||||||
|
epilog=textwrap.dedent(
|
||||||
|
"""
|
||||||
|
We gratefully thank all contributors!
|
||||||
|
Come see the whole list of code and financial contributors at https://github.com/jrnl-org/jrnl
|
||||||
|
And special thanks to Bad Lip Reading for the Yoda joke in the Writing section above :)""" # noqa: E501
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
optional = parser.add_argument_group("Optional Arguments")
|
||||||
|
optional.add_argument(
|
||||||
|
"--debug",
|
||||||
|
dest="debug",
|
||||||
|
action="store_true",
|
||||||
|
help="Print information useful for troubleshooting",
|
||||||
|
)
|
||||||
|
|
||||||
|
standalone = parser.add_argument_group(
|
||||||
|
"Standalone Commands",
|
||||||
|
"These commands will exit after they complete. You may only run one at a time.",
|
||||||
|
)
|
||||||
|
standalone.add_argument("--help", action="help", help="Show this help message")
|
||||||
|
standalone.add_argument("-h", action="help", help=argparse.SUPPRESS)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--version",
|
||||||
|
action="store_const",
|
||||||
|
const=preconfig_version,
|
||||||
|
dest="preconfig_cmd",
|
||||||
|
help="Print version information",
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"-v",
|
||||||
|
action="store_const",
|
||||||
|
const=preconfig_version,
|
||||||
|
dest="preconfig_cmd",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--diagnostic",
|
||||||
|
action="store_const",
|
||||||
|
const=preconfig_diagnostic,
|
||||||
|
dest="preconfig_cmd",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--list",
|
||||||
|
action="store_const",
|
||||||
|
const=postconfig_list,
|
||||||
|
dest="postconfig_cmd",
|
||||||
|
help="""
|
||||||
|
List all configured journals.
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
|
||||||
|
--format [json or yaml]
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--ls",
|
||||||
|
action="store_const",
|
||||||
|
const=postconfig_list,
|
||||||
|
dest="postconfig_cmd",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"-ls",
|
||||||
|
action="store_const",
|
||||||
|
const=lambda **kwargs: deprecated_cmd(
|
||||||
|
"-ls", "--list or --ls", callback=postconfig_list, **kwargs
|
||||||
|
),
|
||||||
|
dest="postconfig_cmd",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--encrypt",
|
||||||
|
help="Encrypt selected journal with a password",
|
||||||
|
action="store_const",
|
||||||
|
metavar="TYPE",
|
||||||
|
const=postconfig_encrypt,
|
||||||
|
dest="postconfig_cmd",
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--decrypt",
|
||||||
|
help="Decrypt selected journal and store it in plain text",
|
||||||
|
action="store_const",
|
||||||
|
metavar="TYPE",
|
||||||
|
const=postconfig_decrypt,
|
||||||
|
dest="postconfig_cmd",
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--import",
|
||||||
|
action="store_const",
|
||||||
|
metavar="TYPE",
|
||||||
|
const=postconfig_import,
|
||||||
|
dest="postconfig_cmd",
|
||||||
|
help=f"""
|
||||||
|
Import entries from another journal.
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
|
||||||
|
--file FILENAME (default: uses stdin)
|
||||||
|
|
||||||
|
--format [{util.oxford_list(IMPORT_FORMATS)}] (default: jrnl)
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
standalone.add_argument(
|
||||||
|
"--file",
|
||||||
|
metavar="FILENAME",
|
||||||
|
dest="filename",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
standalone.add_argument("-i", dest="filename", help=argparse.SUPPRESS)
|
||||||
|
|
||||||
|
compose_msg = """
|
||||||
|
To add a new entry into your journal, simply write it on the command line:
|
||||||
|
|
||||||
|
jrnl yesterday: I was walking and I found this big log.
|
||||||
|
|
||||||
|
The date and the following colon ("yesterday:") are optional. If you leave
|
||||||
|
them out, "now" will be used:
|
||||||
|
|
||||||
|
jrnl Then I rolled the log over.
|
||||||
|
|
||||||
|
Also, you can mark extra special entries ("star" them) with an asterisk:
|
||||||
|
|
||||||
|
jrnl *And underneath was a tiny little stick.
|
||||||
|
|
||||||
|
Please note that asterisks might be a special character in your shell, so you
|
||||||
|
might have to escape them. When in doubt about escaping, put quotes around
|
||||||
|
your entire entry:
|
||||||
|
|
||||||
|
jrnl "saturday at 2am: *Then I was like 'That log had a child!'" """
|
||||||
|
|
||||||
|
composing = parser.add_argument_group(
|
||||||
|
"Writing", textwrap.dedent(compose_msg).strip()
|
||||||
|
)
|
||||||
|
composing.add_argument("text", metavar="", nargs="*")
|
||||||
|
composing.add_argument(
|
||||||
|
"--template",
|
||||||
|
dest="template",
|
||||||
|
help="Path to template file. Can be a local path, absolute path, or a path "
|
||||||
|
"relative to $XDG_DATA_HOME/jrnl/templates/",
|
||||||
|
)
|
||||||
|
|
||||||
|
read_msg = (
|
||||||
|
"To find entries from your journal, use any combination of the below filters."
|
||||||
|
)
|
||||||
|
reading = parser.add_argument_group("Searching", textwrap.dedent(read_msg))
|
||||||
|
reading.add_argument(
|
||||||
|
"-on", dest="on_date", metavar="DATE", help="Show entries on this date"
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-today-in-history",
|
||||||
|
dest="today_in_history",
|
||||||
|
action="store_true",
|
||||||
|
help="Show entries of today over the years",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-month",
|
||||||
|
dest="month",
|
||||||
|
metavar="DATE",
|
||||||
|
help="Show entries on this month of any year",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-day",
|
||||||
|
dest="day",
|
||||||
|
metavar="DATE",
|
||||||
|
help="Show entries on this day of any month",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-year",
|
||||||
|
dest="year",
|
||||||
|
metavar="DATE",
|
||||||
|
help="Show entries of a specific year",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-from",
|
||||||
|
dest="start_date",
|
||||||
|
metavar="DATE",
|
||||||
|
help="Show entries after, or on, this date",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-to",
|
||||||
|
dest="end_date",
|
||||||
|
metavar="DATE",
|
||||||
|
help="Show entries before, or on, this date (alias: -until)",
|
||||||
|
)
|
||||||
|
reading.add_argument("-until", dest="end_date", help=argparse.SUPPRESS)
|
||||||
|
reading.add_argument(
|
||||||
|
"-contains",
|
||||||
|
dest="contains",
|
||||||
|
action="append",
|
||||||
|
metavar="TEXT",
|
||||||
|
help="Show entries containing specific text (put quotes around text with "
|
||||||
|
"spaces)",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-and",
|
||||||
|
dest="strict",
|
||||||
|
action="store_true",
|
||||||
|
help='Show only entries that match all conditions, like saying "x AND y" '
|
||||||
|
"(default: OR)",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-starred",
|
||||||
|
dest="starred",
|
||||||
|
action="store_true",
|
||||||
|
help="Show only starred entries (marked with *)",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-tagged",
|
||||||
|
dest="tagged",
|
||||||
|
action="store_true",
|
||||||
|
help="Show only entries that have at least one tag",
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-n",
|
||||||
|
dest="limit",
|
||||||
|
default=None,
|
||||||
|
metavar="NUMBER",
|
||||||
|
help="Show a maximum of NUMBER entries (note: '-n 3' and '-3' have the same "
|
||||||
|
"effect)",
|
||||||
|
nargs="?",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
reading.add_argument(
|
||||||
|
"-not",
|
||||||
|
dest="excluded",
|
||||||
|
nargs="?",
|
||||||
|
default=[],
|
||||||
|
metavar="TAG/FLAG",
|
||||||
|
action=IgnoreNoneAppendAction,
|
||||||
|
help=(
|
||||||
|
"If passed a string, will exclude entries with that tag. "
|
||||||
|
"Can be also used before -starred or -tagged flags, to exclude "
|
||||||
|
"starred or tagged entries respectively."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
search_options_msg = (
|
||||||
|
" " # Preserves indentation
|
||||||
|
"""
|
||||||
|
These help you do various tasks with the selected entries from your search.
|
||||||
|
If used on their own (with no search), they will act on your entire journal"""
|
||||||
|
)
|
||||||
|
exporting = parser.add_argument_group(
|
||||||
|
"Searching Options", textwrap.dedent(search_options_msg)
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--edit",
|
||||||
|
dest="edit",
|
||||||
|
help="Opens the selected entries in your configured editor",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--delete",
|
||||||
|
dest="delete",
|
||||||
|
action="store_true",
|
||||||
|
help="Interactively deletes selected entries",
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--change-time",
|
||||||
|
dest="change_time",
|
||||||
|
nargs="?",
|
||||||
|
metavar="DATE",
|
||||||
|
const="now",
|
||||||
|
help="Change timestamp for selected entries (default: now)",
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--format",
|
||||||
|
metavar="TYPE",
|
||||||
|
dest="export",
|
||||||
|
choices=EXPORT_FORMATS,
|
||||||
|
help=f"""
|
||||||
|
Display selected entries in an alternate format.
|
||||||
|
|
||||||
|
TYPE can be: {util.oxford_list(EXPORT_FORMATS)}.
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
|
||||||
|
--file FILENAME Write output to file instead of stdout
|
||||||
|
""",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--export",
|
||||||
|
metavar="TYPE",
|
||||||
|
dest="export",
|
||||||
|
choices=EXPORT_FORMATS,
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--tags",
|
||||||
|
dest="tags",
|
||||||
|
action="store_true",
|
||||||
|
help="Alias for '--format tags'. Returns a list of all tags and number of "
|
||||||
|
"occurrences",
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"--short",
|
||||||
|
dest="short",
|
||||||
|
action="store_true",
|
||||||
|
help="Show only titles or line containing the search tags",
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"-s",
|
||||||
|
dest="short",
|
||||||
|
action="store_true",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
exporting.add_argument(
|
||||||
|
"-o",
|
||||||
|
dest="filename",
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
config_overrides = parser.add_argument_group(
|
||||||
|
"Config file override",
|
||||||
|
textwrap.dedent("Apply a one-off override of the config file option"),
|
||||||
|
)
|
||||||
|
config_overrides.add_argument(
|
||||||
|
"--config-override",
|
||||||
|
dest="config_override",
|
||||||
|
action="append",
|
||||||
|
type=str,
|
||||||
|
nargs=2,
|
||||||
|
default=[],
|
||||||
|
metavar="CONFIG_KV_PAIR",
|
||||||
|
help="""
|
||||||
|
Override configured key-value pair with CONFIG_KV_PAIR for this command invocation only.
|
||||||
|
|
||||||
|
Examples: \n
|
||||||
|
\t - Use a different editor for this jrnl entry, call: \n
|
||||||
|
\t jrnl --config-override editor "nano" \n
|
||||||
|
\t - Override color selections\n
|
||||||
|
\t jrnl --config-override colors.body blue --config-override colors.title green
|
||||||
|
""", # noqa: E501
|
||||||
|
)
|
||||||
|
config_overrides.add_argument(
|
||||||
|
"--co",
|
||||||
|
dest="config_override",
|
||||||
|
action="append",
|
||||||
|
type=str,
|
||||||
|
nargs=2,
|
||||||
|
default=[],
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
alternate_config = parser.add_argument_group(
|
||||||
|
"Specifies alternate config to be used",
|
||||||
|
textwrap.dedent("Applies alternate config for current session"),
|
||||||
|
)
|
||||||
|
|
||||||
|
alternate_config.add_argument(
|
||||||
|
"--config-file",
|
||||||
|
dest="config_file_path",
|
||||||
|
type=str,
|
||||||
|
default="",
|
||||||
|
help="""
|
||||||
|
Overrides default (created when first installed) config file for this command only.
|
||||||
|
|
||||||
|
Examples: \n
|
||||||
|
\t - Use a work config file for this jrnl entry, call: \n
|
||||||
|
\t jrnl --config-file /home/user1/work_config.yaml
|
||||||
|
\t - Use a personal config file stored on a thumb drive: \n
|
||||||
|
\t jrnl --config-file /media/user1/my-thumb-drive/personal_config.yaml
|
||||||
|
""", # noqa: E501
|
||||||
|
)
|
||||||
|
|
||||||
|
alternate_config.add_argument(
|
||||||
|
"--cf", dest="config_file_path", type=str, default="", help=argparse.SUPPRESS
|
||||||
|
)
|
||||||
|
|
||||||
|
# Handle '-123' as a shortcut for '-n 123'
|
||||||
|
num = re.compile(r"^-(\d+)$")
|
||||||
|
args = [num.sub(r"-n \1", arg) for arg in args]
|
||||||
|
parsed_args = parser.parse_intermixed_args(args)
|
||||||
|
parsed_args = parse_not_arg(args, parsed_args, parser)
|
||||||
|
|
||||||
|
return parsed_args
|
502
jrnl/cli.py
|
@ -1,502 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
"""
|
|
||||||
jrnl
|
|
||||||
|
|
||||||
license: GPLv3, see LICENSE.md for more details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import jrnl
|
|
||||||
|
|
||||||
from . import install, plugins, util
|
|
||||||
from .Journal import PlainJournal, open_journal
|
|
||||||
from .util import ERROR_COLOR, RESET_COLOR, UserAbort
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
logging.getLogger("keyring.backend").setLevel(logging.ERROR)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args(args=None):
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument(
|
|
||||||
"-v",
|
|
||||||
"--version",
|
|
||||||
dest="version",
|
|
||||||
action="store_true",
|
|
||||||
help="prints version information and exits",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-ls", dest="ls", action="store_true", help="displays accessible journals"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-d", "--debug", dest="debug", action="store_true", help="execute in debug mode"
|
|
||||||
)
|
|
||||||
|
|
||||||
composing = parser.add_argument_group(
|
|
||||||
"Composing",
|
|
||||||
'To write an entry simply write it on the command line, e.g. "jrnl yesterday at 1pm: Went to the gym."',
|
|
||||||
)
|
|
||||||
composing.add_argument("text", metavar="", nargs="*")
|
|
||||||
|
|
||||||
reading = parser.add_argument_group(
|
|
||||||
"Reading",
|
|
||||||
"Specifying either of these parameters will display posts of your journal",
|
|
||||||
)
|
|
||||||
reading.add_argument(
|
|
||||||
"-from", dest="start_date", metavar="DATE", help="View entries after this date"
|
|
||||||
)
|
|
||||||
reading.add_argument(
|
|
||||||
"-until",
|
|
||||||
"-to",
|
|
||||||
dest="end_date",
|
|
||||||
metavar="DATE",
|
|
||||||
help="View entries before this date",
|
|
||||||
)
|
|
||||||
reading.add_argument(
|
|
||||||
"-contains", dest="contains", help="View entries containing a specific string"
|
|
||||||
)
|
|
||||||
reading.add_argument(
|
|
||||||
"-on", dest="on_date", metavar="DATE", help="View entries on this date"
|
|
||||||
)
|
|
||||||
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",
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"--tags",
|
|
||||||
dest="tags",
|
|
||||||
action="store_true",
|
|
||||||
help="Returns a list of all tags and number of occurences",
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"--export",
|
|
||||||
metavar="TYPE",
|
|
||||||
dest="export",
|
|
||||||
choices=plugins.EXPORT_FORMATS,
|
|
||||||
help="Export your journal. TYPE can be {}.".format(
|
|
||||||
plugins.util.oxford_list(plugins.EXPORT_FORMATS)
|
|
||||||
),
|
|
||||||
default=False,
|
|
||||||
const=None,
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"-o",
|
|
||||||
metavar="OUTPUT",
|
|
||||||
dest="output",
|
|
||||||
help="Optionally specifies output file when using --export. If OUTPUT is a directory, exports each entry into an individual file instead.",
|
|
||||||
default=False,
|
|
||||||
const=None,
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"--import",
|
|
||||||
metavar="TYPE",
|
|
||||||
dest="import_",
|
|
||||||
choices=plugins.IMPORT_FORMATS,
|
|
||||||
help="Import entries into your journal. TYPE can be {}, and it defaults to jrnl if nothing else is specified.".format(
|
|
||||||
plugins.util.oxford_list(plugins.IMPORT_FORMATS)
|
|
||||||
),
|
|
||||||
default=False,
|
|
||||||
const="jrnl",
|
|
||||||
nargs="?",
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"-i",
|
|
||||||
metavar="INPUT",
|
|
||||||
dest="input",
|
|
||||||
help="Optionally specifies input file when using --import.",
|
|
||||||
default=False,
|
|
||||||
const=None,
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"--encrypt",
|
|
||||||
metavar="FILENAME",
|
|
||||||
dest="encrypt",
|
|
||||||
help="Encrypts your existing journal with a new password",
|
|
||||||
nargs="?",
|
|
||||||
default=False,
|
|
||||||
const=None,
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"--decrypt",
|
|
||||||
metavar="FILENAME",
|
|
||||||
dest="decrypt",
|
|
||||||
help="Decrypts your journal and stores it in plain text",
|
|
||||||
nargs="?",
|
|
||||||
default=False,
|
|
||||||
const=None,
|
|
||||||
)
|
|
||||||
exporting.add_argument(
|
|
||||||
"--edit",
|
|
||||||
dest="edit",
|
|
||||||
help="Opens your editor to edit the selected entries.",
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
|
|
||||||
exporting.add_argument(
|
|
||||||
"--delete",
|
|
||||||
dest="delete",
|
|
||||||
action="store_true",
|
|
||||||
help="Opens an interactive interface for deleting entries.",
|
|
||||||
)
|
|
||||||
|
|
||||||
if not args:
|
|
||||||
args = []
|
|
||||||
|
|
||||||
# Handle '-123' as a shortcut for '-n 123'
|
|
||||||
num = re.compile(r"^-(\d+)$")
|
|
||||||
args = [num.sub(r"-n \1", arg) for arg in args]
|
|
||||||
|
|
||||||
return parser.parse_args(args)
|
|
||||||
|
|
||||||
|
|
||||||
def guess_mode(args, config):
|
|
||||||
"""Guesses the mode (compose, read or export) from the given arguments"""
|
|
||||||
compose = True
|
|
||||||
export = False
|
|
||||||
import_ = False
|
|
||||||
if args.import_ is not False:
|
|
||||||
compose = False
|
|
||||||
export = False
|
|
||||||
import_ = True
|
|
||||||
elif (
|
|
||||||
args.decrypt is not False
|
|
||||||
or args.encrypt is not False
|
|
||||||
or args.export is not False
|
|
||||||
or any((args.short, args.tags, args.edit, args.delete))
|
|
||||||
):
|
|
||||||
compose = False
|
|
||||||
export = True
|
|
||||||
elif any(
|
|
||||||
(
|
|
||||||
args.start_date,
|
|
||||||
args.end_date,
|
|
||||||
args.on_date,
|
|
||||||
args.limit,
|
|
||||||
args.strict,
|
|
||||||
args.starred,
|
|
||||||
args.contains,
|
|
||||||
)
|
|
||||||
):
|
|
||||||
# Any sign of displaying stuff?
|
|
||||||
compose = False
|
|
||||||
elif args.text and all(
|
|
||||||
word[0] in config["tagsymbols"] for word in " ".join(args.text).split()
|
|
||||||
):
|
|
||||||
# No date and only tags?
|
|
||||||
compose = False
|
|
||||||
|
|
||||||
return compose, export, import_
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(journal, filename=None):
|
|
||||||
""" Encrypt into new file. If filename is not set, we encrypt the journal file itself. """
|
|
||||||
from .EncryptedJournal import EncryptedJournal
|
|
||||||
|
|
||||||
journal.config["encrypt"] = True
|
|
||||||
|
|
||||||
new_journal = EncryptedJournal.from_journal(journal)
|
|
||||||
new_journal.write(filename)
|
|
||||||
|
|
||||||
print(
|
|
||||||
"Journal encrypted to {}.".format(filename or new_journal.config["journal"]),
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(journal, filename=None):
|
|
||||||
""" Decrypts into new file. If filename is not set, we encrypt the journal file itself. """
|
|
||||||
journal.config["encrypt"] = False
|
|
||||||
|
|
||||||
new_journal = PlainJournal.from_journal(journal)
|
|
||||||
new_journal.write(filename)
|
|
||||||
print(
|
|
||||||
"Journal decrypted to {}.".format(filename or new_journal.config["journal"]),
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def list_journals(config):
|
|
||||||
"""List the journals specified in the configuration file"""
|
|
||||||
result = f"Journals defined in {install.CONFIG_FILE_PATH}\n"
|
|
||||||
ml = min(max(len(k) for k in config["journals"]), 20)
|
|
||||||
for journal, cfg in config["journals"].items():
|
|
||||||
result += " * {:{}} -> {}\n".format(
|
|
||||||
journal, ml, cfg["journal"] if isinstance(cfg, dict) else cfg
|
|
||||||
)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def update_config(config, new_config, scope, force_local=False):
|
|
||||||
"""Updates a config dict with new values - either global if scope is None
|
|
||||||
or config['journals'][scope] is just a string pointing to a journal file,
|
|
||||||
or within the scope"""
|
|
||||||
if scope and type(config["journals"][scope]) is dict: # Update to journal specific
|
|
||||||
config["journals"][scope].update(new_config)
|
|
||||||
elif scope and force_local: # Convert to dict
|
|
||||||
config["journals"][scope] = {"journal": config["journals"][scope]}
|
|
||||||
config["journals"][scope].update(new_config)
|
|
||||||
else:
|
|
||||||
config.update(new_config)
|
|
||||||
|
|
||||||
|
|
||||||
def configure_logger(debug=False):
|
|
||||||
logging.basicConfig(
|
|
||||||
level=logging.DEBUG if debug else logging.INFO,
|
|
||||||
format="%(levelname)-8s %(name)-12s %(message)s",
|
|
||||||
)
|
|
||||||
logging.getLogger("parsedatetime").setLevel(
|
|
||||||
logging.INFO
|
|
||||||
) # disable parsedatetime debug logging
|
|
||||||
|
|
||||||
|
|
||||||
def run(manual_args=None):
|
|
||||||
if manual_args is None:
|
|
||||||
manual_args = sys.argv[1:]
|
|
||||||
|
|
||||||
args = parse_args(manual_args)
|
|
||||||
|
|
||||||
configure_logger(args.debug)
|
|
||||||
if args.version:
|
|
||||||
version_str = f"{jrnl.__title__} version {jrnl.__version__}"
|
|
||||||
print(version_str)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
try:
|
|
||||||
config = install.load_or_install_jrnl()
|
|
||||||
except UserAbort as err:
|
|
||||||
print(f"\n{err}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if args.ls:
|
|
||||||
print(list_journals(config))
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
log.debug('Using configuration "%s"', config)
|
|
||||||
original_config = config.copy()
|
|
||||||
|
|
||||||
# If the first textual argument points to a journal file,
|
|
||||||
# use this!
|
|
||||||
|
|
||||||
journal_name = install.DEFAULT_JOURNAL_KEY
|
|
||||||
if args.text and args.text[0] in config["journals"]:
|
|
||||||
journal_name = args.text[0]
|
|
||||||
args.text = args.text[1:]
|
|
||||||
elif install.DEFAULT_JOURNAL_KEY not in config["journals"]:
|
|
||||||
print("No default journal configured.", file=sys.stderr)
|
|
||||||
print(list_journals(config), file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
config = util.scope_config(config, journal_name)
|
|
||||||
|
|
||||||
log.debug('Using journal "%s"', journal_name)
|
|
||||||
|
|
||||||
mode_compose, mode_export, mode_import = guess_mode(args, config)
|
|
||||||
|
|
||||||
# How to quit writing?
|
|
||||||
if "win32" in sys.platform:
|
|
||||||
_exit_multiline_code = "on a blank line, press Ctrl+Z and then Enter"
|
|
||||||
else:
|
|
||||||
_exit_multiline_code = "press Ctrl+D"
|
|
||||||
|
|
||||||
# This is where we finally open the journal!
|
|
||||||
try:
|
|
||||||
journal = open_journal(journal_name, config)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("[Interrupted while opening journal]", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if mode_compose and not args.text:
|
|
||||||
if not sys.stdin.isatty():
|
|
||||||
# Piping data into jrnl
|
|
||||||
raw = sys.stdin.read()
|
|
||||||
elif config["editor"]:
|
|
||||||
template = ""
|
|
||||||
if config["template"]:
|
|
||||||
try:
|
|
||||||
template = open(config["template"]).read()
|
|
||||||
except OSError:
|
|
||||||
print(
|
|
||||||
f"[Could not read template at '{config['template']}']",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
raw = util.get_text_from_editor(config, template)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
print(
|
|
||||||
"[Compose Entry; " + _exit_multiline_code + " to finish writing]\n",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
raw = sys.stdin.read()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("[Entry NOT saved to journal.]", file=sys.stderr)
|
|
||||||
sys.exit(0)
|
|
||||||
if raw:
|
|
||||||
args.text = [raw]
|
|
||||||
else:
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# Import mode
|
|
||||||
if mode_import:
|
|
||||||
plugins.get_importer(args.import_).import_(journal, args.input)
|
|
||||||
|
|
||||||
# Writing mode
|
|
||||||
elif mode_compose:
|
|
||||||
raw = " ".join(args.text).strip()
|
|
||||||
log.debug('Appending raw line "%s" to journal "%s"', raw, journal_name)
|
|
||||||
journal.new_entry(raw)
|
|
||||||
print(f"[Entry added to {journal_name} journal]", file=sys.stderr)
|
|
||||||
journal.write()
|
|
||||||
|
|
||||||
if not mode_compose:
|
|
||||||
old_entries = journal.entries
|
|
||||||
if args.on_date:
|
|
||||||
args.start_date = args.end_date = args.on_date
|
|
||||||
journal.filter(
|
|
||||||
tags=args.text,
|
|
||||||
start_date=args.start_date,
|
|
||||||
end_date=args.end_date,
|
|
||||||
strict=args.strict,
|
|
||||||
short=args.short,
|
|
||||||
starred=args.starred,
|
|
||||||
exclude=args.excluded,
|
|
||||||
contains=args.contains,
|
|
||||||
)
|
|
||||||
journal.limit(args.limit)
|
|
||||||
|
|
||||||
# Reading mode
|
|
||||||
if not mode_compose and not mode_export and not mode_import:
|
|
||||||
print(journal.pprint())
|
|
||||||
|
|
||||||
# Various export modes
|
|
||||||
elif args.short:
|
|
||||||
print(journal.pprint(short=True))
|
|
||||||
|
|
||||||
elif args.tags:
|
|
||||||
print(plugins.get_exporter("tags").export(journal))
|
|
||||||
|
|
||||||
elif args.export is not False:
|
|
||||||
exporter = plugins.get_exporter(args.export)
|
|
||||||
print(exporter.export(journal, args.output))
|
|
||||||
|
|
||||||
elif args.encrypt is not False:
|
|
||||||
encrypt(journal, filename=args.encrypt)
|
|
||||||
# Not encrypting to a separate file: update config!
|
|
||||||
if not args.encrypt:
|
|
||||||
update_config(
|
|
||||||
original_config, {"encrypt": True}, journal_name, force_local=True
|
|
||||||
)
|
|
||||||
install.save_config(original_config)
|
|
||||||
|
|
||||||
elif args.decrypt is not False:
|
|
||||||
decrypt(journal, filename=args.decrypt)
|
|
||||||
# Not decrypting to a separate file: update config!
|
|
||||||
if not args.decrypt:
|
|
||||||
update_config(
|
|
||||||
original_config, {"encrypt": False}, journal_name, force_local=True
|
|
||||||
)
|
|
||||||
install.save_config(original_config)
|
|
||||||
|
|
||||||
elif args.edit:
|
|
||||||
if not config["editor"]:
|
|
||||||
print(
|
|
||||||
"[{1}ERROR{2}: You need to specify an editor in {0} to use the --edit function.]".format(
|
|
||||||
install.CONFIG_FILE_PATH, ERROR_COLOR, RESET_COLOR
|
|
||||||
),
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
other_entries = [e for e in old_entries if e not in journal.entries]
|
|
||||||
# Edit
|
|
||||||
old_num_entries = len(journal)
|
|
||||||
edited = util.get_text_from_editor(config, journal.editable_str())
|
|
||||||
journal.parse_editable_str(edited)
|
|
||||||
num_deleted = old_num_entries - len(journal)
|
|
||||||
num_edited = len([e for e in journal.entries if e.modified])
|
|
||||||
prompts = []
|
|
||||||
if num_deleted:
|
|
||||||
prompts.append(
|
|
||||||
"{} {} deleted".format(
|
|
||||||
num_deleted, "entry" if num_deleted == 1 else "entries"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if num_edited:
|
|
||||||
prompts.append(
|
|
||||||
"{} {} modified".format(
|
|
||||||
num_edited, "entry" if num_deleted == 1 else "entries"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if prompts:
|
|
||||||
print("[{}]".format(", ".join(prompts).capitalize()), file=sys.stderr)
|
|
||||||
journal.entries += other_entries
|
|
||||||
journal.sort()
|
|
||||||
journal.write()
|
|
||||||
|
|
||||||
elif args.delete:
|
|
||||||
if journal.entries:
|
|
||||||
entries_to_delete = journal.prompt_delete_entries()
|
|
||||||
|
|
||||||
if entries_to_delete:
|
|
||||||
journal.entries = old_entries
|
|
||||||
journal.delete_entries(entries_to_delete)
|
|
||||||
|
|
||||||
journal.write()
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
"No entries deleted, because the search returned no results.",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
83
jrnl/color.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import re
|
||||||
|
from string import punctuation
|
||||||
|
from string import whitespace
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import colorama
|
||||||
|
|
||||||
|
from jrnl.os_compat import on_windows
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from jrnl.journals import Entry
|
||||||
|
|
||||||
|
if on_windows():
|
||||||
|
colorama.init()
|
||||||
|
|
||||||
|
|
||||||
|
def colorize(string: str, color: str, bold: bool = False) -> str:
|
||||||
|
"""Returns the string colored with colorama.Fore.color. If the color set by
|
||||||
|
the user is "NONE" or the color doesn't exist in the colorama.Fore attributes,
|
||||||
|
it returns the string without any modification."""
|
||||||
|
color_escape = getattr(colorama.Fore, color.upper(), None)
|
||||||
|
if not color_escape:
|
||||||
|
return string
|
||||||
|
elif not bold:
|
||||||
|
return color_escape + string + colorama.Fore.RESET
|
||||||
|
else:
|
||||||
|
return colorama.Style.BRIGHT + color_escape + string + colorama.Style.RESET_ALL
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_tags_with_background_color(
|
||||||
|
entry: "Entry", text: str, color: str, is_title: bool = False
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Takes a string and colorizes the tags in it based upon the config value for
|
||||||
|
color.tags, while colorizing the rest of the text based on `color`.
|
||||||
|
:param entry: Entry object, for access to journal config
|
||||||
|
:param text: Text to be colorized
|
||||||
|
:param color: Color for non-tag text, passed to colorize()
|
||||||
|
:param is_title: Boolean flag indicating if the text is a title or not
|
||||||
|
:return: Colorized str
|
||||||
|
"""
|
||||||
|
|
||||||
|
def colorized_text_generator(fragments):
|
||||||
|
"""Efficiently generate colorized tags / text from text fragments.
|
||||||
|
Taken from @shobrook. Thanks, buddy :)
|
||||||
|
:param fragments: List of strings representing parts of entry (tag or word).
|
||||||
|
:rtype: List of tuples
|
||||||
|
:returns [(colorized_str, original_str)]"""
|
||||||
|
for part in fragments:
|
||||||
|
if part and part[0] not in config["tagsymbols"]:
|
||||||
|
yield colorize(part, color, bold=is_title), part
|
||||||
|
elif part:
|
||||||
|
yield colorize(part, config["colors"]["tags"], bold=True), part
|
||||||
|
|
||||||
|
config = entry.journal.config
|
||||||
|
if config["highlight"]: # highlight tags
|
||||||
|
text_fragments = re.split(entry.tag_regex(config["tagsymbols"]), text)
|
||||||
|
|
||||||
|
# Colorizing tags inside of other blocks of text
|
||||||
|
final_text = ""
|
||||||
|
previous_piece = ""
|
||||||
|
for colorized_piece, piece in colorized_text_generator(text_fragments):
|
||||||
|
# If this piece is entirely punctuation or whitespace or the start
|
||||||
|
# of a line or the previous piece was a tag or this piece is a tag,
|
||||||
|
# then add it to the final text without a leading space.
|
||||||
|
if (
|
||||||
|
all(char in punctuation + whitespace for char in piece)
|
||||||
|
or previous_piece.endswith("\n")
|
||||||
|
or (previous_piece and previous_piece[0] in config["tagsymbols"])
|
||||||
|
or piece[0] in config["tagsymbols"]
|
||||||
|
):
|
||||||
|
final_text += colorized_piece
|
||||||
|
else:
|
||||||
|
# Otherwise add a leading space and then append the piece.
|
||||||
|
final_text += " " + colorized_piece
|
||||||
|
|
||||||
|
previous_piece = piece
|
||||||
|
return final_text.lstrip()
|
||||||
|
else:
|
||||||
|
return text
|
182
jrnl/commands.py
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
"""
|
||||||
|
Functions in this file are standalone commands. All standalone commands are split into
|
||||||
|
two categories depending on whether they require the config to be loaded to be able to
|
||||||
|
run.
|
||||||
|
|
||||||
|
1. "preconfig" commands don't require the config at all, and can be run before the
|
||||||
|
config has been loaded.
|
||||||
|
2. "postconfig" commands require to config to have already been loaded, parsed, and
|
||||||
|
scoped before they can be run.
|
||||||
|
|
||||||
|
Also, please note that all (non-builtin) imports should be scoped to each function to
|
||||||
|
avoid any possible overhead for these standalone commands.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from jrnl.config import cmd_requires_valid_journal_name
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
from jrnl.messages import Message
|
||||||
|
from jrnl.messages import MsgStyle
|
||||||
|
from jrnl.messages import MsgText
|
||||||
|
from jrnl.output import print_msg
|
||||||
|
|
||||||
|
|
||||||
|
def preconfig_diagnostic(_) -> None:
|
||||||
|
from jrnl import __title__
|
||||||
|
from jrnl import __version__
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"{__title__}: {__version__}\n"
|
||||||
|
f"Python: {sys.version}\n"
|
||||||
|
f"OS: {platform.system()} {platform.release()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def preconfig_version(_) -> None:
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from jrnl import __title__
|
||||||
|
from jrnl import __version__
|
||||||
|
|
||||||
|
output = f"""
|
||||||
|
{__title__} {__version__}
|
||||||
|
|
||||||
|
Copyright © 2012-2023 jrnl contributors
|
||||||
|
|
||||||
|
This is free software, and you are welcome to redistribute it under certain
|
||||||
|
conditions; for details, see: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
output = textwrap.dedent(output).strip()
|
||||||
|
|
||||||
|
print(output)
|
||||||
|
|
||||||
|
|
||||||
|
def postconfig_list(args: argparse.Namespace, config: dict, **_) -> int:
|
||||||
|
from jrnl.output import list_journals
|
||||||
|
|
||||||
|
print(list_journals(config, args.export))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_requires_valid_journal_name
|
||||||
|
def postconfig_import(args: argparse.Namespace, config: dict, **_) -> int:
|
||||||
|
from jrnl.journals import open_journal
|
||||||
|
from jrnl.plugins import get_importer
|
||||||
|
|
||||||
|
# Requires opening the journal
|
||||||
|
journal = open_journal(args.journal_name, config)
|
||||||
|
|
||||||
|
format = args.export if args.export else "jrnl"
|
||||||
|
|
||||||
|
if (importer := get_importer(format)) is None:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.ImporterNotFound,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{"format": format},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
importer.import_(journal, args.filename)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_requires_valid_journal_name
|
||||||
|
def postconfig_encrypt(
|
||||||
|
args: argparse.Namespace, config: dict, original_config: dict
|
||||||
|
) -> int:
|
||||||
|
"""
|
||||||
|
Encrypt a journal in place, or optionally to a new file
|
||||||
|
"""
|
||||||
|
from jrnl.config import update_config
|
||||||
|
from jrnl.install import save_config
|
||||||
|
from jrnl.journals import open_journal
|
||||||
|
|
||||||
|
# Open the journal
|
||||||
|
journal = open_journal(args.journal_name, config)
|
||||||
|
|
||||||
|
if hasattr(journal, "can_be_encrypted") and not journal.can_be_encrypted:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.CannotEncryptJournalType,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"journal_name": args.journal_name,
|
||||||
|
"journal_type": journal.__class__.__name__,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# If journal is encrypted, create new password
|
||||||
|
logging.debug("Clearing encryption method...")
|
||||||
|
|
||||||
|
if journal.config["encrypt"] is True:
|
||||||
|
logging.debug("Journal already encrypted. Re-encrypting...")
|
||||||
|
print(f"Journal {journal.name} is already encrypted. Create a new password.")
|
||||||
|
journal.encryption_method.clear()
|
||||||
|
else:
|
||||||
|
journal.config["encrypt"] = True
|
||||||
|
journal.encryption_method = None
|
||||||
|
|
||||||
|
journal.write(args.filename)
|
||||||
|
|
||||||
|
print_msg(
|
||||||
|
Message(
|
||||||
|
MsgText.JournalEncryptedTo,
|
||||||
|
MsgStyle.NORMAL,
|
||||||
|
{"path": args.filename or journal.config["journal"]},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update the config, if we encrypted in place
|
||||||
|
if not args.filename:
|
||||||
|
update_config(
|
||||||
|
original_config, {"encrypt": True}, args.journal_name, force_local=True
|
||||||
|
)
|
||||||
|
save_config(original_config)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_requires_valid_journal_name
|
||||||
|
def postconfig_decrypt(
|
||||||
|
args: argparse.Namespace, config: dict, original_config: dict
|
||||||
|
) -> int:
|
||||||
|
"""Decrypts to file. If filename is not set, we encrypt the journal file itself."""
|
||||||
|
from jrnl.config import update_config
|
||||||
|
from jrnl.install import save_config
|
||||||
|
from jrnl.journals import open_journal
|
||||||
|
|
||||||
|
journal = open_journal(args.journal_name, config)
|
||||||
|
|
||||||
|
logging.debug("Clearing encryption method...")
|
||||||
|
journal.config["encrypt"] = False
|
||||||
|
journal.encryption_method = None
|
||||||
|
|
||||||
|
journal.write(args.filename)
|
||||||
|
print_msg(
|
||||||
|
Message(
|
||||||
|
MsgText.JournalDecryptedTo,
|
||||||
|
MsgStyle.NORMAL,
|
||||||
|
{"path": args.filename or journal.config["journal"]},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update the config, if we decrypted in place
|
||||||
|
if not args.filename:
|
||||||
|
update_config(
|
||||||
|
original_config, {"encrypt": False}, args.journal_name, force_local=True
|
||||||
|
)
|
||||||
|
save_config(original_config)
|
||||||
|
|
||||||
|
return 0
|
229
jrnl/config.py
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from typing import Any
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
import colorama
|
||||||
|
from rich.pretty import pretty_repr
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
from ruamel.yaml import constructor
|
||||||
|
|
||||||
|
from jrnl import __version__
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
from jrnl.messages import Message
|
||||||
|
from jrnl.messages import MsgStyle
|
||||||
|
from jrnl.messages import MsgText
|
||||||
|
from jrnl.output import list_journals
|
||||||
|
from jrnl.output import print_msg
|
||||||
|
from jrnl.path import get_config_path
|
||||||
|
from jrnl.path import get_default_journal_path
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
DEFAULT_JOURNAL_KEY = "default"
|
||||||
|
|
||||||
|
YAML_SEPARATOR = ": "
|
||||||
|
YAML_FILE_ENCODING = "utf-8"
|
||||||
|
|
||||||
|
|
||||||
|
def make_yaml_valid_dict(input: list) -> dict:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Convert a two-element list of configuration key-value pair into a flat dict.
|
||||||
|
|
||||||
|
The dict is created through the yaml loader, with the assumption that
|
||||||
|
"input[0]: input[1]" is valid yaml.
|
||||||
|
|
||||||
|
:param input: list of configuration keys in dot-notation and their respective values
|
||||||
|
:type input: list
|
||||||
|
:return: A single level dict of the configuration keys in dot-notation and their
|
||||||
|
respective desired values
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert len(input) == 2
|
||||||
|
|
||||||
|
# yaml compatible strings are of the form Key:Value
|
||||||
|
yamlstr = YAML_SEPARATOR.join(input)
|
||||||
|
|
||||||
|
runtime_modifications = YAML(typ="safe").load(yamlstr)
|
||||||
|
|
||||||
|
return runtime_modifications
|
||||||
|
|
||||||
|
|
||||||
|
def save_config(config: dict, alt_config_path: str | None = None) -> None:
|
||||||
|
"""Supply alt_config_path if using an alternate config through --config-file."""
|
||||||
|
config["version"] = __version__
|
||||||
|
|
||||||
|
yaml = YAML(typ="safe")
|
||||||
|
yaml.default_flow_style = False # prevents collapsing of tree structure
|
||||||
|
|
||||||
|
with open(
|
||||||
|
alt_config_path if alt_config_path else get_config_path(),
|
||||||
|
"w",
|
||||||
|
encoding=YAML_FILE_ENCODING,
|
||||||
|
) as f:
|
||||||
|
yaml.dump(config, f)
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_config() -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"version": __version__,
|
||||||
|
"journals": {"default": {"journal": get_default_journal_path()}},
|
||||||
|
"editor": os.getenv("VISUAL") or os.getenv("EDITOR") or "",
|
||||||
|
"encrypt": False,
|
||||||
|
"template": False,
|
||||||
|
"default_hour": 9,
|
||||||
|
"default_minute": 0,
|
||||||
|
"timeformat": "%F %r",
|
||||||
|
"tagsymbols": "#@",
|
||||||
|
"highlight": True,
|
||||||
|
"linewrap": 79,
|
||||||
|
"indent_character": "|",
|
||||||
|
"colors": {
|
||||||
|
"body": "none",
|
||||||
|
"date": "none",
|
||||||
|
"tags": "none",
|
||||||
|
"title": "none",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_colors() -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"body": "none",
|
||||||
|
"date": "black",
|
||||||
|
"tags": "yellow",
|
||||||
|
"title": "cyan",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def scope_config(config: dict, journal_name: str) -> dict:
|
||||||
|
if journal_name not in config["journals"]:
|
||||||
|
return config
|
||||||
|
config = config.copy()
|
||||||
|
journal_conf = config["journals"].get(journal_name)
|
||||||
|
if isinstance(journal_conf, dict):
|
||||||
|
# We can override the default config on a by-journal basis
|
||||||
|
logging.debug(
|
||||||
|
"Updating configuration with specific journal overrides:\n%s",
|
||||||
|
pretty_repr(journal_conf),
|
||||||
|
)
|
||||||
|
config.update(journal_conf)
|
||||||
|
else:
|
||||||
|
# But also just give them a string to point to the journal file
|
||||||
|
config["journal"] = journal_conf
|
||||||
|
|
||||||
|
logging.debug("Scoped config:\n%s", pretty_repr(config))
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def verify_config_colors(config: dict) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures the keys set for colors are valid colorama.Fore attributes, or "None"
|
||||||
|
:return: True if all keys are set correctly, False otherwise
|
||||||
|
"""
|
||||||
|
all_valid_colors = True
|
||||||
|
for key, color in config["colors"].items():
|
||||||
|
upper_color = color.upper()
|
||||||
|
if upper_color == "NONE":
|
||||||
|
continue
|
||||||
|
if not getattr(colorama.Fore, upper_color, None):
|
||||||
|
print_msg(
|
||||||
|
Message(
|
||||||
|
MsgText.InvalidColor,
|
||||||
|
MsgStyle.NORMAL,
|
||||||
|
{
|
||||||
|
"key": key,
|
||||||
|
"color": color,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
all_valid_colors = False
|
||||||
|
return all_valid_colors
|
||||||
|
|
||||||
|
|
||||||
|
def load_config(config_path: str) -> dict:
|
||||||
|
"""Tries to load a config file from YAML."""
|
||||||
|
try:
|
||||||
|
with open(config_path, encoding=YAML_FILE_ENCODING) as f:
|
||||||
|
yaml = YAML(typ="safe")
|
||||||
|
yaml.allow_duplicate_keys = False
|
||||||
|
return yaml.load(f)
|
||||||
|
except constructor.DuplicateKeyError as e:
|
||||||
|
print_msg(
|
||||||
|
Message(
|
||||||
|
MsgText.ConfigDoubleKeys,
|
||||||
|
MsgStyle.WARNING,
|
||||||
|
{
|
||||||
|
"error_message": e,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with open(config_path, encoding=YAML_FILE_ENCODING) as f:
|
||||||
|
yaml = YAML(typ="safe")
|
||||||
|
yaml.allow_duplicate_keys = True
|
||||||
|
return yaml.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def is_config_json(config_path: str) -> bool:
|
||||||
|
with open(config_path, "r", encoding="utf-8") as f:
|
||||||
|
config_file = f.read()
|
||||||
|
return config_file.strip().startswith("{")
|
||||||
|
|
||||||
|
|
||||||
|
def update_config(
|
||||||
|
config: dict, new_config: dict, scope: str | None, force_local: bool = False
|
||||||
|
) -> None:
|
||||||
|
"""Updates a config dict with new values - either global if scope is None
|
||||||
|
or config['journals'][scope] is just a string pointing to a journal file,
|
||||||
|
or within the scope"""
|
||||||
|
if scope and isinstance(config["journals"][scope], dict):
|
||||||
|
config["journals"][scope].update(new_config)
|
||||||
|
elif scope and force_local: # Convert to dict
|
||||||
|
config["journals"][scope] = {"journal": config["journals"][scope]}
|
||||||
|
config["journals"][scope].update(new_config)
|
||||||
|
else:
|
||||||
|
config.update(new_config)
|
||||||
|
|
||||||
|
|
||||||
|
def get_journal_name(args: argparse.Namespace, config: dict) -> argparse.Namespace:
|
||||||
|
args.journal_name = DEFAULT_JOURNAL_KEY
|
||||||
|
|
||||||
|
# The first arg might be a journal name
|
||||||
|
if args.text:
|
||||||
|
potential_journal_name = args.text[0]
|
||||||
|
if potential_journal_name[-1] == ":":
|
||||||
|
potential_journal_name = potential_journal_name[0:-1]
|
||||||
|
|
||||||
|
if potential_journal_name in config["journals"]:
|
||||||
|
args.journal_name = potential_journal_name
|
||||||
|
args.text = args.text[1:]
|
||||||
|
|
||||||
|
logging.debug("Using journal name: %s", args.journal_name)
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_requires_valid_journal_name(func: Callable) -> Callable:
|
||||||
|
def wrapper(args: argparse.Namespace, config: dict, original_config: dict):
|
||||||
|
validate_journal_name(args.journal_name, config)
|
||||||
|
func(args=args, config=config, original_config=original_config)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def validate_journal_name(journal_name: str, config: dict) -> None:
|
||||||
|
if journal_name not in config["journals"]:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.NoNamedJournal,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"journal_name": journal_name,
|
||||||
|
"journals": list_journals(config),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
455
jrnl/controller.py
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from jrnl import install
|
||||||
|
from jrnl import plugins
|
||||||
|
from jrnl import time
|
||||||
|
from jrnl.config import DEFAULT_JOURNAL_KEY
|
||||||
|
from jrnl.config import get_config_path
|
||||||
|
from jrnl.config import get_journal_name
|
||||||
|
from jrnl.config import scope_config
|
||||||
|
from jrnl.editor import get_text_from_editor
|
||||||
|
from jrnl.editor import get_text_from_stdin
|
||||||
|
from jrnl.editor import read_template_file
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
from jrnl.journals import open_journal
|
||||||
|
from jrnl.messages import Message
|
||||||
|
from jrnl.messages import MsgStyle
|
||||||
|
from jrnl.messages import MsgText
|
||||||
|
from jrnl.output import print_msg
|
||||||
|
from jrnl.output import print_msgs
|
||||||
|
from jrnl.override import apply_overrides
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from argparse import Namespace
|
||||||
|
|
||||||
|
from jrnl.journals import Entry
|
||||||
|
from jrnl.journals import Journal
|
||||||
|
|
||||||
|
|
||||||
|
def run(args: "Namespace"):
|
||||||
|
"""
|
||||||
|
Flow:
|
||||||
|
1. Run standalone command if it doesn't need config (help, version, etc), then exit
|
||||||
|
2. Load config
|
||||||
|
3. Run standalone command if it does need config (encrypt, decrypt, etc), then exit
|
||||||
|
4. Load specified journal
|
||||||
|
5. Start append mode, or search mode
|
||||||
|
6. Perform actions with results from search mode (if needed)
|
||||||
|
7. Profit
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Run command if possible before config is available
|
||||||
|
if callable(args.preconfig_cmd):
|
||||||
|
return args.preconfig_cmd(args)
|
||||||
|
|
||||||
|
# Load the config, and extract journal name
|
||||||
|
config = install.load_or_install_jrnl(args.config_file_path)
|
||||||
|
original_config = config.copy()
|
||||||
|
|
||||||
|
# Apply config overrides
|
||||||
|
config = apply_overrides(args, config)
|
||||||
|
|
||||||
|
args = get_journal_name(args, config)
|
||||||
|
config = scope_config(config, args.journal_name)
|
||||||
|
|
||||||
|
# Run post-config command now that config is ready
|
||||||
|
if callable(args.postconfig_cmd):
|
||||||
|
return args.postconfig_cmd(
|
||||||
|
args=args, config=config, original_config=original_config
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- All the standalone commands are now done --- #
|
||||||
|
|
||||||
|
# Get the journal we're going to be working with
|
||||||
|
journal = open_journal(args.journal_name, config)
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
"args": args,
|
||||||
|
"config": config,
|
||||||
|
"journal": journal,
|
||||||
|
"old_entries": journal.entries,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _is_append_mode(**kwargs):
|
||||||
|
append_mode(**kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
|
# If not append mode, then we're in search mode (only 2 modes exist)
|
||||||
|
search_mode(**kwargs)
|
||||||
|
entries_found_count = len(journal)
|
||||||
|
_print_entries_found_count(entries_found_count, args)
|
||||||
|
|
||||||
|
# Actions
|
||||||
|
_perform_actions_on_search_results(**kwargs)
|
||||||
|
|
||||||
|
if entries_found_count != 0 and _has_action_args(args):
|
||||||
|
_print_changed_counts(journal)
|
||||||
|
else:
|
||||||
|
# display only occurs if no other action occurs
|
||||||
|
_display_search_results(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _perform_actions_on_search_results(**kwargs):
|
||||||
|
args = kwargs["args"]
|
||||||
|
|
||||||
|
# Perform actions (if needed)
|
||||||
|
if args.change_time:
|
||||||
|
_change_time_search_results(**kwargs)
|
||||||
|
|
||||||
|
if args.delete:
|
||||||
|
_delete_search_results(**kwargs)
|
||||||
|
|
||||||
|
# open results in editor (if `--edit` was used)
|
||||||
|
if args.edit:
|
||||||
|
_edit_search_results(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_append_mode(args: "Namespace", config: dict, **kwargs) -> bool:
|
||||||
|
"""Determines if we are in append mode (as opposed to search mode)"""
|
||||||
|
# Are any search filters present? If so, then search mode.
|
||||||
|
append_mode = (
|
||||||
|
not _has_search_args(args)
|
||||||
|
and not _has_action_args(args)
|
||||||
|
and not _has_display_args(args)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Might be writing and want to move to editor part of the way through
|
||||||
|
if args.edit and args.text:
|
||||||
|
append_mode = True
|
||||||
|
|
||||||
|
# If the text is entirely tags, then we are also searching (not writing)
|
||||||
|
if append_mode and args.text and _has_only_tags(config["tagsymbols"], args.text):
|
||||||
|
append_mode = False
|
||||||
|
|
||||||
|
return append_mode
|
||||||
|
|
||||||
|
|
||||||
|
def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Gets input from the user to write to the journal
|
||||||
|
0. Check for a template passed as an argument, or in the global config
|
||||||
|
1. Check for input from cli
|
||||||
|
2. Check input being piped in
|
||||||
|
3. Open editor if configured (prepopulated with template if available)
|
||||||
|
4. Use stdin.read as last resort
|
||||||
|
6. Write any found text to journal, or exit
|
||||||
|
"""
|
||||||
|
logging.debug("Append mode: starting")
|
||||||
|
|
||||||
|
template_text = _get_template(args, config)
|
||||||
|
|
||||||
|
if args.text:
|
||||||
|
logging.debug(f"Append mode: cli text detected: {args.text}")
|
||||||
|
raw = " ".join(args.text).strip()
|
||||||
|
if args.edit:
|
||||||
|
raw = _write_in_editor(config, raw)
|
||||||
|
elif not sys.stdin.isatty():
|
||||||
|
logging.debug("Append mode: receiving piped text")
|
||||||
|
raw = sys.stdin.read()
|
||||||
|
else:
|
||||||
|
raw = _write_in_editor(config, template_text)
|
||||||
|
|
||||||
|
if template_text is not None and raw == template_text:
|
||||||
|
logging.error("Append mode: raw text was the same as the template")
|
||||||
|
raise JrnlException(Message(MsgText.NoChangesToTemplate, MsgStyle.NORMAL))
|
||||||
|
|
||||||
|
if not raw or raw.isspace():
|
||||||
|
logging.error("Append mode: couldn't get raw text or entry was empty")
|
||||||
|
raise JrnlException(Message(MsgText.NoTextReceived, MsgStyle.NORMAL))
|
||||||
|
|
||||||
|
logging.debug(
|
||||||
|
f"Append mode: appending raw text to journal '{args.journal_name}': {raw}"
|
||||||
|
)
|
||||||
|
journal.new_entry(raw)
|
||||||
|
if args.journal_name != DEFAULT_JOURNAL_KEY:
|
||||||
|
print_msg(
|
||||||
|
Message(
|
||||||
|
MsgText.JournalEntryAdded,
|
||||||
|
MsgStyle.NORMAL,
|
||||||
|
{"journal_name": args.journal_name},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
journal.write()
|
||||||
|
logging.debug("Append mode: completed journal.write()")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_template(args, config) -> str:
|
||||||
|
# Read template file and pass as raw text into the composer
|
||||||
|
logging.debug(
|
||||||
|
"Get template:\n"
|
||||||
|
f"--template: {args.template}\n"
|
||||||
|
f"from config: {config.get('template')}"
|
||||||
|
)
|
||||||
|
template_path = args.template or config.get("template")
|
||||||
|
|
||||||
|
template_text = None
|
||||||
|
|
||||||
|
if template_path:
|
||||||
|
template_text = read_template_file(template_path)
|
||||||
|
|
||||||
|
return template_text
|
||||||
|
|
||||||
|
|
||||||
|
def search_mode(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Search for entries in a journal, and return the
|
||||||
|
results. If no search args, then return all results
|
||||||
|
"""
|
||||||
|
logging.debug("Search mode: starting")
|
||||||
|
|
||||||
|
# If no search args, then return all results (don't filter anything)
|
||||||
|
if not _has_search_args(args) and not _has_display_args(args) and not args.text:
|
||||||
|
logging.debug("Search mode: has no search args")
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.debug("Search mode: has search args")
|
||||||
|
_filter_journal_entries(args, journal)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_in_editor(config: dict, prepopulated_text: str | None = None) -> str:
|
||||||
|
if config["editor"]:
|
||||||
|
logging.debug("Append mode: opening editor")
|
||||||
|
raw = get_text_from_editor(config, prepopulated_text)
|
||||||
|
else:
|
||||||
|
raw = get_text_from_stdin()
|
||||||
|
|
||||||
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
def _filter_journal_entries(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
||||||
|
"""Filter journal entries in-place based upon search args"""
|
||||||
|
if args.on_date:
|
||||||
|
args.start_date = args.end_date = args.on_date
|
||||||
|
|
||||||
|
if args.today_in_history:
|
||||||
|
now = time.parse("now")
|
||||||
|
args.day = now.day
|
||||||
|
args.month = now.month
|
||||||
|
|
||||||
|
journal.filter(
|
||||||
|
tags=args.text,
|
||||||
|
month=args.month,
|
||||||
|
day=args.day,
|
||||||
|
year=args.year,
|
||||||
|
start_date=args.start_date,
|
||||||
|
end_date=args.end_date,
|
||||||
|
strict=args.strict,
|
||||||
|
starred=args.starred,
|
||||||
|
tagged=args.tagged,
|
||||||
|
exclude=args.excluded,
|
||||||
|
exclude_starred=args.exclude_starred,
|
||||||
|
exclude_tagged=args.exclude_tagged,
|
||||||
|
contains=args.contains,
|
||||||
|
)
|
||||||
|
journal.limit(args.limit)
|
||||||
|
|
||||||
|
|
||||||
|
def _print_entries_found_count(count: int, args: "Namespace") -> None:
|
||||||
|
logging.debug(f"count: {count}")
|
||||||
|
if count == 0:
|
||||||
|
if args.edit or args.change_time:
|
||||||
|
print_msg(Message(MsgText.NothingToModify, MsgStyle.WARNING))
|
||||||
|
elif args.delete:
|
||||||
|
print_msg(Message(MsgText.NothingToDelete, MsgStyle.WARNING))
|
||||||
|
else:
|
||||||
|
print_msg(Message(MsgText.NoEntriesFound, MsgStyle.NORMAL))
|
||||||
|
return
|
||||||
|
elif args.limit and args.limit == count:
|
||||||
|
# Don't show count if the user expects a limited number of results
|
||||||
|
logging.debug("args.limit is true-ish")
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.debug("Printing general summary")
|
||||||
|
my_msg = (
|
||||||
|
MsgText.EntryFoundCountSingular if count == 1 else MsgText.EntryFoundCountPlural
|
||||||
|
)
|
||||||
|
print_msg(Message(my_msg, MsgStyle.NORMAL, {"num": count}))
|
||||||
|
|
||||||
|
|
||||||
|
def _other_entries(journal: "Journal", entries: list["Entry"]) -> list["Entry"]:
|
||||||
|
"""Find entries that are not in journal"""
|
||||||
|
return [e for e in entries if e not in journal.entries]
|
||||||
|
|
||||||
|
|
||||||
|
def _edit_search_results(
|
||||||
|
config: dict, journal: "Journal", old_entries: list["Entry"], **kwargs
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
1. Send the given journal entries to the user-configured editor
|
||||||
|
2. Print out stats on any modifications to journal
|
||||||
|
3. Write modifications to journal
|
||||||
|
"""
|
||||||
|
if not config["editor"]:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.EditorNotConfigured,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{"config_file": get_config_path()},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# separate entries we are not editing
|
||||||
|
other_entries = _other_entries(journal, old_entries)
|
||||||
|
|
||||||
|
# Send user to the editor
|
||||||
|
try:
|
||||||
|
edited = get_text_from_editor(config, journal.editable_str())
|
||||||
|
except JrnlException as e:
|
||||||
|
if e.has_message_text(MsgText.NoTextReceived):
|
||||||
|
raise JrnlException(
|
||||||
|
Message(MsgText.NoEditsReceivedJournalNotDeleted, MsgStyle.WARNING)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
journal.parse_editable_str(edited)
|
||||||
|
|
||||||
|
# Put back entries we separated earlier, sort, and write the journal
|
||||||
|
journal.entries += other_entries
|
||||||
|
journal.sort()
|
||||||
|
journal.write()
|
||||||
|
|
||||||
|
|
||||||
|
def _print_changed_counts(journal: "Journal", **kwargs) -> None:
|
||||||
|
stats = journal.get_change_counts()
|
||||||
|
msgs = []
|
||||||
|
|
||||||
|
if stats["added"] > 0:
|
||||||
|
my_msg = (
|
||||||
|
MsgText.JournalCountAddedSingular
|
||||||
|
if stats["added"] == 1
|
||||||
|
else MsgText.JournalCountAddedPlural
|
||||||
|
)
|
||||||
|
msgs.append(Message(my_msg, MsgStyle.NORMAL, {"num": stats["added"]}))
|
||||||
|
|
||||||
|
if stats["deleted"] > 0:
|
||||||
|
my_msg = (
|
||||||
|
MsgText.JournalCountDeletedSingular
|
||||||
|
if stats["deleted"] == 1
|
||||||
|
else MsgText.JournalCountDeletedPlural
|
||||||
|
)
|
||||||
|
msgs.append(Message(my_msg, MsgStyle.NORMAL, {"num": stats["deleted"]}))
|
||||||
|
|
||||||
|
if stats["modified"] > 0:
|
||||||
|
my_msg = (
|
||||||
|
MsgText.JournalCountModifiedSingular
|
||||||
|
if stats["modified"] == 1
|
||||||
|
else MsgText.JournalCountModifiedPlural
|
||||||
|
)
|
||||||
|
msgs.append(Message(my_msg, MsgStyle.NORMAL, {"num": stats["modified"]}))
|
||||||
|
|
||||||
|
if not msgs:
|
||||||
|
msgs.append(Message(MsgText.NoEditsReceived, MsgStyle.NORMAL))
|
||||||
|
|
||||||
|
print_msgs(msgs)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_predit_stats(journal: "Journal") -> dict[str, int]:
|
||||||
|
return {"count": len(journal)}
|
||||||
|
|
||||||
|
|
||||||
|
def _delete_search_results(
|
||||||
|
journal: "Journal", old_entries: list["Entry"], **kwargs
|
||||||
|
) -> None:
|
||||||
|
entries_to_delete = journal.prompt_action_entries(MsgText.DeleteEntryQuestion)
|
||||||
|
|
||||||
|
journal.entries = old_entries
|
||||||
|
|
||||||
|
if entries_to_delete:
|
||||||
|
journal.delete_entries(entries_to_delete)
|
||||||
|
|
||||||
|
journal.write()
|
||||||
|
|
||||||
|
|
||||||
|
def _change_time_search_results(
|
||||||
|
args: "Namespace",
|
||||||
|
journal: "Journal",
|
||||||
|
old_entries: list["Entry"],
|
||||||
|
no_prompt: bool = False,
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
# separate entries we are not editing
|
||||||
|
# @todo if there's only 1, don't prompt
|
||||||
|
entries_to_change = journal.prompt_action_entries(MsgText.ChangeTimeEntryQuestion)
|
||||||
|
|
||||||
|
if entries_to_change:
|
||||||
|
date = time.parse(args.change_time)
|
||||||
|
journal.entries = old_entries
|
||||||
|
journal.change_date_entries(date, entries_to_change)
|
||||||
|
|
||||||
|
journal.write()
|
||||||
|
|
||||||
|
|
||||||
|
def _display_search_results(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
||||||
|
if len(journal) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get export format from config file if not provided at the command line
|
||||||
|
args.export = args.export or kwargs["config"].get("display_format")
|
||||||
|
|
||||||
|
if args.tags:
|
||||||
|
print(plugins.get_exporter("tags").export(journal))
|
||||||
|
|
||||||
|
elif args.short or args.export == "short":
|
||||||
|
print(journal.pprint(short=True))
|
||||||
|
|
||||||
|
elif args.export == "pretty":
|
||||||
|
print(journal.pprint())
|
||||||
|
|
||||||
|
elif args.export:
|
||||||
|
exporter = plugins.get_exporter(args.export)
|
||||||
|
print(exporter.export(journal, args.filename))
|
||||||
|
else:
|
||||||
|
print(journal.pprint())
|
||||||
|
|
||||||
|
|
||||||
|
def _has_search_args(args: "Namespace") -> bool:
|
||||||
|
"""Looking for arguments that filter a journal"""
|
||||||
|
return any(
|
||||||
|
(
|
||||||
|
args.contains,
|
||||||
|
args.tagged,
|
||||||
|
args.excluded,
|
||||||
|
args.exclude_starred,
|
||||||
|
args.exclude_tagged,
|
||||||
|
args.end_date,
|
||||||
|
args.today_in_history,
|
||||||
|
args.month,
|
||||||
|
args.day,
|
||||||
|
args.year,
|
||||||
|
args.limit,
|
||||||
|
args.on_date,
|
||||||
|
args.starred,
|
||||||
|
args.start_date,
|
||||||
|
args.strict, # -and
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _has_action_args(args: "Namespace") -> bool:
|
||||||
|
return any(
|
||||||
|
(
|
||||||
|
args.change_time,
|
||||||
|
args.delete,
|
||||||
|
args.edit,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _has_display_args(args: "Namespace") -> bool:
|
||||||
|
return any(
|
||||||
|
(
|
||||||
|
args.tags,
|
||||||
|
args.short,
|
||||||
|
args.export, # --format
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _has_only_tags(tag_symbols: str, args_text: str) -> bool:
|
||||||
|
return all(word[0] in tag_symbols for word in " ".join(args_text).split())
|
121
jrnl/editor.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
from jrnl.messages import Message
|
||||||
|
from jrnl.messages import MsgStyle
|
||||||
|
from jrnl.messages import MsgText
|
||||||
|
from jrnl.os_compat import on_windows
|
||||||
|
from jrnl.os_compat import split_args
|
||||||
|
from jrnl.output import print_msg
|
||||||
|
from jrnl.path import absolute_path
|
||||||
|
from jrnl.path import get_templates_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_text_from_editor(config: dict, template: str = "") -> str:
|
||||||
|
suffix = ".jrnl"
|
||||||
|
if config["template"]:
|
||||||
|
template_filename = Path(config["template"]).name
|
||||||
|
suffix = "-" + template_filename
|
||||||
|
filehandle, tmpfile = tempfile.mkstemp(prefix="jrnl", text=True, suffix=suffix)
|
||||||
|
os.close(filehandle)
|
||||||
|
|
||||||
|
with open(tmpfile, "w", encoding="utf-8") as f:
|
||||||
|
if template:
|
||||||
|
f.write(template)
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.call(split_args(config["editor"]) + [tmpfile])
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.EditorMisconfigured,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{"editor_key": config["editor"]},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(tmpfile, "r", encoding="utf-8") as f:
|
||||||
|
raw = f.read()
|
||||||
|
os.remove(tmpfile)
|
||||||
|
|
||||||
|
if not raw:
|
||||||
|
raise JrnlException(Message(MsgText.NoTextReceived, MsgStyle.NORMAL))
|
||||||
|
|
||||||
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
def get_text_from_stdin() -> str:
|
||||||
|
print_msg(
|
||||||
|
Message(
|
||||||
|
MsgText.WritingEntryStart,
|
||||||
|
MsgStyle.TITLE,
|
||||||
|
{
|
||||||
|
"how_to_quit": (
|
||||||
|
MsgText.HowToQuitWindows if on_windows() else MsgText.HowToQuitLinux
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
raw = sys.stdin.read()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logging.error("Append mode: keyboard interrupt")
|
||||||
|
raise JrnlException(
|
||||||
|
Message(MsgText.KeyboardInterruptMsg, MsgStyle.ERROR_ON_NEW_LINE),
|
||||||
|
Message(MsgText.JournalNotSaved, MsgStyle.WARNING),
|
||||||
|
)
|
||||||
|
|
||||||
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
def get_template_path(template_path: str, jrnl_template_dir: str) -> str:
|
||||||
|
actual_template_path = os.path.join(jrnl_template_dir, template_path)
|
||||||
|
if not os.path.exists(actual_template_path):
|
||||||
|
logging.debug(
|
||||||
|
f"Couldn't open {actual_template_path}. "
|
||||||
|
"Treating template path like a local / abs path."
|
||||||
|
)
|
||||||
|
actual_template_path = absolute_path(template_path)
|
||||||
|
|
||||||
|
return actual_template_path
|
||||||
|
|
||||||
|
|
||||||
|
def read_template_file(template_path: str) -> str:
|
||||||
|
"""
|
||||||
|
Reads the template file given a template path in this order:
|
||||||
|
|
||||||
|
* Check $XDG_DATA_HOME/jrnl/templates/template_path.
|
||||||
|
* Check template_arg as an absolute / relative path.
|
||||||
|
|
||||||
|
If a file is found, its contents are returned as a string.
|
||||||
|
If not, a JrnlException is raised.
|
||||||
|
"""
|
||||||
|
|
||||||
|
jrnl_template_dir = get_templates_path()
|
||||||
|
actual_template_path = get_template_path(template_path, jrnl_template_dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(actual_template_path, encoding="utf-8") as f:
|
||||||
|
template_data = f.read()
|
||||||
|
return template_data
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.CantReadTemplate,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"template_path": template_path,
|
||||||
|
"actual_template_path": actual_template_path,
|
||||||
|
"jrnl_template_dir": str(jrnl_template_dir) + os.sep,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|