A dmenu calendar.

git clone git://watertao.xyz/programs/calcurse_dmenu.git

calcurse_dmenu.sh (7086B)


      1 #!/bin/sh
      2 
      3 PROGDIR="$(cd -- "$(dirname -- "$0")" && pwd)"
      4 . $PROGDIR/config.sh
      5 
      6 [ -d "$cal_dir" ] || mkdir -p "$cal_dir"
      7 [ -d "$cal_notes" ] || mkdir -p "$cal_notes"
      8 [ -f "$cal_apts" ] || touch "$cal_apts"
      9 [ -f "$cal_todo" ] || touch "$cal_todo"
     10 [ -f "$cal_alarm" ] || touch "$cal_alarm"
     11 
     12 t="$(mktemp)" && u="$(mktemp)" && v="$(mktemp)" && x="$(mktemp)" && y="$(mktemp)" || exit 1
     13 
     14 cu(){
     15 	rm "$u" "$t" "$v" "$x" "$y" 2>/dev/null
     16 	exit 0
     17 }
     18 
     19 trap cu INT
     20 
     21 cal_msg(){
     22 	msg_m="${1:-""}"
     23 	msg_p="${2:-""}"
     24 	msg_r="${3:-0}"
     25 	printf "%s\n" "$msg_m" | $dmenu -p "$msg_p" && return $msg_r
     26 }
     27 
     28 cal_lno_dmenu_string(){
     29 	l="$(<$u sed -n "s/^.*<\([0-9]\+\)\(${rm_tag}\)*\(${n_tag}\)*\(${e_tag}\)*$/\1/p")" && \
     30 	[ -n "$l" ] && \
     31 	return 0 || return 1
     32 }
     33 
     34 __cal_title(){
     35 	s="$S_TITLE"
     36 	#d="$(date +"%A, %B %d %Y")"
     37 	case "$typeflag" in
     38 		"h") s="$S_HISTORY" ;;
     39 		"t") s="$S_TODO" ;;
     40 		"a") s="$S_ALARM" ;;
     41 	esac
     42 	printf "%s" "$s"
     43 }
     44 
     45 __cal_evt_sel(){
     46 	sh "$PROGDIR/entries.sh" -t "$typeflag" | \
     47 		$dmenu -i -p "$(__cal_title)" || \
     48 	return 1
     49 	#cu
     50 }
     51 
     52 cal_evt_sel(){
     53 	# u = tmp file storing selected dmenu string
     54 	# v = tmp file storing full data line
     55 	# l = db line number
     56 	# n = note filename
     57 	__cal_evt_sel > $u && \
     58 	cal_lno_dmenu_string && \
     59 	< "$db_file" sed -n "${l}p" > $v && \
     60 	n="$(<$v grep -o "$note_pattern" | tr -d ">")" && \
     61 	return 0 || return 1
     62 }
     63 
     64 cal_rm_note_file(){
     65 	f="${cal_notes}/${n}"
     66 	[ -f "$f" ] && rm "$f"
     67 	return 0
     68 }
     69 
     70 cal_is_todo(){ [ "$typeflag" = "t" ]; }
     71 
     72 cal_is_alarm(){ [ "$typeflag" = "a" ]; }
     73 
     74 cal_rm_note_ref(){
     75 	cal_is_todo && s="" || s=" "
     76 	sed -i "${l}s/^\(.*\)${note_pattern}${s}\(.*\)$/\1\2/" "$db_file"
     77 }
     78 
     79 cal_rm_entry(){
     80 	[ "$l" -gt 0 ] && sed -i "${l}d" "$db_file"
     81 }
     82 
     83 cal_note_view(){
     84 	#"$term" $pager "${cal_notes}/${n}"
     85 	"$term" $EDITOR "${cal_notes}/${n}"
     86 }
     87 
     88 cal_entry_view(){
     89 	$term sh $PROGDIR/entry_view.sh $u "$cal_notes/$n" "$typeflag"
     90 }
     91 
     92 grep_prep(){
     93 	# escape special grep chars
     94 	b="$(<$v sed -e 's#\([][\$\*\^]\)#\\\1#g')"
     95 }
     96 
     97 flag_reset(){
     98 	# Type flags
     99 	# c > main calendar
    100 	# h > historia
    101 	# t > todo
    102 	typeflag="c"
    103 }
    104 
    105 cal_note_add(){
    106 
    107 	if cal_is_todo; then
    108 		sed -i "
    109 		${note_lno}s/\(^\[[0-9]\+\]\)\(.*\)$/\1>${n}\2/
    110 		" "$cal_note_add_file" && return 0 || return 1
    111 	else
    112 		sed -i "
    113 		${note_lno}s/\(^[0-9\/]\+ \)\(@[- 0-9\>\/:@]\+\)\({.*} \)*\(|\)/\1\2\3>${n} \4/
    114 		${note_lno}s/\(^[0-9\/]\+ \)\(\[[0-9]\+\] \)\({.*} \)*/\1\2\3>${n} /
    115 		" "$cal_note_add_file" && return 0 || return 1
    116 	fi
    117 }
    118 
    119 cal_note_create(){
    120 
    121 	# Create note
    122 	>$t && "$term" $EDITOR $t
    123 	if [ -s "$t" ]
    124 	then
    125 		# Generate note file name
    126 		n="$(</dev/urandom tr -dc '0-9a-f' | head -c40)"
    127 		# Copy temp to new note file
    128 		cp $t "${cal_notes}/${n}"
    129 		# Update apts db entry with note reference
    130 		cal_note_add_file="$db_file"
    131 		note_lno="$l"
    132 		if ! cal_note_add; then
    133 			rm -v "${cal_notes}/${n}"
    134 			cal_msg "removed note file, aborting cal_note_create" "cal_note_create error"
    135 		fi
    136 	fi
    137 }
    138 
    139 sort_entries(){
    140 	[ -n "$1" ] && \
    141 	<$v grep -E "$1" | \
    142 		sed 's#^\(..\)/\(..\)/\(....\)#\3\1\2 \1/\2/\3#' | \
    143 		sort | \
    144 		cut -d" " -f2- >> $x && \
    145 		return 0 || return 1
    146 }
    147 
    148 sort_todo(){
    149 	# Sort rank then desc
    150 	# Move possible note for sorting, then back
    151 	[ -n "$1" ] && \
    152 	<$v grep "$1" | \
    153 		sed "s/^\(\[[0-9]\]\)\(${note_pattern}\)\( .*\)$/\1\3\2/" | \
    154 		sort | \
    155 		sed "s/^\(\[[0-9]\]\)\( .*\)\(${note_pattern}\)$/\1\3\2/" >> $x && \
    156 		return 0 || return 1
    157 }
    158 sort_finalize(){
    159 	>$x && \
    160 	sort_entries "^[[:digit:]/]{10} \[[[:digit:]]+\] {" && \
    161 	sort_entries "^[[:digit:]/]{10} @.{29}{" && \
    162 	sort_entries "^[[:digit:]/]{10} @.{28}[>|]" && \
    163 	sort_entries "^[[:digit:]/]{10} \[[[:digit:]]+\] [^{]" && \
    164 	sort_todo "^\[[1-9]\]" && \
    165 	sort_todo "^\[0\]" && \
    166 	cp $x "$db_file" && \
    167 	return 0 || return 1
    168 }
    169 
    170 cal_entry_edit(){
    171 	# Edit entry:
    172 	# Parse line into calcurse_dmenu syntax
    173 	# Then run it into dmenu to make changes
    174 	# Then rm old entry
    175 	# Then send it into the awk processing below
    176 	# for new changes to be added to db file.
    177 	# There's more to do here than I
    178 	# initially thought...
    179 	#if entry_edit="$(<$v awk -f "$entry_edit_parser_awk" | $dmenu)"; then
    180 	if <$v awk -f "$entry_edit_parser_awk" | $dmenu >$t; then
    181 		# If edit empty, ignore
    182 		<$t grep -q "^[[:space:]]*$" || [ ! -s $t ] && return 0
    183 		# Add double colon date/description seperator if needed
    184 		<$t grep -q "^.*::.\+$" || sed -i 's/^/::/' $t
    185 		# Attemp parse of entry edit
    186 		if awk -vtypeflag="$typeflag" -f "$entry_add_awk" $t > $y; then
    187 			# If note, add it back to entry
    188 			if [ -n "$n" ]; then
    189 				cal_note_add_file="$y"
    190 				note_lno="1"
    191 				if ! cal_note_add; then
    192 					cal_msg "Error adding note back into edited entry. Aborting edit."
    193 				fi
    194 			fi
    195 
    196 			# Remove original entry (but keep note file)
    197 			cal_rm_entry
    198 
    199 			# Add freshly edited entry
    200 			if [ -f "$db_file" ]; then
    201 				cat "$db_file" "$y" > "$v"
    202 				sort_finalize || cal_msg "Error sorting/finalizing entry edit. Aborting edit."
    203 			fi
    204 
    205 			cal_msg "$(<$y awk -f "$entry_edit_parser_awk")" "Entry Edit Success"
    206 		else
    207 			cal_msg "Entry edit error, aborting edit."
    208 		fi
    209 	fi
    210 }
    211 
    212 cal_view(){
    213 
    214 	if cal_evt_sel
    215 	then
    216 		# Remove if tagged :::r
    217 		if <$u grep -q "$rm_tag$"
    218 		then
    219 			cal_rm_entry
    220 			cal_rm_note_file
    221 
    222 		elif <$u grep -q "$n_tag$"
    223 		then
    224 			# Open note in pager
    225 			if [ -n "$n" ]
    226 			then
    227 				if [ -f "$cal_notes/$n" ]
    228 				then
    229 					cal_note_view
    230 
    231 					# If note empty, rm it
    232 					if [ ! -s "$cal_notes/$n" ]
    233 					then
    234 						cal_rm_note_file
    235 						cal_rm_note_ref
    236 					fi
    237 				fi
    238 			else
    239 				cal_note_create
    240 			fi
    241 		elif <$u grep -q "$e_tag$"
    242 		then
    243 			cal_entry_edit
    244 		else
    245 			cal_entry_view
    246 		fi
    247 	else
    248 		# Emergency exit
    249 		<$u grep -q "^exit$\|^quit$" && cu
    250 
    251 		# If line seperator for today/tomorrow/yesterday, do nothing
    252 		<$u grep "^$S_SEPERATOR$" && return 0
    253 
    254 		# If from historia, back to main list
    255 		[ "$typeflag" = "h" ] && flag_reset && return 0
    256 
    257 		[ "$typeflag" = "t" ] && [ ! -s $u ] && flag_reset && return 0
    258 
    259 		[ "$typeflag" = "a" ] && [ ! -s $u ] && flag_reset && return 0
    260 
    261 		# Exit if selection empty
    262 		<$u grep -q "^[[:space:]]*$" || [ ! -s $u ] && return 1
    263 
    264 		# launch calcurse
    265 		<$u grep -q "^calcurse$" && { $term calcurse; return 1; }
    266 
    267 		# Historia
    268 		<$u grep -q "^${h_tag}$" && typeflag="h" && return 0
    269 
    270 		# Todo
    271 		<$u grep -q "^${t_tag}$" && typeflag="t" && return 0
    272 
    273 		# Alarm
    274 		<$u grep -q "^${a_tag}$" && typeflag="a" && return 0
    275 
    276 		# Prepare for awk parse
    277 
    278 		# Add 2 colons for awk parsing
    279 		# This allows for quick event entries
    280 		# for current day.
    281 		# Cal entry: date(s)::description
    282 		# Todo entry: rank(optional)::description
    283 		<$u grep -q "^.*::.\+$" || sed -i 's/^/::/' $u
    284 
    285 		# Add new entry to apts file
    286 		# Parse new entry with awk
    287 		# Sort new list of entries in following order:
    288 		# 1 > event recurring
    289 		# 2 > apt recurring
    290 		# 3 > apt
    291 		# 4 > event
    292 
    293 		>$v
    294 		[ -f "$db_file" ] && cp "$db_file" "$v"
    295 		awk -vtypeflag="$typeflag" -f "$entry_add_awk" $u >> $v && \
    296 		sort_finalize && \
    297 		return 0
    298 		return 1
    299 	fi
    300 }
    301 
    302 # Set typeflag to Calendar to kick things off
    303 flag_reset
    304 
    305 #And so it begins
    306 while
    307 	db_file="$cal_apts"
    308 	cal_is_todo && db_file="$cal_todo"
    309 	cal_is_alarm && db_file="$cal_alarm"
    310 	cal_view 
    311 do :; done
    312 cu