topos-bible-cli 0.3.0

Find Bible references in files, like ripgrep
topos-bible-cli-0.3.0 is not a library.

τόπος CLI

Examples

Results are truncated. These examples use -m table; on a terminal the default output groups results by file, and when piped it prints path:line:column: reference.

Install

cargo install topos-bible-cli

This installs the topos command. Add --features pdf to also search PDFs (it builds MuPDF, which takes a few minutes). From a clone, use cargo install --path crates/topos-cli.

Default Search

Search for all Bible verses in current directory recursively (respecting .gitignore)

Command

topos -m table

Output

| File                 | Line | Col | Verse              |
| ----                 | ---- | --- | -----              |
| ./Church 07-27-25.md | 24   | 12  | Colossians 2:1-3   |
| ./Church 07-27-25.md | 39   | 12  | Ephesians 6:18     |
| ./Church 07-20-25.md | 6    | 6   | Colossians 3:12-15 |
| ./Church 07-20-25.md | 27   | 12  | Colossians 3:12    |
| ./Church 07-20-25.md | 34   | 12  | Deuteronomy 7:6-8  |

Search Specific File

Command

topos "Church 07-27-25.md" -m table

Output

| File               | Line | Col | Verse            |
| ----               | ---- | --- | -----            |
| Church 07-27-25.md | 24   | 12  | Colossians 2:1-3 |
| Church 07-27-25.md | 39   | 12  | Ephesians 6:18   |
| Church 07-27-25.md | 46   | 12  | Colossians 4:12  |
| Church 07-27-25.md | 49   | 12  | Colossians 2:1   |
| Church 07-27-25.md | 56   | 12  | Romans 16:1-2    |
| Church 07-27-25.md | 61   | 12  | 3 John 5-8       |
..

Filter by Testament

Command

topos --nt -m table   # same as -t new

Output

| File                 | Line | Col | Verse            |
| ----                 | ---- | --- | -----            |
| ./Church 07-27-25.md | 24   | 12  | Colossians 2:1-3 |
| ./Church 07-27-25.md | 39   | 12  | Ephesians 6:18   |
| ./Church 07-27-25.md | 46   | 12  | Colossians 4:12  |
| ./Church 07-27-25.md | 49   | 12  | Colossians 2:1   |

Filter by Genre

Command

topos -g wisdom -m table

Output

| File                 | Line | Col | Verse             |
| ----                 | ---- | --- | -----             |
| ./Church 07-20-25.md | 143  | 12  | Proverbs 16:32    |
| ./Church 07-13-25.md | 229  | 12  | Proverbs 4:24     |
| ./Church 03-02-25.md | 281  | 12  | Proverbs 20:27    |
| ./Church 03-02-25.md | 329  | 12  | Proverbs 28:9     |
| ./Church 06-15-25.md | 68   | 12  | Ecclesiastes 9:10 |

Filter by Book

Command

topos -b Romans -m table

Output

| File                 | Line | Col | Verse         |
| ----                 | ---- | --- | -----         |
| ./Church 07-27-25.md | 56   | 12  | Romans 16:1-2 |
| ./Church 07-20-25.md | 215  | 17  | Romans 15     |
| ./Church 07-20-25.md | 217  | 12  | Romans 15:11  |
| ./Church 07-20-25.md | 271  | 12  | Romans 12:1-2 |
| ./Church 07-13-25.md | 268  | 12  | Romans 12:9   |
| ./Church 07-06-25.md | 98   | 12  | Romans 10:9   |
| ./Church 06-29-25.md | 80   | 12  | Romans 11:29  |
| ./Church 06-22-25.md | 198  | 12  | Romans 12:2   |
| ./Church 02-23-25.md | 224  | 8   | Romans 8      |

Filter by Passage

Command

topos -o "1 Peter 1:1-5, 4:11,14-16" -m table

Output

| File                 | Line | Col | Verse         |
| ----                 | ---- | --- | -----         |
| ./Church 03-02-25.md | 118  | 12  | 1 Peter 1:2   |
| ./Church 06-01-25.md | 24   | 101 | 1 Peter 4     |
| ./Church 05-11-25.md | 334  | 12  | 1 Peter 4:15  |
| ./Church 02-02-25.md | 39   | 12  | 1 Peter 4:11  |
| ./Church 03-09-25.md | 241  | 12  | 1 Peter 1:3-4 |

-o/--overlaps keeps references that share any verse with the passage (like 1 Peter 4 above). -i/--inside only keeps references entirely inside it, so 1 Peter 4 would be dropped.

Exclude Testament/Genre/Book/Passage

Use just like above, but prefix the full option with exclude (or use --outside for passages)

topos --exclude-testament new -m table
| File                 | Line | Col | Verse             |
| ----                 | ---- | --- | -----             |
| ./Church 07-20-25.md | 34   | 12  | Deuteronomy 7:6-8 |
| ./Church 07-20-25.md | 108  | 93  | Numbers 12        |
| ./Church 07-20-25.md | 131  | 12  | Isaiah 53:7       |
| ./Church 07-20-25.md | 143  | 12  | Proverbs 16:32    |
| ./Church 07-20-25.md | 204  | 7   | Psalms 117        |
| ./Church 07-20-25.md | 208  | 12  | Psalms 117:1-2    |
| ./Church 07-20-25.md | 234  | 12  | Habakkuk 2:14     |
| ./Church 07-20-25.md | 255  | 12  | Psalms 117:2      |

Rules

  • Including a testament limits the search to it (--nt -g Gospels is the four Gospels)
  • Included genres and books add up (-g Pentateuch -b Revelation is six books)
  • Filters that can't match anything print a warning: genres or books outside the included testaments (--ot -g "Pauline Epistles"), -i/-o passages only in books that aren't searched (-b Genesis -i "Romans 8"), or only within --outside passages (-i "John 3:16" --outside "John 3")
  • Exclusions always win, so a book can be excluded from an included genre
  • -m count prints matches per file; --total-count prints one total across all files
  • --inside and --overlaps passages are joined with a logical OR, then --outside removes matches
  • Unknown books or genres are errors

Config

Default options go in ~/.config/topos/config.toml (or $XDG_CONFIG_HOME/topos/config.toml). The first run writes a commented config.toml and a queries.toml with a sample query there if they don't exist (it never overwrites them, and doesn't touch the folder with --no-config). Each key is a long option name; the command line overrides them. Use --config PATH to read another file instead, or --no-config to read none.

mode = "grouped"
color = "always"
cache = true
exclude-book = ["Song of Solomon"]
data = "~/bible/custom.json"   # custom books, genres, or chapter and verse counts
merge-data = ["~/bible/more-names.json"]
remove-data = "~/bible/fewer-names.json"

Custom data

--data FILE replaces the built-in books, genres, or chapter and verse counts (whichever parts the file has). To change only a few things, keep the defaults and use either of these, or both. They can be repeated and set in config.toml:

  • --merge-data FILE adds names and values. A book is found by its id, or else by any of its names. A book that isn't found is added, so it needs an id. Renaming a book keeps its old name as an abbreviation, and chapter counts replace the book's.
  • --remove-data FILE removes values. A book or genre listed with nothing else is removed entirely, otherwise just the values listed are removed.

The files use the --data format with every field optional. Values already there aren't added twice, and every name must still mean exactly one book ("gen" for John is an error).

// more-names.json
{
  "books": [
    { "book": "John", "abbreviations": ["jhn"] },
    { "id": 67, "book": "Tobit", "abbreviation": "Tob", "abbreviations": ["tb"] }
  ],
  "genres": [{ "title": "Apocrypha", "books": ["Tobit"] }],
  "chapter_verses": { "Tobit": [22, 14, 17, 21, 22, 18, 16, 21, 6, 13, 18, 22, 18, 15] }
}
// fewer-names.json: "song" no longer matches; Jude isn't a book
{ "books": [{ "book": "Song of Solomon", "abbreviations": ["song"] }, { "book": "Jude" }] }

The order is --data (or the defaults), then each --merge-data, then each --remove-data.

Named queries

Name searches you repeat in ~/.config/topos/queries.toml (next to config.toml), and use them with -q NAME:

paul = '--nt -g "Pauline Epistles"'
sermons = 'Sermons -o "John 1" --exclude-book Philemon'
gospels = ["-g", "Gospels"]   # or the arguments already split
topos -q paul ~/notes          # topos --nt -g "Pauline Epistles" ~/notes
topos -q sermons -m count      # options after -q add to (or override) the query's
topos --list-queries

-q is replaced by the query's options where it appears, so queries can use other queries, and config.toml can set a default one (query = "paul"). The file is read even with --no-config. The Obsidian plugin's saved searches use the same syntax.

Cache

The default config.toml turns the cache on (cache = true); --no-cache skips it for one run, and --cache turns it on without a config. It keeps each file's references between runs, until the file changes (its size or modification time). Results are stored before filtering, so one run serves every later search of the same files, whatever its filters. On a vault with 2,000 EPUBs and notes:

Time
First run 5.7 s
Again, with the same or any other filters (--nt, -b John, -o "Romans 8") 0.1–0.16 s
  • Only --data, --context-book, --context-heading, and the version get a separate cache
  • Each file has a small binary entry in ~/.cache/topos (or $XDG_CACHE_HOME/topos) that records which books it mentions, so files that can't match the filters are skipped
  • Entries for deleted files are removed now and then, as are caches unused for a month; topos --clear-cache deletes everything

Completing references

--complete TEXT prints the completions for a partly typed reference, one per line, for scripts and editors; --list-books (the same as --complete "") prints every book:

topos --complete "John 3:"        # John 3:1 ... John 3:36
topos --complete "jn 3:16-"       # John 3:16-17, John 3:16-18, ...
topos --list-books -f abbreviation --nt
topos --complete "jn 3:" -f osis  # John.3.1 ...
topos --complete "Rom 8" -m json  # {"text":"Romans 8","label":"Romans 8","kind":"chapter"}

-f sets the book style, the book and passage filters narrow the list, and -m json prints each completion's text, label, and kind (book, chapter, or verse).

Shell completions

Tab completes options and their values: modes and formats, book and genre names (-b jn offers Jonah and John; -b "1 Co gives "1 Corinthians"), testaments, your named queries, references for -i/-o/--outside (books, then chapters, verses, and range ends, like the editor plugins), and paths. topos computes them itself when Tab is pressed, so they always match the installed version and your queries.toml.

# bash: load on demand
COMPLETE=bash topos > ~/.local/share/bash-completion/completions/topos
# or in ~/.bashrc
source <(COMPLETE=bash topos)

# zsh (~/.zshrc), fish (~/.config/fish/config.fish), elvish, powershell
source <(COMPLETE=zsh topos)
COMPLETE=fish topos | source

Quote references (-o "John 3:16"): bash splits words at :.

File types

  • .pdf (with the pdf feature) reports the page, and .epub reports a CFI
  • .srt, .vtt, and .sbv also report the cue's start time
  • Everything else is searched as text; binary files and files ignored by .gitignore are skipped

Usage

Find Bible references in files, directories, text, or stdin.

- Including a testament limits the search to it: `--nt -g Gospels` is the four Gospels
- Included genres and books add up: `-g Pentateuch -b Revelation` is six books
- Exclusions always win, so a book can be excluded from an included genre
- `--inside` and `--overlaps` passages are joined with a logical OR, then `--outside` removes matches

Usage: topos [OPTIONS] [PATHS]...

Arguments:
  [PATHS]...
          Files or directories to search (respecting .gitignore); defaults to stdin when piped, otherwise the current directory

Options:
      --text <TEXT>
          Search this text instead of files

  -t, --testament <TESTAMENTS>
          Include books from a testament (old/new)

      --nt
          Include the New Testament (same as `-t new`)

      --ot
          Include the Old Testament (same as `-t old`)

      --exclude-testament <EXCLUDE_TESTAMENTS>
          Exclude books from a testament

  -g, --genre <GENRES>
          Include books of a genre (e.g. epistles, gospels)

      --exclude-genre <EXCLUDE_GENRES>
          Exclude books of a genre

  -b, --book <BOOKS>
          Include a book (e.g. John)

      --exclude-book <EXCLUDE_BOOKS>
          Exclude a book

  -i, --inside <INSIDE>
          Only keep references entirely inside this passage (e.g. "John 1" keeps John 1:2-3)

  -o, --overlaps <OVERLAPS>
          Only keep references that share any verse with this passage (e.g. "John 1" keeps John 1:51-2:1)

      --outside <OUTSIDE>
          Drop references that share any verse with this passage

      --context-book <CONTEXT_BOOK>
          Treat the input as being about this book, so references like 3:16 match

      --context-heading <CONTEXT_HEADING>
          Lines matching this pattern set the book for references after them, like '^#+ {book}$'

      --data <DATA>
          A JSON file with custom books, genres, or chapter and verse counts

      --merge-data <PATH>
          A JSON file (like --data, every field optional) whose names and values are added to the data, keeping the defaults: new abbreviations, books, genres, or chapter counts

      --remove-data <PATH>
          A JSON file (like --data, every field optional) whose values are removed from the data: a book or genre listed alone is removed entirely, otherwise just the values listed

  -q, --query <NAME>
          Use a named query from ~/.config/topos/queries.toml (its options go where this is)

      --list-queries
          List the named queries and exit

      --config <PATH>
          Read default options from this file instead of ~/.config/topos/config.toml

      --no-config
          Do not read default options from a config file

      --total-count
          Print only the total number of matches across all files (same as `-m total-count`)

  -m, --mode <MODE>
          How to print results

          Possible values:
          - auto:        Grouped by file on a terminal, otherwise `path:line:column: reference`
          - grouped:     Grouped by file, with optional context lines
          - quickfix:    `path:line:column: reference` (for Vim's quickfix list)
          - table:       A Markdown table
          - json:        One JSON object per match
          - count:       Matches per file
          - total-count: Matches across all files
          
          [default: auto]

  -f, --format <FORMAT>
          How to write each reference

          Possible values:
          - name:         `Genesis 1:1`
          - abbreviation: `Gn 1:1`
          - osis:         `Gen.1.1`
          
          [default: name]

  -A, --after-context <AFTER_CONTEXT>
          Lines of context to show after each match
          
          [default: 0]

  -B, --before-context <BEFORE_CONTEXT>
          Lines of context to show before each match
          
          [default: 0]

  -C, --context <CONTEXT>
          Lines of context to show before and after each match

      --color <COLOR>
          When to use colors
          
          [default: auto]
          [possible values: auto, always, never]

      --sort
          Print results sorted by path (waits for the whole search)

      --cache
          Reuse results for files that have not changed (stored unfiltered, so any filters can use them)

      --no-cache
          Don't use the cache, even if the config turns it on

      --complete [<TEXT>]
          Print the completions for a partly typed reference, one per line, and exit: books for "" (or nothing), then chapters, verses, and range ends ("John 3:" gives John 3:1, ...). Uses -f for the book style and the book filters; -m json prints objects

      --list-books
          Print every book, one per line, and exit (the same as `--complete ""`)

      --clear-cache
          Delete the cache (in ~/.cache/topos) and exit

      --ext <EXT>
          Only search files with these extensions when walking directories (e.g. md,txt); files named on the command line are always searched

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version