From f663c200d280e0a3410cddf04b89bfadeb2c386e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=84min=20Baumeler?= Date: Fri, 4 Jul 2025 12:56:58 +0200 Subject: [PATCH] feat: category filter --- README.md | 3 +-- src/awk/get.awk | 58 +++++++++++++++++++++++++------------------- src/awk/update.awk | 7 +++--- src/main.sh | 10 ++++++-- src/sh/categories.sh | 17 +++++++++++++ src/sh/icalendar.sh | 4 +-- 6 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 src/sh/categories.sh diff --git a/README.md b/README.md index f72ace8..61edb63 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ In addition, there are the following keybindings: | `alt-up` | Increase task priority | | `alt-down` | Decrease task priority | | `ctrl-a` | Open attachments view | +| `ctrl-t` | Filter by category | | `alt-v` | View bare iCalendar file | | `alt-0` | Default view: Journal, notes, and _open_ tasks | | `alt-1` | Display journal entries | @@ -99,8 +100,6 @@ In the attachment view, you may use the following keys: | Key | Action | | --- | ------ | | `enter` | Open attachment | -| `j` | Down | -| `k` | Up | | `w` | Toggle line wrap | | `ctrl-a` | Add attachment | | `ctrl-alt-d` | Delete attachment | diff --git a/src/awk/get.awk b/src/awk/get.awk index e45b09c..7b0829a 100644 --- a/src/awk/get.awk +++ b/src/awk/get.awk @@ -1,4 +1,4 @@ -# Retrieve content from iCalendar file +# Retrieve content from iCalendar files # # Mandatory variable: `field`. # Name of field to retrieve. @@ -8,34 +8,42 @@ # comma-separated values, and empty values are dropped. # If `format` is set to "date", then the content is interpreted as # a date the output is in the form YYYY-MM-DD. +# +# Optional variable: `oneline`. +# If `oneline` is set, then the all newlines will be replaced by white spaces @include "lib/awk/icalendar.awk" # print content of field `field` -BEGIN { FS = ":"; ORS = ""; regex = "^" field; } +BEGIN { FS = ":"; regex = "^" field; } +BEGINFILE { type = ""; line = ""; } /^BEGIN:(VJOURNAL|VTODO)/ { type = $2 } -/^END:/ && $2 == type { exit } -$0 ~ field { line = $0; next; } +/^END:/ && $2 == type { nextfile } +$0 ~ regex { line = $0; next; } /^ / && line { line = line substr($0, 2); next; } -/^[^ ]/ && line { exit } -END { - if (!type) { exit } - # Process line - content = getcontent(line) - switch (format) { - case "csv" : - split(content, a, ",") - for (i in a) { - if (a[i]) - res = res "," a[i] - } - print substr(res, 2) - break - case "date" : - if (content) - print substr(parse_dt("", content), 1, 10) - break - default : - print content - break +/^[^ ]/ && line { nextfile } +ENDFILE { + if (type) { + # Process line + content = getcontent(line) + if (oneline) + content = singleline(content) + switch (format) { + case "csv" : + split(content, a, ",") + res = "" + for (i in a) { + if (a[i]) + res = res "," a[i] + } + print substr(res, 2) + break + case "date" : + if (content) + print substr(parse_dt("", content), 1, 10) + break + default : + print content + break + } } } diff --git a/src/awk/update.awk b/src/awk/update.awk index 6b21f35..021416c 100644 --- a/src/awk/update.awk +++ b/src/awk/update.awk @@ -39,9 +39,10 @@ NR == FNR && !el { print "Unrecognized header on line "NR": " $ NR == FNR { desc = "D" escape($0); next; } due && type == "VJOURNAL" { print "Notes and journal entries do not have due dates." > "/dev/stderr"; exit 1; } /^BEGIN:(VJOURNAL|VTODO)/ { type = $2; print; next; } -/^X-ALT-DESC/ && type { next; } # drop this alternative description -/^ / && type { next; } # drop this folded line (the only content with folded lines will be updated) -/^(DUE|SUMMARY|CATEGORIES|DESCRIPTION|LAST-MODIFIED)/ && type { next; } # skip for now, we will write updated fields at the end +/^ / && drop { next; } # drop this folded line +/^X-ALT-DESC/ && type { drop = 1; next; } # drop this alternative description +/^(DUE|SUMMARY|CATEGORIES|DESCRIPTION|LAST-MODIFIED)/ && type { drop = 1; next; } # skip for now, we will write updated fields at the end + { drop = 0 } # keep everything else /^SEQUENCE/ && type { seq = $2; next; } # store sequence number and skip /^END:/ && type == $2 { seq = seq ? seq + 1 : 1; diff --git a/src/main.sh b/src/main.sh index e27ac8d..5819dc1 100644 --- a/src/main.sh +++ b/src/main.sh @@ -70,6 +70,9 @@ fi # Attachment handling . "sh/attachment.sh" +# Categories handling +. "sh/categories.sh" + while true; do query=$(stripws "$query") selection=$( @@ -81,7 +84,7 @@ while true; do --print-query \ --accept-nth=4 \ --preview="$0 --preview {4}" \ - --expect="ctrl-n,ctrl-alt-d,alt-v,ctrl-a" \ + --expect="ctrl-n,ctrl-alt-d,alt-v,ctrl-a,ctrl-t" \ --bind="ctrl-r:reload($0 --reload)" \ --bind="ctrl-x:reload($0 --reload --toggle-completed {4})" \ --bind="alt-up:reload($0 --reload --change-priority '+1' {4})" \ @@ -91,7 +94,7 @@ while true; do --bind="alt-2:change-query(🗒️)" \ --bind="alt-3:change-query(✅ | 🔲)" \ --bind='focus:transform:[ {3} = "VTODO" ] && echo "rebind(ctrl-x)+rebind(alt-up)+rebind(alt-down)" || echo "unbind(ctrl-x)+unbind(alt-up)+unbind(alt-down)"' \ - --bind="ctrl-s:execute($SYNC_CMD; [ -n \"${GIT:-}\" ] && ${GIT:-} commit -am 'Synchronized'; printf 'Press to continue.'; read -r tmp)" || + --bind="ctrl-s:execute($SYNC_CMD; [ -n \"${GIT:-}\" ] && ${GIT:-echo} add -A; ${GIT:-echo} commit -am 'Synchronized'; printf 'Press to continue.'; read -r tmp)" || true ) @@ -120,6 +123,9 @@ while true; do "ctrl-a") __attachment_view "$file" ;; + "ctrl-t") + query="'$(__select_category)'" + ;; "") __edit "$file" ;; diff --git a/src/sh/categories.sh b/src/sh/categories.sh new file mode 100644 index 0000000..2c6b84c --- /dev/null +++ b/src/sh/categories.sh @@ -0,0 +1,17 @@ +# List all categories and lest user select +__select_category() { + find "$ROOT" -type f -name "*.ics" -print0 | + xargs -0 -P 0 \ + awk -v field="CATEGORIES" -v format="csv" "$AWK_GET" | + tr ',' '\n' | + sort | + uniq | + grep '.' | + $FZF --prompt="Select category> " \ + --no-sort \ + --tac \ + --margin="30%,30%" \ + --border=bold \ + --border-label="Categories" || + true +} diff --git a/src/sh/icalendar.sh b/src/sh/icalendar.sh index 6564096..51b28cc 100644 --- a/src/sh/icalendar.sh +++ b/src/sh/icalendar.sh @@ -47,8 +47,8 @@ __edit() { echo "::: <| $due" >"$tmpmd" fi { - echo "# $(awk -v field="SUMMARY" "$AWK_GET" "$file" | tr '\n' ' ')" - echo "> $(awk -v field="CATEGORIES" -v format="csv" "$AWK_GET" "$file" | tr '\n' ' ')" + echo "# $(awk -v field="SUMMARY" -v oneline=1 "$AWK_GET" "$file")" + echo "> $(awk -v field="CATEGORIES" -v format="csv" -v oneline=1 "$AWK_GET" "$file")" echo "" awk -v field="DESCRIPTION" "$AWK_GET" "$file" } >>"$tmpmd"