From 847b24c85b00441db14c16c2acabd65494786755 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Saraiva Date: Sat, 5 Jul 2025 17:13:42 -0300 Subject: [PATCH] Update README and functions for v1.4.0: Enhance help messages, add new commands, and improve task management features --- README.md | 97 ++++++++++++++++----------------------------- functions.sh | 79 ++++++++++++++++++++++++++++++++++--- tests.sh | 109 +++++++++++++++++++++++++++++++++++++++++++++------ variables.sh | 4 +- woche.sh | 52 +++++++++++++++++++----- 5 files changed, 250 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 9f6072e..f1946c4 100755 --- a/README.md +++ b/README.md @@ -1,89 +1,64 @@ -# Woche - v1.3.1 +# Woche - v1.4.0 -Woche is a tool for managing weekly tasks using Bash scripts. It creates a new Markdown file for the current week and allows you to add tasks to specific days. "Woche" means 'week' in German, and you can choose between English or German day names. - -![Screencast from 2024-10-20 15-15-38](https://github.com/user-attachments/assets/ef870bad-44c4-40ca-8c3d-a8313ea21d37) +Woche is a command-line tool for managing weekly tasks using Bash scripts. It helps you create and organize tasks in Markdown files, with support for English and German day names. ## Features -- Generates a new Markdown file for the current week with headers for each day. -- Allows adding, editing, and deleting tasks for specific days or lines. -- Lists and displays tasks from different weeks. -- Provides usage tips. +- Create weekly Markdown files. +- Add, edit, delete, and mark tasks as complete. +- View tasks by week, grouped by day with line numbers. +- Search for tasks across all weeks. +- Open weekly files in your preferred editor. ## Usage -### Create a New Markdown File for the Current Week +### Getting Started ```bash ./woche.sh create -# The file 241014.md has been created -``` - -This command creates a file using the YYMMDD format. - -### Add a Task to a Specific Day - -```bash -./woche.sh "" -``` - -Replace `` with the day of the week and `` with the task description. Days in English: mon, tue, wed, thu, fri, sat, sun. Days in German: mont, die, mit, don, frei, sam, son. - -```bash -./woche.sh mon "Do something" -# Do something was added to Monday. +# Creates a new Markdown file for the current week (e.g., 241014.md) ``` -### Display Tasks of the Current Week +### Adding Tasks ```bash -./woche.sh show +./woche.sh "" # Add task to a specific day (e.g., mon, tue, mont, die) +./woche.sh today "" # Add task to the current day ``` -### Edit a Task of the Current Week +### Viewing Tasks ```bash -./woche.sh edit 9 "That task" -# Line 9 edited. +./woche.sh show # Display tasks for the current week +./woche.sh show last # Display tasks for last week +./woche.sh show # Display tasks for a specific week (e.g., 210829) +./woche.sh all # List all weekly Markdown files ``` -### Delete a Task of the Current Week +### Managing Tasks ```bash -./woche.sh delete 3 -# Line 3 deleted. +./woche.sh edit "" # Edit a task by line number +./woche.sh delete # Delete a task by line number (requires confirmation) +./woche.sh done # Mark a task as complete ``` -### List Files of Different Weeks +### Searching Tasks ```bash -./woche.sh all +./woche.sh search "" # Search for a keyword in all weekly files ``` -### Display Tasks of Last Week +### Other Commands ```bash -./woche.sh show last -``` - -### Show Tasks of a Specific Week - -```bash -./woche.sh show 210829 -``` - -### Access Instructions - -```bash -./woche.sh help +./woche.sh open # Open the current week's file in $EDITOR +./woche.sh help # Display all commands and usage ``` ## Testing -The `test.sh` script tests the functionality of `woche.sh`, checking both correct and incorrect user inputs. This test is mandatory for pull requests to the main branch and should be included in the [GitHub Actions](https://github.com/0jonjo/woche/actions) pipeline for automated testing. - -To run the tests: +To run the test suite: ```bash ./test.sh @@ -91,22 +66,18 @@ To run the tests: ## Docker -To use the Dockerized version of Woche: +To use the Dockerized version: ```bash -# Build the image -docker build -t woche-app . - -# Run the container -docker run -it woche-app +docker build -t woche-app . # Build the image +docker run -it woche-app # Run the container ``` -## Customization Tips +## Customization -- Change the file creation path by modifying the `path` variable in `variables.sh`. -- Switch to German day names by replacing `week_array` with `woche_array` in `variables.sh`. -- Alter the date format of the Markdown file by adjusting the `start_day_of_week` method in `functions.sh`. -- Use the Dockerized version if not on an Ubuntu/Debian system. +- Change file path: Modify `path_to_files` in `variables.sh`. +- Switch to German days: Replace `week_array` with `woche_array` in `variables.sh`. +- Adjust date format: Modify `start_day_of_week` in `functions.sh`. ## License diff --git a/functions.sh b/functions.sh index 1617a55..b1185c0 100755 --- a/functions.sh +++ b/functions.sh @@ -1,15 +1,16 @@ #!/usr/bin/env bash -tips() { - echo "tips: woche.sh" +help() { echo "create: a new markdown file for the current week" echo "Use the day alias to add a task to the day of the week." + echo "today: add a task to the current day" echo "show: show the tasks for the current week" echo "show YYMMDD: show the tasks for the week starting on YYMMDD" echo "show last: show the tasks for last week" echo "delete X: delete a task from the current week - X is the line number" echo "edit X: edit a task from the current week - X is the line number" echo "all: show all markdown files in the current directory" + echo "open: open the current week's file in your default editor" } current_week() { @@ -69,8 +70,13 @@ create_week() { } delete_line() { - sed -i "${task}d" "$file.md" - echo "Line ${task} deleted." + read -p "Are you sure you want to delete line ${task}? (y/N): " confirm + if [[ "$confirm" =~ ^[yY]$ ]]; then + sed -i "${task}d" "$file.md" + echo "Line ${task} deleted." + else + echo "Deletion cancelled." + fi } edit_line() { @@ -82,10 +88,73 @@ edit_line() { show_file() { start_day_formatted=$(date -d "$file" "+%d/%m/%Y") printf "Week starts on %s.\n\n" "$start_day_formatted" - cat -n "$file.md" + + legend_string="" + for day_full_name in "${week_array[@]}"; do + header_line=$(grep "^# ${day_full_name}," "$file.md") + if [ -n "$header_line" ]; then + date_part=$(echo "$header_line" | awk -F', ' '{print $2}' | awk '{print $1}') + day_abbr=$(echo "$day_full_name" | cut -c1-3 | tr '[:upper:]' '[:lower:]') + if [ -n "$legend_string" ]; then + legend_string+=", " + fi + legend_string+="${day_abbr} (${date_part})" + fi + done + printf "Current week: %s\n\n" "$legend_string" + + awk_output=$(awk ' + /^# / { + current_day = substr($0, 3); + sub(/,.*$/, "", current_day); + next; + } + /^- / { + print current_day "::" $0 " (" NR ")"; + } + ' "$file.md") + + for ordered_day in "${week_array[@]}"; do + day_tasks=$(echo "$awk_output" | grep "^${ordered_day}::") + + if [ -n "$day_tasks" ]; then + printf "%s:\n" "$ordered_day" + echo "$day_tasks" | sed 's/^[^:]*:://' + printf "\\n" + fi + done } show_all_files() { echo "All markdown files in $path_to_files:" ls -1 ./*.md } + +add_task() { + day_name="$1" + task_text="$2" + escaped_task=$(sed 's/[\/&]/\\&/g' <<< "$task_text") + sed -i "/# $day_name/ a\\- $escaped_task" "$file.md" + echo "Task '$task_text' added to $day_name." +} + +search_files() { + search_term="$1" + echo "Searching for '$search_term' in markdown files:" + grep -n "$search_term" "$path_to_files"/*.md +} + +mark_task_done() { + line_number="$1" + sed -i "${line_number}s/^- /- [x] /" "$file.md" + echo "Task on line ${line_number} marked as done." +} + +open_file_in_editor() { + if [ -z "$EDITOR" ]; then + echo "Error: $EDITOR environment variable is not set. Please set it to your preferred editor (e.g., export EDITOR=nano)." + exit 1 + fi + "$EDITOR" "$file.md" + echo "Opened $file.md in $EDITOR." +} \ No newline at end of file diff --git a/tests.sh b/tests.sh index 8c6fdc2..dad32a0 100755 --- a/tests.sh +++ b/tests.sh @@ -31,7 +31,7 @@ delete_file # Test with more than 3 arguments output=$("$woche_script_path" mon "Test task" "Argument" "Extra argument") -if [[ "$output" == *"tips: woche.sh"* ]]; then +if [[ "$output" == *"create: a new markdown file for the current week"* ]]; then echo "Test 'more than 3 arguments' command: PASSED" else echo "Test 'more than 3 arguments' command: FAILED" @@ -67,7 +67,7 @@ check_test_result # Test invalid command output=$("$woche_script_path" invalid) -if [[ "$output" == *"tips: woche.sh"* ]]; then +if [[ "$output" == *"create: a new markdown file for the current week"* ]]; then echo "Test invalid command: PASSED" else echo "Test invalid command: FAILED" @@ -76,7 +76,7 @@ check_test_result # Test the 'help' command output=$("$woche_script_path" help) -if [[ "$output" == *"tips: woche.sh"* ]]; then +if [[ "$output" == *"create: a new markdown file for the current week"* ]]; then echo "Test 'help' command: PASSED" else echo "Test 'help' command: FAILED" @@ -167,8 +167,9 @@ fi check_test_result # Test edit command with punctituation -output=$("$woche_script_path" edit 2 "New task ,.!@") -if [[ "$output" == *"Line 2 edited."* ]]; then +line_to_edit=$(grep -n "Test task with punctuation" "$path_to_files/$file.md" | cut -d: -f1) +output=$("$woche_script_path" edit "$line_to_edit" "New task ,.!@") +if [[ "$output" == *"Line $line_to_edit edited."* ]]; then echo "Test 'edit' command: PASSED" else echo "Test 'edit' command: FAILED" @@ -176,30 +177,114 @@ fi ## Check if the task is edited on last test cd "$path_to_files" > /dev/null || exit -if ! sed -n "2 p" "$file.md" | grep -q "New task ,.!@"; then +if ! sed -n "${line_to_edit}p" "$file.md" | grep -q "New task ,.!@"; then echo "Error: Task has not been edited." exit 1 fi cd - > /dev/null || exit # Test show command +output=$("$woche_script_path" create) +output=$("$woche_script_path" mon "Task one") +output=$("$woche_script_path" mon "Task two") +output=$("$woche_script_path" tue "Task three") + +line_one=$(grep -n "Task one" "$path_to_files/$file.md" | cut -d: -f1) +line_two=$(grep -n "Task two" "$path_to_files/$file.md" | cut -d: -f1) +line_three=$(grep -n "Task three" "$path_to_files/$file.md" | cut -d: -f1) + output=$("$woche_script_path" show) -if [[ "$output" == *"Week starts on"* ]]; then + +if [[ "$output" == *"Week starts on"* ]] && \ + [[ "$output" == *"Task one"* ]] && \ + [[ "$output" == *"Task two"* ]] && \ + [[ "$output" == *"Task three"* ]]; then echo "Test 'show' command: PASSED" else echo "Test 'show' command: FAILED" fi check_test_result -# Test delete command -output=$("$woche_script_path" delete 2) -if [[ "$output" == *"Line 2 deleted."* ]]; then - echo "Test 'delete' command: PASSED" +# Test 'today' command +output=$("$woche_script_path" today "Test task") +if [[ "$output" == *"Task 'Test task' added to"* ]]; then + echo "Test 'today' command: PASSED" +else + echo "Test 'today' command: FAILED" +fi +check_test_result + +# Test 'search' command +output=$("$woche_script_path" create) +output=$("$woche_script_path" mon "Searchable task") +output=$("$woche_script_path" search "Searchable task") +if [[ "$output" == *"Searchable task"* ]]; then + echo "Test 'search' command: PASSED" +else + echo "Test 'search' command: FAILED" +fi +check_test_result + +# Test delete command with 'y' confirmation +output=$("$woche_script_path" create) +output=$("$woche_script_path" mon "Task to be deleted") +line_to_delete=$(grep -n "Task to be deleted" "$path_to_files/$file.md" | cut -d: -f1) +output=$(echo "y" | "$woche_script_path" delete "$line_to_delete") +if [[ "$output" == *"Line $line_to_delete deleted."* ]]; then + echo "Test 'delete' command with 'y' confirmation: PASSED" +else + echo "Test 'delete' command with 'y' confirmation: FAILED" +fi +check_test_result + +## Check if the task is deleted on last test +cd "$path_to_files" > /dev/null || exit +if grep -q "Task to be deleted" "$file.md"; then + echo "Error: Task has not been deleted." + exit 1 +fi +cd - > /dev/null || exit + +# Test delete command with 'n' confirmation +output=$("$woche_script_path" create) +output=$("$woche_script_path" mon "Task not to be deleted") +line_to_delete=$(grep -n "Task not to be deleted" "$path_to_files/$file.md" | cut -d: -f1) +output=$(echo "n" | "$woche_script_path" delete "$line_to_delete") +if [[ "$output" == *"Deletion cancelled."* ]]; then + echo "Test 'delete' command with 'n' confirmation: PASSED" else - echo "Test 'delete' command: FAILED" + echo "Test 'delete' command with 'n' confirmation: FAILED" fi check_test_result +## Check if the task is not deleted on last test +cd "$path_to_files" > /dev/null || exit +if ! grep -q "Task not to be deleted" "$file.md"; then + echo "Error: Task has been deleted when it shouldn't have been." + exit 1 +fi +cd - > /dev/null || exit + +# Test 'done' command +output=$("$woche_script_path" create) +output=$("$woche_script_path" mon "Task to be marked as done") +line_to_mark_done=$(grep -n "Task to be marked as done" "$path_to_files/$file.md" | cut -d: -f1) +output=$("$woche_script_path" done "$line_to_mark_done") +if [[ "$output" == *"Task on line $line_to_mark_done marked as done."* ]]; then + echo "Test 'done' command: PASSED" +else + echo "Test 'done' command: FAILED" +fi +check_test_result + +## Check if the task is marked as done on last test +cd "$path_to_files" > /dev/null || exit +if ! sed -n "${line_to_mark_done}p" "$file.md" | awk '/^- \[x\] Task to be marked as done/'; then + echo "Error: Task has not been marked as done." + exit 1 +fi +cd - > /dev/null || exit + delete_file # Revert path_to_files to its original value in variables.sh diff --git a/variables.sh b/variables.sh index 5ceebe0..edfebc1 100755 --- a/variables.sh +++ b/variables.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # The path to create and edit the file -path_to_files="/home/$(whoami)/" +path_to_files=/tmp/ # Days of the week in German and English export mont="Montag" @@ -25,7 +25,7 @@ export week_array=("$mon" "$tue" "$wed" "$thu" "$fri" "$sat" "$sun") export woche_array_string=("mont" "die" "mit" "don" "fre" "sam" "son") export week_array_string=("mon" "tue" "wed" "thu" "fri" "sat" "sun") -export options=("create" "show" "help" "delete" "edit" "all") +export options=("create" "show" "help" "delete" "edit" "all" "today" "search" "done" "open") # Create an array that is options + woche_array name of variables as strings export options_to_check=("${options[@]}" "${week_array_string[@]}") diff --git a/woche.sh b/woche.sh index 95f8fc0..3b02a25 100755 --- a/woche.sh +++ b/woche.sh @@ -14,14 +14,14 @@ export file=$current_week # Check the number of arguments if [ "$#" -gt 3 ]; then - tips + help exit 1 fi # Check if $1 is in the options to check if [[ ! " ${options_to_check[@]} " =~ $1 ]]; then echo "Error: Invalid command." - tips + help exit 1 fi @@ -59,16 +59,50 @@ case $1 in exit 0 ;; help) - tips + help exit 0 ;; - *) + today) + file_exists + day_of_week=$(date +%u) + day=${week_array[$((day_of_week-1))]} + add_task "$day" "$task" + exit 0 + ;; + search) + search_files "$task" + exit 0 + ;; + done) + file_exists + line_exists + mark_task_done "$task" + exit 0 + ;; + open) file_exists - day=$(eval echo "\$$1") - escaped_task=$(sed 's/[\/&]/\\&/g' <<< "$task") - sed -i "/# $day/ a\\- $escaped_task" "$file.md" - echo "Task '$task' added to $day." + open_file_in_editor exit 0 ;; -esac + *) + file_exists + day_abbr=$1 + day_full="" + # Find the full day name from the abbreviation + for i in "${!week_array_string[@]}"; do + if [[ "${week_array_string[$i]}" = "$day_abbr" ]]; then + day_full="${week_array[$i]}" + break + fi + done + if [ -z "$day_full" ]; then + echo "Error: Invalid day '$1'." + help + exit 1 + fi + + add_task "$day_full" "$task" + exit 0 + ;; +esac \ No newline at end of file