pomo は、ターミナル上で動くシンプルなTUIポモドーロタイマーである。
画像のような「横長のセグメント型プログレスバー」と「デジタル残り時間表示」を目指す。
POMODORO
████ ████ ████ ████ ████ ████ ████ ░░░░ ░░░░ ░░░░
12:34
p: pause/resume r: restart q: quit
ポモドーロテクニック用に、作業25分、休憩5分のような短いタイマーを素早く起動する。
pomo 25
pomo 5タイマー終了時には macOS の afplay で音を鳴らす。
あわせて osascript で通知センターにも通知を出す。
- 分数を指定するだけで開始。
- TUIで残り時間を表示。
- セグメント型プログレスバーを表示。
- 同梱したフリー音源を
afplayで再生する終了音。 osascriptによるmacOS通知。--cycleで作業/休憩を繰り返すポモドーロサイクル。--long-breakと--roundsで長休憩を挟める。- 色対応ターミナルでは、進捗バーを緑、黄、赤、暗色で表示。
pで一時停止/再開。rでリスタート。qで終了。- Python標準ライブラリ中心で軽量に実装。
- macOS
- Python 3.10以上
afplayosascript- curses対応ターミナル
macOSには通常 afplay と osascript が最初から入っている。
確認:
which afplay
which osascript開発中はリポジトリをcloneして直接実行する。
git clone <repo-url>
cd pomo
python3 main.py 25パッケージ化後は以下を想定する。
pipx install .
pomo 25テスト実行には pytest を使う。
python3 -m pip install pytest
python3 -m pytestpomo 25pomo 5作業25分、休憩5分を繰り返す。
pomo --cycle 25 5作業と休憩は、各セッションが終わると自動で次へ進む。
q または Ctrl-C でサイクル全体を終了する。
4セットごとに15分休憩する。
pomo --work 25 --break 5 --long-break 15 --rounds 4pomoその場合は分数入力を求める。
Minutes: 25
| キー | 動作 |
|---|---|
p |
一時停止/再開 |
r |
現在の分数でリスタート |
q |
終了 |
Ctrl-C |
強制終了 |
デフォルトでは以下を鳴らす。
pomo/assets/alarm-or-siren.mp3
音源は Wikimedia Commons の public domain 音源を同梱している。詳細は THIRD_PARTY_NOTICES.md を参照。
内部的には以下と同等のことを行う。
afplay pomo/assets/alarm-or-siren.mp3さらにmacOS通知センターへ以下と同等の通知を出す。
osascript -e 'display notification "Timer finished" with title "pomo"'--sound オプションで変更できる。
pomo 25 --sound /System/Library/Sounds/Ping.aiffpomo/
__init__.py
__main__.py
app.py
timer.py
tui.py
sound.py
config.py
tests/
test_timer.py
test_sound.py
README.md
PLAN.md
ARCHITECTURE.md
pyproject.toml
タイマーの時間計算には time.monotonic() を使う。
単純に sleep(1) を積み上げると、描画遅延や処理遅延でズレが出る。そこで、開始時に終了予定時刻を決め、毎フレーム現在時刻との差分から残り時間を計算する。
remaining = max(0, deadline - time.monotonic())これにより、TUIの描画が少し遅れてもタイマー全体の精度が保たれやすい。
分数は正の整数のみ。
有効:
pomo 25
pomo 5
pomo 1無効:
pomo 0
pomo -1
pomo abc- 残り時間は
MM:SS。 - プログレスバーは残り時間に応じて短くなる。
- タイマー終了時は
DONEを表示する。
残り時間が0になったら終了音を鳴らす。
その後、以下のどちらかの挙動にする。
DONE表示のままキー入力待ち。- 音を鳴らしたあと自動終了。
MVPでは「DONE 表示のままキー入力待ち」を推奨する。理由は、終了に気づかなかった場合でも画面上で完了状態が残るため。
TUIアプリは例外で落ちるとターミナル表示が崩れることがある。そのため、curses.wrapper() を使う。
import curses
curses.wrapper(main)ノンブロッキング入力にする。
stdscr.nodelay(True)描画更新は0.2秒程度でよい。
TICK_INTERVAL_SEC = 0.2表示上は滑らかで、CPU負荷も低い。
作業25分、休憩5分を繰り返す。
pomo --cycle 25 54セットごとに15分休憩する。
pomo --work 25 --break 5 --long-break 15 --rounds 4osascript を使って通知センターに出す。
osascript -e 'display notification "Timer finished" with title "pomo"'work_minutes = 25
break_minutes = 5
sound = "/System/Library/Sounds/Glass.aiff"
segments = 24MIT