#!/bin/sh export now="$(date +%s.%N)" # load current state mkdir -p "$POMODORO_STATE_PATH" load_or_init() { property="$1" default_value="$2" property_path="$POMODORO_STATE_PATH/current/$property" if [ -f "$property_path" ] ; then eval $property='"$(cat "$property_path")"' else eval $property='$default_value' fi } [ -z "$lap" ] && load_or_init lap 0 [ -z "$state" ] && load_or_init state 'reset' [ -z "$time" ] && load_or_init time 0.0 # save state (for diff) diff_state() { printf '%s:' "$lap" "$state" "$time" ; } original_state="$(diff_state)" # allow overriding this value manually [ -z "$update_time" ] && update_time=0 # calculate remaining time on timer if [ -z "$remaining" ] ; then remaining="$time" [ "$state" = 'running' ] && remaining="$(echo "( $time - $now ) / 1" | bc)" fi # go to next lap if this timer expired if [ "$state" = 'running' ] && [ "${remaining#-}" != "${remaining}" ] ; then lap=$(( $lap + 1 )) state='paused' update_time=1 fi # update remaining time if in reset [ "$state" = 'reset' ] && update_time=1 [ "$time" = "0.0" ] && update_time=1 if [ $update_time -eq 1 ] ; then time="$POMODORO_NORMAL_DURATION" [ $(( $lap % $POMODORO_BREAK_SHORT_INTERVAL )) -eq $(( $POMODORO_BREAK_SHORT_INTERVAL - 1 )) ] && time=$POMODORO_BREAK_SHORT_DURATION [ $(( $lap % $POMODORO_BREAK_LONG_INTERVAL )) -eq $(( $POMODORO_BREAK_LONG_INTERVAL - 1 )) ] && time=$POMODORO_BREAK_LONG_DURATION remaining="$time" fi save_state() { # do not save files if state didn't change [ "$original_state" = "$(diff_state)" ] && return # The state update needs to be atomic since other instances may access the # state during an update. This is accomplished by replacing a single symlink, # which should be atomic on most POSIX-compatible platforms, and is less # complicated than a lockfile. $POMODORO_STATE_PATH contains three items: # # 1. current -- a symlink to `primary` or `secondary` # 2. primary -- folder containing current state* # 3. secondary -- temporary folder used write new state # # * `primary` will only contain stale state during an update (i.e. while # `current` is pointing to `secondary`) mkdir -p "$POMODORO_STATE_PATH/primary" "$POMODORO_STATE_PATH/secondary" echo "$lap" > "$POMODORO_STATE_PATH/secondary/lap" echo "$state" > "$POMODORO_STATE_PATH/secondary/state" echo "$time" > "$POMODORO_STATE_PATH/secondary/time" ln -sf "secondary" "$POMODORO_STATE_PATH/secondary/current" # this is the atomic update that replaces the `current` symlink with the new # state mv "$POMODORO_STATE_PATH/secondary/current" "$POMODORO_STATE_PATH" # next, replace the old `primary` state with the new state from `secondary`, # and update the symlink a second time to now point to `primary` again (this # does not change the state) cp -r "$POMODORO_STATE_PATH/secondary/." "$POMODORO_STATE_PATH/primary/" ln -sf "primary" "$POMODORO_STATE_PATH/primary/current" mv "$POMODORO_STATE_PATH/primary/current" "$POMODORO_STATE_PATH" } # export state variables export lap state time