bible-tui 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bible_tui-0.6.0/LICENSE +21 -0
- bible_tui-0.6.0/PKG-INFO +154 -0
- bible_tui-0.6.0/README.md +123 -0
- bible_tui-0.6.0/bible_tui/__init__.py +3 -0
- bible_tui-0.6.0/bible_tui/__main__.py +3 -0
- bible_tui-0.6.0/bible_tui/bibles/bible_asv.sqlite +0 -0
- bible_tui-0.6.0/bible_tui/bibles/bible_kjv.sqlite +0 -0
- bible_tui-0.6.0/bible_tui/cli.py +339 -0
- bible_tui-0.6.0/bible_tui/config.py +168 -0
- bible_tui-0.6.0/bible_tui/highlights.py +126 -0
- bible_tui-0.6.0/bible_tui/marks.py +108 -0
- bible_tui-0.6.0/bible_tui/paths.py +66 -0
- bible_tui-0.6.0/bible_tui/store.py +186 -0
- bible_tui-0.6.0/bible_tui/tui.py +3933 -0
- bible_tui-0.6.0/bible_tui/update.py +196 -0
- bible_tui-0.6.0/bible_tui/versions.py +135 -0
- bible_tui-0.6.0/bible_tui.egg-info/PKG-INFO +154 -0
- bible_tui-0.6.0/bible_tui.egg-info/SOURCES.txt +32 -0
- bible_tui-0.6.0/bible_tui.egg-info/dependency_links.txt +1 -0
- bible_tui-0.6.0/bible_tui.egg-info/entry_points.txt +2 -0
- bible_tui-0.6.0/bible_tui.egg-info/top_level.txt +1 -0
- bible_tui-0.6.0/pyproject.toml +68 -0
- bible_tui-0.6.0/setup.cfg +4 -0
- bible_tui-0.6.0/tests/test_about.py +93 -0
- bible_tui-0.6.0/tests/test_cli.py +96 -0
- bible_tui-0.6.0/tests/test_cmdline.py +122 -0
- bible_tui-0.6.0/tests/test_glyphs_and_messages.py +77 -0
- bible_tui-0.6.0/tests/test_highlights.py +206 -0
- bible_tui-0.6.0/tests/test_marks.py +219 -0
- bible_tui-0.6.0/tests/test_paths_and_config.py +109 -0
- bible_tui-0.6.0/tests/test_split.py +266 -0
- bible_tui-0.6.0/tests/test_tui.py +290 -0
- bible_tui-0.6.0/tests/test_update.py +298 -0
- bible_tui-0.6.0/tests/test_versions.py +95 -0
bible_tui-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cody Sechelski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
bible_tui-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bible-tui
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: A dependency-free terminal Bible reader with Vim-style navigation and pluggable versions
|
|
5
|
+
Author: Cody Sechelski
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/codysechelski/bible-tui
|
|
8
|
+
Project-URL: Documentation, https://github.com/codysechelski/bible-tui/blob/main/docs/features/index.md
|
|
9
|
+
Project-URL: Issues, https://github.com/codysechelski/bible-tui/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/codysechelski/bible-tui/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: bible,scripture,terminal,tui,curses,vim,kjv,reader
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console :: Curses
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Classifier: Topic :: Religion
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# bible-tui
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<a href="https://github.com/codysechelski/bible-tui/releases"><img alt="Release" src="https://img.shields.io/github/v/release/codysechelski/bible-tui?sort=semver"></a>
|
|
36
|
+
<a href="https://github.com/codysechelski/bible-tui/actions/workflows/release.yml"><img alt="CI" src="https://github.com/codysechelski/bible-tui/actions/workflows/release.yml/badge.svg"></a>
|
|
37
|
+
<a href="https://github.com/codysechelski/bible-tui/blob/main/pyproject.toml"><img alt="Python 3.9+" src="https://img.shields.io/badge/python-3.9%2B-blue"></a>
|
|
38
|
+
<a href="https://github.com/codysechelski/bible-tui/blob/main/pyproject.toml"><img alt="Dependencies: none" src="https://img.shields.io/badge/dependencies-none-brightgreen"></a>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
A fast, dependency-free terminal Bible reader with Vim-style keys.
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
- **[Read and navigate](https://github.com/codysechelski/bible-tui/blob/main/docs/features/navigation.md)** with arrows or Vim keys,
|
|
46
|
+
[jump to `John 3:16`](https://github.com/codysechelski/bible-tui/blob/main/docs/features/go-to-reference.md) with autocomplete, and use a Vim-style
|
|
47
|
+
[`:` command line](https://github.com/codysechelski/bible-tui/blob/main/docs/features/command-line.md).
|
|
48
|
+
- **[Search](https://github.com/codysechelski/bible-tui/blob/main/docs/features/search.md)** within a chapter, or
|
|
49
|
+
[fuzzy-find across the whole Bible](https://github.com/codysechelski/bible-tui/blob/main/docs/features/fuzzy-find.md) with a live preview.
|
|
50
|
+
- **[Compare two versions](https://github.com/codysechelski/bible-tui/blob/main/docs/features/split-view.md)** side by side, with verses lined up.
|
|
51
|
+
- **[Mark](https://github.com/codysechelski/bible-tui/blob/main/docs/features/marks.md) and [highlight](https://github.com/codysechelski/bible-tui/blob/main/docs/features/highlights.md)** verses in six colors. They're
|
|
52
|
+
saved and show in every version.
|
|
53
|
+
- **[Bring any version](https://github.com/codysechelski/bible-tui/blob/main/docs/features/versions.md)**, in any language: each one is a SQLite file. The
|
|
54
|
+
public-domain KJV and ASV are included.
|
|
55
|
+
|
|
56
|
+
| | |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
|  |  |
|
|
59
|
+
| [Highlight verses](https://github.com/codysechelski/bible-tui/blob/main/docs/features/highlights.md) in six colors | [Jump back](https://github.com/codysechelski/bible-tui/blob/main/docs/features/highlights.md) to any highlight or mark |
|
|
60
|
+
|  |  |
|
|
61
|
+
| [Switch versions](https://github.com/codysechelski/bible-tui/blob/main/docs/features/versions.md) and keep your place | [Any language](https://github.com/codysechelski/bible-tui/blob/main/docs/features/versions.md#any-language) works |
|
|
62
|
+
|
|
63
|
+
<sub>The Portuguese screenshot shows the Bíblia Livre (BLIVRE), copyright © 2018 Diego Santos, Mario Sérgio, and Marco Teles, from
|
|
64
|
+
[eBible.org](https://ebible.org/porbr2018/copyright.htm), licensed under
|
|
65
|
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Not bundled with bible-tui.</sub>
|
|
66
|
+
|
|
67
|
+
**[See all features →](https://github.com/codysechelski/bible-tui/blob/main/docs/features/index.md)** Each one has a short animation.
|
|
68
|
+
|
|
69
|
+
## Install
|
|
70
|
+
|
|
71
|
+
Requires Python 3.9+ on macOS or Linux, and nothing else.
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
pipx install git+https://github.com/codysechelski/bible-tui
|
|
75
|
+
bible-tui
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or run it from a clone with `./bible-tui`.
|
|
79
|
+
|
|
80
|
+
bible-tui checks for new releases once a day and tells you in the footer. Run `:update` to install the new
|
|
81
|
+
version and restart where you were. To turn the check off, set `"check_for_updates": false` (see
|
|
82
|
+
[update checks](https://github.com/codysechelski/bible-tui/blob/main/docs/configuration.md#update-checks)).
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
bible-tui # open the default version
|
|
88
|
+
bible-tui asv # open a version by abbreviation
|
|
89
|
+
bible-tui ~/my.sqlite # open a database file directly
|
|
90
|
+
bible-tui --bibles-dir ~/Bibles # search an extra folder (repeatable)
|
|
91
|
+
bible-tui --list-versions
|
|
92
|
+
bible-tui --paths # show the config, state, and Bible folders in use
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Action | Keys |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| Move | arrows, or `h` `j` `k` `l` |
|
|
98
|
+
| Next / previous chapter | `]` / `[` |
|
|
99
|
+
| Go to a reference | `ctrl+g`, or `:John 3:16` |
|
|
100
|
+
| Search the chapter / the whole Bible | `/` / `ctrl+s` |
|
|
101
|
+
| Switch version | `t` |
|
|
102
|
+
| Split to compare versions | `ctrl+w v` |
|
|
103
|
+
| Mark / highlight a verse | `m` / `c` |
|
|
104
|
+
| Copy the verse | `yy` |
|
|
105
|
+
| All commands and keys | `ctrl+p` or `?` |
|
|
106
|
+
| Quit | `q` |
|
|
107
|
+
|
|
108
|
+
Every action also works without Vim keys. The full list is in [docs/keybindings.md](https://github.com/codysechelski/bible-tui/blob/main/docs/keybindings.md).
|
|
109
|
+
|
|
110
|
+
## Adding versions
|
|
111
|
+
|
|
112
|
+
Each version is one SQLite file. Copy a database into `~/.config/bible-tui/bibles/` and it appears in the
|
|
113
|
+
version picker. To make one from a published Bible (USFM, USX, OSIS, and others), use
|
|
114
|
+
[bible-tui-bible-converter](https://github.com/codysechelski/bible-tui-bible-converter). See
|
|
115
|
+
[docs/adding-bibles.md](https://github.com/codysechelski/bible-tui/blob/main/docs/adding-bibles.md) for the steps, and
|
|
116
|
+
[docs/bible-databases.md](https://github.com/codysechelski/bible-tui/blob/main/docs/bible-databases.md) for the schema.
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
`config.json` lives in the app home: `~/.bible-tui` if that folder exists, otherwise `~/.config/bible-tui` (or
|
|
121
|
+
`$BIBLE_TUI_HOME`).
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"default_version": "KJV",
|
|
126
|
+
"bibles_dirs": ["~/Bibles"],
|
|
127
|
+
"book_order": "bible",
|
|
128
|
+
"nerd_font": false,
|
|
129
|
+
"remember_split": false,
|
|
130
|
+
"yank_format": "{text}"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Every setting is described in [docs/configuration.md](https://github.com/codysechelski/bible-tui/blob/main/docs/configuration.md).
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
python3 -m unittest discover -s tests -t .
|
|
140
|
+
python3 -m py_compile bible_tui/*.py tests/*.py
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Releases are automatic from [Conventional Commits](https://www.conventionalcommits.org/) on `main`: `fix:`
|
|
144
|
+
releases a patch and `feat:` a minor version. See [CONTRIBUTING.md](https://github.com/codysechelski/bible-tui/blob/main/CONTRIBUTING.md) to get involved, and
|
|
145
|
+
[ROADMAP.md](https://github.com/codysechelski/bible-tui/blob/main/ROADMAP.md) for what's planned.
|
|
146
|
+
|
|
147
|
+
## Bible texts
|
|
148
|
+
|
|
149
|
+
The bundled KJV and ASV come from [eBible.org](https://ebible.org) and are in the public domain. Sources and
|
|
150
|
+
notes are in [docs/bible-databases.md](https://github.com/codysechelski/bible-tui/blob/main/docs/bible-databases.md#bundled-versions).
|
|
151
|
+
|
|
152
|
+
## Licence
|
|
153
|
+
|
|
154
|
+
bible-tui is released under the [MIT License](https://github.com/codysechelski/bible-tui/blob/main/LICENSE). The bundled Bible texts are in the public domain.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# bible-tui
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/codysechelski/bible-tui/releases"><img alt="Release" src="https://img.shields.io/github/v/release/codysechelski/bible-tui?sort=semver"></a>
|
|
5
|
+
<a href="https://github.com/codysechelski/bible-tui/actions/workflows/release.yml"><img alt="CI" src="https://github.com/codysechelski/bible-tui/actions/workflows/release.yml/badge.svg"></a>
|
|
6
|
+
<a href="https://github.com/codysechelski/bible-tui/blob/main/pyproject.toml"><img alt="Python 3.9+" src="https://img.shields.io/badge/python-3.9%2B-blue"></a>
|
|
7
|
+
<a href="https://github.com/codysechelski/bible-tui/blob/main/pyproject.toml"><img alt="Dependencies: none" src="https://img.shields.io/badge/dependencies-none-brightgreen"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
A fast, dependency-free terminal Bible reader with Vim-style keys.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
- **[Read and navigate](https://github.com/codysechelski/bible-tui/blob/main/docs/features/navigation.md)** with arrows or Vim keys,
|
|
15
|
+
[jump to `John 3:16`](https://github.com/codysechelski/bible-tui/blob/main/docs/features/go-to-reference.md) with autocomplete, and use a Vim-style
|
|
16
|
+
[`:` command line](https://github.com/codysechelski/bible-tui/blob/main/docs/features/command-line.md).
|
|
17
|
+
- **[Search](https://github.com/codysechelski/bible-tui/blob/main/docs/features/search.md)** within a chapter, or
|
|
18
|
+
[fuzzy-find across the whole Bible](https://github.com/codysechelski/bible-tui/blob/main/docs/features/fuzzy-find.md) with a live preview.
|
|
19
|
+
- **[Compare two versions](https://github.com/codysechelski/bible-tui/blob/main/docs/features/split-view.md)** side by side, with verses lined up.
|
|
20
|
+
- **[Mark](https://github.com/codysechelski/bible-tui/blob/main/docs/features/marks.md) and [highlight](https://github.com/codysechelski/bible-tui/blob/main/docs/features/highlights.md)** verses in six colors. They're
|
|
21
|
+
saved and show in every version.
|
|
22
|
+
- **[Bring any version](https://github.com/codysechelski/bible-tui/blob/main/docs/features/versions.md)**, in any language: each one is a SQLite file. The
|
|
23
|
+
public-domain KJV and ASV are included.
|
|
24
|
+
|
|
25
|
+
| | |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
|  |  |
|
|
28
|
+
| [Highlight verses](https://github.com/codysechelski/bible-tui/blob/main/docs/features/highlights.md) in six colors | [Jump back](https://github.com/codysechelski/bible-tui/blob/main/docs/features/highlights.md) to any highlight or mark |
|
|
29
|
+
|  |  |
|
|
30
|
+
| [Switch versions](https://github.com/codysechelski/bible-tui/blob/main/docs/features/versions.md) and keep your place | [Any language](https://github.com/codysechelski/bible-tui/blob/main/docs/features/versions.md#any-language) works |
|
|
31
|
+
|
|
32
|
+
<sub>The Portuguese screenshot shows the Bíblia Livre (BLIVRE), copyright © 2018 Diego Santos, Mario Sérgio, and Marco Teles, from
|
|
33
|
+
[eBible.org](https://ebible.org/porbr2018/copyright.htm), licensed under
|
|
34
|
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Not bundled with bible-tui.</sub>
|
|
35
|
+
|
|
36
|
+
**[See all features →](https://github.com/codysechelski/bible-tui/blob/main/docs/features/index.md)** Each one has a short animation.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
Requires Python 3.9+ on macOS or Linux, and nothing else.
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pipx install git+https://github.com/codysechelski/bible-tui
|
|
44
|
+
bible-tui
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or run it from a clone with `./bible-tui`.
|
|
48
|
+
|
|
49
|
+
bible-tui checks for new releases once a day and tells you in the footer. Run `:update` to install the new
|
|
50
|
+
version and restart where you were. To turn the check off, set `"check_for_updates": false` (see
|
|
51
|
+
[update checks](https://github.com/codysechelski/bible-tui/blob/main/docs/configuration.md#update-checks)).
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
bible-tui # open the default version
|
|
57
|
+
bible-tui asv # open a version by abbreviation
|
|
58
|
+
bible-tui ~/my.sqlite # open a database file directly
|
|
59
|
+
bible-tui --bibles-dir ~/Bibles # search an extra folder (repeatable)
|
|
60
|
+
bible-tui --list-versions
|
|
61
|
+
bible-tui --paths # show the config, state, and Bible folders in use
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Action | Keys |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| Move | arrows, or `h` `j` `k` `l` |
|
|
67
|
+
| Next / previous chapter | `]` / `[` |
|
|
68
|
+
| Go to a reference | `ctrl+g`, or `:John 3:16` |
|
|
69
|
+
| Search the chapter / the whole Bible | `/` / `ctrl+s` |
|
|
70
|
+
| Switch version | `t` |
|
|
71
|
+
| Split to compare versions | `ctrl+w v` |
|
|
72
|
+
| Mark / highlight a verse | `m` / `c` |
|
|
73
|
+
| Copy the verse | `yy` |
|
|
74
|
+
| All commands and keys | `ctrl+p` or `?` |
|
|
75
|
+
| Quit | `q` |
|
|
76
|
+
|
|
77
|
+
Every action also works without Vim keys. The full list is in [docs/keybindings.md](https://github.com/codysechelski/bible-tui/blob/main/docs/keybindings.md).
|
|
78
|
+
|
|
79
|
+
## Adding versions
|
|
80
|
+
|
|
81
|
+
Each version is one SQLite file. Copy a database into `~/.config/bible-tui/bibles/` and it appears in the
|
|
82
|
+
version picker. To make one from a published Bible (USFM, USX, OSIS, and others), use
|
|
83
|
+
[bible-tui-bible-converter](https://github.com/codysechelski/bible-tui-bible-converter). See
|
|
84
|
+
[docs/adding-bibles.md](https://github.com/codysechelski/bible-tui/blob/main/docs/adding-bibles.md) for the steps, and
|
|
85
|
+
[docs/bible-databases.md](https://github.com/codysechelski/bible-tui/blob/main/docs/bible-databases.md) for the schema.
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
|
|
89
|
+
`config.json` lives in the app home: `~/.bible-tui` if that folder exists, otherwise `~/.config/bible-tui` (or
|
|
90
|
+
`$BIBLE_TUI_HOME`).
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"default_version": "KJV",
|
|
95
|
+
"bibles_dirs": ["~/Bibles"],
|
|
96
|
+
"book_order": "bible",
|
|
97
|
+
"nerd_font": false,
|
|
98
|
+
"remember_split": false,
|
|
99
|
+
"yank_format": "{text}"
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Every setting is described in [docs/configuration.md](https://github.com/codysechelski/bible-tui/blob/main/docs/configuration.md).
|
|
104
|
+
|
|
105
|
+
## Development
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
python3 -m unittest discover -s tests -t .
|
|
109
|
+
python3 -m py_compile bible_tui/*.py tests/*.py
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Releases are automatic from [Conventional Commits](https://www.conventionalcommits.org/) on `main`: `fix:`
|
|
113
|
+
releases a patch and `feat:` a minor version. See [CONTRIBUTING.md](https://github.com/codysechelski/bible-tui/blob/main/CONTRIBUTING.md) to get involved, and
|
|
114
|
+
[ROADMAP.md](https://github.com/codysechelski/bible-tui/blob/main/ROADMAP.md) for what's planned.
|
|
115
|
+
|
|
116
|
+
## Bible texts
|
|
117
|
+
|
|
118
|
+
The bundled KJV and ASV come from [eBible.org](https://ebible.org) and are in the public domain. Sources and
|
|
119
|
+
notes are in [docs/bible-databases.md](https://github.com/codysechelski/bible-tui/blob/main/docs/bible-databases.md#bundled-versions).
|
|
120
|
+
|
|
121
|
+
## Licence
|
|
122
|
+
|
|
123
|
+
bible-tui is released under the [MIT License](https://github.com/codysechelski/bible-tui/blob/main/LICENSE). The bundled Bible texts are in the public domain.
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""Command line entry point: resolve paths and settings, pick a version, run the TUI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import curses
|
|
7
|
+
import locale
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from collections.abc import Mapping, Sequence
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from bible_tui import __version__
|
|
14
|
+
from bible_tui.config import ConfigError, Settings, load_settings, load_state, save_state
|
|
15
|
+
from bible_tui.highlights import HighlightStore
|
|
16
|
+
from bible_tui.marks import MarkStore
|
|
17
|
+
from bible_tui.update import (
|
|
18
|
+
RESTORE_POSITION_ENV,
|
|
19
|
+
UPDATED_FROM_ENV,
|
|
20
|
+
UpdateCheck,
|
|
21
|
+
detect_install,
|
|
22
|
+
format_position,
|
|
23
|
+
parse_position,
|
|
24
|
+
restart_command,
|
|
25
|
+
)
|
|
26
|
+
from bible_tui.paths import (
|
|
27
|
+
BIBLES_DIR_NAME,
|
|
28
|
+
BUNDLED_BIBLES_DIR,
|
|
29
|
+
CONFIG_FILE_NAME,
|
|
30
|
+
HIGHLIGHTS_FILE_NAME,
|
|
31
|
+
MARKS_FILE_NAME,
|
|
32
|
+
STATE_FILE_NAME,
|
|
33
|
+
home_candidates,
|
|
34
|
+
resolve_home,
|
|
35
|
+
)
|
|
36
|
+
from bible_tui.versions import (
|
|
37
|
+
BibleVersion,
|
|
38
|
+
Discovery,
|
|
39
|
+
VersionError,
|
|
40
|
+
discover_versions,
|
|
41
|
+
find_version,
|
|
42
|
+
inspect_database,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class CliError(Exception):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
51
|
+
parser = argparse.ArgumentParser(
|
|
52
|
+
prog="bible-tui",
|
|
53
|
+
description="Browse the Bible in your terminal.",
|
|
54
|
+
)
|
|
55
|
+
parser.add_argument(
|
|
56
|
+
"bible",
|
|
57
|
+
nargs="?",
|
|
58
|
+
metavar="VERSION",
|
|
59
|
+
help="version to open: an abbreviation such as KJV, or a path to a .sqlite file",
|
|
60
|
+
)
|
|
61
|
+
parser.add_argument(
|
|
62
|
+
"-d",
|
|
63
|
+
"--bibles-dir",
|
|
64
|
+
action="append",
|
|
65
|
+
default=[],
|
|
66
|
+
type=Path,
|
|
67
|
+
metavar="DIR",
|
|
68
|
+
help="also load Bible databases from DIR (repeatable; searched before the defaults)",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"-c",
|
|
72
|
+
"--config",
|
|
73
|
+
type=Path,
|
|
74
|
+
metavar="FILE",
|
|
75
|
+
help=f"use FILE instead of {CONFIG_FILE_NAME} in the app home",
|
|
76
|
+
)
|
|
77
|
+
parser.add_argument("-l", "--list-versions", action="store_true", help="list available versions and exit")
|
|
78
|
+
parser.add_argument("--paths", action="store_true", help="show where bible-tui looks for files and exit")
|
|
79
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
80
|
+
return parser
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def bibles_search_path(home: Path, settings: Settings, extra_dirs: Sequence[Path]) -> list[Path]:
|
|
84
|
+
"""Directories scanned for databases, highest priority first."""
|
|
85
|
+
return [
|
|
86
|
+
*(directory.expanduser() for directory in extra_dirs),
|
|
87
|
+
*settings.bibles_dirs,
|
|
88
|
+
home / BIBLES_DIR_NAME,
|
|
89
|
+
BUNDLED_BIBLES_DIR,
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def choose_version(
|
|
94
|
+
discovery: Discovery,
|
|
95
|
+
requested: str | None,
|
|
96
|
+
settings: Settings,
|
|
97
|
+
state: Mapping[str, object],
|
|
98
|
+
) -> tuple[BibleVersion, list[str]]:
|
|
99
|
+
"""Pick the version to open: the command line, then ``default_version``, then the
|
|
100
|
+
last version used, then the first available."""
|
|
101
|
+
warnings: list[str] = []
|
|
102
|
+
versions = discovery.versions
|
|
103
|
+
if requested:
|
|
104
|
+
version = find_version(versions, requested)
|
|
105
|
+
if version is None:
|
|
106
|
+
available = ", ".join(v.abbreviation for v in versions) or "none"
|
|
107
|
+
raise CliError(f"unknown version {requested!r} (available: {available})")
|
|
108
|
+
return version, warnings
|
|
109
|
+
if settings.default_version:
|
|
110
|
+
version = find_version(versions, settings.default_version)
|
|
111
|
+
if version is not None:
|
|
112
|
+
return version, warnings
|
|
113
|
+
warnings.append(f"default_version {settings.default_version!r} not found; ignoring it")
|
|
114
|
+
last = state.get("last_version")
|
|
115
|
+
if isinstance(last, str):
|
|
116
|
+
version = find_version(versions, last)
|
|
117
|
+
if version is not None:
|
|
118
|
+
return version, warnings
|
|
119
|
+
if not versions:
|
|
120
|
+
raise CliError("no Bible databases found (run `bible-tui --paths` to see where to put them)")
|
|
121
|
+
return versions[0], warnings
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def remembered_split(
|
|
125
|
+
settings: Settings,
|
|
126
|
+
state: Mapping[str, object],
|
|
127
|
+
versions: Sequence[BibleVersion],
|
|
128
|
+
) -> tuple[str, BibleVersion] | None:
|
|
129
|
+
"""The split to reopen at launch, when ``remember_split`` is on and its version still exists."""
|
|
130
|
+
from bible_tui.tui import SPLITS
|
|
131
|
+
|
|
132
|
+
if not settings.remember_split:
|
|
133
|
+
return None
|
|
134
|
+
split = state.get("split")
|
|
135
|
+
abbreviation = state.get("split_version")
|
|
136
|
+
if split not in SPLITS or not isinstance(abbreviation, str):
|
|
137
|
+
return None
|
|
138
|
+
version = find_version(versions, abbreviation)
|
|
139
|
+
return (split, version) if version is not None else None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def describe(path: Path) -> str:
|
|
143
|
+
home = str(Path.home())
|
|
144
|
+
text = str(path)
|
|
145
|
+
return "~" + text[len(home) :] if text == home or text.startswith(home + os.sep) else text
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def print_paths(home: Path, config_path: Path, search_path: Sequence[Path], env: Mapping[str, str]) -> None:
|
|
149
|
+
def status(path: Path) -> str:
|
|
150
|
+
return "" if path.exists() else " (missing)"
|
|
151
|
+
|
|
152
|
+
print("App home lookup (first existing wins):")
|
|
153
|
+
for candidate in home_candidates(env):
|
|
154
|
+
marker = "*" if candidate == home else " "
|
|
155
|
+
print(f" {marker} {describe(candidate)}{status(candidate)}")
|
|
156
|
+
print(f"\nConfig: {describe(config_path)}{status(config_path)}")
|
|
157
|
+
state_path = home / STATE_FILE_NAME
|
|
158
|
+
print(f"State: {describe(state_path)}{status(state_path)}")
|
|
159
|
+
marks_path = home / MARKS_FILE_NAME
|
|
160
|
+
print(f"Marks: {describe(marks_path)}{status(marks_path)}")
|
|
161
|
+
highlights_path = home / HIGHLIGHTS_FILE_NAME
|
|
162
|
+
print(f"Highlights: {describe(highlights_path)}{status(highlights_path)}")
|
|
163
|
+
print("\nBible folders (earlier folders win when versions share a name):")
|
|
164
|
+
for index, directory in enumerate(search_path, 1):
|
|
165
|
+
print(f" {index}. {describe(directory)}{status(directory)}")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def print_versions(discovery: Discovery, current: BibleVersion | None) -> None:
|
|
169
|
+
if not discovery.versions:
|
|
170
|
+
print("No Bible databases found.")
|
|
171
|
+
width = max((len(version.abbreviation) for version in discovery.versions), default=0)
|
|
172
|
+
for version in discovery.versions:
|
|
173
|
+
marker = "*" if version == current else " "
|
|
174
|
+
name = version.name if version.name != version.abbreviation else ""
|
|
175
|
+
print(f"{marker} {version.abbreviation.ljust(width)} {name}".rstrip())
|
|
176
|
+
print(f" {' ' * width} {describe(version.path)}")
|
|
177
|
+
if discovery.skipped:
|
|
178
|
+
print("\nSkipped:")
|
|
179
|
+
for path, reason in discovery.skipped:
|
|
180
|
+
print(f" {describe(path)}: {reason}")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def run_tui(
|
|
184
|
+
version: BibleVersion,
|
|
185
|
+
versions: Sequence[BibleVersion],
|
|
186
|
+
settings: Settings,
|
|
187
|
+
home: Path,
|
|
188
|
+
state: dict[str, object],
|
|
189
|
+
marks: MarkStore,
|
|
190
|
+
highlights: HighlightStore,
|
|
191
|
+
warnings: Sequence[str] = (),
|
|
192
|
+
notice: str = "",
|
|
193
|
+
position: tuple[int, int, int] | None = None,
|
|
194
|
+
restart_args: Sequence[str] = (),
|
|
195
|
+
) -> None:
|
|
196
|
+
from bible_tui.store import BibleStore
|
|
197
|
+
from bible_tui.tui import MESSAGE_UPDATE, BibleTui
|
|
198
|
+
|
|
199
|
+
def remember(chosen: BibleVersion) -> None:
|
|
200
|
+
state["last_version"] = chosen.abbreviation
|
|
201
|
+
save_state(home, state)
|
|
202
|
+
|
|
203
|
+
def remember_split(split: str | None, split_version: BibleVersion | None) -> None:
|
|
204
|
+
if not settings.remember_split:
|
|
205
|
+
return
|
|
206
|
+
if split is None or split_version is None:
|
|
207
|
+
state.pop("split", None)
|
|
208
|
+
state.pop("split_version", None)
|
|
209
|
+
else:
|
|
210
|
+
state["split"] = split
|
|
211
|
+
state["split_version"] = split_version.abbreviation
|
|
212
|
+
save_state(home, state)
|
|
213
|
+
|
|
214
|
+
update_check = None
|
|
215
|
+
if settings.check_for_updates:
|
|
216
|
+
update_check = UpdateCheck(__version__, state, save=lambda: save_state(home, state))
|
|
217
|
+
update_check.start()
|
|
218
|
+
restart = "" # The position to reopen at, once :update asks for a restart.
|
|
219
|
+
|
|
220
|
+
def run(stdscr: curses.window) -> None:
|
|
221
|
+
nonlocal restart
|
|
222
|
+
app = BibleTui(
|
|
223
|
+
stdscr,
|
|
224
|
+
BibleStore(version.path),
|
|
225
|
+
version,
|
|
226
|
+
versions,
|
|
227
|
+
alphabetical=settings.book_order == "alphabetical",
|
|
228
|
+
on_version_change=remember,
|
|
229
|
+
on_split_change=remember_split,
|
|
230
|
+
marks=marks,
|
|
231
|
+
highlights=highlights,
|
|
232
|
+
nerd_font=settings.nerd_font,
|
|
233
|
+
yank_format=settings.yank_format,
|
|
234
|
+
update_check=update_check,
|
|
235
|
+
install=detect_install(),
|
|
236
|
+
)
|
|
237
|
+
split = remembered_split(settings, state, versions)
|
|
238
|
+
if split is not None:
|
|
239
|
+
app.open_split(*split, restoring=True)
|
|
240
|
+
if position is not None:
|
|
241
|
+
app.jump_to_key(position)
|
|
242
|
+
if warnings:
|
|
243
|
+
app.show_error(f"warning: {warnings[0]}")
|
|
244
|
+
elif notice:
|
|
245
|
+
app.set_message(notice, MESSAGE_UPDATE)
|
|
246
|
+
try:
|
|
247
|
+
app.run()
|
|
248
|
+
finally:
|
|
249
|
+
app.close()
|
|
250
|
+
if app.restart_requested:
|
|
251
|
+
restart = format_position(app.restart_position) or "-"
|
|
252
|
+
|
|
253
|
+
curses.wrapper(run)
|
|
254
|
+
if restart:
|
|
255
|
+
# Replace this process with the updated code. The new one says what changed and reopens here.
|
|
256
|
+
command = restart_command(restart_args)
|
|
257
|
+
sys.stdout.flush()
|
|
258
|
+
os.execve(command[0], command, {**os.environ, UPDATED_FROM_ENV: __version__, RESTORE_POSITION_ENV: restart})
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def update_notice(env: Mapping[str, str]) -> str:
|
|
262
|
+
"""After ``:update`` restarts the app, say whether the version changed."""
|
|
263
|
+
previous = env.get(UPDATED_FROM_ENV)
|
|
264
|
+
if not previous:
|
|
265
|
+
return ""
|
|
266
|
+
if previous == __version__:
|
|
267
|
+
return f"bible-tui {__version__} is up to date"
|
|
268
|
+
return f"updated bible-tui {previous} to {__version__}"
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def main(argv: Sequence[str] | None = None, env: Mapping[str, str] | None = None) -> int:
|
|
272
|
+
env = os.environ if env is None else env
|
|
273
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
274
|
+
args = build_parser().parse_args(argv)
|
|
275
|
+
try:
|
|
276
|
+
home = resolve_home(env)
|
|
277
|
+
if args.config is not None and not args.config.exists():
|
|
278
|
+
raise CliError(f"config file not found: {args.config}")
|
|
279
|
+
config_path = args.config if args.config is not None else home / CONFIG_FILE_NAME
|
|
280
|
+
settings = load_settings(config_path, env)
|
|
281
|
+
for warning in settings.warnings:
|
|
282
|
+
print(f"bible-tui: warning: {warning}", file=sys.stderr)
|
|
283
|
+
search_path = bibles_search_path(home, settings, args.bibles_dir)
|
|
284
|
+
|
|
285
|
+
if args.paths:
|
|
286
|
+
print_paths(home, config_path, search_path, env)
|
|
287
|
+
return 0
|
|
288
|
+
|
|
289
|
+
discovery = discover_versions(search_path)
|
|
290
|
+
if args.bible and Path(args.bible).expanduser().is_file():
|
|
291
|
+
try:
|
|
292
|
+
opened = inspect_database(Path(args.bible).expanduser())
|
|
293
|
+
except VersionError as error:
|
|
294
|
+
raise CliError(f"{args.bible}: not a usable Bible database ({error})") from None
|
|
295
|
+
others = tuple(v for v in discovery.versions if v.abbreviation.casefold() != opened.abbreviation.casefold())
|
|
296
|
+
discovery = Discovery((opened, *others), discovery.skipped)
|
|
297
|
+
args.bible = opened.abbreviation
|
|
298
|
+
|
|
299
|
+
state = load_state(home)
|
|
300
|
+
if args.list_versions:
|
|
301
|
+
current = None
|
|
302
|
+
try:
|
|
303
|
+
current, _ = choose_version(discovery, args.bible, settings, state)
|
|
304
|
+
except CliError:
|
|
305
|
+
pass
|
|
306
|
+
print_versions(discovery, current)
|
|
307
|
+
return 0
|
|
308
|
+
|
|
309
|
+
version, choice_warnings = choose_version(discovery, args.bible, settings, state)
|
|
310
|
+
for warning in choice_warnings:
|
|
311
|
+
print(f"bible-tui: warning: {warning}", file=sys.stderr)
|
|
312
|
+
marks = MarkStore.load(home)
|
|
313
|
+
if marks.load_error:
|
|
314
|
+
choice_warnings.append(f"marks are read-only until this is fixed: {marks.load_error}")
|
|
315
|
+
print(f"bible-tui: warning: {choice_warnings[-1]}", file=sys.stderr)
|
|
316
|
+
highlights = HighlightStore.load(home)
|
|
317
|
+
if highlights.load_error:
|
|
318
|
+
choice_warnings.append(f"highlights are read-only until this is fixed: {highlights.load_error}")
|
|
319
|
+
print(f"bible-tui: warning: {choice_warnings[-1]}", file=sys.stderr)
|
|
320
|
+
warnings = [*settings.warnings, *choice_warnings]
|
|
321
|
+
except (CliError, ConfigError) as error:
|
|
322
|
+
print(f"bible-tui: {error}", file=sys.stderr)
|
|
323
|
+
return 1
|
|
324
|
+
|
|
325
|
+
locale.setlocale(locale.LC_ALL, "")
|
|
326
|
+
run_tui(
|
|
327
|
+
version,
|
|
328
|
+
discovery.versions,
|
|
329
|
+
settings,
|
|
330
|
+
home,
|
|
331
|
+
state,
|
|
332
|
+
marks,
|
|
333
|
+
highlights,
|
|
334
|
+
warnings,
|
|
335
|
+
notice=update_notice(env),
|
|
336
|
+
position=parse_position(env.get(RESTORE_POSITION_ENV)),
|
|
337
|
+
restart_args=argv,
|
|
338
|
+
)
|
|
339
|
+
return 0
|