Add checklist.sh scrpt
This commit is contained in:
parent
75ed1c111a
commit
f566f8d9d0
|
@ -0,0 +1,211 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Check if file argument is provided
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 <path_to_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FILE="$1"
|
||||
|
||||
# Check if file exists
|
||||
if [ ! -f "$FILE" ]; then
|
||||
echo "Error: File '$FILE' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Terminal control functions
|
||||
hide_cursor() {
|
||||
printf '\033[?25l'
|
||||
}
|
||||
|
||||
show_cursor() {
|
||||
printf '\033[?25h'
|
||||
}
|
||||
|
||||
move_cursor() {
|
||||
printf '\033[%d;%dH' "$1" "$2"
|
||||
}
|
||||
|
||||
clear_screen() {
|
||||
printf '\033[2J'
|
||||
printf '\033[H'
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
show_cursor
|
||||
clear_screen
|
||||
echo "Goodbye!"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Trap to ensure cursor is restored on exit
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Hide cursor at start
|
||||
hide_cursor
|
||||
|
||||
# Parse the file and store tasks
|
||||
declare -a categories=()
|
||||
declare -A tasks=()
|
||||
declare -A checked=()
|
||||
declare -a display_items=() # Store display items in order
|
||||
current_category=""
|
||||
task_counter=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
if [[ $line =~ ^@(.+)$ ]]; then
|
||||
current_category="${BASH_REMATCH[1]}"
|
||||
categories+=("$current_category")
|
||||
display_items+=("CATEGORY:$current_category")
|
||||
elif [[ -n "$line" && -n "$current_category" ]]; then
|
||||
task_key="${current_category}_${task_counter}"
|
||||
tasks["$task_key"]="$line"
|
||||
checked["$task_key"]=false
|
||||
display_items+=("TASK:$task_key")
|
||||
((task_counter++))
|
||||
fi
|
||||
done < "$FILE"
|
||||
|
||||
# Current selection
|
||||
current_selection=0
|
||||
total_items=${#display_items[@]}
|
||||
header_lines=3
|
||||
|
||||
# Initial display
|
||||
initial_display() {
|
||||
clear_screen
|
||||
echo "Checklist - Use ↑/↓ to navigate, SPACE to toggle, q to quit"
|
||||
echo "File: $FILE"
|
||||
echo "=================================================="
|
||||
|
||||
for i in "${!display_items[@]}"; do
|
||||
item="${display_items[$i]}"
|
||||
if [[ $item =~ ^CATEGORY:(.+)$ ]]; then
|
||||
category="${BASH_REMATCH[1]}"
|
||||
echo "@$category"
|
||||
elif [[ $item =~ ^TASK:(.+)$ ]]; then
|
||||
task_key="${BASH_REMATCH[1]}"
|
||||
checkbox="[ ]"
|
||||
if [ "${checked[$task_key]}" = true ]; then
|
||||
checkbox="[✓]"
|
||||
fi
|
||||
echo " $checkbox ${tasks[$task_key]}"
|
||||
fi
|
||||
echo # Empty line after each item
|
||||
done
|
||||
}
|
||||
|
||||
# Update single line
|
||||
update_line() {
|
||||
local line_num=$((header_lines + 1 + ($1 * 2))) # *2 because of empty lines
|
||||
move_cursor $line_num 1
|
||||
printf '\033[K' # Clear line
|
||||
|
||||
item="${display_items[$1]}"
|
||||
if [[ $item =~ ^CATEGORY:(.+)$ ]]; then
|
||||
category="${BASH_REMATCH[1]}"
|
||||
if [ $1 -eq $current_selection ]; then
|
||||
printf '\033[7m@%s\033[0m' "$category"
|
||||
else
|
||||
printf '@%s' "$category"
|
||||
fi
|
||||
elif [[ $item =~ ^TASK:(.+)$ ]]; then
|
||||
task_key="${BASH_REMATCH[1]}"
|
||||
checkbox="[ ]"
|
||||
if [ "${checked[$task_key]}" = true ]; then
|
||||
checkbox="[✓]"
|
||||
fi
|
||||
task_line=" $checkbox ${tasks[$task_key]}"
|
||||
if [ $1 -eq $current_selection ]; then
|
||||
printf '\033[7m%s\033[0m' "$task_line"
|
||||
else
|
||||
printf '%s' "$task_line"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Update only the checkbox part of a task line
|
||||
update_checkbox() {
|
||||
local line_num=$((header_lines + 1 + ($1 * 2)))
|
||||
local task_key="${BASH_REMATCH[1]}"
|
||||
|
||||
item="${display_items[$1]}"
|
||||
if [[ $item =~ ^TASK:(.+)$ ]]; then
|
||||
task_key="${BASH_REMATCH[1]}"
|
||||
checkbox="[ ]"
|
||||
if [ "${checked[$task_key]}" = true ]; then
|
||||
checkbox="[✓]"
|
||||
fi
|
||||
|
||||
# Move to checkbox position (column 3) and update just the checkbox
|
||||
move_cursor $line_num 3
|
||||
if [ $1 -eq $current_selection ]; then
|
||||
printf '\033[7m%s\033[0m' "$checkbox"
|
||||
else
|
||||
printf '%s' "$checkbox"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the task key at current selection
|
||||
get_current_task_key() {
|
||||
item="${display_items[$current_selection]}"
|
||||
if [[ $item =~ ^TASK:(.+)$ ]]; then
|
||||
echo "${BASH_REMATCH[1]}"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Show initial display
|
||||
initial_display
|
||||
|
||||
# Highlight first item
|
||||
update_line 0
|
||||
|
||||
# Main loop
|
||||
prev_selection=0
|
||||
while true; do
|
||||
# Read single character
|
||||
IFS= read -rsn1 input
|
||||
|
||||
# Handle different input cases
|
||||
if [[ $input == $'\x1b' ]]; then
|
||||
# ESC sequence - read next two characters
|
||||
IFS= read -rsn2 input
|
||||
case $input in
|
||||
'[A') # Up arrow
|
||||
if [ $current_selection -gt 0 ]; then
|
||||
prev_selection=$current_selection
|
||||
((current_selection--))
|
||||
update_line $prev_selection
|
||||
update_line $current_selection
|
||||
fi
|
||||
;;
|
||||
'[B') # Down arrow
|
||||
if [ $current_selection -lt $((total_items - 1)) ]; then
|
||||
prev_selection=$current_selection
|
||||
((current_selection++))
|
||||
update_line $prev_selection
|
||||
update_line $current_selection
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
elif [[ $input == ' ' ]]; then
|
||||
# Space bar - toggle checkbox
|
||||
task_key=$(get_current_task_key)
|
||||
if [ -n "$task_key" ]; then
|
||||
if [ "${checked[$task_key]}" = true ]; then
|
||||
checked["$task_key"]=false
|
||||
else
|
||||
checked["$task_key"]=true
|
||||
fi
|
||||
# Only update the checkbox, not the entire line
|
||||
update_checkbox $current_selection
|
||||
fi
|
||||
elif [[ $input == 'q' ]] || [[ $input == 'Q' ]]; then
|
||||
# Quit - cleanup will be called by trap
|
||||
exit 0
|
||||
fi
|
||||
done
|
Loading…
Reference in New Issue