#!/bin/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/ding.opus GROMO_SECONDS=$((60 * 20)) STOP_SECONDS=20 DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/gromo CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/gromo TODAY_DIR=$DATA_DIR/$(date -I) DING_FILE=$CACHE_DIR/ding.opus STATE_FILE=${XDG_STATE_HOME:-$HOME/.local/state}/gromo FS=: cmd_help() { cmd=$(basename "$0") echo -e "Usage: $cmd -h \tShow this help $cmd -s \tShow status $cmd -l \tList past gromos $cmd -x \tReturn state formatted for display in xmobar $cmd [options] \tStart task Options: -1 Oneshot: stop after first gromo is completed without blocking the screen. 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 state=idle [ -f "$STATE_FILE" ] && state=$(cat "$STATE_FILE") if [ "$format" = "xmobar" ]; then color=red [ "$state" = "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 "$state$today" else echo -e "state: $state\n" if [ -d "$TODAY_DIR" ]; then # needs nullglob for task_file in "$TODAY_DIR"/*; do sort < "$task_file" done fi fi } 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_SECONDS echo idle > "$STATE_FILE" inc_subtask "$fulltask" if [ "$oneshot" = "1" ]; then mpv --no-terminal "$DING_FILE" & exit 0 fi (sleep $STOP_SECONDS && mpv --no-terminal "$DING_FILE") & slock || exit done