├── .github └── workflows │ └── release.yml ├── .gitignore ├── BETA.md ├── LICENSE ├── README.md ├── adhoc └── convert-dbd.py ├── bin ├── zcreate ├── zettel ├── zfind └── zimport ├── deprecated ├── docs │ ├── Gemfile │ ├── Gemfile.lock │ ├── _config.yml │ ├── _posts │ │ ├── 2017-05-28-welcome-to-zettelgeist.markdown │ │ └── 2021-05-01-see-wiki.markdown │ ├── about.md │ ├── example │ │ └── mlb │ │ │ ├── 20170731132024-chicago-cubs.yaml │ │ │ ├── 20170731133642-cincinnati-reds.yaml │ │ │ ├── 20170731134823-milwaukee-brewers.yaml │ │ │ ├── 20170731135121-pittsburgh-pirates.yaml │ │ │ ├── 20170731135823-st-louis-cardinals.yaml │ │ │ ├── 20170731140433-atlanta-braves.yaml │ │ │ ├── 20170731140750-miami-marlins.yaml │ │ │ ├── 20170731141025-new-york-mets.yaml │ │ │ ├── 20170731141248-philadelphia-phillies.yaml │ │ │ ├── 20170731141625-washington-nationals.yaml │ │ │ ├── 20170731141908-arizona-diamondbacks.yaml │ │ │ ├── 20170731142237-colorado-rockies.yaml │ │ │ ├── 20170731143033-los-angeles-dodgers.yaml │ │ │ ├── 20170731143425-san-diego-padres.yaml │ │ │ ├── 20170731154135-baltimore-orioles.yaml │ │ │ ├── 20170731154404-boston-red-sox.yaml │ │ │ ├── 20170731154645-new-york-yankees.yaml │ │ │ ├── 20170731154837-tampa-bay-rays.yaml │ │ │ ├── 20170731155132-toronto-blue-jays.yaml │ │ │ ├── 20170731155613-chicago-grey-sox.yaml │ │ │ ├── 20170731160002-cleveland-indians.yaml │ │ │ ├── 20170731160508-detroit-tigers.yaml │ │ │ ├── 20170731160722-kansas-city-royals.yaml │ │ │ ├── 20170731160940-minnesota-twins.yaml │ │ │ ├── 20170731161550-houston-astros.yaml │ │ │ ├── 20170731161927-los-angeles-angels.yaml │ │ │ ├── 20170731162502-oakland-athletics.yaml │ │ │ ├── 20170731162806-seattle-mariners.yaml │ │ │ ├── 20170731163040-texas-rangers.yaml │ │ │ └── README.md │ ├── gs.md │ ├── index.md │ ├── install.md │ ├── team.md │ ├── thenote.md │ ├── tutorial-GDocs.md │ ├── tutorial-Terminal.md │ └── tutorial-Word.md └── zettelgeist │ └── zfilter.py ├── docs ├── .gitignore ├── .nojekyll ├── RELEASING.md └── index.html ├── jupyter ├── xyz.txt └── zdemo.ipynb ├── project ├── assembly.sbt ├── build.properties └── plugins.sbt ├── requirements.txt ├── scripts └── deploy.sh ├── setup.cfg ├── setup.py ├── sphinx-docs ├── Makefile ├── make.bat └── source │ ├── about.rst │ ├── conf.py │ ├── gs.rst │ ├── index.rst │ ├── install.rst │ ├── team.rst │ ├── thenote.rst │ ├── tutorial-gdocs.rst │ ├── tutorial-terminal.rst │ └── tutorial-world.rst ├── src └── ps.text ├── tests └── test_zettelgeist.py ├── zdb_funcs.sh └── zettelgeist ├── __init__.py ├── zcreate.py ├── zdb.py ├── zettel.py ├── zfind.py ├── zimport.py ├── zquery.py ├── zutils.py └── zversion.py /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python 🐍 distributions 📦 to PyPI 2 | 3 | on: push 4 | 5 | jobs: 6 | build-n-publish: 7 | name: Build and publish Python 🐍 distributions 📦 to PyPI 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Setup Python 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: '3.10.4' 18 | 19 | - name: Install Requirements 20 | run: >- 21 | python -m 22 | pip install 23 | build 24 | --user 25 | 26 | - name: Build a binary wheel and a source tarball 27 | run: >- 28 | python -m 29 | build 30 | --sdist 31 | --wheel 32 | --outdir dist/ 33 | . 34 | - name: Release to PyPI 35 | if: startsWith(github.ref, 'refs/tags') 36 | uses: pypa/gh-action-pypi-publish@release/v1 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | 41 | - name: Release to GitHub 42 | uses: softprops/action-gh-release@v1 43 | if: startsWith(github.ref, 'refs/tags/') 44 | with: 45 | files: | 46 | dist/*.whl 47 | dist/*.tar.gz 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # ZettelGeist Ignores 92 | data/ 93 | zettels.db 94 | 95 | # OS X Junk 96 | .DS_Store 97 | 98 | *.class 99 | *.log 100 | *~ 101 | 102 | # vim 103 | *.swp 104 | *.swo 105 | 106 | # sbt specific 107 | .cache 108 | .history 109 | .lib/ 110 | dist/* 111 | target/ 112 | lib_managed/ 113 | src_managed/ 114 | project/boot/ 115 | project/plugins/project/ 116 | scala-2.10/ 117 | scala-2.11/ 118 | 119 | # Scala-IDE specific 120 | .scala_dependencies 121 | .worksheet 122 | .idea/ 123 | 124 | 125 | # Temporary folders 126 | 127 | scratch/ 128 | .vscode/ 129 | -------------------------------------------------------------------------------- /BETA.md: -------------------------------------------------------------------------------- 1 | These are some quick notes for the beta. 2 | 3 | Beginning July 17, 2017, we will be placing emphasis on packaging and being able to "use" the tools, even as they are 4 | being created. 5 | 6 | Before beginnign a session, you should set up your environment variables. This is done by sourcing the `setpath.sh` 7 | script as follows: 8 | 9 | ```shell 10 | cd zettelgeist 11 | source setpath.sh 12 | ``` 13 | 14 | You can also put this in your `.bashrc` (or equivalent, e.g. .zshrc) if you wish to avoid re-running it each time you 15 | start a new terminal session, using your favorite text editor. 16 | 17 | Once you have made these settings, you can run any of the ZettelGeist commands, e.g. `zcreate`, `zimport`, and the like. 18 | Not all commands are available yet but will be soon. 19 | 20 | To find out what commands are available, you can `ls zettelgeist/bin` to see what commands are available. 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZettelGeist 2 | 3 | ZettelGeist is a plaintext notetaking system inspired by the Zettelkasten approach. 4 | 5 | # Build Status 6 | 7 | Coming soon. We are migrating from Travis-CI to GitHub Actions. 8 | 9 | # Getting Started 10 | 11 | Please see the [ZettelGeist Wiki](https://github.com/ZettelGeist/zettelgeist/wiki) for detailed installation and usage instructions. 12 | 13 | -------------------------------------------------------------------------------- /adhoc/convert-dbd.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import os 3 | import sys 4 | 5 | dir = sys.argv[1] 6 | files = os.listdir(dir) 7 | 8 | def process(filename): 9 | print("Processing %s" % filename) 10 | (base, ext) = os.path.splitext(filename) 11 | ICONV='iconv -f iso8859-1 -t utf-8 "%(base)s%(ext)s" > "%(base)s.utf8%(ext)s"' % vars() 12 | print("Running",ICONV) 13 | os.system(ICONV) 14 | filename = "%(base)s.utf8%(ext)s" % vars() 15 | #os.system(ICONV) 16 | lines = [] 17 | with open(filename) as infile: 18 | id = infile.readline() 19 | print("Doc ID %s" % id) 20 | lines.append( ('id', id) ) 21 | for line in infile: 22 | kwline = line.strip() 23 | if len(kwline) == 0: 24 | continue 25 | if kwline.startswith('#""'): 26 | lines.append( ('bibkey', kwline[3:])) 27 | elif kwline.startswith('#'): 28 | lines.append( ('tag', kwline[1:])) 29 | else: 30 | lines.append( ('text', line) ) 31 | 32 | doc = { 'id': "", 'tags': [], 'bibkey' : [], 'text' : [] } 33 | for (code, text) in lines: 34 | if code == 'id': 35 | doc['id'] = text.strip() 36 | elif code == 'tag': 37 | doc['tags'].append(text.strip()) 38 | elif code == 'bibkey': 39 | doc['bibkey'].append(text.strip()) 40 | elif code == 'text': 41 | doc['text'].append(text) 42 | 43 | doc['text'] = "\n".join(doc['text']) 44 | 45 | (basename, extension) = os.path.splitext(filename) 46 | outfilename = basename + '.yaml' 47 | with open(outfilename, "w") as outfile: 48 | outfile.write(doc['id'] + '\n') 49 | outfile.write('---\n') 50 | del(doc['id']) 51 | outfile.write(yaml.dump(doc)) 52 | 53 | 54 | for f in files: 55 | if f.endswith('.md'): 56 | if not f.endswith('.utf8.md'): 57 | process( os.path.join(dir, f) ) 58 | else: 59 | print("Skipping generated UTF-8 file", f) 60 | 61 | 62 | -------------------------------------------------------------------------------- /bin/zcreate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from zettelgeist import zcreate 4 | 5 | zcreate.main() 6 | -------------------------------------------------------------------------------- /bin/zettel: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from zettelgeist import zettel 4 | 5 | zettel.main() 6 | -------------------------------------------------------------------------------- /bin/zfind: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from zettelgeist import zfind 4 | 5 | zfind.main() 6 | -------------------------------------------------------------------------------- /bin/zimport: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from zettelgeist import zimport 4 | 5 | zimport.main() 6 | -------------------------------------------------------------------------------- /deprecated/docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | ruby RUBY_VERSION 3 | 4 | # Hello! This is where you manage which Jekyll version is used to run. 5 | # When you want to use a different version, change it below, save the 6 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 7 | # 8 | # bundle exec jekyll serve 9 | # 10 | # This will help ensure the proper Jekyll version is running. 11 | # Happy Jekylling! 12 | gem "jekyll", "3.6.3" 13 | 14 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 15 | gem "minima", "~> 2.0" 16 | 17 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 18 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 19 | # gem "github-pages", group: :jekyll_plugins 20 | 21 | # If you have any plugins, put them here! 22 | group :jekyll_plugins do 23 | gem "jekyll-feed", "~> 0.6" 24 | end 25 | 26 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 27 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 28 | 29 | -------------------------------------------------------------------------------- /deprecated/docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.7.0) 5 | public_suffix (>= 2.0.2, < 5.0) 6 | colorator (1.1.0) 7 | ffi (1.11.1) 8 | forwardable-extended (2.6.0) 9 | jekyll (3.6.3) 10 | addressable (~> 2.4) 11 | colorator (~> 1.0) 12 | jekyll-sass-converter (~> 1.0) 13 | jekyll-watch (~> 1.1) 14 | kramdown (~> 1.14) 15 | liquid (~> 4.0) 16 | mercenary (~> 0.3.3) 17 | pathutil (~> 0.9) 18 | rouge (>= 1.7, < 3) 19 | safe_yaml (~> 1.0) 20 | jekyll-feed (0.9.2) 21 | jekyll (~> 3.3) 22 | jekyll-sass-converter (1.5.2) 23 | sass (~> 3.4) 24 | jekyll-watch (1.5.1) 25 | listen (~> 3.0) 26 | kramdown (1.17.0) 27 | liquid (4.0.3) 28 | listen (3.2.0) 29 | rb-fsevent (~> 0.10, >= 0.10.3) 30 | rb-inotify (~> 0.9, >= 0.9.10) 31 | mercenary (0.3.6) 32 | minima (2.1.1) 33 | jekyll (~> 3.3) 34 | pathutil (0.16.2) 35 | forwardable-extended (~> 2.6) 36 | public_suffix (4.0.1) 37 | rb-fsevent (0.10.3) 38 | rb-inotify (0.10.0) 39 | ffi (~> 1.0) 40 | rouge (2.2.1) 41 | safe_yaml (1.0.5) 42 | sass (3.7.4) 43 | sass-listen (~> 4.0.0) 44 | sass-listen (4.0.0) 45 | rb-fsevent (~> 0.9, >= 0.9.4) 46 | rb-inotify (~> 0.9, >= 0.9.7) 47 | 48 | PLATFORMS 49 | ruby 50 | 51 | DEPENDENCIES 52 | jekyll (= 3.6.3) 53 | jekyll-feed (~> 0.6) 54 | minima (~> 2.0) 55 | tzinfo-data 56 | 57 | RUBY VERSION 58 | ruby 2.4.1p111 59 | 60 | BUNDLED WITH 61 | 1.15.0 62 | -------------------------------------------------------------------------------- /deprecated/docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | 11 | # Site settings 12 | # These are used to personalize your new site. If you look in the HTML files, 13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 14 | # You can create any custom variable you would like, and they will be accessible 15 | # in the templates via {{ site.myvariable }}. 16 | title: ZettelGeist 17 | email: thiruvathukal@gmail.com 18 | description: > # this means to ignore newlines until "baseurl:" 19 | ZettelGeist is a notetaking system based on ZettelKasten system for notetaking. 20 | baseurl: "" # the subpath of your site, e.g. /blog 21 | url: "" # the base hostname & protocol for your site, e.g. http://example.com 22 | twitter_username: tbd 23 | github_username: ZettelGeist 24 | 25 | # Build settings 26 | markdown: kramdown 27 | theme: minima 28 | gems: 29 | - jekyll-feed 30 | exclude: 31 | - Gemfile 32 | - Gemfile.lock 33 | -------------------------------------------------------------------------------- /deprecated/docs/_posts/2017-05-28-welcome-to-zettelgeist.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Welcome to ZettelGeist" 4 | date: 2017-05-28 23:21:33 -0500 5 | categories: zettelgeist update 6 | --- 7 | 8 | Welcome to our project. We are still in the formative stages, especially when it comes to our web site. Luckily, it has become really easy to make 9 | web sites for GitHub projects, simply by putting Markdown for your Jekyll site in the `/docs` folder. Whoa! 10 | 11 | As we haven't really built a beautiful landing page, this post is aimed at helping you find items of interest. 12 | 13 | - GitHub Repository: [zettelgeist-repo][zettelgeist-repo] 14 | - Developer Mailing List: _coming soon_ 15 | 16 | If you are interested in our project, please join the mailing list when it becomes available. 17 | We will also have a list of projects on this site shortly. 18 | 19 | [zettelgeist-repo]: https://github.com/ZettelGeist/zettelgeist 20 | -------------------------------------------------------------------------------- /deprecated/docs/_posts/2021-05-01-see-wiki.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Migrating to GitHub Wiki" 4 | date: 2017-05-01 23:21:00 -0500 5 | categories: zettelgeist update 6 | --- 7 | 8 | For now, we have decided to use [github.com/zettelgeist/zettelgeist](https://github.com/zettelgeist/zettelgeist/) as the main presence for the ZettelGeist project. We're focusing on our energy on building the next version of ZettelGeist. Hosting code *and* documentation on GitHub will allow us to focus on improvements to ZettelGeist and keeping documentation up-to-date. 9 | 10 | If you have any questions about ZettelGeist or wish to help us, please don't hesitate to reach out to [Team ZettelGeist](https://github.com/ZettelGeist/zettelgeist/wiki/Team). 11 | -------------------------------------------------------------------------------- /deprecated/docs/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: About 4 | permalink: /about/ 5 | --- 6 | 7 | See our [Wiki](https://github.com/ZettelGeist/zettelgeist/wiki). 8 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731132024-chicago-cubs.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Chicago_Cubs 3 | summary: Chicago Cubs 4 | note: "The Chicago Cubs are an American professional baseball team based in Chicago,\ 5 | \ Illinois. The Cubs compete in Major League Baseball (MLB) as a member club of\ 6 | \ the National League (NL) Central division, where they are the defending World\ 7 | \ Series champions. The team plays its home games at Wrigley Field, located on the\ 8 | \ city's North Side. The Cubs are one of two major league teams in Chicago; the\ 9 | \ other, the Chicago White Sox, is a member of the American League (AL) Central\ 10 | \ division. The Cubs, first known as the White Stockings, was a founding member\ 11 | \ of the NL in 1876, becoming the Chicago Cubs in 1903.[2] The Cubs have appeared\ 12 | \ in a total of eleven World Series. The 1906 Cubs won 116 games, finishing 116\u2013\ 13 | 36 and posting a modern-era record winning percentage of .763, before losing the\ 14 | \ World Series to the Chicago White Sox by four games to two. The Cubs won back-to-back\ 15 | \ World Series championships in 1907 and 1908, becoming the first major league team\ 16 | \ to play in three consecutive World Series, and the first to win it twice. Most\ 17 | \ recently, the Cubs won the 2016 National League Championship Series and 2016 World\ 18 | \ Series, which ended a 71-year National League pennant drought and a 108-year World\ 19 | \ Series championship drought," 20 | tags: 21 | - MLB 22 | - National League 23 | - NL East 24 | 25 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731133642-cincinnati-reds.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Cincinnati_Reds 3 | summary: Cincinnati Reds 4 | note: The Cincinnati Reds are an American professional baseball team based in Cincinnati, 5 | Ohio. The Reds compete in Major League Baseball (MLB) as a member club of the National 6 | League (NL) Central division. They were a charter member of the American Association 7 | in 1882 and joined the NL in 1890. 8 | tags: 9 | - MLB 10 | - National League 11 | - NL Central 12 | 13 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731134823-milwaukee-brewers.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Milwaukee_Brewers 3 | summary: Milwaukee Brewers 4 | note: The Milwaukee Brewers are an American professional baseball team and are based 5 | in Milwaukee, Wisconsin. The team is named for the city's association with the brewing 6 | industry.[1] Since 2001, the Brewers have played their home games at Miller Park, 7 | which has a seating capacity of 41,900. The team was founded in 1969 as the Seattle 8 | Pilots, an expansion team of the American League (AL), in Seattle, Washington. The 9 | Pilots played their home games at Sick's Stadium. After only one season, the team 10 | relocated to Milwaukee, becoming known as the Brewers and playing their home games 11 | at Milwaukee County Stadium. In 1998, the Brewers joined the National League. They 12 | are the only franchise to play in four divisions since the advent of divisional 13 | play in Major League Baseball in 1969. 14 | tags: 15 | - MLB 16 | - National League 17 | - NL Central 18 | 19 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731135121-pittsburgh-pirates.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Pittsburgh_Pirates 3 | summary: Pittsburgh Pirates 4 | note: The Pittsburgh Pirates are an American professional baseball team based in Pittsburgh, 5 | Pennsylvania. The Pirates compete in Major League Baseball (MLB) as a member club 6 | of the National League (NL) Central division. The Pirates play their home games 7 | at PNC Park; the team previously played at Forbes Field and Three Rivers Stadium, 8 | the latter of which was named after its location near the confluence of the Allegheny, 9 | Monongahela, and Ohio Rivers. Founded on October 15, 1881[2] as Allegheny, the franchise 10 | has won five World Series championships. The Pirates are also often referred to 11 | as the Bucs or the Buccos (derived from buccaneer, a synonym for pirate). 12 | tags: 13 | - MLB 14 | - National League 15 | - NL Central 16 | 17 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731135823-st-louis-cardinals.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/St._Louis_Cardinals 3 | summary: St. Louis Cardinals 4 | note: The St. Louis Cardinals are an American professional baseball team based in 5 | St. Louis, Missouri. The Cardinals compete in Major League Baseball (MLB) as a member 6 | club of the National League (NL) Central division. Busch Stadium has been their 7 | home ballpark since 2006. With origins as one of the early professional baseball 8 | clubs in St. Louis, entrepreneur Chris von der Ahe purchased a barnstorming club 9 | in 1881, then known as the Brown Stockings, and established them as charter members 10 | of the American Association (AA) the following season. Upon the discontinuation 11 | of the AA, St. Louis joined the NL in 1892; at that time, they were called the Browns 12 | and the Perfectos before they were officially renamed as the Cardinals in 1900. 13 | One of the most successful franchises in baseball history, the Cardinals have won 14 | 11 World Series championships, the second-most in Major League Baseball and most 15 | in the National League. Their 19 National League pennants rank third in NL history. 16 | In addition, St. Louis has won 13 division titles in the East and Central divisions. 17 | tags: 18 | - MLB 19 | - National League 20 | - NL Central 21 | 22 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731140433-atlanta-braves.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Atlanta_Braves 3 | summary: Atlanta Braves 4 | note: "The Atlanta Braves are an American professional baseball franchise based in\ 5 | \ the Atlanta metropolitan area. The franchise competes in Major League Baseball\ 6 | \ (MLB) as a member of the National League (NL) East division. The Braves played\ 7 | \ home games at Atlanta\u2013Fulton County Stadium from 1966 to 1996, and Turner\ 8 | \ Field from 1997 to 2016. Since 2017, their home stadium has been SunTrust Park,\ 9 | \ a new stadium 10 miles (16 km) northwest of downtown Atlanta in the Cumberland\ 10 | \ neighborhood of Cobb County.[3] The Braves play spring training games in Lake\ 11 | \ Buena Vista, Florida. In January 2017, the Braves announced a formal agreement\ 12 | \ to move their spring training home to North Port, Florida." 13 | tags: 14 | - MLB 15 | - National League 16 | - NL East 17 | 18 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731140750-miami-marlins.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Miami_Marlins 3 | summary: Miami Marlins 4 | note: The Miami Marlins are an American professional baseball team based in Miami, 5 | Florida. The Marlins compete in Major League Baseball (MLB) as a member of the National 6 | League (NL) East division. Their home park is Marlins Park. Though one of only two 7 | MLB franchises to have never won a division title (the other is the Colorado Rockies), 8 | the Marlins have won two World Series championships as a wild card team. 9 | tags: 10 | - MLB 11 | - National League 12 | - NL East 13 | 14 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731141025-new-york-mets.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/New_York_Mets 3 | summary: New York Mets 4 | note: 'The New York Mets are an American professional baseball team based in the New 5 | York City borough of Queens. The Mets compete in Major League Baseball (MLB) as 6 | a member club of the National League (NL) East division. The Mets are one of two 7 | Major League clubs based in New York City; the other is the New York Yankees. One 8 | of baseball''s first expansion teams, the Mets were founded in 1962 to replace New 9 | York''s departed NL teams, the Brooklyn Dodgers and the New York Giants. ' 10 | tags: 11 | - MLB 12 | - National League 13 | - NL East 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731141248-philadelphia-phillies.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Philadelphia_Phillies 3 | summary: Philadelphia Phillies 4 | note: The Philadelphia Phillies are an American professional baseball team based in 5 | Philadelphia, Pennsylvania. They are the oldest continuous, one-name, one-city franchise 6 | in all of professional American sports, dating back to 1883.[6] The Phillies compete 7 | in Major League Baseball (MLB) as a member club of the National League (NL) East 8 | division. Since 2004, the team's home has been Citizens Bank Park, located in South 9 | Philadelphia. The Phillies have won two World Series championships (against the 10 | Kansas City Royals in 1980 and the Tampa Bay Rays in 2008) and seven National League 11 | pennants, the first of which came in 1915. 12 | tags: 13 | - MLB 14 | - National League 15 | - NL East 16 | 17 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731141625-washington-nationals.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Washington_Nationals 3 | summary: Washington Nationals 4 | note: 'The Washington Nationals are a professional baseball team based in Washington, 5 | D.C. The Nationals compete in Major League Baseball (MLB) as a member club of the 6 | National League (NL) East division. From 2005 to 2007, the team played in RFK Stadium; 7 | since 2008 their home stadium has been Nationals Park on South Capitol Street in 8 | Southeast D.C., near the Anacostia River.[2] The Nationals are the fourth major 9 | league franchise to be based in Washington, D.C., and the first since 1971. ' 10 | tags: 11 | - MLB 12 | - National League 13 | - NL East 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731141908-arizona-diamondbacks.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Arizona_Diamondbacks 3 | summary: Arizona Diamondbacks 4 | note: The Arizona Diamondbacks, often shortened as the D-backs, are an American professional 5 | baseball franchise based in Phoenix, Arizona. The club competes in Major League 6 | Baseball (MLB) as a member of the National League (NL) West division. Since the 7 | team's inception in 1998, the franchise has played home games at Chase Field, formerly 8 | known as Bank One Ballpark. The Diamondbacks have won one World Series championship 9 | (in 2001), becoming the fastest expansion team in the Major Leagues to win a championship, 10 | doing it in only the fourth season since the franchise's inception in the 1998 Major 11 | League Baseball season. 12 | tags: 13 | - MLB 14 | - National League 15 | - NL West 16 | 17 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731142237-colorado-rockies.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Colorado_Rockies 3 | summary: Colorado Rockies 4 | note: The Colorado Rockies are an American professional baseball team based in Denver, 5 | Colorado. The Rockies compete in Major League Baseball (MLB) as a member club of 6 | the National League (NL) West division. The team's home venue is Coors Field, located 7 | in the Lower Downtown area of Denver. The Rockies have won one National League championship, 8 | in 2007, after having won 14 of their final 15 games in order to secure a Wild Card 9 | position. In the World Series they were swept by the American League (AL) champion 10 | Boston Red Sox in four games. 11 | tags: 12 | - MLB 13 | - National League 14 | - NL West 15 | 16 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731143033-los-angeles-dodgers.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Los_Angeles_Dodgers 3 | summary: Los Angeles Dodgers 4 | note: The Los Angeles Dodgers are an American professional baseball team based in 5 | Los Angeles, California. The Dodgers compete in Major League Baseball (MLB) as a 6 | member club of the National League (NL) West division. Established in 1883 in Brooklyn, 7 | New York,[1][2] the team moved to Los Angeles before the 1958 season.[3] They played 8 | for four seasons at the Los Angeles Memorial Coliseum before moving to their current 9 | home of Dodger Stadium in 1962. 10 | tags: 11 | - MLB 12 | - National League 13 | - NL West 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731143425-san-diego-padres.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/San_Diego_Padres 3 | summary: San Diego Padres 4 | note: 'The San Diego Padres are an American professional baseball franchise based 5 | in San Diego, California. The Padres compete in Major League Baseball (MLB) as a 6 | member club of the National League (NL) West division, along with the Arizona Diamondbacks, 7 | Colorado Rockies, Los Angeles Dodgers and San Francisco Giants. Founded in 1969, 8 | the Padres have won the NL pennant twice: in 1984 and 1998, losing in the World 9 | Series both times.' 10 | tags: 11 | - MLB 12 | - National League 13 | - NL West 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731154135-baltimore-orioles.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Baltimore_Orioles 3 | summary: Baltimore Orioles 4 | note: "The Baltimore Orioles are an American professional baseball team based in Baltimore,\ 5 | \ Maryland. The Orioles compete in Major League Baseball (MLB) as a member of the\ 6 | \ American League (AL) East division. As one of the AL's original eight charter\ 7 | \ franchises when the league was established in 1901, this particular franchise\ 8 | \ spent its first year as a major league club in Milwaukee, Wisconsin, as the Milwaukee\ 9 | \ Brewers before moving to St. Louis, Missouri to become the St. Louis Browns. After\ 10 | \ 52 often-beleaguered years in St. Louis, the Browns franchise was purchased in\ 11 | \ November 1953 by a syndicate of Baltimore business interests led by attorney/civic\ 12 | \ activist Clarence Miles and Mayor Thomas D'Alesandro, Jr. The franchise officially\ 13 | \ moved to Baltimore for the 1954 season and began play in Memorial Stadium. The\ 14 | \ Orioles adopted their team name in honor of the official state bird of Maryland;\ 15 | \ it had also been used by several previous major and minor league baseball clubs\ 16 | \ in Baltimore, including the 1901\u20131903 Orioles that would later move and become\ 17 | \ the New York Yankees. Nicknames for the team include the 'O's' and the 'Birds'" 18 | tags: 19 | - MLB 20 | - National League 21 | - AL East 22 | 23 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731154404-boston-red-sox.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: ihttps://en.wikipedia.org/wiki/Boston_Red_Sox 3 | summary: Boston Red Sox 4 | note: 'The Boston Red Sox are an American professional baseball team based in Boston, 5 | Massachusetts. The Red Sox compete in Major League Baseball (MLB) as a member club 6 | of the American League (AL) East division. The Red Sox have won eight World Series 7 | championships and have played in twelve. Founded in 1901 as one of the American 8 | League''s eight charter franchises, the Red Sox'' home ballpark has been Fenway 9 | Park since 1912. ' 10 | tags: 11 | - MLB 12 | - National League 13 | - AL East 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731154645-new-york-yankees.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/New_York_Yankees 3 | summary: New York Yankees 4 | note: The New York Yankees are an American professional baseball team based in the 5 | New York City borough of the Bronx. The Yankees compete in Major League Baseball 6 | (MLB) as a member club of the American League (AL) East division. They are one of 7 | two major league clubs based in New York City, the other being the New York Mets 8 | of the National League. In the 1901 season, the club began play in the AL as the 9 | Baltimore Orioles (no relation to the modern Baltimore Orioles). Frank Farrell and 10 | Bill Devery purchased the franchise (which had ceased operations) and moved it to 11 | New York City, renaming the club the New York Highlanders.[1] The Highlanders were 12 | officially renamed the Yankees in 1913. 13 | tags: 14 | - MLB 15 | - National League 16 | - AL East 17 | 18 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731154837-tampa-bay-rays.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: ihttps://en.wikipedia.org/wiki/Tampa_Bay_Rays 3 | summary: Tampa Bay Rays 4 | note: The Tampa Bay Rays are an American professional baseball team based in St. Petersburg, 5 | Florida. The Rays compete in Major League Baseball (MLB) as a member of the American 6 | League (AL) East division. Since its inception, the team's home venue has been Tropicana 7 | Field. 8 | tags: 9 | - MLB 10 | - National League 11 | - AL East 12 | 13 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731155132-toronto-blue-jays.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Toronto_Blue_Jays 3 | summary: Toronto Blue Jays 4 | note: 'The Toronto Blue Jays are a Canadian professional baseball team based in Toronto, 5 | Ontario. The Blue Jays compete in Major League Baseball (MLB) as a member club of 6 | the American League (AL) East division. The team plays its home games at the Rogers 7 | Centre. The ''Blue Jays'' name originates from the bird of the same name, and blue 8 | is also the traditional colour of two of Toronto''s other professional sports teams: 9 | the Maple Leafs (ice hockey) and the Argonauts (Canadian football).' 10 | tags: 11 | - MLB 12 | - National League 13 | - AL East 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731155613-chicago-grey-sox.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Chicago_White_Sox 3 | summary: Chicago White Sox 4 | note: The White Sox won the 1906 World Series with a defense-oriented team dubbed 5 | 'the Hitless Wonders', and the 1917 World Series led by Eddie Cicotte, Eddie Collins, 6 | and Shoeless Joe Jackson. The 1919 World Series was marred by the Black Sox Scandal, 7 | in which several members of the White Sox were accused of conspiring with gamblers 8 | to fix games. In response, Major League Baseball's new Commissioner Kenesaw Mountain 9 | Landis banned the players from Major League Baseball for life. In 1959, led by Early 10 | Wynn, Nellie Fox, Luis Aparicio and manager Al Lopez, the White Sox won the American 11 | League pennant. They won the AL pennant in 2005, and went on to win the World Series. 12 | tags: 13 | - MLB 14 | - National League 15 | - AL Central 16 | 17 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731160002-cleveland-indians.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Cleveland_Indians 3 | summary: Cleveland Indians 4 | note: 'The Cleveland Indians are an American professional baseball team based in Cleveland, 5 | Ohio. The Indians compete in Major League Baseball (MLB) as a member club of the 6 | American League (AL) Central division. Since 1994, they have played at Progressive 7 | Field and are the defending American League champions. The team''s spring training 8 | facility is at Goodyear Ballpark in Goodyear, Arizona.[2] Since their establishment 9 | as a major league franchise in 1901, the Indians have won two World Series championships: 10 | in 1920 and 1948, along with eight Central Division titles and six American League 11 | pennants. The Indians'' current World Series championship drought is the longest 12 | active drought, and through 2016 is the fifth-longest in baseball history' 13 | tags: 14 | - MLB 15 | - National League 16 | - AL Central 17 | 18 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731160508-detroit-tigers.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Detroit_Tigers 3 | summary: Detroit Tigers 4 | note: iThe Detroit Tigers are an American professional baseball team based in Detroit, 5 | Michigan. The Tigers compete in Major League Baseball (MLB) as a member club of 6 | the American League (AL) Central division. One of the AL's eight charter franchises, 7 | the club was founded in Detroit in 1901. They are the oldest continuous one-name, 8 | one-city franchise in the AL.[2] The Tigers have won four World Series championships 9 | (1935, 1945, 1968, and 1984), 11 AL pennants (1907, 1908, 1909, 1934, 1935, 1940, 10 | 1945, 1968, 1984, 2006, and 2012), and four AL Central division championships (2011, 11 | 2012, 2013, and 2014). The Tigers also won division titles in 1972, 1984 and 1987 12 | while members of the AL East. The team currently plays its home games at Comerica 13 | Park in Downtown Detroit. 14 | tags: 15 | - MLB 16 | - National League 17 | - AL Central 18 | 19 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731160722-kansas-city-royals.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Kansas_City_Royals 3 | summary: Kansas City Royals 4 | note: The Kansas City Royals are an American professional baseball team based in Kansas 5 | City, Missouri. The Royals compete in Major League Baseball (MLB) as a member team 6 | of the American League (AL) Central division. The team was founded as an expansion 7 | franchise in 1969, and has participated in four World Series, winning in 1985 and 8 | 2015, and losing in 1980 and 2014. The name Royals originates from the American 9 | Royal, a livestock show, horse show, rodeo, and championship barbeque competition 10 | held annually in Kansas City since 1899. 11 | tags: 12 | - MLB 13 | - National League 14 | - AL Central 15 | 16 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731160940-minnesota-twins.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Minnesota_Twins 3 | summary: Minnesota Twins 4 | note: The Minnesota Twins are an American professional baseball team based in Minneapolis, 5 | Minnesota. The Twins compete in Major League Baseball (MLB) as a member club of 6 | the American League (AL) Central division. The team is named after the Twin Cities 7 | area comprising Minneapolis and St. Paul. They played in Metropolitan Stadium from 8 | 1961 to 1981 and the Hubert H. Humphrey Metrodome from 1982 to 2009. They played 9 | their inaugural game at the newly completed Target Field on April 12, 2010. 10 | tags: 11 | - MLB 12 | - National League 13 | - AL Central 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731161550-houston-astros.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Houston_Astros 3 | summary: Houston Astros 4 | note: "The Houston Astros are an American professional baseball team based in Houston,\ 5 | \ Texas. The Astros compete in Major League Baseball (MLB) as a member club of the\ 6 | \ American League (AL) West division, having moved to the division in 2013 after\ 7 | \ spending their first 51 seasons in the National League (NL).[2][3] The Astros\ 8 | \ have played their home games at Minute Maid Park since 2000.[4] The Astros were\ 9 | \ established as the Houston Colt .45s and entered the National League in 1962 with\ 10 | \ the expansion New York Mets. The current name\u2014reflecting Houston's role as\ 11 | \ the control center of the U.S. space program\u2014was adopted three years later,\ 12 | \ when they moved into the Astrodome, the world's first domed sports stadium." 13 | tags: 14 | - MLB 15 | - National League 16 | - AL West 17 | 18 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731161927-los-angeles-angels.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Houston_Astros 3 | summary: Houston Astros 4 | note: The Los Angeles Angels of Anaheim, commonly known as the Los Angeles Angels, 5 | are an American professional baseball franchise based in Anaheim, California. The 6 | Angels compete in Major League Baseball (MLB) as a member club of the American League 7 | (AL) West division. The Angels have played home games at Angel Stadium since 1966. 8 | The current Major League franchise was established as an expansion team in 1961 9 | by Gene Autry, the team's first owner. The Angels name was taken by Autry in tribute 10 | to the original Los Angeles Angels, a Minor League franchise in the Pacific Coast 11 | League (PCL), which played in South Central Los Angeles from 1903 to 1957. 12 | tags: 13 | - MLB 14 | - National League 15 | - AL West 16 | 17 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731162502-oakland-athletics.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Oakland_Athletics 3 | summary: Oakland Athletics 4 | note: "The Oakland Athletics (often abbreviated to A's) are an American professional\ 5 | \ baseball team based in Oakland, California. The Athletics compete in Major League\ 6 | \ Baseball (MLB) as a member club of the American League (AL) West division. The\ 7 | \ club plays its home games at the Oakland\u2013Alameda County Coliseum. The club\ 8 | \ has won nine World Series championships, the third most of all current Major League\ 9 | \ Baseball teams. The Athletics' 2017 season will be the team's 50th season in Oakland.\ 10 | \ One of the American League's eight charter franchises, the club was founded in\ 11 | \ Philadelphia, in 1901 as the Philadelphia Athletics. They won three World Series\ 12 | \ championships from 1910 to 1913 and two in a row in 1929 and 1930. The team's\ 13 | \ owner and manager for its first 50 years was Connie Mack and Hall of Fame players\ 14 | \ included Chief Bender, Frank 'Home Run' Baker, Jimmie Foxx, and Lefty Grove." 15 | tags: 16 | - MLB 17 | - National League 18 | - AL West 19 | 20 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731162806-seattle-mariners.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Seattle_Mariners 3 | summary: Seattle Mariners 4 | note: The Seattle Mariners is an American professional baseball team based in Seattle, 5 | Washington. The Mariners compete in Major League Baseball (MLB) as a member club 6 | of the American League (AL) West Division. The team joined the AL as an expansion 7 | team in 1977. Since July 1999, the Mariners' home ballpark has been Safeco Field, 8 | located in the SoDo neighborhood of Seattle. The 'Mariners' name originates from 9 | the prominence of marine culture in the city of Seattle. They are nicknamed the 10 | M's, a title featured in their primary logo from 1987 to 1992. They adopted their 11 | current team colors - Navy blue, northwest green (teal), and silver - prior to the 12 | 1993 season, after having been royal blue and gold since the team's inception.[1] 13 | Their mascot is the Mariner Moose. 14 | tags: 15 | - MLB 16 | - National League 17 | - AL West 18 | 19 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/20170731163040-texas-rangers.yaml: -------------------------------------------------------------------------------- 1 | title: MLB Teams 2 | url: https://en.wikipedia.org/wiki/Texas_Rangers_(baseball) 3 | summary: Texas Rangers 4 | note: "The Texas Rangers are an American professional baseball team based in Arlington,\ 5 | \ Texas, located in the Dallas\u2013Fort Worth metroplex. The Rangers franchise\ 6 | \ is currently a member of the West division of the American League (AL) in Major\ 7 | \ League Baseball (MLB). Since 1994, the Rangers have played in Globe Life Park\ 8 | \ in Arlington in Arlington, Texas. The team's name is borrowed from the famous\ 9 | \ law enforcement agency of the same name." 10 | tags: 11 | - MLB 12 | - National League 13 | - AL West 14 | 15 | -------------------------------------------------------------------------------- /deprecated/docs/example/mlb/README.md: -------------------------------------------------------------------------------- 1 | Dave: Put the .yaml files in this folder. 2 | -------------------------------------------------------------------------------- /deprecated/docs/gs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: User's Guide 4 | permalink: /gs/ 5 | --- 6 | 7 | See [Using the Tools](https://github.com/ZettelGeist/zettelgeist/wiki/Using-the-Tools). 8 | -------------------------------------------------------------------------------- /deprecated/docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # You don't need to edit this file, it's empty on purpose. 3 | # Edit theme's home layout instead if you wanna make some changes 4 | # See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults 5 | layout: home 6 | --- 7 | -------------------------------------------------------------------------------- /deprecated/docs/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Installation 4 | permalink: /install/ 5 | --- 6 | 7 | See [Installing the Tools](https://github.com/ZettelGeist/zettelgeist/wiki/Installing-the-Tools). 8 | -------------------------------------------------------------------------------- /deprecated/docs/team.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: The Team 4 | permalink: /team/ 5 | --- 6 | 7 | See [Team](https://github.com/ZettelGeist/zettelgeist/wiki/Team). 8 | 9 | -------------------------------------------------------------------------------- /deprecated/docs/thenote.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Note Format 4 | permalink: /notes/ 5 | --- 6 | 7 | See [The Zettel Format](https://github.com/ZettelGeist/zettelgeist/wiki/The-Zettel-format). 8 | -------------------------------------------------------------------------------- /deprecated/docs/tutorial-GDocs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Tutorial-GDocs 4 | permalink: /tutorial-gdocs/ 5 | --- 6 | 7 | See [Writing with Google Docs](https://github.com/ZettelGeist/zettelgeist/wiki/Writing-with-Google-Docs). 8 | -------------------------------------------------------------------------------- /deprecated/docs/tutorial-Terminal.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Tutorial-Terminal 4 | permalink: /tutorial-term/ 5 | --- 6 | 7 | See [Tutorial](https://github.com/ZettelGeist/zettelgeist/wiki/Tutorial). 8 | -------------------------------------------------------------------------------- /deprecated/docs/tutorial-Word.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Tutorial-Word 4 | permalink: /tutorial-word/ 5 | --- 6 | 7 | See [Writing with Word](https://github.com/ZettelGeist/zettelgeist/wiki/Word-Musings). 8 | -------------------------------------------------------------------------------- /deprecated/zettelgeist/zfilter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import argparse 3 | import re 4 | import os 5 | import os.path 6 | import yaml 7 | import json 8 | from time import strftime 9 | 10 | from . import zdb, zettel, zquery 11 | 12 | 13 | def get_argparse(): 14 | parser = zdb.get_argparse() 15 | 16 | for field in zettel.ZettelFieldsOrdered: 17 | parser.add_argument('--show-%s' % field, 18 | action='store_const', const=True, default=False, 19 | help="include field <%s> in output" % field) 20 | 21 | parser.add_argument( 22 | '--metadata', action='store_const', const=True, default=False, 23 | help="write metadata") 24 | 25 | parser.add_argument( 26 | '--query-prompt', action='store_const', const=True, default=False, 27 | help="prompt for ZQL query (overrides --query, --query-file))") 28 | 29 | parser.add_argument( 30 | '--query-file', help="load ZQL query from file (overrides --query)", default=None) 31 | 32 | parser.add_argument( 33 | '--query-string', 34 | help="load ZQL from string", default=None) 35 | 36 | parser.add_argument( 37 | '--save-query', 38 | help="save source query to file", default=None) 39 | 40 | parser.add_argument( 41 | '--trace-sql', 42 | help="log all SQL statements used to file", default=None) 43 | 44 | parser.add_argument( 45 | '--save-sql', 46 | help="save compiled SQL to file (for developers only)", default=None) 47 | 48 | parser.add_argument( 49 | '--save', 50 | help="save to output folder", required=True) 51 | 52 | parser.add_argument( 53 | '--snip-size', 54 | help="snippet size", type=int, default=2500) 55 | 56 | return parser 57 | 58 | 59 | def write_data(filename, mode, comment, statement): 60 | if not filename: 61 | return 62 | with open(filename, mode) as outfile: 63 | outfile.write("\n".join([comment, statement]) + "\n\n") 64 | 65 | 66 | def counter(): 67 | i = 0 68 | while True: 69 | yield i 70 | i = i + 1 71 | 72 | 73 | def offsets_gen(int_offsets, text): 74 | iterations = len(int_offsets) // 4 75 | grouped = [tuple(int_offsets[i * 4:i * 4 + 4]) for i in range(0, iterations)] 76 | grouped = sorted(grouped, key=lambda item: item[2]) 77 | 78 | for group in grouped: 79 | (column, term, pos, size) = group 80 | yield {'column': column, 81 | 'term': term, 82 | 'pos': pos, 83 | 'size': size, 84 | 'substring': text[pos:pos + size]} 85 | 86 | 87 | def process_offsets(filename, text, offsets, context): 88 | int_offsets = [int(offset) for offset in offsets.split()] 89 | results = [] 90 | 91 | previous = (len(text), 0) 92 | for info in offsets_gen(int_offsets, text): 93 | pos = info['pos'] 94 | offset = info['size'] 95 | low_pos = max(pos - offset - context, 0) 96 | high_pos = min(pos + offset + context, len(text)) 97 | if pos >= previous[0] and pos + offset <= previous[1]: 98 | continue 99 | else: 100 | previous = (low_pos, high_pos) 101 | results.append(text[low_pos:high_pos]) 102 | return results 103 | 104 | 105 | def write_to_file(filepath, text, **kwargs): 106 | mode = kwargs.get("mode", "a") 107 | newlines = kwargs.get("newlines", 1) 108 | with open(filepath, mode) as outfile: 109 | outfile.write(text) 110 | if newlines: 111 | outfile.write("\n" * int(newlines)) 112 | 113 | 114 | def get_context(snip): 115 | text = snip.strip() 116 | ws_matches = list(re.finditer("\s+", text)) 117 | if len(ws_matches) < 2: 118 | return text 119 | 120 | first = ws_matches[0].end() 121 | last = ws_matches[-1].start() 122 | return text[first:last] 123 | 124 | 125 | # TODO Create zutils.py module 126 | 127 | def dirname(path): 128 | return os.path.split(path)[0] 129 | 130 | 131 | def basename(path): 132 | return os.path.split(path)[1] 133 | 134 | def get_match_clause(query): 135 | try: 136 | match_pos = query.find("MATCH") 137 | query = query[match_pos+len("MATCH"):] 138 | and_pos = query.find("AND") 139 | query = query[:and_pos] 140 | except: 141 | pass 142 | return query 143 | 144 | def main(): 145 | parser = get_argparse() 146 | args = parser.parse_args() 147 | argsd = vars(args) 148 | 149 | output_dir = args.save 150 | if os.path.exists(output_dir): 151 | print("Will not overwrite existing directory %s (exiting)." % output_dir) 152 | sys.exit(1) 153 | 154 | try: 155 | os.mkdir(output_dir) 156 | except: 157 | print("Could not create output folder %s (exiting)." % output_dir) 158 | sys.exit(1) 159 | 160 | if args.query_prompt: 161 | input_line = input("zfilter> ") 162 | elif args.query_file: 163 | with open(args.query_file) as infile: 164 | input_line = infile.read() 165 | elif args.query_string: 166 | input_line = args.query_string 167 | else: 168 | print("No query option (--query, --query-file, or --prompt) found (exiting).") 169 | sys.exit(1) 170 | 171 | print("zfilter writing results to folder %s" % output_dir) 172 | 173 | (ast2, semantics2) = zquery.compile2(input_line) 174 | db = zdb.get(args.database) 175 | gen = None 176 | for statement in [semantics2.sql_drop_matches_table(), semantics2.sql_create_matches_table(ast2)]: 177 | write_data(args.trace_sql, "a", "", statement) 178 | gen = db.fts_query(statement) 179 | for g in gen: 180 | pass 181 | 182 | select_sql = semantics2.sql_get_matches() 183 | 184 | write_data(args.trace_sql, "a", "# query match", select_sql) 185 | write_data(args.save_query, "w", "", input_line) 186 | write_data(args.save_sql, "w", "", ast2) 187 | write_data(args.trace_sql, "a", "# saved SQL query", ast2) 188 | 189 | search_counter = counter() 190 | 191 | search_count = next(search_counter) 192 | snippets_count = 0 193 | 194 | search_result_generator = db.fts_query(select_sql) 195 | 196 | all_results = list(search_result_generator) 197 | format_d_length = len(str(len(all_results))) 198 | match_filenames = [] 199 | snips_written = set() 200 | 201 | for search_result in all_results: 202 | docid = search_result['docid'] 203 | base_name = output_dir + ("-%%0%dd" % format_d_length) % search_count 204 | base_path = os.path.join(output_dir, base_name) 205 | yaml_path = base_path + '.yaml.in' 206 | 207 | print("... " + yaml_path) 208 | 209 | write_to_file( 210 | yaml_path, "# Note: This is a generated .yaml.in file intended for editing (editor or zettel command)", mode="w", newlines=0) 211 | 212 | bound_query = "SELECT *,docid from zettels where docid = %(docid)s" % vars( 213 | ) 214 | write_data(args.trace_sql, "a", 215 | "# finding zettels by docid", bound_query) 216 | 217 | search_details_generator = db.fts_query(bound_query) 218 | try: 219 | row = next(search_details_generator) 220 | except: 221 | print("Unexpected end of iteration") 222 | 223 | current_filename = row['filename'] 224 | match_filenames.append(current_filename) 225 | 226 | write_to_file(yaml_path, "# zfind search results", 227 | mode="a", newlines=1) 228 | write_to_file(yaml_path, "# filename = %s" % 229 | current_filename, mode="a", newlines=1) 230 | write_to_file(yaml_path, "# query = %s" % 231 | input_line.strip(), mode="a", newlines=2) 232 | 233 | try: 234 | loader = zettel.ZettelLoader(row['filename']) 235 | zettels = loader.getZettels() 236 | z = next(zettels) 237 | except: 238 | print("Warning: Cannot load source Zettel %s from filesystem (using database instead)" % 239 | row['filename']) 240 | z = None 241 | 242 | snip_size = max(args.snip_size, 250) 243 | for field in zettel.ZettelFields: 244 | show_field = "show_" + field 245 | if argsd.get(show_field, None): 246 | for query in semantics2.get_field_query_sql(field, snip_size, docid): 247 | field_query_generator = db.fts_query(query) 248 | write_data(args.trace_sql, "a", "", query) 249 | for result in field_query_generator: 250 | if query.find("offsets(") >= 0: 251 | #print("Processing offsets for %s" % field) 252 | snippets = process_offsets(current_filename, 253 | result[field + "_verbatim"], result[field + "_offsets"], snip_size) 254 | snippets_count = snippets_count + len(snippets) 255 | 256 | # Write text version 257 | snip_path = base_path + '-%s.txt' % field 258 | 259 | for snip in snippets: 260 | write_to_file(snip_path, "# filename = %s" % 261 | current_filename, mode="a", newlines=1) 262 | write_to_file(snip_path, "# field = %s" % 263 | field, mode="a", newlines=2) 264 | write_to_file(snip_path, "# query = %s" % get_match_clause(query), mode="a", newlines=2) 265 | write_to_file(snip_path, snip, mode="a", newlines=2) 266 | 267 | snip_id = (field, snip_path) 268 | if snip_id not in snips_written: 269 | write_to_file(yaml_path, 270 | "# %s -> See %s for snippets." % (field, snip_path), mode="a", newlines=2) 271 | snips_written.add(snip_id) 272 | 273 | elif result[field]: 274 | write_to_file(yaml_path, z.get_yaml( 275 | [field]), mode="a", newlines=1) 276 | 277 | search_count = next(search_counter) 278 | 279 | if False: 280 | drop_temp_matches_table = semantics2.sql_drop_matches_table() 281 | write_data(args.trace_sql, "a", "", drop_temp_matches_table) 282 | gen = db.fts_query(drop_temp_matches_table) 283 | for g in gen: 284 | pass 285 | 286 | if args.metadata: 287 | stats_path = os.path.join(output_dir, output_dir + '-stats.json') 288 | files_path = os.path.join(output_dir, output_dir + '-fileset.txt') 289 | 290 | doc = {'count': search_count, 291 | 'query': input_line.strip(), 292 | 'snips': list(snips_written)} 293 | 294 | write_to_file(stats_path, 295 | json.dumps(doc, indent=4, sort_keys=True), mode="w", newlines=1) 296 | write_to_file(files_path, "\n".join( 297 | match_filenames), mode="w", newlines=1) 298 | 299 | 300 | if __name__ == '__main__': 301 | main() 302 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-metadata 4 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZettelGeist/zettelgeist/477fa5427f089f9b9092c45f87f32a93af73e695/docs/.nojekyll -------------------------------------------------------------------------------- /docs/RELEASING.md: -------------------------------------------------------------------------------- 1 | # Notes to Selves 2 | 3 | - Start by updating `zversion.py` 4 | 5 | - We only use major, minor, and point releases (x.y.z) 6 | 7 | - To bump the release, modify `zversion.py`. At some point, we may add a "version bumping" framework, e.g. bump2version, but I don't see an immediate need for this yet. 8 | 9 | - Commit the changes 10 | 11 | - Tag a release in GitHub. Note that releasing on PyPI and releasing on GitHub are two different things. You can avoid having to keep track by runnign `git tag $(python setup.py --version)`. This will give the version that is associated with the Python setup.py file and use it not only to make a release but to ensure this release triggers a release on PyPI. 12 | 13 | - Make sure not only to `git push` but to `git push --tags`. 14 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Redirecting to https://github.com/ZettelGeist/zettelgeist/wiki 4 | 5 | 6 | -------------------------------------------------------------------------------- /jupyter/xyz.txt: -------------------------------------------------------------------------------- 1 | @misc{blahblahblah, 2 | title = {In Depth - In Depth: Ray Kurzweil - Book {TV}}, 3 | url = {http://www.booktv.org/Program/7515/In+Depth+Ray+Kurzweil.aspx}, 4 | urldate = {2011-02-11}, 5 | keywords = {*{AddedToZettels}}, 6 | file = {In Depth - In Depth\: Ray Kurzweil - Book TV:/Users/dbdennis/Library/Application Support/Zotero/Profiles/duztnovb.default/zotero/storage/TWWBX3QV/In+Depth+Ray+Kurzweil.html:text/html} 7 | } 8 | -------------------------------------------------------------------------------- /project/assembly.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.1") 2 | 3 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.15 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0") 2 | addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.9") 3 | addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0") 4 | 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | python-frontmatter 2 | tatsu 3 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Deploy to PyPI. Don't run this script. 3 | # 4 | 5 | rm -rf dist/* 6 | python setup.py sdist bdist_wheel 7 | twine upload --repository pypi dist/* 8 | 9 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZettelGeist/zettelgeist/477fa5427f089f9b9092c45f87f32a93af73e695/setup.cfg -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # setup.py - placeholder for eventual setup script 2 | 3 | from setuptools import setup 4 | from zettelgeist import zversion 5 | 6 | setup( 7 | name='zettelgeist', 8 | packages=['zettelgeist'], 9 | version=zversion.version(), 10 | description='ZettelGeist - a historiographically focused notetaking system', 11 | long_description='ZettelGeist - a historiographically focused notetaking system', 12 | author='ZettelGeist Laboratories', 13 | author_email='gkt@cs.luc.edu', 14 | license='Apache License 2.0', 15 | url='https://github.com/zettelgeist/zettelgeist', 16 | keywords=['notetaking', 'YAML', 'Markdown', 'sqlite3', 'GitHub'], 17 | classifiers=[ 18 | 'Development Status :: 4 - Beta', 19 | 'Programming Language :: Python :: 3', 20 | "Programming Language :: Python :: 3.10", 21 | "Programming Language :: Python :: 3 :: Only", 22 | "Topic :: Software Development", 23 | 'License :: OSI Approved :: Apache Software License' 24 | ], 25 | python_requires='>=3.10', 26 | install_requires=[ 27 | 'python-frontmatter', 28 | 'tatsu' 29 | ], 30 | entry_points = { 31 | 'console_scripts': [ 32 | 'zcreate = zettelgeist.zcreate:main', 33 | 'zimport = zettelgeist.zimport:main', 34 | 'zfind = zettelgeist.zfind:main', 35 | 'zettel = zettelgeist.zettel:main' 36 | ] 37 | } 38 | ) 39 | -------------------------------------------------------------------------------- /sphinx-docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /sphinx-docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /sphinx-docs/source/about.rst: -------------------------------------------------------------------------------- 1 | About 2 | ====== 3 | 4 | ZettelGeist is a plaintext note-taking system, inspired by the 5 | `ZettelKasten 6 | Method `__. 7 | 8 | The project founders have both been interested in taking notes long 9 | before discovering ZettelKasten. We really like the thought process 10 | behind ZettelKasten, however, and think it is ahead of its time by being 11 | “less is more” in its focus. 12 | 13 | A key, salient feature of our approach to implementing a ZettelKasten 14 | system is *not* to get distracted by GUI tools at an early stage of 15 | development. The default assumption of our system is that we work from 16 | plaintext files. We are particularly inspired by systems like Jekyll (a 17 | static-site generator for building web sites) that uses YAML to organize 18 | its front matter and Markdown as the body. We’re even starting more 19 | simply by just using YAML without Markdown, although we might introduce 20 | it at release time. The idea is to focus on true notetaking by not 21 | encouraging the writing of large, complex documents (which aren’t really 22 | notes, right??) 23 | 24 | So ZettelGeist is aimed at supporting the *spirit* of ZettelKasten, 25 | while ensuring that it will be useful in other domains. Our primary 26 | audience is the scholar who wants to write notes using a simple text 27 | editor and storing these notes in the cloud, e.g. in Dropbox, GitHub, 28 | etc. While we’d love to build something like the successor to Evernote 29 | or OneNote–even as a graphical client–our view is that no such tool 30 | should be developed without having the right core abstractions in place. 31 | Ultimately, the *note* is the central abstraction. Having support for 32 | metadata is crucial, especially for scholarly–or other serious–projects. 33 | 34 | Stay tuned!! 35 | -------------------------------------------------------------------------------- /sphinx-docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'ZettelGeist' 21 | copyright = '2020, George K. Thiruvathukal and David B. Dennis' 22 | author = 'George K. Thiruvathukal and David B. Dennis' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | version = os.environ.get("BOOK_VERSION", "beta") 26 | release = version 27 | 28 | 29 | rst_epilog = """ 30 | 31 | .. |site-version| replace:: **version %(version)s** 32 | 33 | """ % vars() 34 | 35 | # -- General configuration --------------------------------------------------- 36 | 37 | # Add any Sphinx extension module names here, as strings. They can be 38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 39 | # ones. 40 | extensions = [ 41 | 'sphinx.ext.todo', 42 | 'sphinx.ext.mathjax', 43 | ] 44 | 45 | # Add any paths that contain templates here, relative to this directory. 46 | templates_path = ['_templates'] 47 | source_suffix = ['.rst', '.md'] 48 | 49 | # List of patterns, relative to source directory, that match files and 50 | # directories to ignore when looking for source files. 51 | # This pattern also affects html_static_path and html_extra_path. 52 | exclude_patterns = [] 53 | 54 | 55 | # -- Options for HTML output ------------------------------------------------- 56 | 57 | # The theme to use for HTML and HTML Help pages. See the documentation for 58 | # a list of builtin themes. 59 | # 60 | html_theme = 'alabaster' 61 | 62 | html_theme_options = { 63 | 'logo': 'peace.png', 64 | 'github_user': 'zettelgeist', 65 | 'github_repo': 'zettelgeist', 66 | #'analytics_id' : 'UA-23507985-1', 67 | 'extra_nav_links' : { 68 | 'Site Index' : 'genindex.html', 69 | 'Software Systems Laboratory' : 'https://ssl.cs.luc.edu', 70 | } 71 | } 72 | 73 | # Add any paths that contain custom static files (such as style sheets) here, 74 | # relative to this directory. They are copied after the builtin static files, 75 | # so a file named "default.css" will overwrite the builtin "default.css". 76 | html_static_path = ['_static'] 77 | -------------------------------------------------------------------------------- /sphinx-docs/source/gs.rst: -------------------------------------------------------------------------------- 1 | Getting Started 2 | =================== 3 | 4 | 5 | Prerequisites 6 | ------------- 7 | 8 | Please visit the `Installation `__ before starting the 9 | tutorial. This tutorial assumes you have installed ZettelGeist and have 10 | confirmed that the tools are available in a Python virtualenv. 11 | 12 | We assume that your virtualenv is named ``zenv`` here. Wherever you see 13 | ``zenv`` here, your setup can be different, as long as you completed the 14 | installation and verified that it is nominally functioning. 15 | 16 | This tutorial also depends on sample files, provided at 17 | https://github.com/ZettelGeist/zg-tutorial. You can visit this page to 18 | download the examples, or you can use ``git`` to fetch it: 19 | 20 | .. code:: shell 21 | 22 | $ git clone https://github.com/ZettelGeist/zg-tutorial.git 23 | 24 | This will create the folder ``zg-tutorial``, which we’ll reference in 25 | this tutorial. 26 | 27 | Creating Zettels 28 | ---------------- 29 | 30 | The ``zettel`` command is used to create zettels. You can also create 31 | zettels using an ordinary text editor. 32 | 33 | Getting help 34 | ~~~~~~~~~~~~ 35 | 36 | .. code:: shell 37 | 38 | zettel --help 39 | 40 | The help shows what at first glance appears to be a bewildering number 41 | of options. However, most of the options are *the same* and are just 42 | being used to do an operation (set, delete, append, etc.) on any given 43 | field. 44 | 45 | Create a simple zettel 46 | ~~~~~~~~~~~~~~~~~~~~~~ 47 | 48 | .. code:: shell 49 | 50 | zettel --set-title "My First Zettel" 51 | 52 | This results in the following output: 53 | 54 | .. code:: yaml 55 | 56 | title: My First Zettel 57 | 58 | Create zettel with multiple fields 59 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 | 61 | A zettel can have as few fields as you wish, including zero. However, a 62 | zettel only becomes interesting as you add more information. Let’s add a 63 | *summary* and a *note*. 64 | 65 | .. code:: shell 66 | 67 | zettel --set-title "My First Zettel" --set-summary "A Zettel with a note" --set-note "Line 1\nLine 2\nLine 3" 68 | 69 | This results in 70 | 71 | .. code:: yaml 72 | 73 | title: My First Zettel 74 | summary: A Zettel with a note 75 | note: |- 76 | Line 1 77 | Line 2 78 | Line 3 79 | 80 | When setting a field to a string value as we have done for each of these 81 | fields, it is permitted to have *embedded newlines* anywhere you like. 82 | For the note we have written, we have three input lines, each of which 83 | appears on a separate line. 84 | 85 | YAML (the format in which Zettels are stored) provides excellent support 86 | for this concept and will take your text and indent it using a multiline 87 | string. As long as each line is indented consistently relative to the 88 | *note* key, it will be valid. 89 | 90 | Obviously, writing longer strings using the command line is sometimes 91 | impractical, so we created two ways of being able to do this easily: 92 | prompting for input (using the ``--prompt-`` options) or by 93 | loading the plaintext from a file (using ``--load-``). Each of 94 | these is easy to demonstrate. 95 | 96 | Let’s try loading some text by having ``zettel`` prompt for it. We’ll 97 | modify the above command as follows: 98 | 99 | .. code:: shell 100 | 101 | zettel --set-title "My First Zettel" --set-summary "A Zettel with a note" --prompt-note 102 | 103 | :: 104 | 105 | Enter text for note. ctrl-d to end. 106 | note> Line 1 107 | note> Line 2 108 | note> Line 3 109 | note> 110 | note> Even a blank line is allowed. 111 | note> 112 | 113 | Results 114 | 115 | .. code:: yaml 116 | 117 | title: My First Zettel 118 | summary: A Zettel with a note 119 | note: |- 120 | Line 1 121 | Line 2 122 | Line 3 123 | 124 | Even a blank line is allowed. 125 | 126 | Load field from another file 127 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 128 | 129 | TODO 130 | 131 | Indexing Zettels for Search 132 | --------------------------- 133 | 134 | For this section, we provide you with access to some sample zettels. 135 | These can be found in the ZettelGeist tutorial repository at 136 | https://github.com/ZettelGeist/zg-tutorial.git. (See Prerequisites 137 | above.) 138 | 139 | You can be in any folder while trying this, but we’ll assume you are in 140 | the ``zettelgeist\docs`` after performing an initial clone of our 141 | repository. 142 | 143 | .. code:: shell 144 | 145 | $ cd zg-tutorial 146 | $ zcreate --database mlb.db 147 | Creating new database mlb.db 148 | 149 | 150 | .. code:: shell 151 | 152 | $ ls zettels/baseball 153 | 154 | arizona-diamondbacks.yaml milwaukee-brewers.yaml 155 | atlanta-braves.yaml minnesota-twins.yaml 156 | baltimore-orioles.yaml new-york-mets.yaml 157 | boston-red-sox.yaml new-york-yankees.yaml 158 | chicago-cubs.yaml oakland-athletics.yaml 159 | chicago-grey-sox.yaml philadelphia-phillies.yaml 160 | cincinnati-reds.yaml pittsburgh-pirates.yaml 161 | cleveland-indians.yaml san-diego-padres.yaml 162 | colorado-rockies.yaml seattle-mariners.yaml 163 | detroit-tigers.yaml st-louis-cardinals.yaml 164 | houston-astros.yaml tampa-bay-rays.yaml 165 | kansas-city-royals.yaml texas-rangers.yaml 166 | los-angeles-angels.yaml toronto-blue-jays.yaml 167 | los-angeles-dodgers.yaml washington-nationals.yaml 168 | miami-marlins.yaml``` 169 | 170 | 171 | .. code:: shell 172 | 173 | $ zimport --database mlb.db --dir $(pwd) 174 | 175 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/baltimore-orioles.yaml 176 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/kansas-city-royals.yaml 177 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/los-angeles-angels.yaml 178 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/miami-marlins.yaml 179 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/milwaukee-brewers.yaml 180 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/seattle-mariners.yaml 181 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/arizona-diamondbacks.yaml 182 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/st-louis-cardinals.yaml 183 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/houston-astros.yaml 184 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/oakland-athletics.yaml 185 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/boston-red-sox.yaml 186 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/new-york-yankees.yaml 187 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/pittsburgh-pirates.yaml 188 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/detroit-tigers.yaml 189 | Importing /Users/gkt/Work/zg-tutorial/zettels/baseball/cincinnati-reds.yaml 190 | [...] 191 | 192 | What you see will differ slightly. Where you see ``/Users/gkt/Work``, 193 | you are likely to see the path to your own checkout directory. 194 | 195 | Let’s look at one of these zettels. 196 | 197 | .. code:: yaml 198 | 199 | title: MLB Teams 200 | summary: Arizona Diamondbacks 201 | note: | 202 | The Arizona Diamondbacks, often shortened as the D-backs, are an American professional 203 | baseball franchise based in Phoenix, Arizona. The club competes in Major League 204 | Baseball (MLB) as a member of the National League (NL) West division. Since the 205 | team's inception in 1998, the franchise has played home games at Chase Field, formerly 206 | known as Bank One Ballpark. The Diamondbacks have won one World Series championship 207 | (in 2001), becoming the fastest expansion team in the Major Leagues to win a championship, 208 | doing it in only the fourth season since the franchise's inception in the 1998 Major 209 | League Baseball season. 210 | tags: 211 | - MLB 212 | - National League 213 | - NL West 214 | cite: 215 | bibkey: arizona-diamondbacks-wikipedia 216 | page: web page 217 | 218 | Each of these zettels contains some information one might typically 219 | place on a note card. In our view of the world, notes would include 220 | important basics. The note will often be one of the longer fields. It 221 | can be written using what is known as the YAML block style. This means 222 | that all lines of input are taken, provided they maintain the same 223 | indentation level and/or blank. Everything will be taken as input until 224 | the next field or end of file is found. 225 | 226 | Also shown here are how you can maintain a list of tags. The ``tags`` 227 | field allows you to specify one or more tags. While we hope one day to 228 | build an auto-classifier (someday, someday…), we find that we actually 229 | need to assign labels, especially in our own book project that is 230 | actually making use of these tools. 231 | 232 | Search Examples 233 | --------------- 234 | 235 | Searching is done (at present) using the ``zfind`` tool. This tool can 236 | only perform AND-style queries, but it will soon offer every conceivable 237 | possibility. This limitation is similar to what you find in systems like 238 | Gmail’s search operators, but even Gmail allows for NOT terms. 239 | 240 | The ``zfind`` tool has options to search every field. Once a field 241 | matches, you can use the show options to project values from the Zettel. 242 | There is also a ``--count`` option to tell you how many Zettels matched 243 | a query. 244 | 245 | Find how many Zettels mention Chicago in the ``summary`` field: 246 | 247 | :: 248 | 249 | zfind --database mlb.db --find-summary Chicago --count 250 | 2 Zettels matched search 251 | 252 | …and print the ``summary and``\ filename\` of the zettels: 253 | 254 | :: 255 | 256 | zfind --database mlb.db --find-summary Chicago --count --show-filename 257 | filename: 258 | 20170731132024-chicago-cubs.yaml 259 | 260 | ---------------------------------------- 261 | 262 | filename: 263 | 20170731155613-chicago-grey-sox.yaml 264 | 265 | ---------------------------------------- 266 | 267 | 2 Zettels matched search 268 | 269 | …and show the ``summary`` about the teams: 270 | 271 | :: 272 | 273 | zfind --database mlb.db --find-summary Chicago --count --show-filename --show-summary 274 | summary: 275 | Chicago Cubs 276 | 277 | filename: 278 | 20170731132024-chicago-cubs.yaml 279 | 280 | ---------------------------------------- 281 | 282 | summary: 283 | Chicago White Sox 284 | 285 | filename: 286 | 20170731155613-chicago-grey-sox.yaml 287 | 288 | ---------------------------------------- 289 | 290 | Find the terms MLB and Central in the ``note`` field. Upon finding a 291 | match, show the ``filename`` and the ``summary`` fields. 292 | 293 | :: 294 | 295 | zfind --database mlb.db --find-note "MLB Central" --show-filename --show-summary 296 | summary: 297 | Chicago Cubs 298 | 299 | filename: 300 | 20170731132024-chicago-cubs.yaml 301 | 302 | ---------------------------------------- 303 | 304 | summary: 305 | Cincinnati Reds 306 | 307 | filename: 308 | 20170731133642-cincinnati-reds.yaml 309 | 310 | ---------------------------------------- 311 | 312 | summary: 313 | Pittsburgh Pirates 314 | 315 | filename: 316 | 20170731135121-pittsburgh-pirates.yaml 317 | 318 | ---------------------------------------- 319 | 320 | summary: 321 | St. Louis Cardinals 322 | 323 | filename: 324 | 20170731135823-st-louis-cardinals.yaml 325 | 326 | ---------------------------------------- 327 | 328 | Find all zettels with Cubs mentioned in the ``note`` field: 329 | 330 | :: 331 | 332 | zfind --database mlb.db --find-note Cubs --show-note 333 | 334 | note: 335 | The Chicago Cubs are an American professional baseball team based in Chicago, Illinois. The Cubs compete in Major League Baseball (MLB) as a member club of the National League (NL) Central division, where they are the defending World Series champions. The team plays its home games at Wrigley Field, located on the city's North Side. The Cubs are one of two major league teams in Chicago; the other, the Chicago White Sox, is a member of the American League (AL) Central division. The Cubs, first known as the White Stockings, was a founding member of the NL in 1876, becoming the Chicago Cubs in 1903.[2] The Cubs have appeared in a total of eleven World Series. The 1906 Cubs won 116 games, finishing 116–36 and posting a modern-era record winning percentage of .763, before losing the World Series to the Chicago White Sox by four games to two. The Cubs won back-to-back World Series championships in 1907 and 1908, becoming the first major league team to play in three consecutive World Series, and the first to win it twice. Most recently, the Cubs won the 2016 National League Championship Series and 2016 World Series, which ended a 71-year National League pennant drought and a 108-year World Series championship drought, 336 | -------------------------------------------------------------------------------- /sphinx-docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to ZettelGeist 2 | ====================== 3 | 4 | ZettelGeist is research software for plaintext notettaking. 5 | 6 | .. toctree:: 7 | :hidden: 8 | :caption: Contents: 9 | 10 | about 11 | gs 12 | install 13 | team 14 | thenote 15 | tutorial-gdocs 16 | tutorial-terminal 17 | tutorial-world 18 | -------------------------------------------------------------------------------- /sphinx-docs/source/install.rst: -------------------------------------------------------------------------------- 1 | Prerequisites for All Installations 2 | ----------------------------------- 3 | 4 | Python 3 is *required* to use ZettelGeist. We don’t have resources to 5 | support multiple versions of Python. 6 | 7 | We also recommend installing 8 | `bibutils `__ and 9 | `sqlite3 with full-text search `__. 10 | You may not need either of these, but should you run into issues, we may 11 | ask you to share some output from sqlite3 commands with us in your bug 12 | reports. 13 | 14 | We only support Unix/Linux, OS X using `Homebrew `__, 15 | and Windows using `Windows Subsystem for 16 | Linux `__. 17 | 18 | Please also note that ZettelGeist is not a web-based or GUI program 19 | (yet). This system is for people who *prefer* working with plaintext, 20 | text editors, and the command line. If this is not you, you will 21 | probably not like ZettelGeist and should proceed at your own peril. 22 | 23 | Installation for General Users 24 | ------------------------------ 25 | 26 | - Create a virtual environment for running ZettelGeist: 27 | 28 | .. code:: shell 29 | 30 | python3 -m venv ~/zenv 31 | 32 | You can install your environment wherever you like, but we are going 33 | to assume ``~/zenv`` in the remaining discussion and in our tutorial 34 | to *avoid* having to talk about user-specific details. 35 | 36 | - Source the virtual environment 37 | 38 | .. code:: shell 39 | 40 | . ~/zenv/bin/activate 41 | 42 | - And *ensure* that you are picking up the right ``python`` and 43 | ``pip``. 44 | 45 | .. code:: shell 46 | 47 | ~ . ~/zenv/bin/activate 48 | (zenv) ~ which pip 49 | /Users/gkt/zenv/bin/pip 50 | (zenv) ~ which python 51 | /Users/gkt/zenv/bin/python 52 | 53 | Your username would likely appear above instead of *gkt*, unless you 54 | share my initials. 55 | 56 | - Now install ZettelGeist 57 | 58 | .. code:: shell 59 | 60 | (zenv) ~ pip install zettelgeist 61 | Collecting zettelgeist 62 | Downloading zettelgeist-0.12.2-py3-none-any.whl 63 | Collecting tatsu (from zettelgeist) 64 | Using cached TatSu-4.2.5-py2.py3-none-any.whl 65 | Collecting PyYAML (from zettelgeist) 66 | Installing collected packages: tatsu, PyYAML, zettelgeist 67 | Successfully installed PyYAML-3.12 tatsu-4.2.5 zettelgeist-0.12.2 68 | 69 | If you see ``zettelgeist-`` in the above output, you should 70 | have a successful install. Let’s verify: 71 | 72 | .. code:: shell 73 | 74 | (zenv) ~ which zcreate 75 | /Users/gkt/zenv2/bin/zcreate 76 | (zenv) ~ which zimport 77 | /Users/gkt/zenv2/bin/zimport 78 | (zenv) ~ which zquicksearch 79 | /Users/gkt/zenv2/bin/zquicksearch 80 | (zenv) ~ which zfilter 81 | /Users/gkt/zenv2/bin/zfilter 82 | (zenv) ~ which zettel 83 | /Users/gkt/zenv2/bin/zettel 84 | 85 | - And create your first zettel: 86 | 87 | .. code:: shell 88 | 89 | zettel --set-title "My First Zettel" --set-summary "I feel empowered." --append-tags "Tutorial" "ZettelGeist" "Install" 90 | title: My First Zettel 91 | summary: I feel empowered. 92 | tags: 93 | - Tutorial 94 | - ZettelGeist 95 | - Install 96 | 97 | - Then you should proceed to the `Getting Started `__ page. 98 | 99 | Developer Install 100 | ----------------- 101 | 102 | Coming soon. 103 | -------------------------------------------------------------------------------- /sphinx-docs/source/team.rst: -------------------------------------------------------------------------------- 1 | Team 2 | ========== 3 | 4 | 5 | - `George K. Thiruvathukal `__ - 6 | Professor of Computer Science at Loyola University Chicago 7 | - `David B. Dennis `__ 8 | - Professor of History at Loyola University Chicago 9 | -------------------------------------------------------------------------------- /sphinx-docs/source/thenote.rst: -------------------------------------------------------------------------------- 1 | The Note Format 2 | ================= 3 | 4 | A note is nothing more than a YAML document. Please note that, 5 | hereafter, we may use the terms notes, cards, and zettels rather 6 | interchangeably. We’ve used other systems and sometimes find ourselves 7 | using the terminology rather freely. 8 | 9 | When we use the term *note*, please keep in mind that the term as we see 10 | it is interchangeable with *index cards*, *cards*, or *zettels*. So 11 | regardless of what terminlology you prefer, we welcome you! 12 | 13 | Anyway, the idea of notetaking is to keep it simple, so a note should 14 | make no assumptions about formatting whatsoever. In our view of the 15 | world, we should be able to introduce other fields but are hopeful that 16 | we have identified most of the important ones. 17 | 18 | In our current thinking, we have the following sections: 19 | 20 | - title: an optional title (string) 21 | - tags: one or more keywords (list of string) 22 | - mentions: one or more mentions (list of string) 23 | - dates: a year (string) and era (string) as a nested dictionary 24 | - bibtex, ris, or inline (string) 25 | - url (string) 26 | - bibkey (string) 27 | - cite: a bibkey (from same or another zettel) and a page number (or 28 | range of page numbers) 29 | - summary: (string) - concise summary of the note (by convention) 30 | - note (string) - details, usually the text you are wanting to cite 31 | - comment (string) - any comment you want to make about the zettel in 32 | general 33 | 34 | In most situations, freeform text is permitted. In some situations, you 35 | will need to put quotes around the text, especially if you are using 36 | reserved YAML characters. 37 | 38 | These all are intended to be string data, so there are no restrictions 39 | on what can be in any field; however, we will likely limit tags, 40 | mentions, dates in some way as we go forward. Fields such as bibtex, 41 | ris, or inline are also subject to validity checking. 42 | 43 | Here’s an example where of a zettel where most fields are being used. 44 | 45 | .. code:: yaml 46 | 47 | title: First BIB Note for Castells 48 | tags: 49 | - Castells 50 | - Network Society 51 | - Charles Babbage is Awesome 52 | - Charles Didn't do Everything 53 | mentions: 54 | - gkt 55 | - dbdennis 56 | dates: 57 | year: "2016" 58 | era: "AD" 59 | cite: 60 | bibkey: Castells Rise 2016 61 | page: ii-iv 62 | comment: This is my first zettel but my comments have nothing to do with the note itself. 63 | summary: Lorem ipsum rocks. This is a summary of what you see in the note field. 64 | note: | 65 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eleifend est sed diam maximus rutrum. Quisque sit amet imperdiet odio, id tristique libero. Aliquam viverra convallis mauris vel tristique. Cras ac dolor non risus porttitor molestie vel at nisi. Donec vitae finibus quam. Phasellus vehicula urna sed nibh condimentum, ultrices interdum velit eleifend. Nam suscipit dolor eu rutrum fringilla. Sed pulvinar purus purus, sit amet venenatis enim convallis a. Duis fringilla nisl sit amet erat lobortis dictum. Nunc fringilla arcu nec ex blandit, a gravida purus commodo. Vivamus lacinia tellus dui, vel maximus lacus ornare id. 66 | 67 | Vivamus euismod justo sit amet luctus bibendum. Integer non mi ullamcorper enim fringilla vulputate sit amet in urna. Nullam eu sodales ipsum. Curabitur id convallis ex. Duis a condimentum lorem. Nulla et urna massa. Duis in nibh eu elit lobortis vehicula. Mauris congue mauris mollis metus lacinia, ut suscipit mi egestas. Donec luctus ante ante, eget viverra est mollis vitae. 68 | 69 | Vivamus in purus in erat dictum scelerisque. Aliquam dictum quis ligula ac euismod. Mauris elementum metus vel scelerisque feugiat. Vivamus bibendum massa eu pellentesque sodales. Nulla nec lacus dolor. Donec scelerisque, nibh sed placerat gravida, nunc turpis tristique nibh, ac feugiat enim massa ut eros. Nulla finibus, augue egestas hendrerit accumsan, tellus augue tempor eros, in sagittis dolor turpis nec mi. Nunc fringilla mi non malesuada aliquet. 70 | bibkey: 71 | Castells Rise 1996 72 | bibtex: | 73 | @book{castells_rise_1996, 74 | address = {Cambridge, Mass.}, 75 | series = {Castells, {Manuel}, 1942- {Information} age . v}, 76 | title = {The rise of the network society}, 77 | isbn = {978-1-55786-616-5}, 78 | language = {eng}, 79 | publisher = {Blackwell Publishers}, 80 | author = {Castells, Manuel}, 81 | year = {1996}, 82 | keywords = {Information networks., Information society., Information technology Economic aspects., Information technology Social aspects., Technology and civilization.} 83 | } 84 | 85 | Here is a simple example of a bookmark: 86 | 87 | .. code:: yaml 88 | 89 | title: Zettelgeist.com 90 | url: http://zettelgeist.com 91 | note: Zettelgeist is a plaintext notetaking system designed for scholarly/research purposes. 92 | 93 | It’s really that simple! 94 | -------------------------------------------------------------------------------- /sphinx-docs/source/tutorial-gdocs.rst: -------------------------------------------------------------------------------- 1 | Gdocs 2 | ======== 3 | 4 | 5 | **This page is under construction. Pardon the sketchiness for now.** 6 | 7 | What do you want to do? 8 | ----------------------- 9 | 10 | - Take research notes for a paper in order to be able to search them 11 | for … anything. 12 | 13 | - Follow the traditional (and ever-valid) methods of writing a note 14 | with a title, some keywords (tags), a note (with comment or summary 15 | if desired), and some bibliographical information (book or article 16 | title and page number[s]). 17 | 18 | - Find particular notes on particular themes and issues. 19 | 20 | - Send those particular notes to a file that will be the basis for a 21 | portion of your outline or draft. 22 | 23 | All of these basic research, organization, and writing steps are steeped in traditional methods. 24 | ------------------------------------------------------------------------------------------------ 25 | 26 | - As researchers and writers of papers, articles, books – from grade 27 | school, high school, college, graduate school, through our 28 | professional writings – as well as teachers and editors of countless 29 | efforts by others, we know the game. Indeed, we are the coaches and 30 | referees and main players of the game! And our own coaches taught us 31 | how to do it right! 32 | 33 | - On the basis of this experience, we made ZettelGeist to do the most 34 | important, fundamental steps of research and writing as clearly and 35 | directly as possible, based on the methods that our mentors used to 36 | write great books before personal computers came into being. 37 | 38 | - But because we are ourselves computerized (having come into 39 | professional life just as the pc revolution occurred and, therefore, 40 | having played *that game* ever since), we have here merged these 41 | techniques into the computer world more directly than any program has 42 | before. (Believe us: we know! We have tried and deployed every option 43 | out there, from 1980 until yesterday – as a matter of professional 44 | need.) 45 | 46 | - Since we know the frustration that many so-called “notetaking 47 | programs” cause, we have made a fundamental decision to ensure that 48 | the basis for all of this is already in the computer you own and the 49 | internet sites you have access to. 50 | 51 | - You don’t have to go and buy anything new. You already have 52 | *supercomputers* that earlier great writers could never have 53 | imagined. This system will just help you to take advantage of these 54 | machines in ways consistent with the key principles of research and 55 | organization that the great writers developed, but most computer 56 | programs have left out. 57 | 58 | - This is the Research-Writing-Computer Singularity we have been 59 | waiting for! 60 | 61 | The first thing to know is that with ZettelGeist you can do ALL of the above by starting (and finishing) your writing with ANY SOFTWARE YOU WANT TO USE!! The ZettelGeist program works with and *between* your preferred word processors. 62 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 63 | 64 | - Many programs suggest they are “app-gnostic” (agnostic or indifferent 65 | about which app you use), but that usually just means you can save 66 | your work into another format (docx, pdf, txt, etc.). 67 | 68 | - ZettelGeist is truly app neutral in the sense that you can make notes 69 | (zettels) with any software, as long as you make them according to a 70 | certain pattern (indicating note section, title section, etc…) and 71 | save or download them in good old “.txt” format. 72 | 73 | - The “pattern” is exactly what you would use to write out a notecard 74 | in the traditional way (by hand, or typed on paper or computer), so 75 | it really isn’t that big a deal. Plus, once you make one card (or 76 | zettel), you can just edit the same card to make any necessary 77 | changes for the next card (change the note, change the page numbers, 78 | etc.) then save the new card with a new filename, eg. “note02.txt” 79 | and move on… 80 | 81 | - You can do this with ANY word processor you want to use: Google Docs, 82 | Microsoft Word, LibreOffice. In fact, you could just use one of the 83 | most basic editors that are already residing on your computer, or 84 | easily installed for free: Notepad, Wordpad (on Windows), TextEdit 85 | (Mac), Vim, Emacs, etc. 86 | 87 | - If that last sentence confuses you, don’t worry. Just use Google Docs 88 | or Word or whatever you are used to. (The surprise is that you don’t 89 | actually have to buy any word processor at all because the above 90 | basic text editors come with your system and ZettelGeist would allow 91 | you to use those for free to research, organize, and write any great 92 | work you need to produce – but let’s set that issue aside for the 93 | moment.) 94 | 95 | Let’s try it out with Google Docs since we all have access to that. 96 | ------------------------------------------------------------------- 97 | 98 | - As you can see on the “Get Started” and “Note Format” page above, a 99 | note in ZettelGeist is just a set of information put together in 100 | sections marked with a colon, like title: or note: or tags:, etc. 101 | 102 | - There are a number of those built into the system (see Note Format 103 | page) because, as researchers, we know you might also want to 104 | “comment:” or write a “summary:” or add bibliographical information 105 | such as “bibkey:” and “pages:”, and so on. 106 | 107 | - BUT this is completely up to you. You can add any of these elements, 108 | or only one or two, in any order according to your needs. A 109 | completely valid note would just start with “note:” and then just 110 | consist of the text of your note in the following line surrounded by 111 | quotations, including all the information you want to produce or 112 | record right there. That would work just fine. You could then save it 113 | as “note-01.txt” and it could be processed in ZettelGeist without a 114 | problem (after a minor change to the filename so it can be searched 115 | and used in the system – more on that in a minute). 116 | 117 | - If you want the other elements, like title: summary: or comment: 118 | great, just add them too. As long as you name sections according to 119 | the list on the “Note Format” page, or listed in “zettel –help”, you 120 | can create notes however you prefer, with sections in whatever order 121 | you like. Basically, you are making up your own notetaking system 122 | (based on these universally valid “fields”) and can treat any “file” 123 | as a blank notecard, just as you do when you buy a pack of 3 x 5 124 | notecards at the pharmacy and make flash cards for a high school 125 | class. Fill them out as you like! 126 | 127 | So, with that flexibilty in mind, let’s make your first note. 128 | ------------------------------------------------------------- 129 | 130 | For now, just go to Google Docs (or Word, or…your choice – but we will use Google Docs for this example since we all have access and some familiarity with this editor.) 131 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 132 | 133 | - Start a new Doc. 134 | 135 | - Then take one step that will help with this experiment. 136 | 137 | - Go to “Tools>Preferences” and **uncheck** most of the automatic 138 | styling elements. 139 | 140 | ``Uncheck "Automatically capitalize" "Use smart quotes" "Automatically detect lists" and the main "Automatic substitution."`` 141 | 142 | - We want the simplest and plainest characters possible (most programs 143 | add fancier “unicode” characters with these features – but we don’t 144 | need them and they actually mess up searching and finding later). 145 | 146 | - You can always turn these back on later, but you probably wouldn’t 147 | miss most of these anyway. 148 | 149 | - Close preferences and then just look at your plain Doc page. But now 150 | you can think of it a little differently. This is now a *notecard* 151 | (right out of your 3 x 5 package)! Even though it is on a 152 | supercomputer in the “cloud” linked to the internet, it is just a 153 | “card” now. Let’s just fill it in as we would by hand. 154 | 155 | - Let’s say you want to give it a title (remember, it’s up to you 156 | whether you need a title, but this will remind you what this field 157 | and other subsequent ones in this research session are about). 158 | 159 | - So, type: 160 | 161 | ``title: Reading notes on The Great Gatsby`` 162 | 163 | - Ok. That’s the top line of your note, just like on the “red” line of 164 | your good old notecard. 165 | 166 | - Now, let’s put in something about the book you are reading, for 167 | instance (you could be taking notes for anything including your own 168 | novel or writing poetry or writing a shopping list, but we are 169 | thinking research paper for now). 170 | 171 | - Make a new line and type: 172 | 173 | ``note: "This is a note about The Great Gatsby, a novel by F. Scott Fitzgerald. Written during The Jazz Age, it is a masterpiece of American Literature."`` 174 | 175 | - Notice that I put the text part of this note: “inside quotation 176 | marks.” This is necessary when you write longer notes because it 177 | means you can put quotes and colons and multiple lines into your 178 | plain text card. Just a formality, but not a big deal. If you just 179 | write a single line without colons and other such things, you don’t 180 | need the quotes. But it works better with them if you are making 181 | notes this initial way with GDocs or another word processer. 182 | 183 | - For now, let’s just stop there and see what we can do with that very 184 | first note. 185 | 186 | - Let’s name the file, on Google Docs, by simply clicking in the file 187 | name box above (as usual – you know) and typing “Gatsby-Note”. 188 | 189 | - Now let’s download it to your computer so we can soon make it into a 190 | zettel for research processing. 191 | 192 | - Click “File>Download as” and select “Plain Text (.txt)”. 193 | 194 | - Immediately, it will save to your computer (into the directory set by 195 | your browser for downloads – usually Downloads). 196 | 197 | - If you want, you can click on the download tab at the bottom of your 198 | browser to open it, or go into the directory to see it there. It will 199 | look just like your original, but maybe a little simpler in a plain 200 | text editor (which is retro-cool). 201 | 202 | But let’s make a couple of more notes (zettels) before we do any more. 203 | ---------------------------------------------------------------------- 204 | 205 | - All you need to do to make your next note(s) is edit your existing 206 | Google Doc! You don’t have to create a new one or anything. You 207 | already saved your first card, so it is safe. Now just edit your next 208 | one on the basis of this start, and save the new iteration as the 209 | next note. 210 | 211 | - We can leave title: the same… So no changes there. 212 | 213 | - Let’s change the note: (obviously). Just highlight from the first 214 | quotation mark to the last, delete the original note, and write 215 | another. 216 | 217 | ``note: "The novel opens with the lines 'In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since. 'Whenever you feel like criticizing any one,' he told me, 'just remember that all the people in this world haven’t had the advantages that you’ve had.' (Gatsby, 1)"`` 218 | 219 | - We just added a quote from the book. So you might want to write 220 | something about that citation (your own opinion of its importance, 221 | etc.) as well. (Teachers want to hear your voice, and you want to 222 | remember why you took the note.) 223 | 224 | - That’s simple: You could just add something to the “note:” section 225 | itself: 226 | 227 | ``"The novel opens with the lines 'In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since. “Whenever you feel like criticizing any one,' he told me, 'just remember that all the people in this world haven’t had the advantages that you’ve had.' (Gatsby, 1) Comment: This is a famous first line and my teacher says that we should analyze it carefully."`` 228 | 229 | - See the “Comment” at the end? That would do it. As a result, you have 230 | title, note, citation-page (Gatsby, 1), and a comment (inside that 231 | last quotation mark). All the elements of a traditional notecard are 232 | there, just within the “note:” field. So let’s save that as a second 233 | note. 234 | 235 | - Just click “File>Download>Plain Text (.txt) again. It will 236 | automatically download (and get a new name with”(1)" added by Google 237 | Docs) – so you don’t have to do anything to change the filename, etc. 238 | Just click. 239 | 240 | - Cool. Two notes are now in your research “card stack” for processing. 241 | If we did pull them into the system, they would be completely 242 | searchable and usable. Again: you could just take notes with “notes:” 243 | or “title:” and “note:” and that will do the job. 244 | 245 | - But, you can do a lot more if you want to. ZettelGeist allows you to 246 | break up these elements of research notes into each of the 247 | traditional elements listed on the “Note Format” page! 248 | 249 | So let’s go back to our GDocs page and adjust this note to make a third with a little more…zing! 250 | ------------------------------------------------------------------------------------------------ 251 | 252 | - Highlight “Comment: This is a famous first line and my teacher says 253 | that we should analyze it carefully.” Then cut that (not delete). 254 | 255 | - Make a new line and paste it. Then make the capital “C” into a 256 | lowercase “c” and put your comment in quotations, resulting in: 257 | 258 | ``comment: This is a famous first line and my teacher says that we should analyze it carefully."`` 259 | 260 | - You just set up a new “comment:” field that can be searched 261 | separately if you want. This is not necessary (as above) but it does 262 | allow you to separate, let’s say, the quotes you take from the source 263 | (in “note:”) and your ideas (in “comment:”). It’s up to you, but just 264 | in case you like it, it’s that easy to add more fields (per the “Note 265 | Format” page). 266 | 267 | - Now, let’s do something else that is key to research. Add “tags” to 268 | the note. This is another traditional part of any notecard system. It 269 | allows you to mark each note as being relevant to a theme or a 270 | keyword or a part of your paper (Intro, Body 1, Body 2, Conclusion, 271 | etc.). Adding tags is also really easy with the ZettelGeist method. 272 | 273 | - Continue with the existing GDoc. 274 | 275 | - (See? Making new “cards” just means editing and then re-saving 276 | your existing card in .txt format with a new name – done 277 | automatically in GDocs. But the process is essentially the same 278 | for Word or whatever editor you are using – just give each new 279 | “save as” a different number: Gatsby-Note-01.yaml, 280 | Gatsby-Note-02.yaml, Gatsby-Note-03.yaml, etc. The existing 281 | elements just get reused over and over as you save every new 282 | version to your “stack.”) 283 | 284 | - To add tags, start a new line under the “comment:” line. 285 | 286 | - Type this: 287 | 288 | :: 289 | 290 | tags: 291 | - My first tag 292 | - Gatsby note 293 | - First line of book 294 | 295 | - Could it be simpler? Ha! “tags:” is the new section, just as above. 296 | But each tag is separate, so you just start the line for each tag 297 | with a hyphen to indicate this is the case. That’s all!!! (BTW: This 298 | is why we turned off “automatic lists,” because that feature would 299 | make those hyphens into bullet points. We just want clean hyphens.) 300 | 301 | - Let’s save that fancier note, just as above: “File>Download>Plain 302 | Text.” 303 | 304 | Your research stack is growing! Let’s do one more, adding one more feature. Again, it isn’t necessary, but “It’s there!” So what the heck? 305 | ------------------------------------------------------------------------------------------------------------------------------------------ 306 | 307 | - Edit the GDoc again. 308 | 309 | - Let’s find a new citation from the book and put it in the “note:” 310 | section (between quotes) and write a new “comment:” Just zap the old 311 | material and add the new, adjusting only what is necessary for the 312 | new note, resulting in something like: 313 | 314 | :: 315 | 316 | title: Reading notes on The Great Gatsby 317 | note: "Conduct may be founded on the hard rock or the wet marshes, but after a certain point I don’t care what it’s founded on. When I came back from the East last autumn I felt that I wanted the world to be in uniform and at a sort of moral attention forever; I wanted no more riotous excursions with privileged glimpses into the human heart." 318 | comment: "In second paragraph, Fitzgerald begins to suggest Gatsby's cynicism and hints at fact that he was a veteran of the First World War" 319 | tags: 320 | - Gatsby note 321 | - Cynicism 322 | - Impact of WWI 323 | 324 | - You can also change the tags for this next note, as I did here. 325 | 326 | - Obviously, you could save this to the “stack,” go on to the next, and 327 | be fine. 328 | 329 | - But notice that this time (for demonstration purposes) I didn’t add 330 | an bibliographical indicator like “(Gatsby, 2)”. Most of us would 331 | just put that MLA element in and be fine. In fact, for 99% of users, 332 | that’s enough. Just keep track of which books you are using and add 333 | the notes or footnotes when you pull things together later. No 334 | problem. 335 | 336 | - But if you are into “bibtex” and plan to build your paper with zotero 337 | and pandoc (for more advanced users) you could also use this system 338 | to keep track of your bibliography. That just involves adding the 339 | following at the bottom: 340 | 341 | :: 342 | 343 | cite: 344 | bibkey: fitzgerald_gatsby_1925 345 | page: p. 2 346 | 347 | - That’s all. If you don’t know what “bibkey” means right now, don’t 348 | worry about it. (Just use MLA as above.) But if you do, you can add 349 | it and link this to your .bib file and when you build with pandoc all 350 | will be well. Just notice the spaces before bibkey: and page: Don’t 351 | use tabs to indent – put in two spaces. 352 | 353 | - Now let’s save this new card, as above. 354 | 355 | - OK! Now we have a “Stack” of cards in our “Downloads” directory, each 356 | named “Gatsby-Note….txt” You could write a million more. Just change 357 | the elements that need to be changed and save the new version as a 358 | new card: copy or type out new quotes from your book; add comments; 359 | just write out notes; change tags; change page(s); change title if 360 | you want, etc. 361 | 362 | - *Quick tip*: copying and pasting from electronic sources can be a 363 | little tricky because you don’t know about the “fancy characters” 364 | that will end up in your note. It’s best to just type out a quote 365 | (and paraphrase more than quoting, as the masters say). But if you 366 | do this, then *highlight* the whole note and click the “Clear 367 | formatting” button to zap weird characters (as much as it will). 368 | Also make sure you are pasting things are inside those quotation 369 | marks). You might end up, after processing below, with some 370 | strange charcters like in your notecards. 371 | They can be deleted, but are a little bit of a pain (and why plain 372 | text writing emphasizes plain text). 373 | 374 | Let’s process our notes. 375 | ------------------------ 376 | 377 | - Anyway, based on our start, let’s begin to process the notes we have 378 | made. (Just think about how you would start shuffling or organizing a 379 | stack of notecards you have written on paper.) 380 | 381 | - This is actually where the real power of this system starts. 382 | 383 | - Remember, the idea is to make a notecard for every idea for your 384 | project, then be able to find them, select the ones you need, then 385 | print them out for your paper or for each section of your paper, 386 | according to themes or keywords or… 387 | 388 | - This is waaaaaaay different from having all of your notes in a 389 | single document or having them on a few “Onenote” or “Evernote” 390 | pages, but then having difficulty selecting the particular cards 391 | or notes you need in particular. This is where the ZettelGeist 392 | system becomes an electronic version of “moving the cards around” 393 | when you start to outline or write the paper. 394 | 395 | - First, think about whether you want to keep working in the directory 396 | where your browser saved the cards, or somewhere else. It’s probably 397 | best to move them. 398 | 399 | - If you want to move them out of Downloads, make a new directory 400 | called Gatsby-Paper and move the notes there. 401 | 402 | - Now, we just need to rename these “.txt” files so they are understood 403 | as “.yaml” files by the system. That’s the “format” that the 404 | ZettelGeist system needs to work with. 405 | 406 | - This can be done a number of ways. Since we only have a few cards 407 | now, we can just do it with File Manager (or whatever) 408 | individually. You can also do them in bulk with some File Managers 409 | (on Mac) or with a command in the terminal. But for now, just 410 | change them by hand. 411 | 412 | - So, in your new Gatsby-Paper directory, change the names of each 413 | “.txt” file to “Gatsby-Note.yaml”. For GDocs users, you might also 414 | adjust the numbers automatically added, removing the parentheses 415 | but not the numbers. So, Gatsby-Note (1).txt becomes 416 | Gatsby-Note-1.yaml. It’s just neater that way. 417 | 418 | - When this is done, you are ready to rock. Now you can do everything 419 | that is demonstrated with the “test” materials on the “Getting 420 | Started” page, but with your own research notes written in GDocs or 421 | Word or… 422 | 423 | - Everything from this point on assumes you have installed ZettelGeist 424 | and have your zenv environment working as explained on the 425 | Installation page. 426 | 427 | - This can be done right in the same directory you are working in. 428 | 429 | - First create a database name. 430 | 431 | ``zcreate --database gatsby.db`` 432 | 433 | - Then import all of the new yaml notecards (or zettels) into your 434 | database. 435 | 436 | ``zimport --database --dir $(pwd)`` 437 | 438 | - The output will show each of your notes being pulled into the 439 | database. 440 | 441 | - Once that is done, you are ready to start searching and organizing 442 | your notes. 443 | 444 | - Of course, with only a few it isn’t super exciting. But if you have 445 | taken notes on every thought you had when reading The Great Gatsby, 446 | the game would really be on!! 447 | 448 | - Let’s search for something in our stack. To do this, you use “zfind.” 449 | To see all the elements of zfind, you could type “zfind –help”. But 450 | we will keep things simple now. 451 | 452 | - Let’s search for the card that had to do with the First World War. 453 | 454 | - To do that, at the command line, type: 455 | 456 | ``zfind --database Gatsby.db --query-string 'comment:"First World War"' --show-title --show-note --show-comment`` 457 | 458 | - When you enter this, the output will be the card that included the 459 | “string” First World War in the “commment:” field. See? 460 | 461 | - There are a zillion things to be done now that you have this 462 | searching ability. Again, it really comes into play when you have a 463 | bunch of notes and want to search on them. But this is the start. 464 | Let’s do one more. 465 | 466 | ``zfind --database Gatsby.db --query-string 'tags:"First Line"' --show-title --show-note --show-comment`` 467 | 468 | - Take a look at what each of those commands is doing. ``zfind`` is 469 | starting the search engine. It is looking in the 470 | ``--database Gatsby.db``. It is searching for particular strings of 471 | letters in particular fields 472 | ``--query-string 'comment:"First World War"' and --query-string 'tags:"First line"'``. 473 | Then, for each card that has those elements, it is showing the title, 474 | showing the note, and showing the comment. That is what is showing up 475 | on the output. 476 | 477 | - The real power of zfind (searching in ZettelGeist) comes from 478 | combining these things (in as many ways as you want to use for your 479 | purposes). Here is an example. Let’s search for *both* of these 480 | elements in your cards: those with tags with First Line and those 481 | with commments with First World War. To do that, you just use the 482 | “or” command (the vertical bar created by [shift-backslash] in the 483 | query string, as in: 484 | 485 | ``zfind --database Gatsby.db --query-string 'tags:"First Line" | comment:"First World War"' --show-title --show-note --show-comment`` 486 | 487 | - Hit enter, and both of those cards will flash by (or the parts you 488 | specified: title, note, and comment – though you could have asked for 489 | tags and cite and… any elements you include). 490 | 491 | - You have just searched and found the two notes that met those 492 | requirements. Not such a big deal out of 4 notes, but out of 100? 493 | That’s cool. 494 | 495 | But, you want to use them for a portion of your paper on those themes, right? 496 | ----------------------------------------------------------------------------- 497 | 498 | - To do that, just add one more basic element into your search command: 499 | “> search-results.txt” That’s all you need. The “>” sign (like an 500 | arrow) means “send that output into a file” – as in, your results 501 | file… Or your Gatsby-results.txt file… Or your 502 | “Gatsby-Body-Part-1.txt” file, depending on how you want to arrange 503 | your information. 504 | 505 | Let’s do the last one: 506 | 507 | ``zfind --database Gatsby.db --query-string 'tags:"First Line" | comment:"First World War"' --show-title --show-note --show-comment > Gatsby-Body-Part-1.txt`` 508 | 509 | - Hit enter, and in an instant you will have a file with all the 510 | searched data under that name. Open Gatsby-Body-Part-1.txt with your 511 | editor. Or upload it to GDocs and open it there. It will have your 512 | notes on those issues all in one place for you to put into your paper 513 | document where you need it. 514 | 515 | - THAT’S how to use the *notecard* notetaking system to take notes, 516 | mark them for particular content, find them, collect them, and then 517 | pull them into your paper – all using the computer instead of paper 518 | notecards (not that there is anything wrong with paper notecards, 519 | they still rock, but we are digital writers now). 520 | 521 | - ZettelGeist has been made to make this great, traditional, powerful 522 | way to do research (on anything) or just write or just make lists or… 523 | as immediate as possible, but without trapping you in one word 524 | processing system OR trapping your notes (etc.) in a onenote system 525 | or an evernote system. (Nerd joke: EverNote keeps your notes, 526 | forever: like a black hole, once the information goes in, it never 527 | comes out.) ZettelGeist allows you to put your material in (according 528 | to some classic rules) and then GET IT OUT in the bits and pieces 529 | that you actually need. 530 | 531 | - The zfind feature can be modified in many ways to get more 532 | “fine-tuned” material from your electronic card stack(s). Also, you 533 | can break things up into the various fields we have discussed. BUT, 534 | again, you could also just take notes as “note:” and be fine, 535 | including whatever you need in that field alone (in quotations to be 536 | sure there aren’t processing issues) and then search for strings in 537 | all the “notes” sections. It can be that simple, or as complex or 538 | professional as you want. It is completely up to you. 539 | 540 | - It is as flexible as paper notecards were, but as powerful as any 541 | supercomputers are. That’s what we are talking about!!!! 542 | 543 | In conclusion, for GDocs users… 544 | ------------------------------- 545 | 546 | **Your notetaking system is still there, ready and waiting for you to 547 | continue with your project! Just take a look back at the GDocs page you 548 | were working on – the master “card” is ever-ready for you to edit and 549 | save your next idea, and your next, and … (Fractals, baby!!)** 550 | -------------------------------------------------------------------------------- /sphinx-docs/source/tutorial-world.rst: -------------------------------------------------------------------------------- 1 | World 2 | ======== 3 | 4 | 5 | **This page is under construction. Pardon the sketchiness for now.** 6 | 7 | What do you want to do? 8 | ----------------------- 9 | 10 | - Take research notes for a paper in order to be able to search them 11 | for … anything. 12 | 13 | - Follow the traditional (and ever-valid) methods of writing a note 14 | with a title, some keywords (tags), a note (with comment or summary 15 | if desired), and some bibliographical information (book or article 16 | title and page number[s]). 17 | 18 | - Find particular notes on particular themes and issues. 19 | 20 | - Send those particular notes to a file that will be the basis for a 21 | portion of your outline or draft. 22 | 23 | All of these basic research, organization, and writing steps are steeped in traditional methods. 24 | ------------------------------------------------------------------------------------------------ 25 | 26 | - As researchers and writers of papers, articles, books – from grade 27 | school, high school, college, graduate school, through our 28 | professional writings – as well as teachers and editors of countless 29 | efforts by others, we know the game. Indeed, we are the coaches and 30 | referees and main players of the game! And our own coaches taught us 31 | how to do it right! 32 | 33 | - On the basis of this experience, we made ZettelGeist to do the most 34 | important, fundamental steps of research and writing as clearly and 35 | directly as possible, based on the methods that our mentors used to 36 | write great books before personal computers came into being. 37 | 38 | - But because we are ourselves computerized (having come into 39 | professional life just as the pc revolution occurred and, therefore, 40 | having played *that game* ever since), we have here merged these 41 | techniques into the computer world more directly than any program has 42 | before. (Believe us: we know! We have tried and deployed every option 43 | out there, from 1980 until yesterday – as a matter of professional 44 | need.) 45 | 46 | - Since we know the frustration that many so-called “notetaking 47 | programs” cause, we have made a fundamental decision to ensure that 48 | the basis for all of this is already in the computer you own and the 49 | internet sites you have access to. 50 | 51 | - You don’t have to go and buy anything new. You already have 52 | *supercomputers* that earlier great writers could never have 53 | imagined. This system will just help you to take advantage of these 54 | machines in ways consistent with the key principles of research and 55 | organization that the great writers developed, but most computer 56 | programs have left out. 57 | 58 | - This is the Research-Writing-Computer Singularity we have been 59 | waiting for! 60 | 61 | The first thing to know is that with ZettelGeist you can do ALL of the above by starting (and finishing) your writing with ANY SOFTWARE YOU WANT TO USE!! The ZettelGeist program works with and *between* your preferred word processors. 62 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 63 | 64 | - Many programs suggest they are “app-gnostic” (agnostic or indifferent 65 | about which app you use), but that usually just means you can save 66 | your work into another format (docx, pdf, txt, etc.). 67 | 68 | - ZettelGeist is truly app neutral in the sense that you can make notes 69 | (zettels) with any software, as long as you make them according to a 70 | certain pattern (indicating note section, title section, etc…) and 71 | save or download them in good old “.txt” format. 72 | 73 | - The “pattern” is exactly what you would use to write out a notecard 74 | in the traditional way (by hand, or typed on paper or computer), so 75 | it really isn’t that big a deal. Plus, once you make one card (or 76 | zettel), you can just edit the same card to make any necessary 77 | changes for the next card (change the note, change the page numbers, 78 | etc.) then save the new card with a new filename, eg. “note02.txt” 79 | and move on… 80 | 81 | - You can do this with ANY word processor you want to use: Google Docs, 82 | Microsoft Word, LibreOffice. In fact, you could just use one of the 83 | most basic editors that are already residing on your computer, or 84 | easily installed for free: Notepad, Wordpad (on Windows), TextEdit 85 | (Mac), Vim, Emacs, etc. 86 | 87 | - If that last sentence confuses you, don’t worry. Just use Google Docs 88 | or Word or whatever you are used to. (The surprise is that you don’t 89 | actually have to buy any word processor at all because the above 90 | basic text editors come with your system and ZettelGeist would allow 91 | you to use those for free to research, organize, and write any great 92 | work you need to produce – but let’s set that issue aside for the 93 | moment.) 94 | 95 | Let’s try it out with Microsoft Word. 96 | ------------------------------------- 97 | 98 | - As you can see on the “Get Started” and “Note Format” page above, a 99 | note in ZettelGeist is just a set of information put together in 100 | sections marked with a colon, like title: or note: or tags:, etc. 101 | 102 | - There are a number of those built into the system (see Note Format 103 | page) because, as researchers, we know you might also want to 104 | “comment:” or write a “summary:” or add bibliographical information 105 | such as “bibkey:” and “pages:”, and so on. 106 | 107 | - BUT this is completely up to you. You can add any of these elements, 108 | or only one or two, in any order according to your needs. A 109 | completely valid note would just start with “note:” and then just 110 | consist of the text of your note in the following line surrounded by 111 | quotations, including all the information you want to produce or 112 | record right there. That would work just fine. You could then save it 113 | as “note-01.txt” and it could be processed in ZettelGeist without a 114 | problem (after a minor change to the filename so it can be searched 115 | and used in the system – more on that in a minute). 116 | 117 | - If you want the other elements, like title: summary: or comment: 118 | great, just add them too. As long as you name sections according to 119 | the list on the “Note Format” page, or listed in “zettel –help”, you 120 | can create notes however you prefer, with sections in whatever order 121 | you like. Basically, you are making up your own notetaking system 122 | (based on these universally valid “fields”) and can treat any “file” 123 | as a blank notecard, just as you do when you buy a pack of 3 x 5 124 | notecards at the pharmacy and make flash cards for a high school 125 | class. Fill them out as you like! 126 | 127 | So, with that flexibilty in mind, let’s make your first note. 128 | ------------------------------------------------------------- 129 | 130 | For now, just go to Word, or GDocs (on the other tab)…your choice. 131 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 132 | 133 | - Start a new document. 134 | 135 | - Then take one step that will help with this experiment. 136 | 137 | - Go to “Tools>Preferences>AutoCorrect” and **uncheck** most of the 138 | automatic styling elements. (This is based on the Mac version, but 139 | it should be about the same on the PC.) 140 | 141 | - Uncheck “Capitalize first letter of sentences” 142 | 143 | - Under “AutoFormat As You Type” uncheck “Automatic bulleted 144 | lists” and "“Straight quotes with smart quotes” and all the 145 | others. 146 | 147 | - We want the simplest and plainest characters possible (most 148 | programs add fancier “unicode” characters with these features – 149 | but we don’t need them and they actually mess up searching and 150 | finding later). 151 | 152 | - You can always turn these back on later, but you probably wouldn’t 153 | miss most of these anyway. 154 | 155 | - Close preferences and then just look at your plain document page. But 156 | now you can think of it a little differently. This is now a 157 | *notecard* (right out of your 3 x 5 package)! Even though it is on a 158 | supercomputer in the “cloud” linked to the internet, it is just a 159 | “card” now. Let’s just fill it in as we would by hand. 160 | 161 | - Let’s say you want to give it a title (remember, it’s up to you 162 | whether you need a title, but this will remind you what this field 163 | and other subsequent ones in this research session are about). 164 | 165 | - So, type: 166 | 167 | ``title: Reading notes on The Great Gatsby`` 168 | 169 | - Ok. That’s the top line of your note, just like on the “red” line of 170 | your good old notecard. 171 | 172 | - Now, let’s put in something about the book you are reading, for 173 | instance (you could be taking notes for anything including your own 174 | novel or writing poetry or writing a shopping list, but we are 175 | thinking research paper for now). 176 | 177 | - Make a new line and type: 178 | 179 | ``note: "This is a note about The Great Gatsby, a novel by F. Scott Fitzgerald. Written during The Jazz Age, it is a masterpiece of American Literature."`` 180 | 181 | - Notice that I put the text part of this note: “inside quotation 182 | marks.” This is necessary when you write longer notes because it 183 | means you can put quotes and colons and multiple lines into your 184 | plain text card. Just a formality, but not a big deal. If you just 185 | write a single line without colons and other such things, you don’t 186 | need the quotes. But it works better with them if you are making 187 | notes this initial way with Word or another word processer. 188 | 189 | - For now, let’s just stop there and see what we can do with that very 190 | first note. 191 | 192 | - Let’s name the file, on Google Docs, by simply clicking in the file 193 | name box above (as usual – you know) and typing “Gatsby-Note”. 194 | 195 | - Now let’s save it so we can soon make it into a zettel for research 196 | processing. 197 | 198 | - Click File> Save As, then, under file format “Plain Text.txt.” 199 | 200 | - Then name the file “Gatsby-Note-1.yaml” and save it to a directory 201 | called “Gatsby-Reading-Notes” (for this project): “.yaml” is the 202 | “format” that the ZettelGeist system needs to work with. 203 | 204 | - If it asks about “text encoding,” select "Western (ASCII) 205 | 206 | - Immediately, it will save to your computer (into the directory set by 207 | your browser for downloads – usually Downloads). 208 | 209 | But let’s make a couple of more notes (zettels) before we do any more. 210 | ---------------------------------------------------------------------- 211 | 212 | - All you need to do to make your next note(s) is edit your existing 213 | document! You don’t have to create a new one or anything. You already 214 | saved your first card, so it is safe. Now just edit your next one on 215 | the basis of this start, and save the new iteration as the next note. 216 | 217 | - We can leave title: the same… So no changes there. 218 | 219 | - Let’s change the note: (obviously). Just highlight from the first 220 | quotation mark to the last, delete the original note, and write 221 | another. 222 | 223 | ``note: "The novel opens with the lines 'In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since. 'Whenever you feel like criticizing any one,' he told me, 'just remember that all the people in this world haven’t had the advantages that you’ve had.' (Gatsby, 1)"`` 224 | 225 | - We just added a quote from the book. So you might want to write 226 | something about that citation (your own opinion of its importance, 227 | etc.) as well. (Teachers want to hear your voice, and you want to 228 | remember why you took the note.) 229 | 230 | - That’s simple: You could just add something to the “note:” section 231 | itself: 232 | 233 | ``"The novel opens with the lines 'In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since. “Whenever you feel like criticizing any one,' he told me, 'just remember that all the people in this world haven’t had the advantages that you’ve had.' (Gatsby, 1) Comment: This is a famous first line and my teacher says that we should analyze it carefully."`` 234 | 235 | - See the “Comment” at the end? That would do it. As a result, you have 236 | title, note, citation-page (Gatsby, 1), and a comment (inside that 237 | last quotation mark). All the elements of a traditional notecard are 238 | there, just within the “note:” field. So let’s save that as a second 239 | note. 240 | 241 | - Just click “File>Save As” again. You don’t have to change settings 242 | again. Just change the name to “Gatsby-Note-2.yaml”. 243 | 244 | - Cool. Two notes are now in your research “card stack” for processing. 245 | If we did pull them into the system, they would be completely 246 | searchable and usable. Again: you could just take notes with “notes:” 247 | or “title:” and “note:” and that will do the job. 248 | 249 | - But, you can do a lot more if you want to. ZettelGeist allows you to 250 | break up these elements of research notes into each of the 251 | traditional elements listed on the “Note Format” page! 252 | 253 | So let’s go back to our document and adjust this note to make a third with a little more…zing! 254 | ---------------------------------------------------------------------------------------------- 255 | 256 | - Highlight “Comment: This is a famous first line and my teacher says 257 | that we should analyze it carefully.” Then cut that (not delete). 258 | 259 | - Make a new line and paste it. Then make the capital “C” into a 260 | lowercase “c” and put your comment in quotations, resulting in: 261 | 262 | ``comment: This is a famous first line and my teacher says that we should analyze it carefully."`` 263 | 264 | - You just set up a new “comment:” field that can be searched 265 | separately if you want. This is not necessary (as above) but it does 266 | allow you to separate, let’s say, the quotes you take from the source 267 | (in “note:”) and your ideas (in “comment:”). It’s up to you, but just 268 | in case you like it, it’s that easy to add more fields (per the “Note 269 | Format” page). 270 | 271 | - Now, let’s do something else that is key to research. Add “tags” to 272 | the note. This is another traditional part of any notecard system. It 273 | allows you to mark each note as being relevant to a theme or a 274 | keyword or a part of your paper (Intro, Body 1, Body 2, Conclusion, 275 | etc.). Adding tags is also really easy with the ZettelGeist method. 276 | 277 | - Continue with the existing document. 278 | 279 | - (See? Making new “cards” just means editing and then re-saving 280 | your existing card in .yaml format with a new numbered name. Just 281 | give each new “save as” a different number: Gatsby-Note-01.yaml, 282 | Gatsby-Note-02.yaml, Gatsby-Note-03.yaml, etc. The existing 283 | elements just get reused over and over as you save every new 284 | version to your “stack.”) 285 | 286 | - To add tags, start a new line under the “comment:” line. 287 | 288 | - Type this: 289 | 290 | :: 291 | 292 | tags: 293 | - My first tag 294 | - Gatsby note 295 | - First line of book 296 | 297 | - Could it be simpler? Ha! “tags:” is the new section, just as above. 298 | But each tag is separate, so you just start the line for each tag 299 | with a hyphen to indicate this is the case. That’s all!!! (BTW: This 300 | is why we turned off “automatic lists,” because that feature would 301 | make those hyphens into bullet points. We just want clean hyphens.) 302 | 303 | - Let’s save that fancier note, just as above: “File>Save 304 | as>Gatsby-Note-03.yaml,” and so on.) 305 | 306 | Your research stack is growing! Let’s do one more, adding one more feature. Again, it isn’t necessary, but “It’s there!” So what the heck? 307 | ------------------------------------------------------------------------------------------------------------------------------------------ 308 | 309 | - Edit the document again. 310 | 311 | - Let’s find a new citation from the book and put it in the “note:” 312 | section (between quotes) and write a new “comment:” Just zap the old 313 | material and add the new, adjusting only what is necessary for the 314 | new note, resulting in something like: 315 | 316 | :: 317 | 318 | title: Reading notes on The Great Gatsby 319 | note: "Conduct may be founded on the hard rock or the wet marshes, but after a certain point I don’t care what it’s founded on. When I came back from the East last autumn I felt that I wanted the world to be in uniform and at a sort of moral attention forever; I wanted no more riotous excursions with privileged glimpses into the human heart." 320 | comment: "In second paragraph, Fitzgerald begins to suggest Gatsby's cynicism and hints at fact that he was a veteran of the First World War" 321 | tags: 322 | - Gatsby note 323 | - Cynicism 324 | - Impact of WWI 325 | 326 | - You can also change the tags for this next note, as I did here. 327 | 328 | - Obviously, you could save this to the “stack,” go on to the next, and 329 | be fine. 330 | 331 | - But notice that this time (for demonstration purposes) I didn’t add 332 | an bibliographical indicator like “(Gatsby, 2)”. Most of us would 333 | just put that MLA element in and be fine. In fact, for 99% of users, 334 | that’s enough. Just keep track of which books you are using and add 335 | the notes or footnotes when you pull things together later. No 336 | problem. 337 | 338 | - But if you are into “bibtex” and plan to build your paper with zotero 339 | and pandoc (for more advanced users) you could also use this system 340 | to keep track of your bibliography. That just involves adding the 341 | following at the bottom: 342 | 343 | :: 344 | 345 | cite: 346 | bibkey: fitzgerald_gatsby_1925 347 | page: p. 2 348 | 349 | - That’s all. If you don’t know what “bibkey” means right now, don’t 350 | worry about it. (Just use MLA as above.) But if you do, you can add 351 | it and link this to your .bib file and when you build with pandoc all 352 | will be well. Just notice the spaces before bibkey: and page: Don’t 353 | use tabs to indent – put in two spaces. 354 | 355 | - Now let’s save this new card, as above. 356 | 357 | - OK! Now we have a “Stack” of cards in our “Gatsby-Reading-Notes” 358 | directory, each named “Gatsby-Note….txt” You could write a million 359 | more. Just change the elements that need to be changed and save the 360 | new version as a new card: copy or type out new quotes from your 361 | book; add comments; just write out notes; change tags; change 362 | page(s); change title if you want, etc. 363 | 364 | - *Quick tip*: copying and pasting from electronic sources can be a 365 | little tricky because you don’t know about the “fancy characters” 366 | that will end up in your note. It’s best to just type out a quote 367 | (and paraphrase more than quoting, as the masters say). But if you 368 | do this, saving as plain text and Western (ASCII) should take care 369 | of it. Also make sure you are pasting things are inside those 370 | quotation marks). You might end up, after processing below, with 371 | some strange charcters like in your 372 | notecards. They can be deleted, but are a little bit of a pain 373 | (and why plain text writing emphasizes plain text). 374 | 375 | Let’s process our notes. 376 | ------------------------ 377 | 378 | - Anyway, based on our start, let’s begin to process the notes we have 379 | made. (Just think about how you would start shuffling or organizing a 380 | stack of notecards you have written on paper.) 381 | 382 | - This is actually where the real power of this system starts. 383 | 384 | - Remember, the idea is to make a notecard for every idea for your 385 | project, then be able to find them, select the ones you need, then 386 | print them out for your paper or for each section of your paper, 387 | according to themes or keywords or… 388 | 389 | - This is waaaaaaay different from having all of your notes in a 390 | single document or having them on a few “Onenote” or “Evernote” 391 | pages, but then having difficulty selecting the particular cards 392 | or notes you need in particular. This is where the ZettelGeist 393 | system becomes an electronic version of “moving the cards around” 394 | when you start to outline or write the paper. 395 | 396 | - OK: you are ready to rock. Now you can do everything that is 397 | demonstrated with the “test” materials on the “Getting Started” page, 398 | but with your own research notes written in Word or GDocs or … 399 | 400 | - Everything from this point on assumes you have installed ZettelGeist 401 | and have your zenv environment working as explained on the 402 | Installation page. 403 | 404 | - This can be done right in the same directory you are working in. 405 | 406 | - First create a database name. 407 | 408 | ``zcreate --database gatsby.db`` 409 | 410 | - Then import all of the new yaml notecards (or zettels) into your 411 | database. 412 | 413 | ``zimport --database --dir $(pwd)`` 414 | 415 | - The output will show each of your notes being pulled into the 416 | database. 417 | 418 | - Once that is done, you are ready to start searching and organizing 419 | your notes. 420 | 421 | - Of course, with only a few it isn’t super exciting. But if you have 422 | taken notes on every thought you had when reading The Great Gatsby, 423 | the game would really be on!! 424 | 425 | - Let’s search for something in our stack. To do this, you use “zfind.” 426 | To see all the elements of zfind, you could type “zfind –help”. But 427 | we will keep things simple now. 428 | 429 | - Let’s search for the card that had to do with the First World War. 430 | 431 | - To do that, at the command line, type: 432 | 433 | ``zfind --database Gatsby.db --query-string 'comment:"First World War"' --show-title --show-note --show-comment`` 434 | 435 | - When you enter this, the output will be the card that included the 436 | “string” First World War in the “commment:” field. See? 437 | 438 | - There are a zillion things to be done now that you have this 439 | searching ability. Again, it really comes into play when you have a 440 | bunch of notes and want to search on them. But this is the start. 441 | Let’s do one more. 442 | 443 | ``zfind --database Gatsby.db --query-string 'tags:"First Line"' --show-title --show-note --show-comment`` 444 | 445 | - Take a look at what each of those commands is doing. ``zfind`` is 446 | starting the search engine. It is looking in the 447 | ``--database Gatsby.db``. It is searching for particular strings of 448 | letters in particular fields 449 | ``--query-string 'comment:"First World War"' and --query-string 'tags:"First line"'``. 450 | Then, for each card that has those elements, it is showing the title, 451 | showing the note, and showing the comment. That is what is showing up 452 | on the output. 453 | 454 | - The real power of zfind (searching in ZettelGeist) comes from 455 | combining these things (in as many ways as you want to use for your 456 | purposes). Here is an example. Let’s search for *both* of these 457 | elements in your cards: those with tags with First Line and those 458 | with commments with First World War. To do that, you just use the 459 | “or” command (the vertical bar created by [shift-backslash] in the 460 | query string, as in: 461 | 462 | ``zfind --database Gatsby.db --query-string 'tags:"First Line" | comment:"First World War"' --show-title --show-note --show-comment`` 463 | 464 | - Hit enter, and both of those cards will flash by (or the parts you 465 | specified: title, note, and comment – though you could have asked for 466 | tags and cite and… any elements you include). 467 | 468 | - You have just searched and found the two notes that met those 469 | requirements. Not such a big deal out of 4 notes, but out of 100? 470 | That’s cool. 471 | 472 | But, you want to use them for a portion of your paper on those themes, right? 473 | ----------------------------------------------------------------------------- 474 | 475 | - To do that, just add one more basic element into your search command: 476 | “> search-results.txt” That’s all you need. The “>” sign (like an 477 | arrow) means “send that output into a file” – as in, your results 478 | file… Or your Gatsby-results.txt file… Or your 479 | “Gatsby-Body-Part-1.txt” file, depending on how you want to arrange 480 | your information. 481 | 482 | Let’s do the last one: 483 | 484 | ``zfind --database Gatsby.db --query-string 'tags:"First Line" | comment:"First World War"' --show-title --show-note --show-comment > Gatsby-Body-Part-1.txt`` 485 | 486 | - Hit enter, and in an instant you will have a file with all the 487 | searched data under that name. Open Gatsby-Body-Part-1.txt with Word 488 | or any editor. It will have your notes on those issues all in one 489 | place for you to put into your paper document where you need it. 490 | 491 | - THAT’S how to use the *notecard* notetaking system to take notes, 492 | mark them for particular content, find them, collect them, and then 493 | pull them into your paper – all using the computer instead of paper 494 | notecards (not that there is anything wrong with paper notecards, 495 | they still rock, but we are digital writers now). 496 | 497 | - ZettelGeist has been made to make this great, traditional, powerful 498 | way to do research (on anything) or just write or just make lists or… 499 | as immediate as possible, but without trapping you in one word 500 | processing system OR trapping your notes (etc.) in a onenote system 501 | or an evernote system. (Nerd joke: EverNote keeps your notes, 502 | forever: like a black hole, once the information goes in, it never 503 | comes out.) ZettelGeist allows you to put your material in (according 504 | to some classic rules) and then GET IT OUT in the bits and pieces 505 | that you actually need. 506 | 507 | - The zfind feature can be modified in many ways to get more 508 | “fine-tuned” material from your electronic card stack(s). Also, you 509 | can break things up into the various fields we have discussed. BUT, 510 | again, you could also just take notes as “note:” and be fine, 511 | including whatever you need in that field alone (in quotations to be 512 | sure there aren’t processing issues) and then search for strings in 513 | all the “notes” sections. It can be that simple, or as complex or 514 | professional as you want. It is completely up to you. 515 | 516 | - It is as flexible as paper notecards were, but as powerful as any 517 | supercomputers are. That’s what we are talking about!!!! 518 | 519 | In conclusion, for Word (etc.) users… 520 | ------------------------------------- 521 | 522 | **Your notetaking system is still there, ready and waiting for you to 523 | continue with your project! Just take a look back at the Word document 524 | you were working on – the master “card” is ever-ready for you to edit 525 | and “save as” your next idea, and your next, and … (Fractals, baby!!)** 526 | -------------------------------------------------------------------------------- /src/ps.text: -------------------------------------------------------------------------------- 1 | USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND 2 | _windowserver 22462 5.3 0.6 3810764 52512 ?? Ss Tue11PM 97:34.94 /System/Library/PrivateFrameworks/SkyLight.framework/Resources/WindowServer -daemon 3 | gkt 41927 5.3 4.6 3569996 387396 ?? S 9:52PM 0:43.32 /Applications/Paltalk.app/Contents/MacOS/Paltalk 4 | _coreaudiod 170 4.9 0.1 2474348 5288 ?? Ss Sun11PM 112:38.13 /usr/sbin/coreaudiod 5 | gkt 22660 3.5 2.5 3677892 206684 ?? S Wed07AM 109:15.02 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome 6 | gkt 26378 3.1 1.0 2940736 86936 ?? S Thu03PM 4:56.22 /Applications/iTerm.app/Contents/MacOS/iTerm2 7 | root 57 1.7 0.2 2509160 18132 ?? Ss Sun11PM 14:47.52 /usr/libexec/airportd 8 | _hidd 99 1.2 0.1 2473184 6372 ?? Ss Sun11PM 64:39.83 /usr/libexec/hidd 9 | root 77 0.9 0.2 2521356 16884 ?? Ss Sun11PM 1:24.75 /usr/libexec/opendirectoryd 10 | -------------------------------------------------------------------------------- /tests/test_zettelgeist.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import textwrap 3 | import yaml 4 | 5 | from zettelgeist import zettel 6 | 7 | # content of test_sysexit.py 8 | import pytest 9 | 10 | 11 | def f(): 12 | raise SystemExit(1) 13 | 14 | 15 | def test_mytest(): 16 | with pytest.raises(SystemExit): 17 | f() 18 | 19 | 20 | def test_parse_empty(): 21 | doc = {} 22 | zettel.parse_zettel(doc) 23 | 24 | 25 | def test_parse_simple_valid(): 26 | doc = { 27 | 'title': "Valid title" 28 | } 29 | zettel.parse_zettel(doc) 30 | 31 | 32 | def test_parse_simple_bad_value(): 33 | doc = { 34 | 'title': 35 35 | } 36 | with pytest.raises(zettel.ParseError): 37 | zettel.parse_zettel(doc) 38 | 39 | 40 | def test_simple_zettel(): 41 | zdoc = """ 42 | title: My First Zettel 43 | mentions: 44 | - dbdennis 45 | - gkt 46 | tags: 47 | - Charles Babbage 48 | - Ada Lovelace 49 | cite: 50 | bibkey: Ifrah 51 | page: "22-36" 52 | dates: 53 | year: "1841" 54 | era: CE 55 | summary: An amazing Zettel 56 | note: Text of Zettel 57 | bibkey: BibKey 58 | bibtex: "@article{key, entries}" 59 | """ 60 | zdoc = textwrap.dedent(zdoc) 61 | print(zdoc) 62 | zdict = yaml.load(zdoc) 63 | z = zettel.Zettel(zdict) 64 | 65 | 66 | def test_creator_and_load(): 67 | z = zettel.Zettel({}) 68 | z.set_field('title', 'My First Zettel') 69 | z.reset_list_field('mentions') 70 | z.append_list_field('mentions', 'dbdennis') 71 | z.append_list_field('mentions', 'gkt') 72 | z.reset_list_field('tags') 73 | z.append_list_field('tags', 'Charles Babbage') 74 | z.append_list_field('tags', 'Ada Lovelace') 75 | z.set_citation('Ifrah', '22-36') 76 | z.set_dates('1841', 'CE') 77 | z.set_field('summary', 'An amazing Zettel') 78 | z.set_field('note', 'Text of Zettel') 79 | z.set_field('bibkey', 'BibKey') 80 | z.set_field('bibtex', '@article{ley, entries}') 81 | text = z.get_yaml() 82 | 83 | ydoc = yaml.load(text) 84 | z2 = zettel.Zettel(ydoc) 85 | text2 = z2.get_yaml() 86 | assert text == text2 87 | 88 | 89 | def test_creator_and_load_optional_fields(): 90 | z = zettel.Zettel({}) 91 | z.set_field('title', 'My First Zettel') 92 | z.reset_list_field('mentions') 93 | z.append_list_field('mentions', 'dbdennis') 94 | z.append_list_field('mentions', 'gkt') 95 | z.reset_list_field('tags') 96 | z.append_list_field('tags', 'Charles Babbage') 97 | z.append_list_field('tags', 'Ada Lovelace') 98 | z.set_citation('Ifrah') 99 | z.set_dates('1841') 100 | z.set_field('summary', 'An amazing Zettel') 101 | z.set_field('note', 'Text of Zettel') 102 | z.set_field('bibkey', 'BibKey') 103 | z.set_field('bibtex', '@article{ley, entries}') 104 | text = z.get_yaml() 105 | 106 | ydoc = yaml.load(text) 107 | z2 = zettel.Zettel(ydoc) 108 | text2 = z2.get_yaml() 109 | assert text == text2 110 | 111 | 112 | def test_zettel_fts_strings(): 113 | z = zettel.Zettel({}) 114 | z.set_field("title", "title") 115 | z.set_field("summary", "a summary") 116 | expected = {'title': 'title', 'summary': 'a summary'} 117 | z.get_indexed_representation() == expected 118 | 119 | 120 | def test_zettel_fts_lists(): 121 | z = zettel.Zettel({}) 122 | z.reset_list_field("tags") 123 | z.append_list_field("tags", "Babbage") 124 | z.append_list_field("tags", "Lovelace") 125 | expected = {'tags': 'Babbage,Lovelace'} 126 | z.get_indexed_representation() == expected 127 | 128 | 129 | def test_zettel_fts_cite(): 130 | z = zettel.Zettel({}) 131 | z.set_citation("Castells 2006", "ii-iv") 132 | z.get_indexed_representation() 133 | expected = {'cite': 'bibkey:Castells 2006,page:ii-iv'} 134 | z.get_indexed_representation() == expected 135 | 136 | z.set_citation("Castells 2006") # omitting page numbers 137 | expected = {'cite': 'bibkey:Castells 2006'} 138 | z.get_indexed_representation() == expected 139 | 140 | 141 | def test_zettel_fts_dates(): 142 | z = zettel.Zettel({}) 143 | z.set_dates('2006', 'CE') 144 | expected = {'dates': 'year:2006,era:CE'} 145 | z.get_indexed_representation() == expected 146 | 147 | z.set_dates('2006') # omit era 148 | expected = {'dates': 'year:2006'} 149 | z.get_indexed_representation() == expected 150 | 151 | 152 | def test_invalid_zettel_fields(): 153 | z = zettel.Zettel({}) 154 | with pytest.raises(zettel.ParseError): 155 | z.set_field('blah', 'blah') 156 | z.delete_field('blah') 157 | 158 | # checks for injection of bad values in nested citation dictionary 159 | z.set_citation('Castells 2006', 'ii-iv') 160 | with pytest.raises(zettel.ParseError): 161 | z.zettel['cite']['blah'] = 'blah' 162 | z.get_yaml() # force checks 163 | 164 | del(z.zettel['cite']['blah']) 165 | 166 | # checks for injection of bad values in nested dates dictionary 167 | z.set_dates('2006', 'CE') 168 | with pytest.raises(zettel.ParseError): 169 | z.zettel['dates']['blah'] = 'blah' 170 | z.get_yaml() 171 | del(z.zettel['dates']['blah']) 172 | -------------------------------------------------------------------------------- /zdb_funcs.sh: -------------------------------------------------------------------------------- 1 | # To use these in bash/zsh, you can source this file. 2 | # Usage: 3 | # db_keywords filename.db 4 | # db_mentions filename.db 5 | # 6 | # This is for keyword/mention discoery in a zdb until we can decide on 7 | # proper z-commands and how they would work. 8 | 9 | zdb_tags() { 10 | sqlite3 $1 'select distinct(lower(tag)) from tags' | sort -f | uniq -i 11 | } 12 | 13 | zdb_mentions() { 14 | sqlite3 $1 'select distinct(lower(mention)) from mentions' | sort -f | uniq -i 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /zettelgeist/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZettelGeist/zettelgeist/477fa5427f089f9b9092c45f87f32a93af73e695/zettelgeist/__init__.py -------------------------------------------------------------------------------- /zettelgeist/zcreate.py: -------------------------------------------------------------------------------- 1 | # zcreate.py - create Zettel database 2 | 3 | import os.path 4 | import argparse 5 | from . import zdb 6 | 7 | 8 | def parse_options(): 9 | parser = zdb.get_argparse() 10 | parser.add_argument('--delete', action='store_const', const=True, 11 | default=False, help="delete if it already exists") 12 | return parser.parse_args() 13 | 14 | 15 | def zcreate(args): 16 | if args.delete and os.path.exists(args.database): 17 | print("Deleting %s" % args.database) 18 | os.unlink(args.database) 19 | 20 | if not os.path.exists(args.database): 21 | print("Creating new database %s" % args.database) 22 | db = zdb.get(args.database) 23 | db.drop_table() 24 | db.create_table() 25 | db.done() 26 | else: 27 | print("Won't delete existing database %s" % args.database) 28 | print("- Rerun with --delete option to achieve this.") 29 | 30 | 31 | def main(): 32 | args = parse_options() 33 | print("Warning: zcreate is deprecated - use zimport --create --database %s" % args.database) 34 | zcreate(args) 35 | 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /zettelgeist/zdb.py: -------------------------------------------------------------------------------- 1 | 2 | # ZettelGeist uses a FTS system for organizing Zettels. The index is intended 3 | # to be emphemeral and can be regenerated at any time. The schema itself is 4 | # ephemeral and can be augmented with additional fields of interest. 5 | # 6 | 7 | import argparse 8 | import os 9 | import os.path 10 | import sqlite3 11 | 12 | from . import zettel 13 | 14 | # TODO: 'filename' and 'document' are special fields for stuff not really part of the YAML dictionary 15 | # but still needing to be indexable and searchable. 16 | 17 | ZettelSQLFields = zettel.ZettelFieldsOrdered 18 | # Default Zettel DB name 19 | ZDB = 'zettels.db' 20 | 21 | 22 | def get_argparse(): 23 | parser = argparse.ArgumentParser() 24 | parser.add_argument( 25 | '--database', help="database name", required=True) 26 | return parser 27 | 28 | 29 | import pprint 30 | printer = pprint.PrettyPrinter(indent=2) 31 | 32 | 33 | def unquote(text): 34 | return text.replace('"', '').replace("'", "") 35 | 36 | 37 | class SQLiteFTS(object): 38 | def __init__(self, db_name, field_names): 39 | self.db_name = db_name 40 | self.conn = sqlite3.connect(db_name) 41 | self.conn.row_factory = sqlite3.Row 42 | self.cursor = self.conn.cursor() 43 | 44 | self.fts_field_names = field_names 45 | # for sqlite insert template generation 46 | self.fts_field_refs = ['?'] * len(self.fts_field_names) 47 | self.fts_field_init = [''] * len(self.fts_field_names) 48 | self.fts_fields = dict(zip(self.fts_field_names, self.fts_field_refs)) 49 | self.fts_default_record = dict( 50 | zip(self.fts_field_names, self.fts_field_init)) 51 | self.zettel = None 52 | 53 | def bind(self, zettel, filename, document=""): 54 | self.zettel = zettel 55 | doc = zettel.get_indexed_representation() 56 | doc.update({'filename': filename}) 57 | doc.update({'document': document}) 58 | self.record = self.fts_default_record.copy() 59 | for k in doc.keys(): 60 | if k in self.record.keys(): 61 | if doc[k] != None: 62 | self.record[k] = doc[k] 63 | else: 64 | print("Unknown fts field %s - deleting it" % k) 65 | 66 | # self.record.update(doc) 67 | 68 | def drop_table(self): 69 | self.cursor.execute("DROP TABLE IF EXISTS zettels") 70 | self.conn.commit() 71 | 72 | def create_table(self): 73 | sql_fields = ",".join(self.fts_default_record.keys()) 74 | #print("CREATE VIRTUAL TABLE zettels USING fts4(%s)" % sql_fields) 75 | self.cursor.execute( 76 | "CREATE VIRTUAL TABLE zettels USING fts4(%s)" % sql_fields) 77 | self.conn.commit() 78 | self.create_index_table('tags', 'tag') 79 | self.create_index_table('mentions', 'mention') 80 | 81 | def create_index_table(self, table_name, field_name): 82 | self.cursor.execute("DROP TABLE IF EXISTS %(table_name)s" % vars()) 83 | self.cursor.execute( 84 | "CREATE TABLE %(table_name)s (%(field_name)s text)" % vars()) 85 | self.conn.commit() 86 | 87 | def update_index(self, table_name, field_name, items): 88 | if not items: 89 | return 90 | for item in items: 91 | self.cursor.execute( 92 | "INSERT INTO %(table_name)s (%(field_name)s) VALUES (?)" % vars(), (item,)) 93 | # NB: (item,) means to pack this item into a tuple as required by sqlite3. 94 | 95 | def insert_into_table(self): 96 | sql_params = ",".join(self.fts_fields.values()) 97 | sql_columns = ",".join(list(self.record.keys())) 98 | sql_insert_values = list(self.record.values()) 99 | insert_sql = "INSERT INTO zettels (%s) VALUES (%s)" % ( 100 | sql_columns, sql_params) 101 | self.cursor.execute(insert_sql, sql_insert_values) 102 | self.conn.commit() 103 | self.update_index('tags', 'tag', self.zettel.get_list_field('tags')) 104 | self.update_index('mentions', 'mention', 105 | self.zettel.get_list_field('mentions')) 106 | 107 | # A term_list is a list of 3-tuples (not-option, fieldname, word) 108 | 109 | def fts_search(self, term_list): 110 | safe_term_list = [] 111 | for term in term_list: 112 | if type(term) == type(()) and len(term) == 3: 113 | (name, not_operator, words) = term 114 | words = unquote(words) 115 | if not_operator not in '-': 116 | not_operator = '' 117 | if name not in self.fts_field_names: 118 | continue 119 | for word in words.split(): 120 | safe_term_list.append((name, ":", not_operator, word)) 121 | 122 | # print(safe_term_list) 123 | fts_terms = " ".join(["".join(list(term)) for term in safe_term_list]) 124 | Q = "SELECT * from zettels where zettels match '%s'" % fts_terms 125 | # print(Q) 126 | for row in self.cursor.execute(Q): 127 | yield(row) 128 | 129 | def fts_query(self, prepared_sql): 130 | return self.cursor.execute(prepared_sql) 131 | 132 | def get_tags_generator(self): 133 | Q = "select distinct(tag) from tags" 134 | for row in self.cursor.execute(Q): 135 | yield(row['tag']) 136 | 137 | def get_tags_list(self): 138 | gen = self.get_tags_generator() 139 | return list(gen) 140 | 141 | def get_mentions_generator(self): 142 | Q = "select distinct(mention) from mentions" 143 | for row in self.cursor.execute(Q): 144 | yield(row['mention']) 145 | 146 | def get_mentions_list(self): 147 | gen = self.get_mentions_generator() 148 | return list(gen) 149 | 150 | def done(self): 151 | self.conn.commit() 152 | self.conn.close() 153 | 154 | 155 | class FNF(Exception): 156 | def __init__(self, text): 157 | self.text = text 158 | 159 | def __str__(self): 160 | return "File not found: " + self.text 161 | 162 | 163 | def get(db_name): 164 | return SQLiteFTS(db_name, ZettelSQLFields) 165 | 166 | GRAMMAR = """@@grammar::ZQUERY 167 | 168 | start = expression $ ; 169 | 170 | expression 171 | = 172 | | or_expr 173 | | term 174 | ; 175 | 176 | or_expr 177 | = 178 | left:expression op:'|' right:term 179 | ; 180 | 181 | term 182 | = 183 | | and_expr 184 | | factor 185 | ; 186 | 187 | and_expr 188 | = left:term op:and_op right:factor 189 | ; 190 | 191 | and_op 192 | = op:'&' 193 | | op:'!' 194 | ; 195 | 196 | not_expr 197 | = left:term op:'!' right:factor 198 | ; 199 | 200 | factor 201 | = 202 | | '(' @:expression ')' 203 | | z_field 204 | ; 205 | 206 | z_field 207 | = field:literal ':' text:literal 208 | ; 209 | 210 | literal 211 | = word:/"(\s+|\w+)*"/ 212 | | word:/\w+/ 213 | ; 214 | """ 215 | -------------------------------------------------------------------------------- /zettelgeist/zettel.py: -------------------------------------------------------------------------------- 1 | # 2 | # zettel.py - A checker for Zettels 3 | # 4 | 5 | import sys 6 | import argparse 7 | import readline # for input() 8 | 9 | import frontmatter # to accommodate Markdown with YAML frontmatter 10 | import yaml 11 | try: 12 | from yaml import CLoader as Loader, CDumper as Dumper 13 | except ImportError: 14 | from yaml import Loader, Dumper 15 | 16 | import os 17 | import os.path 18 | import json 19 | import shutil 20 | 21 | from time import strftime 22 | 23 | # Recursive descent parsing of Zettel dictionary format. 24 | 25 | ZettelStringFields = ['title', 'bibkey', 'bibtex', 26 | 'ris', 'inline', 'url', 'summary', 'comment', 'note'] 27 | ZettelListFields = ['tags', 'mentions'] 28 | ZettelStructuredFields = ['cite', 'dates'] 29 | ZettelExtraFields = ['filename', 'document'] 30 | ZettelFieldsOrdered = ZettelStringFields + \ 31 | ZettelListFields + ZettelStructuredFields + ZettelExtraFields 32 | ZettelFields = set(ZettelFieldsOrdered) 33 | CitationFields = set(['bibkey', 'page']) 34 | DatesFields = set(['year', 'era']) 35 | 36 | ZettelMarkdownExtensions = ['.text', '.txt', '.md', '.markdown'] 37 | 38 | 39 | class ParseError(Exception): 40 | def __init__(self, message): 41 | self.message = message 42 | 43 | def __str__(self): 44 | return self.message 45 | 46 | 47 | def typename(value): 48 | return type(value).__name__ 49 | 50 | 51 | def parse_zettel(doc): 52 | if not isinstance(doc, dict): 53 | raise ParseError( 54 | "Zettels require key/value mappings at top-level. Found %s" % typename(doc)) 55 | 56 | parse_check_zettel_field_names(doc) 57 | 58 | # These fields are all optional but, if present, must be strings 59 | parse_string_field(doc, 'title') 60 | parse_string_field(doc, 'bibkey') 61 | parse_string_field(doc, 'bibtex') 62 | parse_string_field(doc, 'ris') 63 | parse_string_field(doc, 'inline') 64 | parse_string_field(doc, 'url') 65 | parse_string_field(doc, 'summary') 66 | parse_string_field(doc, 'comment') 67 | parse_string_field(doc, 'note') 68 | parse_string_field(doc, 'document') 69 | 70 | # These fields are all optional but, if present, must be list of strings 71 | 72 | parse_list_of_string_field(doc, 'tags') 73 | parse_list_of_string_field(doc, 'mentions') 74 | 75 | parse_citation(doc, 'cite') 76 | parse_dates(doc, 'dates') 77 | 78 | # TODO: Check for extraneous fields in all cases 79 | 80 | 81 | def parse_check_zettel_field_names(doc): 82 | check_field_names(doc, ZettelFields, "Zettel") 83 | 84 | 85 | def parse_check_citation_field_names(doc): 86 | check_field_names(doc, CitationFields, "Citation") 87 | 88 | 89 | def parse_check_dates_field_names(doc): 90 | check_field_names(doc, DatesFields, "Dates") 91 | 92 | 93 | def check_field_names(doc, name_set, label): 94 | for key in doc.keys(): 95 | if key not in name_set: 96 | raise ParseError("Invalid field %s found in %s" % (key, label)) 97 | 98 | 99 | def parse_string_field(doc, field, required=False): 100 | value = doc.get(field, None) 101 | if value == None: 102 | if required: 103 | raise ParseError("Field %s requires a string but found %s of type %s" % ( 104 | field, value, typename(value))) 105 | # This extra check is needed to handle situation where a YAML field is 106 | # present but is null. We cannot allow it. 107 | if field in doc: 108 | raise ParseError("Field %s may not be (YAML) null" % field) 109 | return 110 | if not isinstance(value, str): 111 | raise ParseError("Field %s must be a string or not present at all - found value %s of type %s" % 112 | (field, value, typename(value))) 113 | #if len(value) == 0: 114 | # raise ParseError("Field %s is an empty string. Not permitted." % field) 115 | 116 | 117 | # TODO: There is a possible bug in list of string that allows a field to be defined as YAML none. 118 | 119 | def parse_list_of_string_field(doc, field, required=False): 120 | value = doc.get(field, None) 121 | if value == None: 122 | if required: 123 | raise ParseError("Field %s requires a list of strings" % field) 124 | # This extra check is needed to handle situation where a YAML field is 125 | # present but is null. We cannot allow it. 126 | if field in doc: 127 | raise ParseError("Field %s may not be (YAML) null" % field) 128 | return 129 | if not isinstance(value, (list, tuple)): 130 | raise ParseError("Field %s must be a list or not present at all - found value %s of type %s" % 131 | (field, value, typename(value))) 132 | 133 | # Make a dictionary of the list items for checking purposes only 134 | # That is, treat the list like a dictionary. Will simplify with comprehension magic later 135 | doc2 = {} 136 | pos = 0 137 | for item in value: 138 | doc2["%s(%d)" % (field, pos)] = item 139 | pos = pos + 1 140 | for key in doc2.keys(): 141 | parse_string_field(doc2, key, True) 142 | 143 | 144 | def parse_citation(doc, field): 145 | value = doc.get(field, None) 146 | if value == None: 147 | return 148 | if not isinstance(value, dict): 149 | raise ParseError("%s must be a nested (citation) dictoinary" % field) 150 | parse_check_citation_field_names(value) 151 | parse_string_field(value, 'bibkey', True) 152 | parse_string_field(value, 'page') 153 | 154 | 155 | def parse_dates(doc, field): 156 | value = doc.get(field, None) 157 | if value == None: 158 | return 159 | if not isinstance(value, dict): 160 | raise ParseError("%s must be a nested (dates) dictionary" % field) 161 | parse_check_dates_field_names(value) 162 | parse_string_field(value, 'year', True) 163 | parse_string_field(value, 'era') 164 | 165 | # This is to support formatting of resulting YAML (after modification of the underlying dictionary) 166 | 167 | 168 | # Credit to StackOverflow for helping figure out how to format YAML 169 | # multiline strings properly (when emitting YAML representation of Zettel) 170 | 171 | from collections import OrderedDict 172 | 173 | 174 | class quoted(str): 175 | pass 176 | 177 | 178 | class literal(str): 179 | pass 180 | 181 | 182 | def quoted_presenter(dumper, data): 183 | return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"') 184 | 185 | # Note: Only use multiline syntax when there are actually multiple lines. 186 | 187 | 188 | def str_presenter(dumper, data): 189 | if len(data.splitlines()) > 1: 190 | return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') 191 | return dumper.represent_scalar('tag:yaml.org,2002:str', data) 192 | 193 | 194 | def ordered_dict_presenter(dumper, data): 195 | return dumper.represent_dict(data.items()) 196 | 197 | 198 | class ZettelBadKey(Exception): 199 | def __init__(self, name): 200 | self.name = name 201 | 202 | 203 | class ZettelStringRequired(Exception): 204 | def __init__(self, value): 205 | self.value = value 206 | 207 | 208 | def get_argparse(): 209 | parser = argparse.ArgumentParser() 210 | 211 | # note is being deprecated in future releases to give users time to migrate away from it 212 | 213 | for field in ZettelFieldsOrdered: 214 | parser.add_argument('--delete-%s' % field, action="store_true", 215 | help="delete field %s" % field, default=False) 216 | 217 | for field in ZettelStringFields + ZettelExtraFields: # allow for filename, doc 218 | parser.add_argument('--set-%s' % 219 | field, help="set the value of field %s" % field) 220 | parser.add_argument('--load-%s' % 221 | field, help="load field %s from filename" % field) 222 | 223 | for field in ZettelListFields: 224 | parser.add_argument('--reset-%s' % field, action="store_true", 225 | help="reset list field %s" % field, default=False) 226 | parser.add_argument('--remove-entries-in-%s' % field, nargs=2, metavar=('FASS ENTRY', 'LIST ENTRY'), type=str, 227 | help="delete comma-separated LIST ENTRY positions from FASS ENTRY") 228 | parser.add_argument('--append-%s' % 229 | field, nargs="+", help="add value to list field %s" % field) 230 | 231 | parser.add_argument('--set-cite', nargs='+', type=str, metavar=('BIBKEY', 'PAGES'), 232 | help="set citation BIBKEY [ PAGE* ] - leave blank to override existing BIBKEY") 233 | 234 | parser.add_argument('--set-dates', nargs='+', type=str, metavar=('YEAR', 'ERA'), 235 | help="set dates; YEAR required - ERA is optional (extra arguments beyond the 2nd are ignored but allowed") 236 | 237 | for field in ZettelFieldsOrdered: 238 | parser.add_argument('--prompt-%s' % field, action="store_true", 239 | help="prompt for input of %s" % field, 240 | default=False) 241 | 242 | parser.add_argument( 243 | '--file', help='Zettel file (.yaml) to process (or check syntax)') 244 | 245 | parser.add_argument('--save', help='Write output to specified file.') 246 | 247 | parser.add_argument('--in-place', action="store_true", default=False, 248 | help="overwrite original file specified by --file") 249 | 250 | parser.add_argument( 251 | '--backup-id', help='backup suffix for original filename', default="orig") 252 | 253 | parser.add_argument('--name', nargs='+', help="order of components, e.g. id, or timestamp") 254 | parser.add_argument('--name-dir', type=str, help="folder where to write file generated by --name (will NOT be created, if it does not exist)", default=".") 255 | parser.add_argument('--id', help="human-understandable id to include in filename") 256 | parser.add_argument('--digits', type=int, help="digits in counter (default=4)", default=4) 257 | 258 | parser.add_argument('--separator', type=str, help="separate components with delimiter (default is '-')", default="-") 259 | parser.add_argument('--counter', type=str, help="counter name (defaults to --id if present) ") 260 | parser.add_argument('--counter-path', type=str, help="counter filename/path to filename", default=".counter.dat") 261 | 262 | parser.add_argument('--restrict-output-fields', 263 | nargs="+", help="restrict output fields (list of Zettel field names)", 264 | default=ZettelFieldsOrdered) 265 | 266 | # deprecated 267 | parser.add_argument('--omit-markdown-header', action="store_true", default=False, 268 | help="add markdown header when writing Markdown for each YAML field") 269 | 270 | return parser 271 | 272 | 273 | def flatten(item): 274 | if item == None: 275 | return [""] 276 | elif isinstance(item, dict): 277 | return flatten([":".join([k, item[k]]) for k in item]) 278 | elif not isinstance(item, (tuple, list)): 279 | return [str(item)] 280 | 281 | if len(item) == 0: 282 | return item 283 | else: 284 | return flatten(item[0]) + flatten(item[1:]) 285 | 286 | 287 | def prompt(field): 288 | print("Enter text for %s. ctrl-d to end." % field) 289 | lines = [] 290 | while True: 291 | try: 292 | line = input("%s> " % field) 293 | lines.append(line) 294 | except EOFError: 295 | print() 296 | break 297 | return lines 298 | 299 | 300 | class Zettel(object): 301 | 302 | def __init__(self, data={}): 303 | self.zettel = data 304 | parse_zettel(self.zettel) 305 | 306 | def set_field(self, name, value): 307 | self.zettel[name] = value 308 | parse_zettel(self.zettel) 309 | 310 | def delete_field(self, name): 311 | try: 312 | del(self.zettel[name]) 313 | except: 314 | pass 315 | parse_zettel(self.zettel) 316 | 317 | def reset_list_field(self, name): 318 | self.zettel[name] = [] 319 | parse_zettel(self.zettel) 320 | 321 | def delete_list_field_entries(self, name, positions): 322 | if name not in self.zettel: 323 | return 324 | positions.sort(reverse=True) 325 | for position in positions: 326 | del(self.zettel[name][position]) 327 | if len(self.zettel[name]) == 0: 328 | del(self.zettel[name]) 329 | 330 | def append_list_field(self, name, value): 331 | self.zettel[name] = self.zettel.get(name, []) 332 | tag_set = set(self.zettel[name]) 333 | if not value in tag_set: 334 | self.zettel[name].append(value) 335 | parse_zettel(self.zettel) 336 | 337 | def get_list_field(self, name): 338 | return self.zettel.get(name, []) 339 | 340 | def set_citation(self, bibkey, page=None): 341 | citation = {'bibkey': bibkey} 342 | if page != None: 343 | citation['page'] = page 344 | self.zettel['cite'] = citation 345 | parse_zettel(self.zettel) 346 | 347 | def has_citation(self): 348 | return 'cite' in self.zettel 349 | 350 | def set_cite_bibkey(self, bibkey): 351 | if len(bibkey) == 0: 352 | return 353 | if self.has_citation(): 354 | self.zettel['cite']['bibkey'] = bibkey 355 | parse_zettel(self.zettel) 356 | 357 | def set_cite_page(self, page): 358 | if len(page) == 0: 359 | return 360 | if self.has_citation(): 361 | self.zettel['cite']['page'] = page 362 | parse_zettel(self.zettel) 363 | 364 | def has_dates(self): 365 | return 'dates' in self.zettel 366 | 367 | def set_dates_year(self, year): 368 | if len(year) == 0: 369 | return 370 | if self.has_dates(): 371 | self.zettel['dates']['year'] = year 372 | parse_zettel(self.zettel) 373 | 374 | def set_dates_era(self, era): 375 | if len(era) == 0: 376 | return 377 | if self.has_dates(): 378 | self.zettel['dates']['era'] = era 379 | parse_zettel(self.zettel) 380 | 381 | def set_dates(self, year, era=None): 382 | dates = {'year': year} 383 | if era != None: 384 | dates['era'] = era 385 | self.zettel['dates'] = dates 386 | parse_zettel(self.zettel) 387 | 388 | def load_field(self, name, filename): 389 | text = [] 390 | with open(filename, 'r') as infile: 391 | text = infile.readlines() 392 | text = ''.join(text) 393 | text = text.strip() 394 | self.set_field(name, text) 395 | parse_zettel(self.zettel) 396 | 397 | def get_yaml(self, restrict_to_fields=ZettelFieldsOrdered): 398 | yaml.add_representer(quoted, quoted_presenter) 399 | yaml.add_representer(literal, str_presenter) 400 | yaml.add_representer(OrderedDict, ordered_dict_presenter) 401 | parse_zettel(self.zettel) 402 | yaml_zettel = OrderedDict() 403 | for key in ZettelFieldsOrdered: 404 | if key not in self.zettel: 405 | continue 406 | if key not in restrict_to_fields: 407 | continue 408 | if key in ZettelStringFields: 409 | yaml_zettel[key] = literal(self.zettel[key]) 410 | elif key != 'document': # Only field not allowed is Markdown document 411 | try: 412 | yaml_zettel[key] = self.zettel[key].copy() 413 | except: 414 | print("Warning: Cannot copy %s" % key) 415 | if len(yaml_zettel) > 0: 416 | return yaml.dump(yaml_zettel, default_flow_style=False) 417 | else: 418 | return "" 419 | 420 | def get_document(self): 421 | return self.zettel.get('document','') 422 | 423 | def get_filename(self): 424 | return self.zettel.get('filename','') 425 | 426 | # Unlikely we need this code anymore. 427 | # def get_text(self, omit_markdown_header, restrict_to_fields=ZettelFieldsOrdered): 428 | # text = [] 429 | # parse_zettel(self.zettel) 430 | # for key in ZettelFieldsOrdered: 431 | # if key not in self.zettel: 432 | # continue 433 | # if key not in restrict_to_fields: 434 | # continue 435 | # if not omit_markdown_header: 436 | # text.append(markdown_h1(key)) 437 | # if key in ZettelStringFields: 438 | # text.append(self.zettel[key].strip()) 439 | # elif key in ZettelListFields: 440 | # for item in self.zettel[key]: 441 | # text.append(markdown_listitem(item)) 442 | # else: 443 | # text.append(self.get_yaml([key])) 444 | # text.append("\n") 445 | # return "\n".join(text) 446 | 447 | def get_yaml_subset(self, fields=[]): 448 | z = Zettel({}) 449 | for field in fields: 450 | z.zettel[field] = self.zettel[field].copy() 451 | 452 | def get_indexed_representation(self): 453 | parse_zettel(self.zettel) 454 | return {key: ",".join(flatten(self.zettel[key])) for key in self.zettel} 455 | 456 | 457 | # deprecated 458 | # def markdown_h1(text): 459 | # return "\n".join([text, len(text) * "="]) + "\n" 460 | # deprecated 461 | #def markdown_listitem(text): 462 | # return "- %s" % text.strip().replace("\n", "").replace("\r", "") 463 | 464 | 465 | class ZettelLoaderError(Exception): 466 | def __init__(self, message): 467 | self.message = message 468 | 469 | 470 | def load_pure_yaml(filepath): 471 | # TODO: Consider using the frontmatter to load the YAML and do all error reporting. 472 | #print("Importing YAML: %s" % filepath) 473 | ydoc = {} 474 | document = "" 475 | with open(filepath) as infile: 476 | try: 477 | text = infile.read() 478 | except: 479 | print("- Warning: I/O error on %s; is doc UTF-8" % filepath) 480 | return (ydoc, document) 481 | try: 482 | ydocs = yaml.load_all(text, Loader=Loader) 483 | except: 484 | print("- Warning: Cannot load YAML from %s; consider running YAML linter" % filepath) 485 | return (ydoc, document) 486 | 487 | try: 488 | ydoc = next(ydocs) 489 | except: 490 | print("- Warning: Cannot load first YAML document from %s" % filepath) 491 | return (ydoc, document) 492 | return (ydoc, document) 493 | 494 | def load_markdown_with_frontmatter(filepath): 495 | #print("Importing Markdown with Frontmatter: %s" % filepath) 496 | post = frontmatter.load(filepath) 497 | return (post.metadata, post.content) 498 | 499 | 500 | class ZettelLoader(object): 501 | def __init__(self, infile): 502 | # developer note: When we developed this code, we were thinking about a "fass" of zettels. 503 | # Now we just have individual zettels. 504 | if infile.endswith('.yaml'): 505 | self.ydocs = [load_pure_yaml(infile)] 506 | elif infile.endswith('.md'): 507 | self.ydocs = [load_markdown_with_frontmatter(infile)] 508 | else: 509 | self.ydocs = [] 510 | 511 | def getZettels(self): 512 | for yaml_document in self.ydocs: 513 | (ydoc, document) = yaml_document 514 | ydoc['document'] = document 515 | if isinstance(ydoc, dict): 516 | yield Zettel(ydoc) 517 | else: 518 | yield Zettel({}) 519 | 520 | 521 | def main(): 522 | parser = get_argparse() 523 | args = parser.parse_args() 524 | argsd = vars(args) 525 | argsd['timestamp'] = True 526 | z_generator = gen_new_zettels(args) 527 | 528 | try: 529 | first_zettel = next(z_generator) 530 | except ParseError as error: 531 | print(error) 532 | 533 | filename = None 534 | if args.in_place: 535 | if not args.file: 536 | print("--in-place requires --file") 537 | sys.exit(1) 538 | filename = args.file 539 | filename_parts = os.path.splitext(filename) 540 | if filename_parts[1] not in ['.yaml', '.md']: 541 | print("Input file not .yaml/.md: %s" % filename) 542 | sys.exit(1) 543 | backup_filename = ".".join([filename, args.backup_id]) 544 | shutil.copyfile(filename, backup_filename) 545 | outfile = open(args.file, "w") 546 | elif args.save: 547 | filename = args.save 548 | if args.file == args.save: 549 | print("Use --in-place instead of --save if you want to replace input file (specified with --file)") 550 | sys.exit(1) 551 | if os.path.exists(filename): 552 | backup_filename = ".".join([filename, args.backup_id]) 553 | shutil.copyfile(filename, backup_filename) 554 | outfile = open(args.save, "w") 555 | elif args.name: 556 | name_components = {} 557 | name_dir = args.name_dir 558 | if not os.path.exists(name_dir): 559 | print("Destination directory specified (--name-dir %s) does not exist. Will not write file.") 560 | sys.exit(1) 561 | for arg in args.name: 562 | if arg not in ['id','timestamp', 'counter']: 563 | print("--name may only use id, counter, and timestamp (%s found)" % arg) 564 | sys.exit(1) 565 | if not argsd.get(arg, None) != None: 566 | print("--name %s requires --%s" % (args.name, arg)) 567 | print(argsd) 568 | sys.exit(1) 569 | if args.id != None: 570 | name_components['id'] = args.id 571 | digits = args.digits 572 | 573 | # --counter and --id can be specified separately 574 | # If omitted, --counter takes on --id 575 | # If both are omitted, then we are not using counters in the generated names. 576 | counter_name = args.counter 577 | if not args.counter: 578 | counter_name = args.id 579 | 580 | if counter_name != None: 581 | seq = get_count(args.counter_path, counter_name) 582 | seq_text = str(seq) 583 | digits = max(len(seq_text), digits) 584 | pad_text = "0" * (digits - len(seq_text)) 585 | name_components['counter'] = pad_text + seq_text 586 | 587 | name_components['timestamp'] = strftime("%Y%m%d%H%M%S") 588 | 589 | name_template = args.separator.join(["%%(%s)s" % name for name in args.name]) + ".md" 590 | name_template = "/".join([name_dir, name_template]) 591 | filename = name_template % name_components 592 | if os.path.exists(filename): 593 | backup_filename = ".".join([filename, args.backup_id]) 594 | shutil.copyfile(filename, backup_filename) 595 | outfile = open(filename, "w") 596 | else: 597 | outfile = sys.stdout 598 | 599 | if filename: 600 | (basename, extension) = os.path.splitext(filename) 601 | else: 602 | extension = '.yaml' 603 | 604 | try: 605 | yaml_repr_stripped = first_zettel.get_yaml(args.restrict_output_fields).rstrip() 606 | document = first_zettel.get_document() 607 | if len(yaml_repr_stripped) > 0: 608 | outfile.write('\n'.join(['---', yaml_repr_stripped, '---', document.rstrip()])+'\n') 609 | else: 610 | doc_stripped = document.rstrip() 611 | if len(doc_stripped) > 0: 612 | outfile.write(doc_stripped + '\n') 613 | except ParseError as error: 614 | print(error) 615 | 616 | def gen_id(): 617 | id = 0 618 | while True: 619 | yield id 620 | id = id + 1 621 | 622 | 623 | def gen_new_zettels(args): 624 | vargs = vars(args) 625 | id_gen = gen_id() 626 | if args.file: 627 | loader = ZettelLoader(args.file) 628 | last_z = None 629 | for z in loader.getZettels(): 630 | last_z = process_zettel_command_line_options( 631 | z, vargs, next(id_gen)) 632 | yield last_z 633 | if not last_z: 634 | yield process_zettel_command_line_options(Zettel(), vargs, next(id_gen)) 635 | else: 636 | yield process_zettel_command_line_options(Zettel(), vargs, next(id_gen)) 637 | 638 | 639 | def process_zettel_command_line_options(z, vargs, id): 640 | # --reset-*, --delete-*, and --remove_entries_in-* are evaluated first 641 | for arg in vargs: 642 | if not vargs[arg]: 643 | continue 644 | 645 | if arg.startswith("reset_"): 646 | reset_what = arg[len("reset_"):] 647 | z.reset_list_field(reset_what) 648 | 649 | if arg.startswith("delete_"): 650 | delete_what = arg[len("delete_"):] 651 | z.delete_field(delete_what) 652 | 653 | if arg.startswith("remove_entries_in_"): 654 | delete_what = arg[len("remove_entries_in_"):] 655 | try: 656 | (zettel_id, list_entries) = vargs[arg][:2] 657 | zettel_id = int(zettel_id) 658 | list_entries = [int(pos) for pos in list_entries.split(",")] 659 | except: 660 | print( 661 | "Non-integer zettel ID or list position found in %s. Aborting." % arg) 662 | sys.exit(1) 663 | if id == zettel_id: 664 | z.delete_list_field_entries(delete_what, list_entries) 665 | 666 | for arg in vargs: 667 | if not vargs[arg]: 668 | continue 669 | if arg == "set_cite": 670 | cite_info = vargs[arg] 671 | bibkey = cite_info[0] 672 | pages = ",".join(cite_info[1:]) 673 | 674 | if z.has_citation(): 675 | z.set_cite_bibkey(bibkey) 676 | z.set_cite_page(pages) 677 | else: 678 | z.set_citation(bibkey, pages) 679 | 680 | elif arg == "set_dates": 681 | date_info = vargs[arg] 682 | year = date_info[0] 683 | era = ','.join(date_info[1:]) 684 | if z.has_dates(): 685 | z.set_dates_year(year) 686 | z.set_dates_era(era) 687 | else: 688 | z.set_dates(year, era) 689 | 690 | elif arg.startswith("set_"): 691 | set_what = arg[len("set_"):] 692 | value = vargs[arg].replace(r"\n", "\n") 693 | z.set_field(set_what, value) 694 | 695 | elif arg.startswith("prompt_"): 696 | prompt_field = arg[len("prompt_"):] 697 | lines = prompt(prompt_field) 698 | if prompt_field in ZettelStringFields: 699 | z.set_field(prompt_field, "\n".join(lines)) 700 | elif prompt_field in ZettelExtraFields: 701 | z.set_field(prompt_field, "\n".join(lines)) 702 | elif prompt_field in ZettelListFields: 703 | for line in lines: 704 | z.append_list_field(prompt_field, line) 705 | elif prompt_field == "dates": 706 | if len(lines) > 0: 707 | try: 708 | z.set_dates(lines[0], lines[1]) 709 | except: 710 | z.set_dates(lines[0]) 711 | elif prompt_field == "cite": 712 | if len(lines) > 0: 713 | try: 714 | z.set_citation(lines[0], lines[1]) 715 | except: 716 | z.set_citation(lines[0]) 717 | 718 | if arg.startswith("append_"): 719 | append_what = arg[len("append_"):] 720 | for text in vargs[arg]: 721 | z.append_list_field(append_what, text) 722 | 723 | if arg.startswith("load_"): 724 | load_what = arg[len("load_"):] 725 | z.load_field(load_what, vargs[arg]) 726 | return z 727 | 728 | 729 | def get_count(counter_path, counter_name): 730 | # Create counter db if not present. 731 | if not os.path.exists(counter_path): 732 | with open(counter_path, 'w') as dbfile: 733 | json.dump({}, dbfile) 734 | 735 | # Read count from counter. If non-existent, start at 0. 736 | with open(counter_path, 'r') as dbfile: 737 | db = json.load(dbfile) 738 | count = db.get(counter_name, -1) + 1 739 | 740 | # save count for next invocation 741 | with open(counter_path, 'w') as dbfile: 742 | db[counter_name] = count 743 | json.dump(db, dbfile) 744 | return count 745 | 746 | def dict_as_yaml(data): 747 | yaml.add_representer(quoted, quoted_presenter) 748 | yaml.add_representer(literal, str_presenter) 749 | yaml.add_representer(OrderedDict, ordered_dict_presenter) 750 | presented_data = OrderedDict() 751 | for key in data: 752 | if key in ZettelStringFields: 753 | presented_data[key] = literal(data[key]) 754 | else: 755 | presented_data[key] = data[key] 756 | return yaml.dump(presented_data, default_flow_style=False, Dumper=Dumper) 757 | 758 | 759 | if __name__ == '__main__': 760 | main() 761 | -------------------------------------------------------------------------------- /zettelgeist/zfind.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from time import strftime 4 | import yaml 5 | from . import zdb, zettel, zquery 6 | from .zutils import * 7 | 8 | YAML_HEADER = '---' 9 | 10 | def get_argparse(): 11 | parser = zdb.get_argparse() 12 | 13 | for field in zdb.ZettelSQLFields: 14 | parser.add_argument('--show-%s' % field, 15 | action='store_const', const=True, default=False, 16 | help="include field <%s> in output" % field) 17 | 18 | parser.add_argument('--show-all', 19 | action='store_const', const=True, default=False, 20 | help="include all fields in output") 21 | 22 | parser.add_argument('--publish', help="use template to publish zfind output (suppresses all --show-FIELD)", default=None) 23 | 24 | parser.add_argument('--publish-conf', help="use publish configuration file to format special fields", default=None) 25 | 26 | parser.add_argument('--count', action='store_const', const=True, 27 | default=False, help="Show number of Zettels matching this search") 28 | 29 | parser.add_argument( 30 | '--query-prompt', action='store_const', const=True, default=False, 31 | help="prompt for ZQL query (overrides --query-string, --query-file))") 32 | 33 | parser.add_argument( 34 | '--query-file', help="load ZQL query from file (overrides --query)", default=None) 35 | 36 | parser.add_argument( 37 | '--query-string', 38 | help="load ZQL from string", default=None) 39 | 40 | parser.add_argument( 41 | '--fileset', help="write fileset to filename", default=None) 42 | 43 | parser.add_argument( 44 | '--stats', help="write statistics and parameters to filename", default=None) 45 | 46 | parser.add_argument( 47 | '--get-all-tags', help="show all tags in this database (disables all other options)", action="store_true", default=False) 48 | 49 | parser.add_argument( 50 | '--get-all-mentions', help="show all mentions in this database (disables all other options)", action="store_true", default=False) 51 | 52 | 53 | return parser 54 | 55 | 56 | def main(): 57 | parser = get_argparse() 58 | args = parser.parse_args() 59 | argsd = vars(args) 60 | 61 | db = zdb.get(args.database) 62 | 63 | # The --get-all-tags and --get-all-mentions stop processing of all other tags 64 | # TODO: Make each group of functions a function to make this more comprehensible. 65 | 66 | if args.get_all_tags: 67 | print('\n'.join(db.get_tags_list())) 68 | exit(0) 69 | 70 | if args.get_all_mentions: 71 | print('\n'.join(db.get_mentions_list())) 72 | exit(0) 73 | 74 | # The --query-{prompt,file,string} options are for ZQL processing. 75 | 76 | if args.query_prompt: 77 | input_line = input("zfind> ") 78 | elif args.query_file: 79 | with open(args.query_file) as infile: 80 | input_line = infile.read() 81 | elif args.query_string: 82 | input_line = args.query_string 83 | else: 84 | print("No query option (--query-string, --query-file, or --query-prompt) found") 85 | return 86 | 87 | if input_line: 88 | ast = zquery.compile(input_line) 89 | gen = db.fts_query(ast[0]) 90 | else: 91 | print("Warning: Query could not be loaded via --query, --query-file, or --query-prompt") 92 | sys.exit(1) 93 | 94 | # This is the actual logic to find and process results. 95 | 96 | search_count = 0 97 | match_filenames = [] 98 | 99 | # This is for the --publish option. Publish suppresses all other output. 100 | 101 | if args.publish: 102 | template_file = args.publish 103 | publish_conf = args.publish_conf 104 | for row in gen: 105 | loader = zettel.ZettelLoader(row['filename']) 106 | zettels = loader.getZettels() 107 | z = next(zettels) 108 | publish(row, z, template_file, publish_conf) 109 | return 110 | 111 | # This is for the --show options 112 | for row in gen: 113 | search_count = search_count + 1 114 | printed_something = False 115 | match_filenames.append(row['filename']) 116 | loader = zettel.ZettelLoader(row['filename']) 117 | zettels = loader.getZettels() 118 | z = next(zettels) 119 | 120 | # Handle output of YAML here 121 | this_result_output = [] 122 | for field in row.keys(): 123 | show_field = 'show_' + field 124 | if argsd.get(show_field, None) or argsd.get('show_all'): 125 | if field == 'filename': 126 | filename_yaml = yaml.dump({ 'filename' : row['filename']}) 127 | this_result_output.append(filename_yaml.rstrip()) 128 | elif field == 'document': 129 | continue 130 | elif row[field]: 131 | if z: 132 | this_result_output.append(z.get_yaml([field]).rstrip()) 133 | else: 134 | this_result_output.append("%s:" % field) 135 | this_result_output.append(row[field]) 136 | 137 | # No output if just --- and --- 138 | if len(this_result_output) > 0: 139 | print('\n'.join([YAML_HEADER] + this_result_output + [YAML_HEADER])) 140 | 141 | if argsd.get("show_document"): 142 | document = row['document'] 143 | if len(document) > 0: 144 | print(row['document']) 145 | print() 146 | 147 | # --count here / Should this be added to the YAML payload? I think the answer is yes. 148 | 149 | if args.count: 150 | print("%d Zettels matched search" % search_count) 151 | 152 | # --fileset handled here / Should --fileset actually suppress the --show options? 153 | # It's primary purpose is to *avoid* showing output for subsequent processing, say, in a shell loop 154 | 155 | if args.fileset: 156 | if not os.path.exists(args.fileset): 157 | write_to_file(args.fileset, "\n".join(match_filenames), mode="w", newlines=1) 158 | else: 159 | print("Filename %s exists; will not overwrite." % args.fileset) 160 | 161 | # --stats seems to duplicate the work of --count. yes, it goes to a file, but that would 162 | # allow for subsequent querying, say, with yq or equivalent. 163 | 164 | if args.stats: 165 | if not os.path.exists(args.stats): 166 | doc = {'count': search_count, 'query': input_line.strip()} 167 | write_to_file(args.stats, zettel.dict_as_yaml(doc), mode="w", newlines=1) 168 | else: 169 | print("Filename %s exists; will not overwrite." % args.stats) 170 | 171 | def publish(row, z, template_file, publish_conf): 172 | import json 173 | 174 | formatting = {} 175 | if publish_conf: 176 | with open(publish_conf) as jsonf: 177 | formatting = json.load(jsonf) 178 | 179 | all_vars = { k:'' for k in zettel.ZettelFields } 180 | all_vars.update(z.zettel) 181 | all_vars['filename'] = row['filename'] 182 | 183 | 184 | 185 | tags = reformat_tags(all_vars, formatting) 186 | mentions = reformat_mentions(all_vars, formatting) 187 | cite = reformat_cite(all_vars, formatting) 188 | 189 | reformatted_data = { 'tags' : tags, 'mentions' : mentions, 'cite' : cite } 190 | 191 | all_vars.update(reformatted_data) 192 | 193 | with open(template_file) as tf: 194 | text = tf.read() 195 | print(text % all_vars) 196 | 197 | def reformat_tags(all_vars, formatting): 198 | tags_format = formatting.get('tags', {}) 199 | tags = all_vars.get('tags', []) 200 | if len(tags) == 0: 201 | return '' 202 | default_tag_format = '%(tag)s' 203 | formatted_tags = \ 204 | [ tags_format.get('tag', default_tag_format) % { 'tag' : tag } for tag in tags ] 205 | return tags_format.get('before','') + ''.join(formatted_tags) + tags_format.get('after','') 206 | 207 | def reformat_mentions(all_vars, formatting): 208 | mentions_format = formatting.get('mentions', {}) 209 | mentions = all_vars.get('mentions', []) 210 | if len(mentions) == 0: 211 | return '' 212 | default_mention_format = '%(mention)s' 213 | formatted_mentions = \ 214 | [ mentions_format.get('mention', default_mention_format) % { 'mention' : mention } for mention in mentions ] 215 | return mentions_format.get('before','') + ''.join(formatted_mentions) + mentions_format.get('after','') 216 | 217 | def reformat_cite(all_vars, formatting): 218 | cite_format = formatting.get('cite', {}) 219 | cite = all_vars.get("cite", {}) 220 | if len(cite) == 0: 221 | return '' 222 | if len(cite) > 0 and type(cite_format) == type({}): 223 | cite_template = cite_format.get('before') 224 | cite_template += cite_format.get('bibkey', '%(bibkey)s') 225 | cite_template += cite_format.get('page', '%(page)s') 226 | cite_template += cite_format.get('after') 227 | new_cite = cite_template % cite 228 | return new_cite 229 | else: 230 | return '' 231 | 232 | if __name__ == '__main__': 233 | main() 234 | -------------------------------------------------------------------------------- /zettelgeist/zimport.py: -------------------------------------------------------------------------------- 1 | # zimport.py - Import Zettels into an exising database 2 | 3 | import os 4 | import os.path 5 | import sys 6 | import frontmatter # to accommodate Markdown with YAML frontmatter 7 | 8 | from . import zdb, zettel 9 | 10 | import yaml 11 | try: 12 | from yaml import CLoader as Loader, CDumper as Dumper 13 | except ImportError: 14 | from yaml import Loader, Dumper 15 | 16 | 17 | def get_zettels(dir): 18 | for (dirpath, dirnames, filenames) in os.walk(dir): 19 | for filename in filenames: 20 | if filename.endswith('.yaml') or filename.endswith('.md'): 21 | yield os.path.join(dirpath, filename) 22 | 23 | 24 | def main(): 25 | parser = zdb.get_argparse() 26 | parser.add_argument( 27 | '--dir', help="location of Zettels (path to folder)", required=True) 28 | 29 | parser.add_argument('--fullpath', action="store_true", 30 | help="store full path to file in index", default=False) 31 | 32 | parser.add_argument('--validate', action="store_true", 33 | help="check Zettels only (don't import)", default=False) 34 | 35 | parser.add_argument('--create', action="store_true", 36 | help="create database and delete existing if present", default=False) 37 | 38 | args = parser.parse_args() 39 | 40 | if args.create or not os.path.exists(args.database): 41 | zcreate(args) 42 | 43 | db = zdb.get(args.database) 44 | zettel_dir = args.dir 45 | 46 | for entry in get_zettels(zettel_dir): 47 | if args.fullpath: 48 | filepath = os.path.abspath(entry) 49 | else: 50 | filepath = entry 51 | print("Processing %s" % filepath) 52 | if filepath.endswith('.yaml'): 53 | yaml_info = zettel.load_pure_yaml(filepath) 54 | elif filepath.endswith('.md'): 55 | yaml_info = zettel.load_markdown_with_frontmatter(filepath) 56 | else: 57 | print("Warning: %s is not .yaml or .md (ignoring)") 58 | 59 | (ydoc, document) = yaml_info 60 | if len(ydoc) > 0: 61 | try: 62 | z = zettel.Zettel(ydoc) 63 | except zettel.ParseError as error: 64 | error_text = str(error) 65 | print("%s:\n%s" % (filepath, error_text)) 66 | continue 67 | 68 | if not args.validate: 69 | db.bind(z, filepath, document) 70 | db.insert_into_table() 71 | 72 | db.done() 73 | 74 | 75 | def zcreate(args): 76 | if os.path.exists(args.database): 77 | print("Deleting existing database %s" % args.database) 78 | os.unlink(args.database) 79 | print("Creating new database %s" % args.database) 80 | db = zdb.get(args.database) 81 | db.drop_table() 82 | db.create_table() 83 | db.done() 84 | 85 | if __name__ == '__main__': 86 | main() 87 | -------------------------------------------------------------------------------- /zettelgeist/zquery.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import readline 3 | import pprint 4 | import json 5 | import tatsu 6 | import argparse 7 | import os.path 8 | import tempfile 9 | import pprint 10 | 11 | from . import zdb, zettel 12 | 13 | 14 | def unquote(text): 15 | return text.replace('"', '').replace("'", "") 16 | 17 | 18 | class ZG(object): 19 | def literal(self, ast): 20 | return ast.word 21 | 22 | def _get_match_clause(self, ast, negate): 23 | text = unquote(ast.text) 24 | words = text.split() 25 | return " NEAR/1 ".join(["%s%s:%s" % (negate, ast.field, word) for word in words]) 26 | 27 | def z_field(self, ast): 28 | match_clause = self._get_match_clause(ast, '') 29 | return "SELECT * FROM zettels WHERE zettels MATCH '%s'" % match_clause 30 | 31 | def and_expr(self, ast): 32 | if ast.op == '&': 33 | return "SELECT * from (%s INTERSECT %s)" % (ast.left, ast.right) 34 | elif ast.op == '!': 35 | return "SELECT * from (%s EXCEPT %s)" % (ast.left, ast.right) 36 | # else: parser should have caught any non-op 37 | 38 | def and_op(self, ast): 39 | return ast.op 40 | 41 | def or_expr(self, ast): 42 | return "SELECT * from (%s UNION %s)" % (ast.left, ast.right) 43 | 44 | 45 | def get_temp_table_name(): 46 | return os.path.split(tempfile.mktemp())[1] 47 | 48 | 49 | class ZG2(object): 50 | def __init__(self, select_fields=["docid"]): 51 | self.queries = {} 52 | self.select_fields = ",".join(select_fields) 53 | self.temp_table_name = get_temp_table_name() 54 | self.create_temp_table_clause = "CREATE TABLE %s AS %%s" % self.temp_table_name 55 | self.drop_table_statement = "DROP TABLE IF EXISTS %s" % self.temp_table_name 56 | self.select_all = "SELECT docid from %s" % self.temp_table_name 57 | 58 | def sql_drop_matches_table(self): 59 | return self.drop_table_statement 60 | 61 | def sql_create_matches_table(self, compiled_query): 62 | return self.create_temp_table_clause % compiled_query 63 | 64 | def sql_get_matches(self): 65 | return self.select_all 66 | 67 | def get_field_query_sql(self, field, field_context, docid): 68 | default = """SELECT docid, %(field)s FROM zettels WHERE docid = %(docid)s""" % vars( 69 | ) 70 | field_queries = self.queries.get(field, [default]).copy() 71 | for i in range(0, len(field_queries)): 72 | field_queries[i] = field_queries[i] % vars() 73 | #print(">>> field_queries", field_queries) 74 | return field_queries 75 | 76 | def literal(self, ast): 77 | return ast.word 78 | 79 | def _get_match_clause(self, ast, negate): 80 | text = unquote(ast.text) 81 | words = text.split() 82 | return " NEAR/1 ".join(["%s%s:%s" % (negate, ast.field, word) for word in words]) 83 | 84 | def z_field(self, ast): 85 | match_clause = self._get_match_clause(ast, '') 86 | query_list = self.queries.get(ast.field, []) 87 | field_query = "SELECT docid FROM zettels WHERE zettels MATCH '%s'" % match_clause 88 | context_query = """SELECT docid, snippet(zettels, '[', ']', '...', -1, -%%(field_context)s) as %s, %s as %s_verbatim, offsets(zettels) as %s_offsets FROM zettels WHERE zettels MATCH '%s' AND docid = %%(docid)s""" % ( 89 | ast.field, ast.field, ast.field, ast.field, match_clause) 90 | query_list.append(context_query) 91 | self.queries[ast.field] = query_list 92 | return field_query 93 | 94 | def and_expr(self, ast): 95 | if ast.op == '&': 96 | return "SELECT %s from (%s INTERSECT %s)" % (self.select_fields, ast.left, ast.right) 97 | elif ast.op == '!': 98 | return "SELECT %s from (%s EXCEPT %s)" % (self.select_fields, ast.left, ast.right) 99 | # else: parser should have caught any non-op 100 | 101 | def and_op(self, ast): 102 | return ast.op 103 | 104 | def or_expr(self, ast): 105 | return "SELECT %s from (%s UNION %s)" % (self.select_fields, ast.left, ast.right) 106 | 107 | 108 | def compile(input_line): 109 | parser = tatsu.compile(zdb.GRAMMAR) 110 | zg_semantics = ZG() 111 | ast = parser.parse(input_line, semantics=zg_semantics) 112 | return (ast, zg_semantics) 113 | 114 | 115 | def compile2(input_line): 116 | parser = tatsu.compile(zdb.GRAMMAR) 117 | zg_semantics = ZG2() 118 | ast = parser.parse(input_line, semantics=zg_semantics) 119 | return (ast, zg_semantics) 120 | -------------------------------------------------------------------------------- /zettelgeist/zutils.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import os.path 4 | import sqlite3 5 | 6 | from . import zettel 7 | 8 | # Compute MD5 for large files 9 | # 10 | # Credit to: 11 | # stackoverflow.com/questions/1131220/get-md5-hash-of-big-files-in-python 12 | 13 | 14 | def md5_for_file(f, block_size=2**20): 15 | md5 = hashlib.md5() 16 | while True: 17 | data = f.read(block_size) 18 | if not data: 19 | break 20 | md5.update(data) 21 | return md5.digest() 22 | 23 | 24 | def write_to_file(filepath, text, **kwargs): 25 | mode = kwargs.get("mode", "a") 26 | newlines = kwargs.get("newlines", 1) 27 | with open(filepath, mode) as outfile: 28 | outfile.write(text) 29 | if newlines: 30 | outfile.write("\n" * int(newlines)) 31 | 32 | 33 | def write_data(filename, mode, comment, statement): 34 | if not filename: 35 | return 36 | with open(filename, mode) as outfile: 37 | outfile.write("\n".join([comment, statement]) + "\n\n") 38 | 39 | 40 | def dirname(path): 41 | return os.path.split(path)[0] 42 | 43 | 44 | def basename(path): 45 | return os.path.split(path)[1] 46 | -------------------------------------------------------------------------------- /zettelgeist/zversion.py: -------------------------------------------------------------------------------- 1 | # 2 | # ZettelGeist Version for Python 3 | # 4 | 5 | __version__ = "1.1.5" 6 | 7 | def version(): 8 | return __version__ 9 | --------------------------------------------------------------------------------