Skip to main content

A mouse-aware terminal todo app with natural-language dates

Project description

soonish

A small mouse-aware terminal todo list, written in plain Python with no framework — raw-mode input decoding, ANSI rendering, and persistence are all implemented in-tree. The name is how it treats time: entry dates display with just enough precision to answer "what's happening soonish?".

You type entries into a prompt at the bottom of the screen; they appear above it, split into undated todos and date-scheduled tasks. Clicking an entry completes it.

Installation and usage

pip install soonish          # or: pip install soonish[watch]
soonish [--debug-events | --no-debug-events] [--discard-unknown-fields]

python -m soonish works too. From a source checkout, pip install -e . gives the same entry points.

Requires Python 3.10+ (uses match statements); dateparser is installed as a dependency, and the [watch] extra adds inotify for live reload when another instance or editor changes the data file. Must be run in a real terminal; mouse support needs a terminal that speaks SGR mouse reporting (any modern one does). Requires a terminal of at least 5 columns × 3 rows; below that the app displays a frowning face (☹) until the window is resized.

Options:

  • --debug-events / --no-debug-events — show / silently ignore unhandled input events on the status line (useful for development); when neither is given, the debug_events setting (F4; default on) decides
  • --discard-unknown-fields — load a data file written by a newer version of the software, dropping the fields this version does not understand (by default such a file is refused, so no data is silently lost)

Adding entries

Type at the prompt and press Enter:

Input Effect
todo: buy milk Add an undated todo (if the line starts with todo:, the rest is the text)
tomorrow 9am: standup Add a task due at that time (the date is everything before the last ": " in the line, falling back to the last : if there is no colon-space — so times like 17:30: dentist work)
next friday: review next <weekday>/last <weekday> resolve to the nearest such day strictly in the future/past (never today, at most a week away); next week/next month mean the same day next week/month. last ... and other past dates are allowed — the task just shows as already due
todo: [high] pay rent Tags: a todo starting with [high] sorts above untagged todos, [low] below (tags are case-insensitive, shown as typed; only leading [...] words count)
/query Live search: filters the current view as you type. A date or range (/friday, /june, /next week, /2026-06-12) filters tasks by due time — the range is as wide as what you typed (a day, a week, a month, a year); plain text filters both panes case-insensitively; /friday: dentist applies both; /todo: milk searches only todos. Matching tasks show full-precision dates. ESC cancels; Enter ends the search (and records it in input history)
done: milk (ACTIVE view only; prefix case-insensitive) live search like /, but when Enter is hit with exactly one entry matching, that entry is marked complete — the keyboard alternative to a left click

Dates are understood in English plus your locale's language (from $LANGUAGE/$LANG — under LANG=fr_FR.UTF-8, demain: x works). Letting dateparser guess the language of every input instead is far too slow for the live search, which parses the query on each keystroke; the dateparser_languages setting (F4) adds languages your locale doesn't mention, or selects them all (leave it empty), at that price.

Keys and mouse

  • F1 / F2 / F3 — switch between ACTIVE, COMPLETED, and CALENDAR views; clicking a mode label in the heading does the same. The current view's label is highlighted bright+bold (or [bracketed] on colourless terminals)
  • F4 — the settings view: every tunable (date language list, layout thresholds, ASCII markers, linger time, colour off, …) as a row. Click a tickbox (or Enter on the Up/Down-selected row) to toggle a boolean; click any other row to edit its value on the prompt, Enter to apply. Changes apply immediately and persist to a settings.tsv next to the data file. F4 or ESC leaves
  • CALENDAR view — as many month grids as fit the window; dates colour-coded (red = overdue tasks, green = upcoming, grey = nothing scheduled, plain = all done; today bold); PgUp/PgDn page months; clicking a date jumps to ACTIVE/COMPLETED with a / search for that date applied
  • Left click an entry — mark complete (it lingers ~15 s, then leaves the ACTIVE view); the keyboard alternative is a done: search (see above)
  • Right click an entry — un-complete it (in the COMPLETED view it lingers ~15 s before leaving, for the same mid-glance reasons)
  • Middle click an entry — edit it: the prompt is pre-filled with its date: text form, the entry mirrors your typing live (in bold), and Enter replaces it (creation time is kept). ESC or an empty Enter cancels. Ending a / search with Enter when exactly one entry matches also opens it for editing. Committing an edit of a completed entry un-completes it — the keyboard alternative to a right click (find it with /, Enter to edit, Enter to commit)
  • Up/Down arrows or scroll wheel — input history
  • Shift+Left/Right — horizontally scroll truncated entry text (half a screen per press; markers and dates stay put; resets on mode switch, Enter or ESC)
  • PgUp/PgDn — scroll the todo/task panes by half a pane per press; click the whitespace after an entry's text to make that pane active (rendered bold) and scroll it alone — click again or press ESC to deactivate
  • Enter on an empty prompt — clears the status line
  • Usual line-editing keys at the prompt: Home/End, Ctrl+Left/Right (by word), Insert (overwrite mode), ESC (clear line)
  • Ctrl-C — quit

On terminals that render unicode (probed at startup) and are at least 80×25, the whole UI is framed with box-drawing borders — mode labels and clock embedded in the top border, indicators where a pane has more entries than fit. Smaller or glyph-less terminals keep the plain layout. At 160 columns or wider, todos and tasks display side by side (todos left, 50/50 split) instead of stacked.

On colour-capable terminals (set NO_COLOR to opt out), the ACTIVE view colours tasks green when due within 30 minutes and red when overdue; just-completed entries linger in green; a leading [high] tag is shown in high intensity.

Storage

Entries are kept in a single TSV file at $XDG_DATA_HOME/soonish/soonish.tsv (default ~/.local/share/soonish/soonish.tsv). The app was previously named todo; an existing ~/.local/share/todo/todo.tsv is adopted (moved over) automatically on first start, unless a soonish data file already exists. Writes are atomic (temp file + rename), fsync'd to protect against power loss, and preserve the file's permissions. The file is human-readable: a name:type header row describing the columns, then one line per entry:

created:t	due:t	complete:t	uid:s	modified:t	text:s
<created>\t<due|None>\t<complete|None>\t<uid>\t<modified>\t<text>

The header makes the format forward-compatible: old headerless files are read and silently upgraded on the next change (a .bak copy is kept), and fields a future version adds will default sensibly when missing.

Two running instances (e.g. two users with write access to the same file) can share a task list: writes take a lock and merge concurrent changes by entry uid (the newer change wins), and a running instance notices external changes to the file via inotify and folds them in within half a second. See doc/database.md for the details.

Code layout

The package lives in src/soonish/:

Module Role
main.py cli() entry point, event loop, command dispatch
events.py Raw terminal input → typed events; TextBuffer line editor and its History
rendering.py View: screen layout, modes, status line
calendar_view.py The CALENDAR mode's month grids and paging
database.py Entry records and the TSV-backed Database
search.py Date parsing (parse_when) and live / search queries
tags.py [tag] semantics ([high]/[low] priority bands)
caps.py Terminal capability detection (colour, cursor control, glyph width)
ansi.py ANSI escape-sequence constants/builders
config.py The defaults for every user-tunable value
settings.py Settings schema and settings.tsv persistence (the F4 view's backend)

Per-module documentation lives in doc/. Tests (tests/, pytest) run against the source tree directly: python3 -m pytest -q.

License

GPLv3 (see LICENSE).

Status

Working but in progress; pending small features are marked with todo: comments in the source.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

soonish-0.1.1.tar.gz (108.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

soonish-0.1.1-py3-none-any.whl (60.4 kB view details)

Uploaded Python 3

File details

Details for the file soonish-0.1.1.tar.gz.

File metadata

  • Download URL: soonish-0.1.1.tar.gz
  • Upload date:
  • Size: 108.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for soonish-0.1.1.tar.gz
Algorithm Hash digest
SHA256 288d830543e80bf883c47741f3b6293655373f9c6bb97e4c0eab89cc3512ab28
MD5 d046f310fe87ca7e5ff735c723e1b8c8
BLAKE2b-256 09b8a2a8b177aff135a8b848ca7ef918811f47d0441d7d8ce128441908d99eaa

See more details on using hashes here.

File details

Details for the file soonish-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: soonish-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 60.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for soonish-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9c34f4c4ef166cac30499ec246e0b2bfd7212705f64c728b464fecce3d2b08e3
MD5 2061dfb6d53bfadbb3540c52e5165b17
BLAKE2b-256 a5a5bdf8dbc1bac9281d5424106bdfd9e7555956311f5b5626756a1d615d3e56

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page