Compare commits

...

14 Commits

17 changed files with 335 additions and 215 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
fzf-vcal fzf-vcal
fzf-vcal.debug

View File

@@ -1,7 +1,16 @@
## src/awk/approx.awk ## src/awk/approx.awk
##
## Generate single-line approximate information for every iCalendar argument. ## Generate single-line approximate information for every iCalendar argument.
## The fields in each line are separated by "\t"
## The fields are the following:
## 1. "~" (constant, indicating that the lines contains approximate information)
## 2. start (this can be used in date (1))
## 3. end (this can be used in date (1)
## 4. string to display
## 5. filename (collection/name)
## ##
## @assign collection_labels: See configuration of the current program. ## @assign collection_labels: See configuration of the current program.
## @assign style_line: Style for each line
@include "lib/awk/icalendar.awk" @include "lib/awk/icalendar.awk"
@@ -25,18 +34,18 @@ function fn(path, n, a) {
# @return: colorized single-line title string # @return: colorized single-line title string
function title(start, summary) { function title(start, summary) {
summary = getcontent(summary) summary = getcontent(summary)
gsub("\n", " ", summary) # This will be put on a single line gsub("\n", " ", summary) # This will be put on a single line
gsub("\\|", ":", summary) # we use "|" as delimiter gsub("\t", " ", summary) # we use "\t" as delimiter
depth = split(FILENAME, path, "/") depth = split(FILENAME, path, "/")
collection = depth > 1 ? path[depth-1] : "" collection = depth > 1 ? path[depth-1] : ""
collection = collection in collection2label ? collection2label[collection] : collection collection = collection in collection2label ? collection2label[collection] : collection
return FAINT "~ " collection " " gensub(/^[^0-9]*([0-9]{4})([0-9]{2}).*$/, "\\1-\\2", "1", start) " " summary OFF return style_line "~ " collection " " gensub(/^[^0-9]*([0-9]{4})([0-9]{2}).*$/, "\\1-\\2", "1", start) " " summary OFF
} }
# AWK program # AWK program
BEGIN { BEGIN {
FS="[:;=]" FS="[:;=]"
OFS="|" OFS="\t"
split(collection_labels, mapping, ";") split(collection_labels, mapping, ";")
for (map in mapping) for (map in mapping)
{ {
@@ -44,13 +53,12 @@ BEGIN {
collection2label[m[1]] = m[2] collection2label[m[1]] = m[2]
} }
# Colors # Colors
FAINT = "\033[2m"
OFF = "\033[m" OFF = "\033[m"
} }
BEGINFILE { inside = 0; rs = 0; dur = 0; summary = ""; start = "ERROR"; end = "ERROR" } BEGINFILE { inside = 0; rs = 0; dur = 0; summary = ""; start = "ERROR"; end = "ERROR" }
/^END:VEVENT/ { print "~", start, dur ? start " " end : end, title(start, summary), fn(FILENAME); nextfile } /^END:VEVENT/ { print "~", start, dur ? start " " end : end, title(start, summary), fn(FILENAME); nextfile }
/^DTSTART/ && inside { start = parse() } /^DTSTART/ && inside { start = parse_dt(getparam($0), getcontent($0)) }
/^DTEND/ && inside { end = parse() } /^DTEND/ && inside { end = parse_dt(getparam($0), getcontent($0)) }
/^DURATION/ && inside { end = parse_duration($NF); dur = 1 } /^DURATION/ && inside { end = parse_duration($NF); dur = 1 }
/^[^ ]/ && rs { rs = 0 } /^[^ ]/ && rs { rs = 0 }
/^ / && rs { summary = summary substr($0, 2) } /^ / && rs { summary = summary substr($0, 2) }

View File

@@ -3,22 +3,24 @@
## ##
## @assign cur: Day-of-month to mark as `today` ## @assign cur: Day-of-month to mark as `today`
## @assign day: Day-of-month to highlight ## @assign day: Day-of-month to highlight
## @assign style_month: Theme to use for month
## @assign style_weekdays: Theme to use for weekdays
## @assign style_cur: Theme to use for current day
## @assign style_highlight: Theme to use for highlighted day
BEGIN { BEGIN {
BLACK = "\033[1;30m"
GREEN = "\033[1;32m"
RED = "\033[1;31m"
FAINT = "\033[2m"
BOLD = "\033[1m"
BG = "\033[41m"
OFF = "\033[m" OFF = "\033[m"
day = day + 0 day = day + 0
cur = cur + 0 cur = cur + 0
} }
NR == 1 { print GREEN $0 OFF; next } NR == 1 { print style_month $0 OFF; next }
NR == 2 { print FAINT $0 OFF; next } NR == 2 { print style_weekdays $0 OFF; next }
{ {
sub("\\y"cur"\\y", BG BLACK BOLD cur OFF) if (day == cur) {
sub("\\y"day"\\y", RED BOLD day OFF) sub("\\y"cur"\\y", style_highlight style_cur cur OFF)
} else {
sub("\\y"cur"\\y", style_cur cur OFF)
sub("\\y"day"\\y", style_highlight day OFF)
}
print print
} }

View File

@@ -1,12 +1,33 @@
## src/awk/dayview.awk ## src/awk/dayview.awk
## Generate the view of a day from lines of the form ## Take as input (tab-delimited):
## ``` ## 1. s (start time, as HH:MM)
## <start_date>|<end_date>|<start_time>|<end_time>|<file_path>|<collection>|<description> ## 2. e (end time, as HH:MM)
## ```. ## 3. starttime
## 4. endtime
## 5. fpath
## 6. collection
## 7. description
## 8. status
##
## filter out irrelevant lines, and generate the view of a day
## (tab-delimited), including empty hours:
## 1. start date
## 2. start time
## 3. end time
## 4. file path
## 5. collection
## 6. description
## ##
## @assign today: Date of `today` in the format %D (%m/%d/%y) ## @assign today: Date of `today` in the format %D (%m/%d/%y)
## @assign daystart: Hour of start of the day ## @assign daystart: Hour of start of the day
## @assign dayend: Hour of end of the day ## @assign dayend: Hour of end of the day
## @assign style_allday
## @assign style_timerange
## @assign style_confirmed
## @assign style_tentative
## @assign style_cancelled
## @assign style_hour
## @assign style_emptyhour
# Functions # Functions
@@ -15,7 +36,7 @@
# @input status: Event status, one of TENTATIVE, CONFIRMED, CANCELLED # @input status: Event status, one of TENTATIVE, CONFIRMED, CANCELLED
# @return: Color modifier # @return: Color modifier
function color_from_status(status) { function color_from_status(status) {
return status == "CANCELLED" ? STRIKE CYAN : status == "TENTATIVE" ? FAINT CYAN : CYAN return status == "CANCELLED" ? style_cancelled : status == "TENTATIVE" ? style_tentative : style_confirmed
} }
# Return line for all-day event. # Return line for all-day event.
@@ -27,7 +48,7 @@ function color_from_status(status) {
# @return: Single-line string # @return: Single-line string
function allday(collection, desc, status, color) { function allday(collection, desc, status, color) {
color = color_from_status(status) color = color_from_status(status)
return collection " " LIGHT_CYAN ITALIC FAINT " (allday) " OFF color desc OFF return collection " " style_allday color desc OFF
} }
# Return line for multi-day event, or event that starts at midnight, which ends today. # Return line for multi-day event, or event that starts at midnight, which ends today.
@@ -40,7 +61,7 @@ function allday(collection, desc, status, color) {
# @return: Single-line string # @return: Single-line string
function endstoday(stop, collection, desc, status) { function endstoday(stop, collection, desc, status) {
color = color_from_status(status) color = color_from_status(status)
return collection " " LIGHT_CYAN " → " stop ": " OFF color desc OFF return collection " " style_timerange " → " stop ": " OFF color desc OFF
} }
# Return line for event that starts sometime today. # Return line for event that starts sometime today.
@@ -55,9 +76,9 @@ function endstoday(stop, collection, desc, status) {
function slice(start, stop, collection, desc, status) { function slice(start, stop, collection, desc, status) {
color = color_from_status(status) color = color_from_status(status)
if (stop == "00:00") if (stop == "00:00")
return collection " " LIGHT_CYAN start " → " ": " OFF color desc OFF return collection " " style_timerange start " → " ": " OFF color desc OFF
else else
return collection " " LIGHT_CYAN start " " stop ": " OFF color desc OFF return collection " " style_timerange start " " stop ": " OFF color desc OFF
} }
# Print line for a single hour entry. # Print line for a single hour entry.
@@ -65,7 +86,7 @@ function slice(start, stop, collection, desc, status) {
# @input hour: Hour of the entry # @input hour: Hour of the entry
function hrline(hour) { function hrline(hour) {
hour = hour < 10 ? "0"hour : hour hour = hour < 10 ? "0"hour : hour
print today, hour, "", "", "", " " FAINT hour ":00 ----------------------" OFF print today, hour, "", "", "", " " style_hou hour ":00" OFF " " style_emptyhour
} }
# Print lines for hour entries before an event that starts at `start` and stops # Print lines for hour entries before an event that starts at `start` and stops
@@ -91,14 +112,9 @@ function hrlines(start, stop, h, starth, stoph, tmp, i) {
# AWK program # AWK program
BEGIN { BEGIN {
FS = "|" FS = "\t"
LIGHT_CYAN = "\033[1;36m" OFS = "\t"
CYAN = "\033[1;36m"
ITALIC = "\033[3m"
FAINT = "\033[2m"
STRIKE = "\033[9m"
OFF = "\033[m" OFF = "\033[m"
OFS = "|"
} }
$1 == "00:00" && $2 == "00:00" { print today, $1, $3, $4, $5, allday($6, $7, $8); next } $1 == "00:00" && $2 == "00:00" { print today, $1, $3, $4, $5, allday($6, $7, $8); next }
$1 == "00:00" { print today, $1, $3, $4, $5, endstoday($2, $6, $7, $8); next } $1 == "00:00" { print today, $1, $3, $4, $5, endstoday($2, $6, $7, $8); next }

View File

@@ -4,14 +4,16 @@
## to the weeks at which the events take place. ## to the weeks at which the events take place.
# AWK program # AWK program
BEGIN { FS="|" } BEGIN { FS="\t"; OFS="\t" }
NR == FNR { NR == FNR {
i = i + 1 i = i + 1
from_year[i] = $1 split($0, parts, ":")
from_week[i] = $2 from_year[i] = parts[1]
from_week[i] = parts[2]
getline getline
to_year[i] = $1 split($0, parts, ":")
to_week[i] = $2 to_year[i] = parts[1]
to_week[i] = parts[2]
next next
} # Load start and end week numbers from first file } # Load start and end week numbers from first file
@@ -21,8 +23,8 @@ NR == FNR {
year_end = to_year[FNR] year_end = to_year[FNR]
week_end = to_week[FNR] week_end = to_week[FNR]
while(year_i <= year_end && (year_i < year_end || week_i <= week_end)) { while(year_i <= year_end && (year_i < year_end || week_i <= week_end)) {
label = year_i"|"week_i label = year_i ":" week_i ":"
week[label] = week[label] " " $5 week[label] = week[label] ? week[label] " " $5 : $5
week_i++ week_i++
if (week_i > 53) { if (week_i > 53) {
week_i = 1 week_i = 1
@@ -30,4 +32,4 @@ NR == FNR {
} }
} }
} }
END { for (label in week) print label week[label] } END { for (label in week) print label, week[label] }

View File

@@ -3,6 +3,8 @@
## ``` ## ```
## <start> <end> <fpath> <collection> <status> <summary> ## <start> <end> <fpath> <collection> <status> <summary>
## ```. ## ```.
## The output is space delimited.
## Summary may contain spaces, but it's the last in the list.
## ##
## @assign collection_labels: See configuration of the current program. ## @assign collection_labels: See configuration of the current program.
@@ -17,7 +19,8 @@
# @input summary: Content of SUMMARY field of the event # @input summary: Content of SUMMARY field of the event
function print_data(start, dur, end, summary, cmd, collection, depth, path) { function print_data(start, dur, end, summary, cmd, collection, depth, path) {
summary = getcontent(summary) summary = getcontent(summary)
gsub("\n", " ", summary) # This will be put on a single line gsub("\n", " ", summary) # This will be put on a single line
gsub("\t", " ", summary) # Generally, we use tab as delimiter.
depth = split(FILENAME, path, "/") depth = split(FILENAME, path, "/")
fpath = path[depth-1] "/" path[depth] fpath = path[depth-1] "/" path[depth]
collection = depth > 1 ? path[depth-1] : "" collection = depth > 1 ? path[depth-1] : ""
@@ -45,8 +48,8 @@ BEGIN {
} }
} }
/^END:VEVENT/ && inside { print_data(start, dur, end, summary); exit } /^END:VEVENT/ && inside { print_data(start, dur, end, summary); exit }
/^DTSTART/ && inside { start = parse() } /^DTSTART/ && inside { start = parse_dt(getparam($0), getcontent($0)) }
/^DTEND/ && inside { end = parse() } /^DTEND/ && inside { end = parse_dt(getparam($0), getcontent($0)) }
/^DURATION/ && inside { end = parse_duration($NF); dur = 1 } /^DURATION/ && inside { end = parse_duration($NF); dur = 1 }
/^STATUS/ && inside { status = $NF } /^STATUS/ && inside { status = $NF }
/^[^ ]/ && rs { rs = 0 } /^[^ ]/ && rs { rs = 0 }

View File

@@ -1,34 +1,39 @@
## src/awk/weekview.awk ## src/awk/weekview.awk
## Print view of all appointments of the current week. ## Print view of all appointments of the current week.
## Generates view from
## printf "%s\t%s\t%s\t%s\n" "$i" "$s" "$e" "$description"
## ##
## @assign startofweek: Date of first day in the week ## @assign startofweek: Date of first day in the week
## @assign style_day: Style for dates
## @assign style_event_delim: Event delimiter
## @assign style_summary: Style for summary lines
## @assign style_time: Style for times
# Functions # Functions
# Compose line that will display a day in the week. # Compose line that will display a day in the week.
# #
# @input desc: String with a description of the event
# @return: Single-line string # @return: Single-line string
function c() { function c(desc) {
return CYAN substr($0, index($0, ">") + 1) OFF " " RED "/" OFF return style_summary desc OFF " " style_event_delim
} }
# AWK program # AWK program
BEGIN { BEGIN {
GREEN = "\033[1;32m" FS = "\t"
RED = "\033[1;31m" OFS = "\t"
CYAN = "\033[1;36m"
OFF = "\033[m" OFF = "\033[m"
OFS = "|"
} }
/^[0-7] 00:00 -- 00:00/ { dayline = dayline " " c(); next } $2 == "00:00" && $3 == "00:00" { dayline = dayline " " c($4); next }
/^[0-7] 00:00 -- / { dayline = dayline " → " $4 " " c(); next } $2 == "00:00" { dayline = dayline style_time " → " $3 OFF " " c($4); next }
/^[0-7] [0-9]{2}:[0-9]{2} -- 00:00/ { dayline = dayline " " $2 " → " c(); next } $3 == "00:00" { dayline = dayline style_time " " $2 " → " OFF c($4); next }
/^[0-7] [0-9]{2}:[0-9]{2} -- [0-9]{2}:[0-9]{2}/ { dayline = dayline " " $2 " " $4 " " c(); next } NF == 4 { dayline = dayline style_time " " $2 " " $3 OFF " " c($4); next }
/^[0-7]$/ && dayline { print "+", startofweek " +" $0-1 " days", "", dayline } NF == 1 && dayline { print "+", startofweek " +" $1-1 " days", "", dayline }
/^[0-7]$/ { NF == 1 {
cmd = "date -d '" startofweek " +" $0 " days' +\"%a %e %b %Y\"" cmd = "date -d '" startofweek " +" $1 " days' +\"%a %e %b %Y\""
cmd | getline dayline cmd | getline dayline
close(cmd) close(cmd)
dayline = GREEN dayline ": " OFF dayline = style_day dayline ": " OFF
} }

View File

@@ -5,6 +5,7 @@
function escape(str) function escape(str)
{ {
gsub("\\\\", "\\\\", str) gsub("\\\\", "\\\\", str)
gsub("\\n", "\\n", str)
gsub(";", "\\;", str) gsub(";", "\\;", str)
gsub(",", "\\,", str) gsub(",", "\\,", str)
return str return str
@@ -37,7 +38,7 @@ function print_fold(nameparam, content, i, s)
# @input str: String # @input str: String
# @return: Unescaped string # @return: Unescaped string
function unescape(str, i, c, c2, res) { function unescape(str, i, c, c2, res) {
for(i=1; i<=length(str);i++) { for(i = 1; i <= length(str); i++) {
c = substr(str, i, 1) c = substr(str, i, 1)
if (c != "\\") { if (c != "\\") {
res = res c res = res c
@@ -57,6 +58,17 @@ function unescape(str, i, c, c2, res) {
return res return res
} }
# Isolate parameter part of an iCalendar line.
#
# @input str: String
# @return: Parameter part
function getparam(str, i) {
i = index(str, ";")
if (!i)
return ""
return substr(str, i + 1, index(str, ":") - i)
}
# Isolate content part of an iCalendar line, and unescape. # Isolate content part of an iCalendar line, and unescape.
# #
# @input str: String # @input str: String
@@ -65,22 +77,27 @@ function getcontent(str) {
return unescape(substr(str, index(str, ":") + 1)) return unescape(substr(str, index(str, ":") + 1))
} }
# Time-zone aware parsing of the date/date-time entry at the current record. # Time-zone aware parsing of DTSTART or DTEND entries.
# #
# @local variables: dt # @local variables: tz
# @input dt_param: iCalendar DTSTART or DTEND parameter string
# @input dt_content: iCalendar DTSTART or DTEND content string
# @return: date or date-time string that can be used in date (1) # @return: date or date-time string that can be used in date (1)
function parse( dt) { function parse_dt(dt_param, dt_content, tz, a, i, k) {
# Get timezone information if (dt_param) {
for (i=2; i<NF-1; i+=2) { split(dt_param, a, ";")
if ($i == "TZID") { for (i in a) {
dt = "TZ=\"" $(i+1) "\" " k = index(a[i], "=")
break if (substr(a[i], 1, k-1) == "TZID") {
tz = "TZ=\"" substr(a[i], k + 1) "\" "
break
}
} }
} }
# Get date/date-time # Get date/date-time
return length($NF) == 8 ? return length(dt_content) == 8 ?
dt $NF : dt dt_content :
dt gensub(/^([0-9]{8})T([0-9]{2})([0-9]{2})([0-9]{2})(Z)?$/, "\\1 \\2:\\3:\\4\\5", "g", $NF) dt gensub(/^([0-9]{8})T([0-9]{2})([0-9]{2})([0-9]{2})(Z)?$/, "\\1 \\2:\\3:\\4\\5", "g", dt_content)
} }
# Map iCalendar duration specification into the format to be used in date (1). # Map iCalendar duration specification into the format to be used in date (1).

View File

@@ -32,6 +32,9 @@ EOF
exit exit
fi fi
# Configuration
. "sh/config.sh"
# Theme # Theme
. "sh/theme.sh" . "sh/theme.sh"
@@ -50,9 +53,6 @@ fi
# Reloading command-line options # Reloading command-line options
. "sh/clireload.sh" . "sh/clireload.sh"
# Configuration
. "sh/config.sh"
# Access to awk scripts # Access to awk scripts
. "sh/awkscripts.sh" . "sh/awkscripts.sh"
@@ -68,24 +68,6 @@ fi
### Start ### Start
__refresh_data __refresh_data
### Exports
# The preview calls run in subprocesses. These require the following variables:
export ROOT CAT AWK_GET AWK_CALSHIFT AWK_CALANNOT CYAN STRIKE FAINT WHITE ITALIC OFF AWK_ATTACHLS
# The reload commands also run in subprocesses, and use in addition
export COLLECTION_LABELS DAY_START DAY_END AWK_DAYVIEW AWK_WEEKVIEW AWK_PARSE
# as well as the following variables that will be dynamically specified. So, we
# export them in the main loop using the following function.
# __export()
# Re-export dynamical variables to subshells.
__export() {
DISPLAY_DATE=$(date -R -d "$DISPLAY_DATE")
export DISPLAY_DATE WEEKLY_DATA_FILE APPROX_DATA_FILE
if [ -n "${TZ:-}" ]; then
export TZ
fi
}
### ###
### Main loop with the command-line argument ### Main loop with the command-line argument
### --today ### --today
@@ -176,35 +158,39 @@ while true; do
--list-border="top" \ --list-border="top" \
--list-label-pos=3 \ --list-label-pos=3 \
--cycle \ --cycle \
--delimiter='|' \ --delimiter='\t' \
--with-nth='{6}' \ --with-nth='{6}' \
--accept-nth='1,2,3,4,5' \ --accept-nth='1,2,3,4,5' \
--preview="$0 --preview-event {}" \ --preview="$0 --preview-event {}" \
--expect="ctrl-n,ctrl-t,ctrl-g,ctrl-alt-d,esc,backspace,q,alt-v,x,c,a" \ --expect="ctrl-n,ctrl-t,ctrl-g,ctrl-alt-d,esc,backspace,q,alt-v,x,c,a" \
--bind="load:pos(1)+transform( --bind='load:pos(1)+transform(
echo change-border-label:🗓️ \$(date -d {1} +\"%A %e %B %Y\") echo change-border-label:🗓️ $(date -d {1} +"%A %e %B %Y")
)+transform( )+transform(
[ -n \"\${TZ:-}\" ] && echo \"change-list-label:\$WHITE\$ITALIC(\$TZ)\$OFF\" [ -n "${TZ:-}" ] && echo "change-list-label:$STYLE_DV_TZ($TZ)$OFF"
)+transform( )+transform(
[ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview [ -n {5} ] && echo show-preview
)" \ )' \
--bind="start:hide-preview" \ --bind="start:hide-preview" \
--bind="j:down+hide-preview+transform([ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview)" \ --bind="j:down" \
--bind="k:up+hide-preview+transform([ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview)" \ --bind="k:up" \
--bind="ctrl-j:down+hide-preview+transform([ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview)" \ --bind="l:reload:$0 --reload-day {1} '+1 day'" \
--bind="ctrl-k:up+hide-preview+transform([ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview)" \ --bind="h:reload:$0 --reload-day {1} '-1 day'" \
--bind="down:down+hide-preview+transform([ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview)" \ --bind="right:reload:$0 --reload-day {1} '+1 day'" \
--bind="up:up+hide-preview+transform([ -n \"\$(echo {} | cut -d '|' -f 5)\" ] && echo show-preview)" \ --bind="left:reload:$0 --reload-day {1} '-1 day'" \
--bind="l:hide-preview+reload:$0 --reload-day {1} '+1 day'" \ --bind="ctrl-l:reload:$0 --reload-day {1} '+1 week'" \
--bind="h:hide-preview+reload:$0 --reload-day {1} '-1 day'" \ --bind="ctrl-h:reload:$0 --reload-day {1} '-1 week'" \
--bind="right:hide-preview+reload:$0 --reload-day {1} '+1 day'" \ --bind="alt-l:reload:$0 --reload-day {1} '+1 month'" \
--bind="left:hide-preview+reload:$0 --reload-day {1} '-1 day'" \ --bind="alt-h:reload:$0 --reload-day {1} '-1 month'" \
--bind="ctrl-l:hide-preview+reload:$0 --reload-day {1} '+1 week'" \ --bind="ctrl-r:reload:$0 --reload-day today" \
--bind="ctrl-h:hide-preview+reload:$0 --reload-day {1} '-1 week'" \
--bind="alt-l:hide-preview+reload:$0 --reload-day {1} '+1 month'" \
--bind="alt-h:hide-preview+reload:$0 --reload-day {1} '-1 month'" \
--bind="ctrl-r:hide-preview+reload:$0 --reload-day today" \
--bind="ctrl-s:execute($SYNC_CMD ; printf 'Press <enter> to continue.'; read -r tmp)" \ --bind="ctrl-s:execute($SYNC_CMD ; printf 'Press <enter> to continue.'; read -r tmp)" \
--bind='tab:down' \
--bind='shift-tab:up' \
--bind='focus:hide-preview+transform(
[ "$FZF_KEY" = "tab" ] && [ -z {5} ] && [ "$FZF_POS" -lt "$FZF_TOTAL_COUNT" ] && echo down
[ "$FZF_KEY" = "shift-tab" ] && [ -z {5} ] && [ "$FZF_POS" -gt "1" ] && echo up
)+transform(
[ -n {5} ] && echo show-preview
)' \
--bind="w:toggle-preview-wrap" \ --bind="w:toggle-preview-wrap" \
--bind="ctrl-d:preview-down" \ --bind="ctrl-d:preview-down" \
--bind="ctrl-u:preview-up" --bind="ctrl-u:preview-up"
@@ -214,11 +200,11 @@ while true; do
if [ "$line" = "$key" ]; then if [ "$line" = "$key" ]; then
line="" line=""
fi fi
DISPLAY_DATE=$(echo "$line" | cut -d '|' -f 1) DISPLAY_DATE=$(echo "$line" | cut -f 1)
hour=$(echo "$line" | cut -d '|' -f 2) hour=$(echo "$line" | cut -f 2)
start=$(echo "$line" | cut -d '|' -f 3) start=$(echo "$line" | cut -f 3)
end=$(echo "$line" | cut -d '|' -f 4) end=$(echo "$line" | cut -f 4)
fpath=$(echo "$line" | cut -d '|' -f 5 | sed "s/ /|/g") fpath=$(echo "$line" | cut -f 5)
if [ "$key" = "ctrl-n" ]; then if [ "$key" = "ctrl-n" ]; then
if echo "$hour" | grep ":"; then if echo "$hour" | grep ":"; then
hour="$DAY_START" hour="$DAY_START"
@@ -257,7 +243,7 @@ while true; do
--print-query \ --print-query \
--bind="start:hide-input" \ --bind="start:hide-input" \
--bind="ctrl-alt-d:show-input+change-query(ctrl-alt-d)+accept" \ --bind="ctrl-alt-d:show-input+change-query(ctrl-alt-d)+accept" \
--bind="load:transform:[ \"\$FZF_TOTAL_COUNT\" -eq 0 ] && echo 'unbind(enter)+unbind(ctrl-alt-d)'" \ --bind='load:transform:[ "$FZF_TOTAL_COUNT" -eq 0 ] && echo "unbind(enter)+unbind(ctrl-alt-d)"' \
--bind="w:toggle-wrap" \ --bind="w:toggle-wrap" \
--bind="j:down" \ --bind="j:down" \
--bind="k:up" || --bind="k:up" ||
@@ -371,7 +357,7 @@ while true; do
--no-sort \ --no-sort \
--no-hscroll \ --no-hscroll \
--ellipsis="" \ --ellipsis="" \
--delimiter="|" \ --delimiter="\t" \
--with-nth="{4}" \ --with-nth="{4}" \
--accept-nth=1,2 \ --accept-nth=1,2 \
--ansi \ --ansi \
@@ -381,21 +367,21 @@ while true; do
--info=right \ --info=right \
--margin="1" \ --margin="1" \
--info-command="printf \"$(date +"%R %Z")\"; [ -n \"\${TZ:-}\" ] && printf \" (\$TZ)\"" \ --info-command="printf \"$(date +"%R %Z")\"; [ -n \"\${TZ:-}\" ] && printf \" (\$TZ)\"" \
--preview-window=up,7,border-bottom \ --preview-window=up,8,border-bottom \
--preview="$0 --preview-week {}" \ --preview="$0 --preview-week {}" \
--bind="load:pos($DISPLAY_POS)" \ --bind="load:pos($DISPLAY_POS)+unbind(load)" \
--expect="ctrl-n,ctrl-g,ctrl-t" \ --expect="ctrl-n,ctrl-g,ctrl-t" \
--bind="q:abort" \ --bind="q:abort" \
--bind="j:down" \ --bind="j:down" \
--bind="k:up" \ --bind="k:up" \
--bind="l:unbind(load)+reload:$0 --reload-week {2} '+1 week'" \ --bind="l:reload:$0 --reload-week {2} '+1 week'" \
--bind="h:unbind(load)+reload:$0 --reload-week {2} '-1 week'" \ --bind="h:reload:$0 --reload-week {2} '-1 week'" \
--bind="right:unbind(load)+reload:$0 --reload-week {2} '+1 week'" \ --bind="right:reload:$0 --reload-week {2} '+1 week'" \
--bind="left:unbind(load)+reload:$0 --reload-week {2} '-1 week'" \ --bind="left:reload:$0 --reload-week {2} '-1 week'" \
--bind="ctrl-l:unbind(load)+reload:$0 --reload-week {2} '+1 month'" \ --bind="ctrl-l:reload:$0 --reload-week {2} '+1 month'" \
--bind="ctrl-h:unbind(load)+reload:$0 --reload-week {2} '-1 month'" \ --bind="ctrl-h:reload:$0 --reload-week {2} '-1 month'" \
--bind="alt-l:unbind(load)+reload:$0 --reload-week {2} '+1 year'" \ --bind="alt-l:reload:$0 --reload-week {2} '+1 year'" \
--bind="alt-h:unbind(load)+reload:$0 --reload-week {2} '-1 year'" \ --bind="alt-h:reload:$0 --reload-week {2} '-1 year'" \
--bind="ctrl-r:rebind(load)+reload($0 --reload-week today)+show-preview" \ --bind="ctrl-r:rebind(load)+reload($0 --reload-week today)+show-preview" \
--bind="ctrl-s:execute($SYNC_CMD ; printf 'Press <enter> to continue.'; read -r tmp)" \ --bind="ctrl-s:execute($SYNC_CMD ; printf 'Press <enter> to continue.'; read -r tmp)" \
--bind="/:show-input+unbind(q)+unbind(j)+unbind(k)+unbind(l)+unbind(h)+unbind(ctrl-l)+unbind(ctrl-h)+unbind(alt-l)+unbind(alt-h)+unbind(load)+hide-preview+reload:$0 --reload-all" \ --bind="/:show-input+unbind(q)+unbind(j)+unbind(k)+unbind(l)+unbind(h)+unbind(ctrl-l)+unbind(ctrl-h)+unbind(alt-l)+unbind(alt-h)+unbind(load)+hide-preview+reload:$0 --reload-all" \
@@ -408,8 +394,8 @@ while true; do
if [ "$line" = "$key" ]; then if [ "$line" = "$key" ]; then
line="" line=""
fi fi
sign=$(echo "$line" | cut -d '|' -f 1) sign=$(echo "$line" | cut -f 1)
DISPLAY_DATE=$(echo "$line" | cut -d '|' -f 2) DISPLAY_DATE=$(echo "$line" | cut -f 2)
if [ "$key" = "ctrl-n" ]; then if [ "$key" = "ctrl-n" ]; then
if [ "$sign" = "~" ]; then if [ "$sign" = "~" ]; then
DISPLAY_DATE="" DISPLAY_DATE=""

View File

@@ -20,87 +20,102 @@ AWK_APPROX=$(
@@include awk/approx.awk @@include awk/approx.awk
EOF EOF
) )
export AWK_APPROX
AWK_MERGE=$( AWK_MERGE=$(
cat <<'EOF' cat <<'EOF'
@@include awk/merge.awk @@include awk/merge.awk
EOF EOF
) )
export AWK_MERGE
AWK_PARSE=$( AWK_PARSE=$(
cat <<'EOF' cat <<'EOF'
@@include awk/parse.awk @@include awk/parse.awk
EOF EOF
) )
export AWK_PARSE
AWK_WEEKVIEW=$( AWK_WEEKVIEW=$(
cat <<'EOF' cat <<'EOF'
@@include awk/weekview.awk @@include awk/weekview.awk
EOF EOF
) )
export AWK_WEEKVIEW
AWK_DAYVIEW=$( AWK_DAYVIEW=$(
cat <<'EOF' cat <<'EOF'
@@include awk/dayview.awk @@include awk/dayview.awk
EOF EOF
) )
export AWK_DAYVIEW
AWK_GET=$( AWK_GET=$(
cat <<'EOF' cat <<'EOF'
@@include awk/get.awk @@include awk/get.awk
EOF EOF
) )
export AWK_GET
AWK_UPDATE=$( AWK_UPDATE=$(
cat <<'EOF' cat <<'EOF'
@@include awk/update.awk @@include awk/update.awk
EOF EOF
) )
export AWK_UPDATE
AWK_NEW=$( AWK_NEW=$(
cat <<'EOF' cat <<'EOF'
@@include awk/new.awk @@include awk/new.awk
EOF EOF
) )
export AWK_NEW
AWK_CALSHIFT=$( AWK_CALSHIFT=$(
cat <<'EOF' cat <<'EOF'
@@include awk/calshift.awk @@include awk/calshift.awk
EOF EOF
) )
export AWK_CALSHIFT
AWK_CALANNOT=$( AWK_CALANNOT=$(
cat <<'EOF' cat <<'EOF'
@@include awk/calannot.awk @@include awk/calannot.awk
EOF EOF
) )
export AWK_CALANNOT
AWK_SET=$( AWK_SET=$(
cat <<'EOF' cat <<'EOF'
@@include awk/set.awk @@include awk/set.awk
EOF EOF
) )
export AWK_SET
AWK_ATTACHLS=$( AWK_ATTACHLS=$(
cat <<'EOF' cat <<'EOF'
@@include awk/attachls.awk @@include awk/attachls.awk
EOF EOF
) )
export AWK_ATTACHLS
AWK_ATTACHDD=$( AWK_ATTACHDD=$(
cat <<'EOF' cat <<'EOF'
@@include awk/attachdd.awk @@include awk/attachdd.awk
EOF EOF
) )
export AWK_ATTACHDD
AWK_ATTACHRM=$( AWK_ATTACHRM=$(
cat <<'EOF' cat <<'EOF'
@@include awk/attachrm.awk @@include awk/attachrm.awk
EOF EOF
) )
export AWK_ATTACHRM
AWK_ATTACH=$( AWK_ATTACH=$(
cat <<'EOF' cat <<'EOF'
@@include awk/attach.awk @@include awk/attach.awk
EOF EOF
) )
export AWK_ATTACH

View File

@@ -6,10 +6,10 @@
# #
# @input $2: Line from day view containing an event # @input $2: Line from day view containing an event
if [ "${1:-}" = "--preview-event" ]; then if [ "${1:-}" = "--preview-event" ]; then
hour=$(echo "$2" | cut -d '|' -f 2) hour=$(echo "$2" | cut -f 2)
start=$(echo "$2" | cut -d '|' -f 3) start=$(echo "$2" | cut -f 3)
end=$(echo "$2" | cut -d '|' -f 4) end=$(echo "$2" | cut -f 4)
fpath=$(echo "$2" | cut -d '|' -f 5 | sed "s/ /|/g") fpath=$(echo "$2" | cut -f 5)
if [ -n "$hour" ] && [ -n "$fpath" ]; then if [ -n "$hour" ] && [ -n "$fpath" ]; then
fpath="$ROOT/$fpath" fpath="$ROOT/$fpath"
start=$(datetime_str "$start" "%a ") start=$(datetime_str "$start" "%a ")
@@ -21,9 +21,9 @@ if [ "${1:-}" = "--preview-event" ]; then
elif [ "$status" = "CANCELLED" ]; then elif [ "$status" = "CANCELLED" ]; then
symb="❌" symb="❌"
fi fi
echo "📅${symb:-} ${CYAN}$start${OFF}${CYAN}$end${OFF}" echo "📅${symb:-} ${STYLE_EPV_DATETIME}$start${OFF}${STYLE_EPV_DATETIME}$end${OFF}"
if [ -n "${location:-}" ]; then if [ -n "${location:-}" ]; then
echo "📍 ${CYAN}$location${OFF}" echo "📍 ${STYLE_EPV_LOCATION}$location${OFF}"
fi fi
attcnt=$(awk "$AWK_ATTACHLS" "$fpath" | wc -l) attcnt=$(awk "$AWK_ATTACHLS" "$fpath" | wc -l)
if [ "$attcnt" -gt 0 ]; then if [ "$attcnt" -gt 0 ]; then
@@ -39,9 +39,9 @@ fi
# #
# @input $2: Line from week view # @input $2: Line from week view
if [ "${1:-}" = "--preview-week" ]; then if [ "${1:-}" = "--preview-week" ]; then
sign=$(echo "$2" | cut -d '|' -f 1) sign=$(echo "$2" | cut -f 1)
if [ "$sign" = "+" ]; then if [ "$sign" = "+" ]; then
startdate=$(echo "$2" | cut -d '|' -f 2) startdate=$(echo "$2" | cut -f 2)
set -- $(date -d "$startdate" +"%Y %m %d") set -- $(date -d "$startdate" +"%Y %m %d")
year=$1 year=$1
month=$2 month=$2
@@ -88,13 +88,13 @@ if [ "${1:-}" = "--preview-week" ]; then
fi fi
# show # show
( (
cal "$month_pre2" "$year_pre2" | awk "$AWK_CALSHIFT" | awk -v cur="${var_pre2:-}" "$AWK_CALANNOT" cal "$month_pre2" "$year_pre2" | awk "$AWK_CALSHIFT" | awk -v cur="${var_pre2:-}" -v style_month="$STYLE_CALENDAR_MONTH" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" "$AWK_CALANNOT"
cal "$month_pre" "$year_pre" | awk "$AWK_CALSHIFT" | awk -v cur="${var_pre:-}" "$AWK_CALANNOT" cal "$month_pre" "$year_pre" | awk "$AWK_CALSHIFT" | awk -v cur="${var_pre:-}" -v style_month="$STYLE_CALENDAR_MONTH" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" "$AWK_CALANNOT"
cal "$month" "$year" | awk "$AWK_CALSHIFT" | awk -v cur="${var:-}" -v day="$day" "$AWK_CALANNOT" cal "$month" "$year" | awk "$AWK_CALSHIFT" | awk -v cur="${var:-}" -v day="$day" -v style_month="$STYLE_CALENDAR_MONTH" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" "$AWK_CALANNOT"
cal "$month_nex" "$year_nex" | awk "$AWK_CALSHIFT" | awk -v cur="${var_nex:-}" "$AWK_CALANNOT" cal "$month_nex" "$year_nex" | awk "$AWK_CALSHIFT" | awk -v cur="${var_nex:-}" -v style_month="$STYLE_CALENDAR_MONTH" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" "$AWK_CALANNOT"
cal "$month_nex2" "$year_nex2" | awk "$AWK_CALSHIFT" | awk -v cur="${var_nex2:-}" "$AWK_CALANNOT" cal "$month_nex2" "$year_nex2" | awk "$AWK_CALSHIFT" | awk -v cur="${var_nex2:-}" -v style_month="$STYLE_CALENDAR_MONTH" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" "$AWK_CALANNOT"
cal "$month_nex3" "$year_nex3" | awk "$AWK_CALSHIFT" | awk -v cur="${var_nex3:-}" "$AWK_CALANNOT" cal "$month_nex3" "$year_nex3" | awk "$AWK_CALSHIFT" | awk -v cur="${var_nex3:-}" -v style_month="$STYLE_CALENDAR_MONTH" -v style_weekdays="$STYLE_CALENDAR_WEEKDAYS" -v style_cur="$STYLE_CALENDAR_CURRENT_DAY" -v style_highlight="$STYLE_CALENDAR_HL_DAY" "$AWK_CALANNOT"
) | awk '{ l[NR%8] = l[NR%8] " " $0 } END {for (i in l) if (i>0) print l[i] }' ) | awk '{ l[(NR-1)%8] = l[(NR-1)%8] " " $0 } END {for (i in l) print l[i] }'
fi fi
exit exit
fi fi

View File

@@ -20,15 +20,16 @@ if [ -z "${ROOT:-}" ] || [ -z "${COLLECTION_LABELS:-}" ]; then
err "Configuration is incomplete." err "Configuration is incomplete."
exit 1 exit 1
fi fi
SYNC_CMD=${SYNC_CMD:-echo 'Synchronization disabled'} export ROOT COLLECTION_LABELS
DAY_START=${DAY_START:-8} export SYNC_CMD=${SYNC_CMD:-echo 'Synchronization disabled'}
DAY_END=${DAY_END:-18} export DAY_START=${DAY_START:-8}
ZI_DIR=${ZI_DIR:-/usr/share/zoneinfo/posix} export DAY_END=${DAY_END:-18}
export ZI_DIR=${ZI_DIR:-/usr/share/zoneinfo/posix}
if [ ! -d "$ZI_DIR" ]; then if [ ! -d "$ZI_DIR" ]; then
err "Could not determine time-zone information" err "Could not determine time-zone information"
exit 1 exit 1
fi fi
OPEN=${OPEN:-open} export OPEN=${OPEN:-open}
# Check and load required tools # Check and load required tools
# - FZF: Fuzzy finder `fzf`` # - FZF: Fuzzy finder `fzf``
@@ -39,14 +40,14 @@ OPEN=${OPEN:-open}
# The presence of POSIX tools is not checked. # The presence of POSIX tools is not checked.
if command -v "fzf" >/dev/null; then if command -v "fzf" >/dev/null; then
FZF="fzf --black" export FZF="fzf --black"
else else
err "Did not find the command-line fuzzy finder fzf." err "Did not find the command-line fuzzy finder fzf."
exit 1 exit 1
fi fi
if command -v "uuidgen" >/dev/null; then if command -v "uuidgen" >/dev/null; then
UUIDGEN="uuidgen" export UUIDGEN="uuidgen"
else else
err "Did not find the uuidgen command." err "Did not find the uuidgen command."
exit 1 exit 1
@@ -58,8 +59,8 @@ elif command -v "batcat" >/dev/null; then
CAT="batcat" CAT="batcat"
fi fi
CAT=${CAT:+$CAT --color=always --style=numbers --language=md} CAT=${CAT:+$CAT --color=always --style=numbers --language=md}
CAT=${CAT:-cat} export CAT=${CAT:-cat}
if command -v "git" >/dev/null && [ -d "$ROOT/.git" ]; then if command -v "git" >/dev/null && [ -d "$ROOT/.git" ]; then
GIT="git -C $ROOT" export GIT="git -C $ROOT"
fi fi

View File

@@ -12,15 +12,12 @@
# @input $1: Start date/date-time # @input $1: Start date/date-time
# @input $2: End date/date-time # @input $2: End date/date-time
# @input $3: Path to iCalendar file (relative to `$ROOT`) # @input $3: Path to iCalendar file (relative to `$ROOT`)
# @req $AWK_GET: Awk script to extract fields from iCalendar file
# @req $AWK_UPDATE: Awk script to update iCalendar file
# @req $EDITOR: Environment variable of your favorite editor
__edit() { __edit() {
start=$(__datetime_human_machine "$1") start=$(__datetime_human_machine "$1")
end=$(__datetime_human_machine "$2") end=$(__datetime_human_machine "$2")
fpath="$ROOT/$3" fpath="$ROOT/$3"
location=$(awk -v field="LOCATION" "$AWK_GET" "$fpath") location=$(awk -v field="LOCATION" "$AWK_GET" "$fpath" | tr -d "\n")
summary=$(awk -v field="SUMMARY" "$AWK_GET" "$fpath") summary=$(awk -v field="SUMMARY" "$AWK_GET" "$fpath" | tr -d "\n")
description=$(awk -v field="DESCRIPTION" "$AWK_GET" "$fpath") description=$(awk -v field="DESCRIPTION" "$AWK_GET" "$fpath")
filetmp=$(mktemp --suffix='.md') filetmp=$(mktemp --suffix='.md')
printf "::: |> %s\n::: <| %s\n" "$start" "$end" >"$filetmp" printf "::: |> %s\n::: <| %s\n" "$start" "$end" >"$filetmp"
@@ -61,12 +58,6 @@ __edit() {
# If the user specified a malformed date/date-time, we fail. # If the user specified a malformed date/date-time, we fail.
# #
# @input $1 (optional): Date or datetime, defaults to today. # @input $1 (optional): Date or datetime, defaults to today.
# @req $COLLECTION_LABELS: Mapping between collections and lables (see configuration)
# @req $UUIDGEN: `uuidgen` command
# @req $ROOT: Path that contains the collections (see configuration)
# @req $EDITOR: Environment variable of your favorite editor
# @req $AWK_GET: Awk script to extract fields from iCalendar file
# @req $AWK_new: Awk script to generate iCalendar file
__new() { __new() {
collection=$(echo "$COLLECTION_LABELS" | tr ';' '\n' | awk '/./ {print}' | $FZF --margin="30%" --no-info --delimiter='=' --with-nth=2 --accept-nth=1) collection=$(echo "$COLLECTION_LABELS" | tr ';' '\n' | awk '/./ {print}' | $FZF --margin="30%" --no-info --delimiter='=' --with-nth=2 --accept-nth=1)
fpath="" fpath=""
@@ -119,8 +110,6 @@ __new() {
# Delete iCalendar file # Delete iCalendar file
# #
# @input $1: Path to iCalendar file, relative to `$ROOT` # @input $1: Path to iCalendar file, relative to `$ROOT`
# @req $ROOT: Path that contains the collections (see configuration)
# @req $AWK_GET: Awk script to extract fields from iCalendar file
__delete() { __delete() {
fpath="$ROOT/$1" fpath="$ROOT/$1"
summary=$(awk -v field="SUMMARY" "$AWK_GET" "$fpath") summary=$(awk -v field="SUMMARY" "$AWK_GET" "$fpath")
@@ -152,9 +141,6 @@ __delete() {
# #
# @input $1: path to iCalendar file # @input $1: path to iCalendar file
# @input $2: collection name # @input $2: collection name
# @req $ROOT: Path that contains the collections (see configuration)
# @req $UUIDGEN: `uuidgen` command
# @req $AWK_SET: Awk script to set field value
__import_to_collection() { __import_to_collection() {
file="$1" file="$1"
collection="$2" collection="$2"
@@ -175,9 +161,6 @@ __import_to_collection() {
# Set status of appointment to CANCELLED or CONFIRMED (toggle) # Set status of appointment to CANCELLED or CONFIRMED (toggle)
# #
# @input $1: path to iCalendar file # @input $1: path to iCalendar file
# @req $ROOT: Path that contains the collections (see configuration)
# @req $AWK_SET: Awk script to set field value
# @req $AWK_GET: Awk script to extract fields from iCalendar file
__cancel_toggle() { __cancel_toggle() {
fpath="$ROOT/$1" fpath="$ROOT/$1"
status=$(awk -v field="STATUS" "$AWK_GET" "$fpath") status=$(awk -v field="STATUS" "$AWK_GET" "$fpath")
@@ -197,9 +180,6 @@ __cancel_toggle() {
# Toggle status flag: CONFIRMED <-> TENTATIVE # Toggle status flag: CONFIRMED <-> TENTATIVE
# #
# @input $1: path to iCalendar file # @input $1: path to iCalendar file
# @req $ROOT: Path that contains the collections (see configuration)
# @req $AWK_SET: Awk script to set field value
# @req $AWK_GET: Awk script to extract fields from iCalendar file
__tentative_toggle() { __tentative_toggle() {
fpath="$ROOT/$1" fpath="$ROOT/$1"
status=$(awk -v field="STATUS" "$AWK_GET" "$fpath") status=$(awk -v field="STATUS" "$AWK_GET" "$fpath")
@@ -219,9 +199,6 @@ __tentative_toggle() {
# Prepend attachment to iCalendar file # Prepend attachment to iCalendar file
# #
# @input $1: path to iCalendar file # @input $1: path to iCalendar file
# @req $ROOT: Path that contains the collections (see configuration)
# @req $FZF: Fuzzy finder
# @req $AWK_ATTACH: Awk script to add attachment
__add_attachment() { __add_attachment() {
fpath="$ROOT/$1" fpath="$ROOT/$1"
sel=$( sel=$(

View File

@@ -9,14 +9,15 @@ __load_approx_data() {
xargs -0 -P0 \ xargs -0 -P0 \
awk \ awk \
-v collection_labels="$COLLECTION_LABELS" \ -v collection_labels="$COLLECTION_LABELS" \
-v style_line="$STYLE_LV" \
"$AWK_APPROX" "$AWK_APPROX"
} }
# For every relevant week, print associated iCalendar files # For every relevant week, print associated iCalendar files
__load_weeks() { __load_weeks() {
dates=$(awk -F'|' '{ print $2; print $3 }' "$APPROX_DATA_FILE") dates=$(awk -F'\t' '{ print $2; print $3 }' "$APPROX_DATA_FILE")
file_dates=$(mktemp) file_dates=$(mktemp)
echo "$dates" | date --file="/dev/stdin" +"%G|%V" >"$file_dates" echo "$dates" | date --file="/dev/stdin" +"%G:%V:" >"$file_dates"
awk "$AWK_MERGE" "$file_dates" "$APPROX_DATA_FILE" awk "$AWK_MERGE" "$file_dates" "$APPROX_DATA_FILE"
rm "$file_dates" rm "$file_dates"
} }
@@ -27,15 +28,18 @@ __load_weeks() {
# file `$APPROX_DATA_FILE` and the output of `__load_weeks` in the temporary # file `$APPROX_DATA_FILE` and the output of `__load_weeks` in the temporary
# file `@WEEKLY_DATA_FILE`. # file `@WEEKLY_DATA_FILE`.
__refresh_data() { __refresh_data() {
if [ -n "${APPROX_DATA_FILE:-}" ]; then if [ -z "${APPROX_DATA_FILE:-}" ]; then
rm -f "$APPROX_DATA_FILE" APPROX_DATA_FILE=$(mktemp)
trap 'rm -f "$APPROX_DATA_FILE"' EXIT INT
fi fi
if [ -n "${WEEKLY_DATA_FILE:-}" ]; then if [ -z "${WEEKLY_DATA_FILE:-}" ]; then
rm -f "$WEEKLY_DATA_FILE" WEEKLY_DATA_FILE=$(mktemp)
trap 'rm -f "$WEEKLY_DATA_FILE"' EXIT INT
fi fi
APPROX_DATA_FILE=$(mktemp) debug "__refresh_data(): going to load approx data"
__load_approx_data >"$APPROX_DATA_FILE" __load_approx_data >"$APPROX_DATA_FILE"
WEEKLY_DATA_FILE=$(mktemp) debug "__refresh_data(): approx data loaded"
debug "__refresh_data(): going to load weeks"
__load_weeks >"$WEEKLY_DATA_FILE" __load_weeks >"$WEEKLY_DATA_FILE"
trap 'rm -f "$APPROX_DATA_FILE" "$WEEKLY_DATA_FILE"' EXIT INT debug "__refresh_data(): weeks loaded"
} }

View File

@@ -6,6 +6,14 @@ err() {
echo "$1" >/dev/tty echo "$1" >/dev/tty
} }
# debug()
# Pring debug message to fzf-vcal.debug
#
# @input $1: Debug message
debug() {
echo "$(date +"%D %T.%N"): $1" >>"/tmp/fzf-vcal.debug"
}
# Print date or datetime in a human and machine readable form. # Print date or datetime in a human and machine readable form.
# #
# @input $1: Seconds since epoch # @input $1: Seconds since epoch
@@ -25,3 +33,12 @@ __datetime_human_machine() {
__summary_for_commit() { __summary_for_commit() {
awk -v field="SUMMARY" "$AWK_GET" "$1" | tr -c -d "[:alnum:][:blank:]" | head -c 15 awk -v field="SUMMARY" "$AWK_GET" "$1" | tr -c -d "[:alnum:][:blank:]" | head -c 15
} }
# Re-export dynamical variables to subshells.
__export() {
DISPLAY_DATE=$(date -R -d "$DISPLAY_DATE")
export DISPLAY_DATE
if [ -n "${TZ:-}" ]; then
export TZ
fi
}

View File

@@ -1,8 +1,47 @@
# Colors
GREEN="\033[1;32m" GREEN="\033[1;32m"
BLACK="\033[1;30m"
RED="\033[1;31m" RED="\033[1;31m"
WHITE="\033[1;97m" WHITE="\033[1;97m"
CYAN="\033[1;36m" CYAN="\033[1;36m"
LIGHT_CYAN="\033[1;36m"
STRIKE="\033[9m" STRIKE="\033[9m"
ITALIC="\033[3m" ITALIC="\033[3m"
FAINT="\033[2m" FAINT="\033[2m"
OFF="\033[m" BOLD="\033[1m"
BG="\033[41m"
export OFF="\033[m"
# Style
# Calendar
export STYLE_CALENDAR_MONTH="${STYLE_CALENDAR_MONTH:-$GREEN}"
export STYLE_CALENDAR_WEEKDAYS="${STYLE_CALENDAR_WEEKDAYS:-$FAINT}"
export STYLE_CALENDAR_CURRENT_DAY="${STYLE_CALENDAR_CURRENT_DAY:-$BLACK$BG}"
export STYLE_CALENDAR_HL_DAY="${STYLE_CALENDAR_HL_DAY:-$BOLD$RED}"
# Week view
export STYLE_WV_DAY="${STYLE_WV_DAY:-$GREEN}"
export STYLE_WV_EVENT_DELIM="${STYLE_WV_EVENT_DELIM:-$RED / $OFF}"
export STYLE_WV_SUMMARY="${STYLE_WV_SUMMARY:-$CYAN}"
export STYLE_WV_TIME="${STYLE_WV_TIME:-$WHITE}"
export STYLE_WV_CONFIRMED="${STYLE_WV_CONFIRMED:-$CYAN}"
export STYLE_WV_TENTATIVE="${STYLE_WV_TENTATIVE:-$FAINT$CYAN}"
export STYLE_WV_CANCELLED="${STYLE_WV_CANCELLED:-$STRIKE$FAINT$CYAN}"
# List view
export STYLE_LV="${STYLE_LV:-$FAINT}"
# Day view
export STYLE_DV_ALLDAY="${STYLE_DV_ALLDAY:-$LIGHT_CYAN$ITALIC$FAINT (allday) $OFF}"
export STYLE_DV_TIME="${STYLE_DV_TIME:-$LIGHT_CYAN}"
export STYLE_DV_CONFIRMED="${STYLE_DV_CONFIRMED:-$CYAN}"
export STYLE_DV_TENTATIVE="${STYLE_DV_TENTATIVE:-$FAINT$CYAN}"
export STYLE_DV_CANCELLED="${STYLE_DV_CANCELLED:-$STRIKE$FAINT$CYAN}"
export STYLE_DV_HOUR="${STYLE_DV_HOUR:-$FAINT}"
export STYLE_DV_EMPTYHOUR="${STYLE_DV_EMPTYHOUR:-$FAINT----------------------$OFF}"
export STYLE_DV_TZ="$WHITE$ITALIC"
# Event preview
export STYLE_EPV_DATETIME="${STYLE_EPV_DATETIME:-$CYAN}"
export STYLE_EPV_LOCATION="${STYLE_EPV_LOCATION:-$GREEN}"

View File

@@ -3,10 +3,17 @@
# - __view_week # - __view_week
# - __view_all # - __view_all
# This function prints the view for the day specified in `$DISPLAY_DATE`. # This function prints the view for the day specified in `$DISPLAY_DATE`, in
# the tab-delimited format with the fields:
# 1. start date
# 2. start time
# 3. end time
# 4. file path
# 5. collection
# 6. description
__view_day() { __view_day() {
weeknr=$(date -d "$DISPLAY_DATE" +"%G.%V") weeknr=$(date -d "$DISPLAY_DATE" +"%G:%V:")
files=$(grep "^$weeknr\ " "$WEEKLY_DATA_FILE" | cut -d " " -f 2-) files=$(grep "^$weeknr" "$WEEKLY_DATA_FILE" | cut -f 2)
# Find relevant files in list of week files # Find relevant files in list of week files
sef=$({ sef=$({
set -- $files set -- $files
@@ -17,6 +24,7 @@ __view_day() {
"$AWK_PARSE" "$file" "$AWK_PARSE" "$file"
done done
}) })
# $sef holds (space-delimited): <start> <end> <fpath> <collection> <status> <summary>
today=$(date -d "$DISPLAY_DATE" +"%D") today=$(date -d "$DISPLAY_DATE" +"%D")
if [ -n "$sef" ]; then if [ -n "$sef" ]; then
sef=$(echo "$sef" | while IFS= read -r line; do sef=$(echo "$sef" | while IFS= read -r line; do
@@ -25,13 +33,13 @@ __view_day() {
shift shift
endtime="$1" endtime="$1"
shift shift
fpath="$(echo "$1" | sed 's/|/ /g')" # we will use | as delimiter (need to convert back!) fpath="$1" # we will use | as delimiter (need to convert back!)
shift shift
collection="$1" collection="$1"
shift shift
status="$1" status="$1"
shift shift
description="$(echo "$*" | sed 's/|/:/g')" # we will use | as delimiter description="$*"
# #
daystart=$(date -d "$today 00:00:00" +"%s") daystart=$(date -d "$today 00:00:00" +"%s")
dayend=$(date -d "$today 23:59:59" +"%s") dayend=$(date -d "$today 23:59:59" +"%s")
@@ -50,29 +58,41 @@ __view_day() {
else else
continue continue
fi fi
echo "$s|$e|$starttime|$endtime|$fpath|$collection|$description|$status" printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" "$s" "$e" "$starttime" "$endtime" "$fpath" "$collection" "$description" "$status"
done) done)
fi fi
echo "$sef" | sort -n | awk -v today="$today" -v daystart="$DAY_START" -v dayend="$DAY_END" "$AWK_DAYVIEW" echo "$sef" | sort -n | awk \
-v today="$today" \
-v daystart="$DAY_START" \
-v dayend="$DAY_END" \
-v style_allday="$STYLE_DV_ALLDAY" \
-v style_timerange="$STYLE_DV_TIME" \
-v style_confirmed="$STYLE_DV_CONFIRMED" \
-v style_tentative="$STYLE_DV_TENTATIVE" \
-v style_cancelled="$STYLE_DV_CANCELLED" \
-v style_hour="$STYLE_DV_HOUR" \
-v style_emptyhour="$STYLE_DV_EMPTYHOUR" \
"$AWK_DAYVIEW"
} }
# This function prints the view for the week that contains the day specified in `$DISPLAY_DATE`. # This function prints the view for the week that contains the day specified in `$DISPLAY_DATE`.
__view_week() { __view_week() {
weeknr=$(date -d "$DISPLAY_DATE" +"%G.%V") debug "__view_week(): Enter"
files=$(grep "^$weeknr\ " "$WEEKLY_DATA_FILE" | cut -d " " -f 2-) weeknr=$(date -d "$DISPLAY_DATE" +"%G:%V:")
files=$(grep "^$weeknr" "$WEEKLY_DATA_FILE" | cut -f 2)
dayofweek=$(date -d "$DISPLAY_DATE" +"%u") dayofweek=$(date -d "$DISPLAY_DATE" +"%u")
delta=$((1 - dayofweek)) delta=$((1 - dayofweek))
startofweek=$(date -d "$DISPLAY_DATE -$delta days" +"%D") startofweek=$(date -d "$DISPLAY_DATE -$delta days" +"%D")
# loop over files # loop over files
debug "__view_week(): loop over files"
sef=$({ sef=$({
set -- $files printf "%s" "$files" | xargs -d " " -I {} -P0 \
for file in "$@"; do
file="$ROOT/$file"
awk \ awk \
-v collection_labels="$COLLECTION_LABELS" \ -v collection_labels="$COLLECTION_LABELS" \
"$AWK_PARSE" "$file" "$AWK_PARSE" "$ROOT/{}"
done
}) })
debug "__view_week(): loop over files ended"
debug "__view_week(): prepare week view"
if [ -n "$sef" ]; then if [ -n "$sef" ]; then
sef=$(echo "$sef" | while IFS= read -r line; do sef=$(echo "$sef" | while IFS= read -r line; do
set -- $line set -- $line
@@ -87,11 +107,11 @@ __view_week() {
status="$1" status="$1"
shift shift
if [ "$status" = "TENTATIVE" ]; then if [ "$status" = "TENTATIVE" ]; then
symb="$FAINT$CYAN" symb="$STYLE_WV_TENTATIVE"
elif [ "$status" = "CANCELLED" ]; then elif [ "$status" = "CANCELLED" ]; then
symb="$STRIKE" symb="$STYLE_WV_CANCELLED"
else else
symb="" symb="$STYLE_WV_CONFIRMED"
fi fi
description="${symb:-}$*$OFF" description="${symb:-}$*$OFF"
for i in $(seq 0 7); do for i in $(seq 0 7); do
@@ -99,29 +119,36 @@ __view_week() {
dayend=$(date -d "$startofweek +$i days 23:59:59" +"%s") dayend=$(date -d "$startofweek +$i days 23:59:59" +"%s")
if [ "$starttime" -gt "$daystart" ] && [ "$starttime" -lt "$dayend" ]; then if [ "$starttime" -gt "$daystart" ] && [ "$starttime" -lt "$dayend" ]; then
s=$(date -d "@$starttime" +"%H:%M") s=$(date -d "@$starttime" +"%H:%M")
s="$s -"
elif [ "$starttime" -le "$daystart" ] && [ "$endtime" -gt "$daystart" ]; then elif [ "$starttime" -le "$daystart" ] && [ "$endtime" -gt "$daystart" ]; then
s="00:00 -" s="00:00"
else else
continue continue
fi fi
if [ "$endtime" -gt "$daystart" ] && [ "$endtime" -lt "$dayend" ]; then if [ "$endtime" -gt "$daystart" ] && [ "$endtime" -lt "$dayend" ]; then
e=$(date -d "@$endtime" +"%H:%M") e=$(date -d "@$endtime" +"%H:%M")
e="- $e"
elif [ "$endtime" -ge "$dayend" ] && [ "$starttime" -lt "$dayend" ]; then elif [ "$endtime" -ge "$dayend" ] && [ "$starttime" -lt "$dayend" ]; then
e="- 00:00" e="00:00"
else else
continue continue
fi fi
echo "$i $s$e >$description" printf "%s\t%s\t%s\t%s\n" "$i" "$s" "$e" "$description"
done done
done) done)
fi fi
debug "__view_week(): prepare week view ended"
debug "__view_week(): generate week view"
sef=$({ sef=$({
echo "$sef" echo "$sef"
seq 0 7 seq 0 7
} | sort -n) } | sort -n)
echo "$sef" | awk -v startofweek="$startofweek" "$AWK_WEEKVIEW" echo "$sef" | awk \
-v startofweek="$startofweek" \
-v style_day="$STYLE_WV_DAY" \
-v style_event_delim="$STYLE_WV_EVENT_DELIM" \
-v style_summary="$STYLE_WV_SUMMARY" \
-v style_time="$STYLE_WV_TIME" \
"$AWK_WEEKVIEW"
debug "__view_week(): generate week view ended"
} }
# This function prints all entries. # This function prints all entries.