#!/usr/bin/env bash # # gromo - To count your daily Gromodoros :thumbsup. A Gromo is a short unit of # time, usually 20 minutes, in which you are committed to do your work # and only your work. It's basically the Pomodoro technique, but more # opinionated. In particular, it's designed to implement the advice an # optician once gave me, the "20/20/20" rule, which is: for each 20 # minutes looking at the screen, look away at least 20 meters away for # at least 20 seconds. Also, not every type of work benefits from the # interruptions 5-minute rests provoke. So, if the mainstream is not # enough for you, enter the all-flexible, eye-careful, non-interrupting # Gromodoros. # # Dependencies: curl and mpv for the 'ding' sound; slock to force you to rest :) ################################################################################ shopt -s nullglob DEFAULT_DING=https://gramos.me/sounds/ding.opus DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/gromo CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/gromo TODAY_DIR=$DATA_DIR/$(date '+%Y-%m-%d') DING_FILE=$CACHE_DIR/ding.opus STATE_FILE=${XDG_STATE_HOME:-$HOME/.local/state}/gromo FS=: gromo_duration=$((60 * 20)) stop_duration=20 cmd_help() { cmd=$(basename "$0") echo -e "Usage: $cmd -h \tShow this help $cmd -x \tShow status formatted for xmobar $cmd -l \tList past gromos $cmd \tShow status $cmd [options] \tStart task Options: -1 Oneshot: stop after first gromo is completed without blocking the screen. -t test the 'ding' sound -d Set custom gromo duration (format: Ns, Nm, Nh). -s Set custom stop duration (format: Ns, Nm, Nh). Ignored if combined with -1. Tasks can be divided in subtasks by using dots (.), e.g., 'gromo work.retro'. Only the first level is taken into account for organization purposes: the top-level task is considered the 'main task' and a file is created after it to account for its subtasks. " } cmd_list() { find "$DATA_DIR/" -type f -print0 | xargs -0 -n 1 basename | sort -u } cmd_status() { format=$1 status=idle [ -f "$STATE_FILE" ] && status=$(cat "$STATE_FILE") if [ "$format" = "xmobar" ]; then color=red [ "$status" = "idle" ] && color=green if [ -d "$TODAY_DIR" ]; then today="" # needs nullglob for task_file in "$TODAY_DIR"/*; do today+="$(basename "$task_file"): $(sum_subtasks "$task_file"), " done [ -n "$today" ] && today=" (${today%, })" fi echo "$status$today" else echo -e "status: $status\n" if [ -d "$TODAY_DIR" ]; then # needs nullglob for task_file in "$TODAY_DIR"/*; do out+=$( gawk -F $FS -f - "$task_file" <[smh]." >&2 return 1 ;; esac } sum_subtasks() { file=$1 awk -F $FS '{ sum += $3 } END { print sum }' "$file" } inc_subtask() { task=$1 maintask="${fulltask%%.*}" task_file="$TODAY_DIR/$maintask" if [ ! -f "$task_file" ]; then touch "$task_file" fi awk -F $FS -f - "$task_file" > tmp < "$STATE_FILE" trap 'rm $STATE_FILE 2> /dev/null; exit' INT TERM EXIT while true; do echo -ne "\r\033[K[** IN PROGRESS: $fulltask **] " echo "$fulltask" > "$STATE_FILE" sleep "$gromo_duration" echo idle > "$STATE_FILE" inc_subtask "$fulltask" if [ "$oneshot" = "1" ]; then mpv --no-terminal "$DING_FILE" & exit 0 fi (sleep "$stop_duration" && mpv --no-terminal "$DING_FILE") & slock || exit done