Compare commits
25 Commits
local
...
caec86c5a0
Author | SHA1 | Date | |
---|---|---|---|
caec86c5a0 | |||
83beaa3ad5 | |||
ee02a7647b | |||
bcbd2a9077 | |||
0b8066923b | |||
06020740cc | |||
903c870dba | |||
4a17512819 | |||
16193b5554 | |||
e09c38ee29 | |||
7ed2df2399 | |||
23cbe26d94 | |||
13aebae71f | |||
93317350f1 | |||
e67fcca02c | |||
735665bb92 | |||
0ffa57373a | |||
6d8520a016 | |||
ff898c84c8 | |||
dc88d5a965 | |||
cdc008e361 | |||
7549acb20c | |||
aee1a1bf24 | |||
4ebcbe36e3 | |||
acc231027b |
96
README.md
96
README.md
@@ -1,4 +1,7 @@
|
||||
A [fzf](https://github.com/junegunn/fzf)-based **calendar** application with CalDav support.
|
||||
If you are interested in this, then you may also be interested in the
|
||||
corresponding journaling application
|
||||
[fzf-vjour](https://github.com/baumea/fzf-vjour).
|
||||
|
||||
Description and Use Case
|
||||
------------------------
|
||||
@@ -60,37 +63,78 @@ item_types = ["VEVENT"]
|
||||
...
|
||||
```
|
||||
|
||||
Here is the complete list of configuration options:
|
||||
|
||||
```
|
||||
### ROOT: Directory containing the collections
|
||||
### COLLECTION_LABELS: Mappings between collections and labels
|
||||
### SYNC_CMD (optional): Synchronization command
|
||||
### DAY_START (optional): Hour of start of the day (defaults to 8)
|
||||
### DAY_END (optional): Hour of end of the day (defaults to 18)
|
||||
### EDITOR (optional): Your favorite editor, is usually already exported
|
||||
### TZ (optional): Your favorite timezone, usually system's choice
|
||||
### LC_TIME (optional): Your favorite locale for date and time
|
||||
### ZI_DIR (optional): Location of tzdata, defaults to /usr/share/zoneinfo
|
||||
```
|
||||
|
||||
Usage
|
||||
-----
|
||||
Use the default `fzf` keys to navigate your calendar entries, e.g., `ctrl-j`
|
||||
and `ctrl-k` for going down/up in the list.
|
||||
After starting `fzf-vcal`, you are presented with a view on the current week.
|
||||
You can navigate that week using `j` and `h` for going down and up.
|
||||
Hit `<enter>` on any day, and you will see all entries for that date, including
|
||||
previews. In both, the week and day views, you can add entries by hitting
|
||||
`ctrl-n`.
|
||||
|
||||
Here is the list of available keybindings:
|
||||
| Key | View | Action |
|
||||
| --- | ---- | ------ |
|
||||
| `enter` | week view | Switch to day view |
|
||||
| `ctrl-n` | week view | Make a new entry |
|
||||
| any letter | week view | Search in the list of all entries |
|
||||
| `backspace` on empty query | week view | Undo search |
|
||||
| `ctrl-u` | week view | Go back one week |
|
||||
| `ctrl-d` | week view | Go forth one week |
|
||||
| `ctrl-alt-u` | week view | Go back one month |
|
||||
| `ctrl-alt-d` | week view | Go forth one month |
|
||||
| `ctrl-s` | week view | Run the synchronization command |
|
||||
| `ctrl-l` | week view | Go to current week |
|
||||
| `ctrl-g` | week view | Goto date |
|
||||
| `enter` | day view | Open selected calendar entry in your favorite `$EDITOR` |
|
||||
| `ctrl-n` | day view | Make a new entry |
|
||||
| `esc`, `backspace` or `q` | day view | Go back to week view |
|
||||
| `ctrl-s` | day view | Run the synchronization command |
|
||||
| `ctrl-alt-d` | day view | Delete selected entry |
|
||||
| `j` | day view | Scroll down in preview window |
|
||||
| `k` | day view | Scroll up in preview window |
|
||||
| `w` | day view | Toggle line wrap in preview window ||
|
||||
Here is the list of all available keybindings:
|
||||
|
||||
### Week view
|
||||
|
||||
| Key | Action |
|
||||
| --- | ------ |
|
||||
| `q` | quit |
|
||||
| `enter` | open day |
|
||||
| `j` | down |
|
||||
| `k` | up |
|
||||
| `l` | go to next week |
|
||||
| `h` | go to previous week |
|
||||
| `ctrl-l` | go to next month |
|
||||
| `ctrl-h` | go to previous month |
|
||||
| `alt-l` | go to next year |
|
||||
| `alt-h` | go to previous year |
|
||||
| `ctrl-r` | reload and go to week that contains `today` |
|
||||
| `ctrl-g` | interactively go to specified week |
|
||||
| `ctrl-t` | set timezon |
|
||||
| `ctrl-s` | synchronize |
|
||||
| `ctrl-n` | add new entry |
|
||||
| `\` | search all appointment s|
|
||||
|
||||
### Day view
|
||||
|
||||
| Key | Action |
|
||||
| --- | ------ |
|
||||
| `enter` | edit appointment |
|
||||
| `j` | down |
|
||||
| `k` | up |
|
||||
| `l` | go to next day |
|
||||
| `h` | go to previous day |
|
||||
| `ctrl-l` | go to next week |
|
||||
| `ctrl-h` | go to previous week |
|
||||
| `alt-l` | go to next month |
|
||||
| `alt-h` | go to previous month |
|
||||
| `ctrl-r` | reload and go to `today` |
|
||||
| `ctrl-g` | interactively go to specified day |
|
||||
| `ctrl-t` | set timezon |
|
||||
| `ctrl-s` | synchronize |
|
||||
| `ctrl-n` | add new entry |
|
||||
| `ctrl-alt-d` | delete entry |
|
||||
| `w` | toggle line wrap in preview |
|
||||
| `ctrl-d` | down in preview |
|
||||
| `ctrl-u` | up in preview |
|
||||
| `alt-v` | view raw iCalendar file |
|
||||
| `esc` | return to week view, you can also do this with `q` or `backspace` |
|
||||
|
||||
|
||||
### There is more
|
||||
|
||||
You may also invoke the script with `--help` to see further command-line options.
|
||||
|
||||
@@ -98,6 +142,10 @@ Also, you may set `LC_TIME` to your preferred language, and `TZ` to your
|
||||
preferred timezone. The latter is in particular helpful if you want to take a
|
||||
look at your calendar relative to being in another timezone.
|
||||
|
||||
Git support
|
||||
-----------
|
||||
You can track your events with `git` by simply running `fzf-vcal --git-init`.
|
||||
|
||||
License
|
||||
-------
|
||||
This project is licensed under the [MIT License](./LICENSE).
|
||||
|
98
src/awk/approx.awk
Normal file
98
src/awk/approx.awk
Normal file
@@ -0,0 +1,98 @@
|
||||
## src/awk/approx.awk
|
||||
## Generate single-line approximate information for every iCalendar argument.
|
||||
##
|
||||
## @assign collection_labels: See configuration of the current program.
|
||||
|
||||
# Functions
|
||||
|
||||
# Time-zone aware parsing of the date/date-time entry at the current record.
|
||||
#
|
||||
# @local variables: dt
|
||||
# @return: date or date-time string that can be used in date (1)
|
||||
function parse( dt) {
|
||||
# Get timezone information
|
||||
for (i=2; i<NF-1; i+=2) {
|
||||
if ($i == "TZID") {
|
||||
dt = "TZ=\"" $(i+1) "\" "
|
||||
break
|
||||
}
|
||||
}
|
||||
# Get date/date-time
|
||||
return length($NF) == 8 ?
|
||||
dt $NF :
|
||||
dt gensub(/^([0-9]{8})T([0-9]{2})([0-9]{2})([0-9]{2})(Z)?$/, "\\1 \\2:\\3:\\4\\5", "g", $NF)
|
||||
}
|
||||
|
||||
# Map iCalendar duration specification into the format to be used in date (1).
|
||||
#
|
||||
# @local variables: dt, dta, i, n, a, seps
|
||||
# @input duration: iCalendar duration string
|
||||
# @return: relative-date/date-time specification to be used in date (1)
|
||||
function parse_duration(duration, dt, dta, i, n, a, seps) {
|
||||
n = split(duration, a, /[PTWHMSD]/, seps)
|
||||
for (i=2; i<=n; i++) {
|
||||
if(seps[i] == "W") dta["weeks"] = a[i]
|
||||
if(seps[i] == "H") dta["hours"] = a[i]
|
||||
if(seps[i] == "M") dta["minutes"] = a[i]
|
||||
if(seps[i] == "S") dta["seconds"] = a[i]
|
||||
if(seps[i] == "D") dta["days"] = a[i]
|
||||
}
|
||||
dt = a[1] ? a[1] : "+"
|
||||
for (i in dta)
|
||||
dt = dt " " dta[i] " " i
|
||||
return dt
|
||||
}
|
||||
|
||||
# Get relative file path.
|
||||
#
|
||||
# @local variables: n, a
|
||||
# @input path: Path to file
|
||||
# @return: File path of depth 1
|
||||
function fn(path, n, a) {
|
||||
n = split(path, a, "/")
|
||||
return a[n-1] "/" a[n]
|
||||
}
|
||||
|
||||
# Generate title string that will be displayed to user. Here, the start date
|
||||
# gets a monthly resolution.
|
||||
#
|
||||
# @input start: Parsed content of DTSTART field
|
||||
# @input summary: Content of SUMMARY field
|
||||
# @return: colorized single-line title string
|
||||
function title(start, summary) {
|
||||
summary = substr(summary, index(summary, ":") + 1)
|
||||
gsub("\\\\n", " ", summary)
|
||||
gsub("\\\\N", " ", summary)
|
||||
gsub("\\\\,", ",", summary)
|
||||
gsub("\\\\;", ";", summary)
|
||||
gsub("\\\\\\\\", "\\", summary)
|
||||
gsub("\\|", ":", summary) # we use "|" as delimiter
|
||||
depth = split(FILENAME, path, "/")
|
||||
collection = depth > 1 ? path[depth-1] : ""
|
||||
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
|
||||
}
|
||||
|
||||
# AWK program
|
||||
BEGIN {
|
||||
FS="[:;=]"
|
||||
OFS="|"
|
||||
split(collection_labels, mapping, ";")
|
||||
for (map in mapping)
|
||||
{
|
||||
split(mapping[map], m, "=")
|
||||
collection2label[m[1]] = m[2]
|
||||
}
|
||||
# Colors
|
||||
FAINT = "\033[2m"
|
||||
OFF = "\033[m"
|
||||
}
|
||||
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 }
|
||||
/^DTSTART/ && inside { start = parse() }
|
||||
/^DTEND/ && inside { end = parse() }
|
||||
/^DURATION/ && inside { end = parse_duration($NF); dur = 1 }
|
||||
/^[^ ]/ && rs { rs = 0 }
|
||||
/^ / && rs { summary = summary substr($0, 2) }
|
||||
/^SUMMARY/ && inside { rs = 1; summary = $0 }
|
||||
/^BEGIN:VEVENT/ { inside = 1 }
|
@@ -1,3 +1,9 @@
|
||||
## src/awk/calannot.awk
|
||||
## Annotate monthly calendar
|
||||
##
|
||||
## @assign cur: Day-of-month to mark as `today`
|
||||
## @assign day: Day-of-month to highlight
|
||||
|
||||
BEGIN {
|
||||
BLACK = "\033[1;30m"
|
||||
GREEN = "\033[1;32m"
|
23
src/awk/calshift.awk
Normal file
23
src/awk/calshift.awk
Normal file
@@ -0,0 +1,23 @@
|
||||
## src/awk/calshift.awk
|
||||
## Rearrange days of a monthly output from cal (1), such that Monday is the
|
||||
## first day of the week.
|
||||
|
||||
BEGIN {
|
||||
ORS = ""
|
||||
W3 = " "
|
||||
W17 = W3 W3 W3 W3 W3 " "
|
||||
}
|
||||
NR == 1 { i++; print $0 "\n"; next }
|
||||
NR == 2 { i++; print substr($0, 4, 17) " " substr($0, 1, 3) " \n"; next }
|
||||
NR == 3 && /^ 1/ { print W17; }
|
||||
NR == 3 && /^ / { print substr($0, 4, 17); next }
|
||||
/[0-9]/ {
|
||||
i++
|
||||
print " " substr($0, 1, 3) " \n" substr($0, 4, 17)
|
||||
}
|
||||
END {
|
||||
i++
|
||||
print " " W3 " \n"
|
||||
for (i; i<8; i++)
|
||||
print " " W17 W3 " \n"
|
||||
}
|
@@ -1,26 +1,69 @@
|
||||
# 11:00|13:00|1748422800|1748430000|fpath|desc...
|
||||
# 00:00|00:00|1748296800|1748383200|fpath|desc...
|
||||
function allday(desc) {
|
||||
return ITALIC FAINT " (allday) " OFF desc
|
||||
## src/awk/dayview.awk
|
||||
## Generate the view of a day from lines of the form
|
||||
## ```
|
||||
## <start_date>|<end_date>|<start_time>|<end_time>|<file_path>|<collection>|<description>
|
||||
## ```.
|
||||
##
|
||||
## @assign today: Date of `today` in the format %D (%m/%d/%y)
|
||||
## @assign daystart: Hour of start of the day
|
||||
## @assign dayend: Hour of end of the day
|
||||
|
||||
# Functions
|
||||
|
||||
# Return line for all-day event.
|
||||
#
|
||||
# @input collection: Collection symbol
|
||||
# @input desc: Event description
|
||||
# @return: Single-line string
|
||||
function allday(collection, desc) {
|
||||
return collection " " ITALIC FAINT " (allday) " OFF desc
|
||||
}
|
||||
function endstoday(stop, desc) {
|
||||
return CYAN " -- " stop OFF ": " desc
|
||||
|
||||
# Return line for multi-day event, or event that starts at midnight, which ends today.
|
||||
#
|
||||
# @input stop: Time at which the event ends
|
||||
# @input collection: Collection symbol
|
||||
# @input desc: Event description
|
||||
# @return: Single-line string
|
||||
function endstoday(stop, collection, desc) {
|
||||
return collection " " CYAN " -- " stop OFF ": " desc
|
||||
}
|
||||
function slice(start, stop, desc) {
|
||||
|
||||
# Return line for event that starts sometime today.
|
||||
#
|
||||
# @input start: Time at which the event starts
|
||||
# @input stop: Time at which the event ends
|
||||
# @input collection: Collection symbol
|
||||
# @input desc: Event description
|
||||
# @return: Single-line string
|
||||
function slice(start, stop, collection, desc) {
|
||||
if (stop == "00:00")
|
||||
return CYAN start " -- " OFF ": " desc
|
||||
return collection " " CYAN start " -- " OFF ": " desc
|
||||
else
|
||||
return CYAN start OFF " -- " CYAN stop OFF ": " desc
|
||||
return collection " " CYAN start OFF " -- " CYAN stop OFF ": " desc
|
||||
}
|
||||
|
||||
# Print line for a single hour entry.
|
||||
#
|
||||
# @input hour: Hour of the entry
|
||||
function hrline(hour) {
|
||||
hour = hour < 10 ? "0"hour : hour
|
||||
print hour, "", "", "", FAINT hour ":00 ----------------------" OFF
|
||||
print today, hour, "", "", "", " " FAINT hour ":00 ----------------------" OFF
|
||||
}
|
||||
|
||||
# Print lines for hour entries before an event that starts at `start` and stops
|
||||
# at `stop`.
|
||||
#
|
||||
# @local variables: starth, stoph, tmp, i
|
||||
# @input start: Time at which the event starts
|
||||
# @input stop: Time at which the event ends
|
||||
# @input h: Last event-free hour
|
||||
# @return: Hour of now last event-free hour
|
||||
function hrlines(start, stop, h, starth, stoph, tmp, i) {
|
||||
starth = substr(start, 1, 2)
|
||||
stoph = substr(stop, 1, 2)
|
||||
tmp = substr(start, 4, 2) == "00" ? 0 : 1
|
||||
for (i=h; i < starth + tmp; i++)
|
||||
for (i=h; i < starth + tmp && i < dayend; i++)
|
||||
hrline(i)
|
||||
tmp = substr(stop, 4, 2) == "00" ? 0 : 1
|
||||
if (stoph + tmp < daystart)
|
||||
@@ -28,23 +71,20 @@ function hrlines(start, stop, h, starth, stoph, tmp, i) {
|
||||
else
|
||||
return stoph + tmp
|
||||
}
|
||||
|
||||
# AWK program
|
||||
BEGIN {
|
||||
FS = "|"
|
||||
GREEN = "\033[1;32m"
|
||||
RED = "\033[1;31m"
|
||||
WHITE = "\033[1;97m"
|
||||
CYAN = "\033[1;36m"
|
||||
ITALIC = "\033[3m"
|
||||
FAINT = "\033[2m"
|
||||
OFF = "\033[m"
|
||||
OFS = "|"
|
||||
}
|
||||
$1 == "00:00" && $2 == "00:00" { print $1, $3, $4, $5, allday($6); next }
|
||||
$1 == "00:00" { print $1, $3, $4, $5, endstoday($2, $6); next }
|
||||
$1 == "00:00" && $2 == "00:00" { print today, $1, $3, $4, $5, allday($6, $7); next }
|
||||
$1 == "00:00" { print today, $1, $3, $4, $5, endstoday($2, $6, $7); next }
|
||||
$1 ~ /^[0-9]{2}:[0-9]{2}$/ {
|
||||
daystart = hrlines($1, $2, daystart, starth, stoph, tmp, i)
|
||||
print $1, $3, $4, $5, slice($1, $2, $6)
|
||||
}
|
||||
END {
|
||||
hrlines(dayend":00", 0, daystart, starth, stoph, tmp, i)
|
||||
daystart = hrlines($1, $2, daystart)
|
||||
print today, $1, $3, $4, $5, slice($1, $2, $6, $7)
|
||||
}
|
||||
END { hrlines(dayend":00", 0, daystart) }
|
||||
|
@@ -1,18 +1,23 @@
|
||||
# print content of field `field`
|
||||
BEGIN { FS = ":"; regex = "^" field; }
|
||||
## src/awk/get.awk
|
||||
## Print content of a field of an iCalendar file.
|
||||
##
|
||||
## @assign field: Field name
|
||||
|
||||
# AWK program
|
||||
BEGIN { FS = ":"; regex = "^" field }
|
||||
/^BEGIN:VEVENT$/ { inside = 1 }
|
||||
/^END:VEVENT$/ { exit }
|
||||
$0 ~ regex { content = $0; next; }
|
||||
/^ / && content { content = content substr($0, 2); next; }
|
||||
$0 ~ regex { content = $0; next }
|
||||
/^ / && content { content = content substr($0, 2); next }
|
||||
/^[^ ]/ && content { exit }
|
||||
END {
|
||||
if (!inside) { exit }
|
||||
# Process content line
|
||||
content = substr(content, index(content, ":") + 1);
|
||||
gsub("\\\\n", "\n", content);
|
||||
gsub("\\\\N", "\n", content);
|
||||
gsub("\\\\,", ",", content);
|
||||
gsub("\\\\;", ";", content);
|
||||
gsub("\\\\\\\\", "\\", content);
|
||||
print content;
|
||||
content = substr(content, index(content, ":") + 1)
|
||||
gsub("\\\\n", "\n", content)
|
||||
gsub("\\\\N", "\n", content)
|
||||
gsub("\\\\,", ",", content)
|
||||
gsub("\\\\;", ";", content)
|
||||
gsub("\\\\\\\\", "\\", content)
|
||||
print content
|
||||
}
|
||||
|
@@ -1,79 +0,0 @@
|
||||
function parse( dt) {
|
||||
# Get timezone information
|
||||
dt = "";
|
||||
for (i=2; i<NF-1; i+=2) {
|
||||
if ($i == "TZID") {
|
||||
dt = "TZ=\"" $(i+1) "\" ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
# Get date/datetime
|
||||
return length($NF) == 8 ?
|
||||
dt $NF :
|
||||
dt gensub(/^([0-9]{8})T([0-9]{2})([0-9]{2})([0-9]{2})(Z)?$/, "\\1 \\2:\\3:\\4\\5", "g", $NF);
|
||||
}
|
||||
|
||||
function parse_duration( dt, dta, i, n, a, seps) {
|
||||
n = split($NF, a, /[PTWHMSD]/, seps);
|
||||
delete dta;
|
||||
for (i=2; i<=n; i++) {
|
||||
if(seps[i] == "W") dta["weeks"] = a[i];
|
||||
if(seps[i] == "H") dta["hours"] = a[i];
|
||||
if(seps[i] == "M") dta["minutes"] = a[i];
|
||||
if(seps[i] == "S") dta["seconds"] = a[i];
|
||||
if(seps[i] == "D") dta["days"] = a[i];
|
||||
}
|
||||
dt = a[1] ? a[1] : "+";
|
||||
for (i in dta) {
|
||||
dt = dt " " dta[i] " " i;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
function fn(path, n, a) {
|
||||
n = split(path, a, "/");
|
||||
return a[n-1] "/" a[n];
|
||||
}
|
||||
|
||||
function title(start, summary) {
|
||||
summary = substr(summary, index(summary, ":") + 1);
|
||||
#gsub("\\\\n", "\n", summary); # one-liner
|
||||
#gsub("\\\\N", "\n", summary); # one-liner
|
||||
gsub("\\\\n", " ", summary);
|
||||
gsub("\\\\N", " ", summary);
|
||||
gsub("\\\\,", ",", summary);
|
||||
gsub("\\\\;", ";", summary);
|
||||
gsub("\\\\\\\\", "\\", summary);
|
||||
gsub("\\|", ":", summary); # we use "|" as delimiter
|
||||
depth = split(FILENAME, path, "/");
|
||||
collection = depth > 1 ? path[depth-1] : "";
|
||||
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
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
FS="[:;=]";
|
||||
OFS="|"
|
||||
split(collection_labels, mapping, ";");
|
||||
for (map in mapping)
|
||||
{
|
||||
split(mapping[map], m, "=");
|
||||
collection2label[m[1]] = m[2];
|
||||
}
|
||||
# Colors
|
||||
GREEN = "\033[1;32m";
|
||||
RED = "\033[1;31m";
|
||||
WHITE = "\033[1;97m";
|
||||
CYAN = "\033[1;36m";
|
||||
FAINT = "\033[2m";
|
||||
OFF = "\033[m";
|
||||
}
|
||||
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, n, a); nextfile }
|
||||
/^DTSTART/ && inside { start = parse( dt) }
|
||||
/^DTEND/ && inside { end = parse( dt) }
|
||||
/^DURATION/ && inside { end = parse_duration( dt, dta, i, n, a, seps); dur = 1 }
|
||||
/^[^ ]/ && rs { rs = 0 }
|
||||
/^ / && rs { summary = summary substr($0, 2); }
|
||||
/^SUMMARY/ && inside { rs = 1; summary = $0; }
|
||||
/^BEGIN:VEVENT/ { inside = 1 }
|
@@ -1,17 +1,33 @@
|
||||
BEGIN { FS="|"; i=0; dlt = -259200; spw = 604800; }
|
||||
## src/awk/merge.awk
|
||||
## Merge a file that contains pairs of lines for start and end dates of events
|
||||
## with the approximate data file, and group the iCalendar file paths according
|
||||
## to the weeks at which the events take place.
|
||||
|
||||
# AWK program
|
||||
BEGIN { FS="|" }
|
||||
NR == FNR {
|
||||
i = i + 1;
|
||||
from[i] = int(($1 + dlt)/ spw);
|
||||
getline;
|
||||
to[i] = int(($1 + dlt) / spw);
|
||||
i = i + 1
|
||||
from_year[i] = $1
|
||||
from_week[i] = $2
|
||||
getline
|
||||
to_year[i] = $1
|
||||
to_week[i] = $2
|
||||
next
|
||||
} # Load start and end week numbers from first file
|
||||
|
||||
{
|
||||
if (from[FNR] > to[FNR])
|
||||
print "FNR", FNR, ":", from[FNR],"-",to[FNR], " ",$0;
|
||||
for(i=from[FNR]; i<=to[FNR]; i++) {
|
||||
week[i] = week[i] " " $5
|
||||
year_i = from_year[FNR]
|
||||
week_i = from_week[FNR]
|
||||
year_end = to_year[FNR]
|
||||
week_end = to_week[FNR]
|
||||
while(year_i <= year_end && (year_i < year_end || week_i <= week_end)) {
|
||||
label = year_i"|"week_i
|
||||
week[label] = week[label] " " $5
|
||||
week_i++
|
||||
if (week_i > 53) {
|
||||
week_i = 1
|
||||
year_i++
|
||||
}
|
||||
}
|
||||
}
|
||||
END { for (i in week) print i week[i]; }
|
||||
END { for (label in week) print label week[label] }
|
||||
|
141
src/awk/new.awk
141
src/awk/new.awk
@@ -1,95 +1,140 @@
|
||||
## src/awk/new.awk
|
||||
## Generate iCalendar file from markdown description.
|
||||
##
|
||||
## @assign uid: UID to use
|
||||
|
||||
# Functions
|
||||
|
||||
# Escape string to be used as content in iCalendar files.
|
||||
#
|
||||
# @input str: String to escape
|
||||
# @return: Escaped string
|
||||
function escape(str)
|
||||
{
|
||||
gsub("\\\\", "\\\\", str);
|
||||
gsub(";", "\\\\;", str);
|
||||
gsub(",", "\\\\,", str);
|
||||
gsub("\\\\", "\\\\", str)
|
||||
gsub(";", "\\;", str)
|
||||
gsub(",", "\\,", str)
|
||||
return str
|
||||
}
|
||||
|
||||
# Print property with its content and fold according to the iCalendar
|
||||
# specification.
|
||||
#
|
||||
# @local variables: i, s
|
||||
# @input nameparam: Property name with optional parameters
|
||||
# @input content: Escaped content
|
||||
function print_fold(nameparam, content, i, s)
|
||||
{
|
||||
i = 74 - length(nameparam);
|
||||
s = substr(content, 1, i);
|
||||
print nameparam s;
|
||||
s = substr(content, i+1, 73);
|
||||
i = i + 73;
|
||||
i = 74 - length(nameparam)
|
||||
s = substr(content, 1, i)
|
||||
print nameparam s
|
||||
s = substr(content, i+1, 73)
|
||||
i = i + 73
|
||||
while (s)
|
||||
{
|
||||
print " " s;
|
||||
s = substr(content, i+1, 73);
|
||||
i = i + 73;
|
||||
print " " s
|
||||
s = substr(content, i+1, 73)
|
||||
i = i + 73
|
||||
}
|
||||
}
|
||||
|
||||
# AWK program
|
||||
BEGIN {
|
||||
FS=":";
|
||||
zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1);
|
||||
FS=":"
|
||||
zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1)
|
||||
}
|
||||
desc { desc = desc "\\n" $0; next; }
|
||||
desc { desc = desc "\\n" $0; next }
|
||||
{
|
||||
from = substr($0, 1, 6) == "::: |>" ? substr($0, 8) : "";
|
||||
from = substr($0, 1, 6) == "::: |>" ? substr($0, 8) : ""
|
||||
if (!from)
|
||||
exit 1
|
||||
getline
|
||||
to = substr($0, 1, 6) == "::: <|" ? substr($0, 8) : "";
|
||||
to = substr($0, 1, 6) == "::: <|" ? substr($0, 8) : ""
|
||||
if (!to)
|
||||
exit 1
|
||||
getline
|
||||
location = substr($0, 1, 2) == "@ " ? substr($0, 3) : ""
|
||||
if (location) getline
|
||||
summary = substr($0, 1, 2) == "# " ? substr($0, 3) : ""
|
||||
if (!summary)
|
||||
exit 1
|
||||
getline # This line should be empty
|
||||
getline # First line of description
|
||||
desc = $0;
|
||||
next;
|
||||
desc = $0
|
||||
next
|
||||
}
|
||||
END {
|
||||
# Sanitize input
|
||||
# If nanoseconds are not 0, then we assume user enterd "tomorrow" or
|
||||
# If nanoseconds are not 0, then we assume user entered "tomorrow" or
|
||||
# something the like, and we make this a date entry, as opposed to a
|
||||
# date-time entry.
|
||||
from = from ? from : "now"
|
||||
cmd = "date -d \"" from "\" +\"%N\"";
|
||||
# Similarly, if the time is 00:00, we make this a date, as opposed to a
|
||||
# date-time entry.
|
||||
gsub("\"", "\\\"", from)
|
||||
cmd = "date -d \"" from "\" +\"%N\""
|
||||
cmd | getline n
|
||||
close(cmd)
|
||||
n = n + 0
|
||||
cmd = "date -d \"" from "\" +\"%H%M\""
|
||||
cmd | getline t
|
||||
close(cmd)
|
||||
t = t + 0
|
||||
if (t == 0) {
|
||||
if (n != 0 || t == 0) {
|
||||
from_type = "DATE"
|
||||
cmd = "date -d \"" from "\" +\"%Y%m%d\""
|
||||
} else {
|
||||
from_type = "DATE-TIME"
|
||||
cmd = "date -d \"" from "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
|
||||
} else {
|
||||
from_type = "DATE"
|
||||
cmd = "date -d \"" from "\" +\"%Y%m%d\"";
|
||||
}
|
||||
cmd | getline from
|
||||
suc = cmd | getline from
|
||||
close(cmd)
|
||||
if (suc != 1) {
|
||||
exit 1
|
||||
}
|
||||
#
|
||||
to = to ? to : "now"
|
||||
cmd = "date -d \"" to "\" +\"%N\"";
|
||||
gsub("\"", "\\\"", to)
|
||||
cmd = "date -d \"" to "\" +\"%N\""
|
||||
cmd | getline n
|
||||
close(cmd)
|
||||
n = n + 0
|
||||
cmd = "date -d \"" to "\" +\"%H%M\""
|
||||
cmd | getline t
|
||||
close(cmd)
|
||||
t = t + 0
|
||||
if (t == 0) {
|
||||
if (n != 0 || t == 0) {
|
||||
to_type = "DATE"
|
||||
cmd = "date -d \"" to "\" +\"%Y%m%d\""
|
||||
} else {
|
||||
to_type = "DATE-TIME"
|
||||
cmd = "date -d \"" to "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
|
||||
} else {
|
||||
to_type = "DATE"
|
||||
cmd = "date -d \"" to "\" +\"%Y%m%d\"";
|
||||
}
|
||||
cmd | getline to
|
||||
suc = cmd | getline to
|
||||
close(cmd)
|
||||
escape(summary);
|
||||
escape(desc);
|
||||
if (suc != 1) {
|
||||
exit 1
|
||||
}
|
||||
summary = escape(summary)
|
||||
location = escape(location)
|
||||
desc = escape(desc)
|
||||
|
||||
# print ical
|
||||
print "BEGIN:VCALENDAR";
|
||||
print "VERSION:2.0";
|
||||
print "CALSCALE:GREGORIAN";
|
||||
print "PRODID:-//fab//awk//EN";
|
||||
print "BEGIN:VCALENDAR"
|
||||
print "VERSION:2.0"
|
||||
print "CALSCALE:GREGORIAN"
|
||||
print "PRODID:-//fab//awk//EN"
|
||||
print "BEGIN:VEVENT"
|
||||
print "DTSTAMP:" zulu;
|
||||
print "UID:" uid;
|
||||
print "CLASS:PRIVATE";
|
||||
print "CREATED:" zulu;
|
||||
print "SEQUENCE:1";
|
||||
print "LAST-MODIFIED:" zulu;
|
||||
print "STATUS:FINAL";
|
||||
print "DTSTAMP:" zulu
|
||||
print "UID:" uid
|
||||
print "CLASS:PRIVATE"
|
||||
print "CREATED:" zulu
|
||||
print "SEQUENCE:1"
|
||||
print "LAST-MODIFIED:" zulu
|
||||
print "STATUS:VEVENT"
|
||||
print "DTSTART;VALUE=" from_type ":" from
|
||||
print "DTEND;VALUE=" to_type ":" to
|
||||
if (summary) print_fold("SUMMARY:", summary, i, s);
|
||||
if (desc) print_fold("DESCRIPTION:", desc, i, s);
|
||||
if (summary) print_fold("SUMMARY:", summary)
|
||||
if (desc) print_fold("DESCRIPTION:", desc)
|
||||
if (location) print_fold("LOCATION:", location)
|
||||
print "END:VEVENT"
|
||||
print "END:VCALENDAR"
|
||||
}
|
||||
|
@@ -1,46 +1,69 @@
|
||||
## src/awk/parse.awk
|
||||
## Parse iCalendar file and print its key aspects:
|
||||
## ```
|
||||
## <start> <end> <fpath> <collection> <summary>
|
||||
## ```.
|
||||
##
|
||||
## @assign collection_labels: See configuration of the current program.
|
||||
|
||||
# Functions
|
||||
|
||||
# Time-zone aware parsing of the date/date-time entry at the current record.
|
||||
#
|
||||
# @local variables: dt
|
||||
# @return: date or date-time string that can be used in date (1)
|
||||
function parse( dt) {
|
||||
# Get timezone information
|
||||
dt = "";
|
||||
for (i=2; i<NF-1; i+=2) {
|
||||
if ($i == "TZID") {
|
||||
dt = "TZ=\"" $(i+1) "\" ";
|
||||
break;
|
||||
dt = "TZ=\"" $(i+1) "\" "
|
||||
break
|
||||
}
|
||||
}
|
||||
# Get date/datetime
|
||||
# Get date/date-time
|
||||
return length($NF) == 8 ?
|
||||
dt $NF :
|
||||
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", $NF)
|
||||
}
|
||||
|
||||
function parse_duration( dt, dta, i, n, a, seps) {
|
||||
n = split($NF, a, /[PTWHMSD]/, seps);
|
||||
delete dta;
|
||||
# Map iCalendar duration specification into the format to be used in date (1).
|
||||
#
|
||||
# @local variables: dt, dta, i, n, a, seps
|
||||
# @input duration: iCalendar duration string
|
||||
# @return: relative-date/date-time specification to be used in date (1)
|
||||
function parse_duration(duration, dt, dta, i, n, a, seps) {
|
||||
n = split(duration, a, /[PTWHMSD]/, seps)
|
||||
for (i=2; i<=n; i++) {
|
||||
if(seps[i] == "W") dta["weeks"] = a[i];
|
||||
if(seps[i] == "H") dta["hours"] = a[i];
|
||||
if(seps[i] == "M") dta["minutes"] = a[i];
|
||||
if(seps[i] == "S") dta["seconds"] = a[i];
|
||||
if(seps[i] == "D") dta["days"] = a[i];
|
||||
if(seps[i] == "W") dta["weeks"] = a[i]
|
||||
if(seps[i] == "H") dta["hours"] = a[i]
|
||||
if(seps[i] == "M") dta["minutes"] = a[i]
|
||||
if(seps[i] == "S") dta["seconds"] = a[i]
|
||||
if(seps[i] == "D") dta["days"] = a[i]
|
||||
}
|
||||
dt = a[1] ? a[1] : "+";
|
||||
for (i in dta) {
|
||||
dt = dt " " dta[i] " " i;
|
||||
}
|
||||
return dt;
|
||||
dt = a[1] ? a[1] : "+"
|
||||
for (i in dta)
|
||||
dt = dt " " dta[i] " " i
|
||||
return dt
|
||||
}
|
||||
|
||||
function print_data(start, dur, end, summary, cmd, collection) {
|
||||
summary = substr(summary, index(summary, ":") + 1);
|
||||
gsub("\\\\n", " ", summary); # one-liner
|
||||
gsub("\\\\N", " ", summary); # one-liner
|
||||
gsub("\\\\,", ",", summary);
|
||||
gsub("\\\\;", ";", summary);
|
||||
gsub("\\\\\\\\", "\\", summary);
|
||||
depth = split(FILENAME, path, "/");
|
||||
# Print string of parsed data.
|
||||
#
|
||||
# @local variables: cmd, collection, depth, path
|
||||
# @input start: Start time of event
|
||||
# @input dur: Boolean that indicates that `end` specifies a duration
|
||||
# @input end: End time of event, or event duration (see `dur`)
|
||||
# @input summary: Content of SUMMARY field of the event
|
||||
function print_data(start, dur, end, summary, cmd, collection, depth, path) {
|
||||
summary = substr(summary, index(summary, ":") + 1)
|
||||
gsub("\\\\n", " ", summary) # one-liner
|
||||
gsub("\\\\N", " ", summary) # one-liner
|
||||
gsub("\\\\,", ",", summary)
|
||||
gsub("\\\\;", ";", summary)
|
||||
gsub("\\\\\\\\", "\\", summary)
|
||||
depth = split(FILENAME, path, "/")
|
||||
fpath = path[depth-1] "/" path[depth]
|
||||
collection = depth > 1 ? path[depth-1] : "";
|
||||
collection = collection in collection2label ? collection2label[collection] : collection;
|
||||
collection = depth > 1 ? path[depth-1] : ""
|
||||
collection = collection in collection2label ? collection2label[collection] : collection
|
||||
collection = collection2label[path[depth-1]]
|
||||
end = dur ? start " " end : end
|
||||
cmd = "date -d '" start "' +\"%s\""
|
||||
@@ -52,20 +75,21 @@ function print_data(start, dur, end, summary, cmd, collection) {
|
||||
print start, end, fpath, collection, summary
|
||||
}
|
||||
|
||||
# AWK program
|
||||
BEGIN {
|
||||
FS="[:;=]";
|
||||
split(collection_labels, mapping, ";");
|
||||
FS="[:;=]"
|
||||
split(collection_labels, mapping, ";")
|
||||
for (map in mapping)
|
||||
{
|
||||
split(mapping[map], m, "=");
|
||||
collection2label[m[1]] = m[2];
|
||||
split(mapping[map], m, "=")
|
||||
collection2label[m[1]] = m[2]
|
||||
}
|
||||
}
|
||||
/^END:VEVENT/ && inside { print_data(start, dur, end, summary, cmd, collection); exit }
|
||||
/^DTSTART/ && inside { start = parse( dt) }
|
||||
/^DTEND/ && inside { end = parse( dt) }
|
||||
/^DURATION/ && inside { end = parse_duration( dt, dta, i, n, a, seps); dur = 1 }
|
||||
/^END:VEVENT/ && inside { print_data(start, dur, end, summary); exit }
|
||||
/^DTSTART/ && inside { start = parse() }
|
||||
/^DTEND/ && inside { end = parse() }
|
||||
/^DURATION/ && inside { end = parse_duration($NF); dur = 1 }
|
||||
/^[^ ]/ && rs { rs = 0 }
|
||||
/^ / && rs { summary = summary substr($0, 2); }
|
||||
/^SUMMARY/ && inside { rs = 1; summary = $0; }
|
||||
/^ / && rs { summary = summary substr($0, 2) }
|
||||
/^SUMMARY/ && inside { rs = 1; summary = $0 }
|
||||
/^BEGIN:VEVENT/ { inside = 1 }
|
||||
|
33
src/awk/set.awk
Normal file
33
src/awk/set.awk
Normal file
@@ -0,0 +1,33 @@
|
||||
## src/awk/set.awk
|
||||
## Set or replace the content of a specified field in the iCalendar file.
|
||||
##
|
||||
## @assign field: iCalendar field
|
||||
## @assign value: Content to set it to
|
||||
##
|
||||
## LIMITATION: This program does not fold long content lines.
|
||||
|
||||
# Functions
|
||||
|
||||
# Escape string to be used as content.
|
||||
#
|
||||
# @input str: Content string
|
||||
# @return: Escaped string
|
||||
function escape(str)
|
||||
{
|
||||
gsub("\\\\", "\\\\", str)
|
||||
gsub(";", "\\;", str)
|
||||
gsub(",", "\\,", str)
|
||||
return str
|
||||
}
|
||||
|
||||
# AWK program
|
||||
|
||||
BEGIN { FS = "[:;]" }
|
||||
/^BEGIN:VEVENT$/ { inside = 1 }
|
||||
/^END:VEVENT$/ { inside = 0; if (!duplic) print field ":" escape(value) }
|
||||
$1 == field && inside { con = 1; duplic = 1; print field ":" escape(value); next }
|
||||
$1 == field && duplic { con = 1; next }
|
||||
/^ / && con { next }
|
||||
/^ / && con { next }
|
||||
/^[^ ]/ && con { con = 0 }
|
||||
{ print }
|
@@ -1,92 +1,128 @@
|
||||
function getcontent(content_line, prop)
|
||||
{
|
||||
return substr(content_line[prop], index(content_line[prop], ":") + 1);
|
||||
}
|
||||
## src/awk/update.awk
|
||||
## Update iCalendar file from markdown file.
|
||||
|
||||
# Functions
|
||||
|
||||
# Escape string to be used as content in iCalendar files.
|
||||
#
|
||||
# @input str: String to escape
|
||||
# @return: Escaped string
|
||||
function escape(str)
|
||||
{
|
||||
gsub("\\\\", "\\\\", str);
|
||||
gsub(";", "\\\\;", str);
|
||||
gsub(",", "\\\\,", str);
|
||||
gsub("\\\\", "\\\\", str)
|
||||
gsub(";", "\\;", str)
|
||||
gsub(",", "\\,", str)
|
||||
return str
|
||||
}
|
||||
|
||||
# Print property with its content and fold according to the iCalendar
|
||||
# specification.
|
||||
#
|
||||
# @local variables: i, s
|
||||
# @input nameparam: Property name with optional parameters
|
||||
# @input content: Escaped content
|
||||
function print_fold(nameparam, content, i, s)
|
||||
{
|
||||
i = 74 - length(nameparam);
|
||||
s = substr(content, 1, i);
|
||||
print nameparam s;
|
||||
s = substr(content, i+1, 73);
|
||||
i = i + 73;
|
||||
i = 74 - length(nameparam)
|
||||
s = substr(content, 1, i)
|
||||
print nameparam s
|
||||
s = substr(content, i+1, 73)
|
||||
i = i + 73
|
||||
while (s)
|
||||
{
|
||||
print " " s;
|
||||
s = substr(content, i+1, 73);
|
||||
i = i + 73;
|
||||
print " " s
|
||||
s = substr(content, i+1, 73)
|
||||
i = i + 73
|
||||
}
|
||||
}
|
||||
|
||||
# AWK program
|
||||
|
||||
BEGIN {
|
||||
FS=":";
|
||||
zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1);
|
||||
FS=":"
|
||||
zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1)
|
||||
}
|
||||
|
||||
ENDFILE {
|
||||
if (NR == FNR)
|
||||
{
|
||||
# If nanoseconds are not 0, then we assume user enterd "tomorrow" or
|
||||
# If nanoseconds are not 0, then we assume user entered "tomorrow" or
|
||||
# something the like, and we make this a date entry, as opposed to a
|
||||
# date-time entry.
|
||||
from = from ? from : "now"
|
||||
cmd = "date -d \"" from "\" +\"%N\"";
|
||||
gsub("\"", "\\\"", from)
|
||||
cmd = "date -d \"" from "\" +\"%N\""
|
||||
cmd | getline n
|
||||
close(cmd)
|
||||
n = n + 0
|
||||
cmd = "date -d \"" from "\" +\"%H%M\""
|
||||
cmd | getline t
|
||||
close(cmd)
|
||||
t = t + 0
|
||||
if (t == 0) {
|
||||
if (n != 0 || t == 0) {
|
||||
from_type = "DATE"
|
||||
cmd = "date -d \"" from "\" +\"%Y%m%d\""
|
||||
} else {
|
||||
from_type = "DATE-TIME"
|
||||
cmd = "date -d \"" from "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
|
||||
} else {
|
||||
from_type = "DATE"
|
||||
cmd = "date -d \"" from "\" +\"%Y%m%d\"";
|
||||
}
|
||||
cmd | getline from
|
||||
suc = cmd | getline from
|
||||
close(cmd)
|
||||
if (suc != 1) {
|
||||
exit 1
|
||||
}
|
||||
#
|
||||
to = to ? to : "now"
|
||||
cmd = "date -d \"" to "\" +\"%N\"";
|
||||
gsub("\"", "\\\"", to)
|
||||
cmd = "date -d \"" to "\" +\"%N\""
|
||||
cmd | getline n
|
||||
close(cmd)
|
||||
n = n + 0
|
||||
cmd = "date -d \"" to "\" +\"%H%M\""
|
||||
cmd | getline t
|
||||
close(cmd)
|
||||
t = t + 0
|
||||
if (t == 0) {
|
||||
if (n != 0 || t == 0) {
|
||||
to_type = "DATE"
|
||||
cmd = "date -d \"" to "\" +\"%Y%m%d\""
|
||||
} else {
|
||||
to_type = "DATE-TIME"
|
||||
cmd = "date -d \"" to "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
|
||||
} else {
|
||||
to_type = "DATE"
|
||||
cmd = "date -d \"" to "\" +\"%Y%m%d\"";
|
||||
}
|
||||
cmd | getline to
|
||||
suc = cmd | getline to
|
||||
close(cmd)
|
||||
if (suc != 1) {
|
||||
exit 1
|
||||
}
|
||||
summary = escape(summary)
|
||||
location = escape(location)
|
||||
desc = escape(desc)
|
||||
}
|
||||
escape(summary);
|
||||
escape(desc);
|
||||
}
|
||||
|
||||
NR == FNR && desc { desc = desc "\\n" $0; next; }
|
||||
NR == FNR && desc { desc = desc "\\n" $0; next }
|
||||
NR == FNR {
|
||||
from = substr($0, 1, 6) == "::: |>" ? substr($0, 8) : "";
|
||||
from = substr($0, 1, 6) == "::: |>" ? substr($0, 8) : ""
|
||||
if (!from)
|
||||
exit 1
|
||||
getline
|
||||
to = substr($0, 1, 6) == "::: <|" ? substr($0, 8) : "";
|
||||
to = substr($0, 1, 6) == "::: <|" ? substr($0, 8) : ""
|
||||
if (!to)
|
||||
exit 1
|
||||
getline
|
||||
location = substr($0, 1, 2) == "@ " ? substr($0, 3) : ""
|
||||
if (location) getline
|
||||
summary = substr($0, 1, 2) == "# " ? substr($0, 3) : ""
|
||||
if (!summary)
|
||||
exit 1
|
||||
getline # This line should be empty
|
||||
getline # First line of description
|
||||
desc = $0;
|
||||
next;
|
||||
desc = $0
|
||||
next
|
||||
}
|
||||
|
||||
/^BEGIN:VEVENT$/ { inside = 1; print; next }
|
||||
/^X-ALT-DESC/ && inside { next } # drop this alternative description
|
||||
/^ / && inside { next } # drop this folded line (the only content with folded lines will be updated)
|
||||
/^(DTSTART|DTEND|SUMMARY|CATEGORIES|DESCRIPTION|LAST-MODIFIED)/ && inside { next } # skip for now, we will write updated fields at the end
|
||||
/^(DTSTART|DTEND|SUMMARY|LOCATION|CATEGORIES|DESCRIPTION|LAST-MODIFIED)/ && inside { next } # skip for now, we will write updated fields at the end
|
||||
/^SEQUENCE/ && inside { seq = $2; next } # store sequence number and skip
|
||||
/^END:VEVENT$/ {
|
||||
seq = seq ? seq + 1 : 1
|
||||
@@ -94,8 +130,9 @@ NR == FNR {
|
||||
print "LAST-MODIFIED:" zulu
|
||||
print "DTSTART;VALUE=" from_type ":" from
|
||||
print "DTEND;VALUE=" to_type ":" to
|
||||
print_fold("SUMMARY:", summary, i, s)
|
||||
print_fold("DESCRIPTION:", desc, i, s)
|
||||
print_fold("SUMMARY:", summary)
|
||||
print_fold("DESCRIPTION:", desc)
|
||||
print_fold("LOCATION:", location)
|
||||
inside = ""
|
||||
}
|
||||
{ print }
|
||||
|
@@ -1,44 +0,0 @@
|
||||
function parse( dt) {
|
||||
# Get timezone information
|
||||
dt = "";
|
||||
for (i=2; i<NF-1; i+=2) {
|
||||
if ($i == "TZID") {
|
||||
dt = "TZ=\"" $(i+1) "\" ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
# Get date/datetime
|
||||
return length($NF) == 8 ?
|
||||
dt $NF :
|
||||
dt gensub(/^([0-9]{8})T([0-9]{2})([0-9]{2})([0-9]{2})(Z)?$/, "\\1 \\2:\\3:\\4\\5", "g", $NF);
|
||||
}
|
||||
|
||||
function parse_duration( dt, dta, i, n, a, seps) {
|
||||
n = split($NF, a, /[PTWHMSD]/, seps);
|
||||
delete dta;
|
||||
for (i=2; i<=n; i++) {
|
||||
if(seps[i] == "W") dta["weeks"] = a[i];
|
||||
if(seps[i] == "H") dta["hours"] = a[i];
|
||||
if(seps[i] == "M") dta["minutes"] = a[i];
|
||||
if(seps[i] == "S") dta["seconds"] = a[i];
|
||||
if(seps[i] == "D") dta["days"] = a[i];
|
||||
}
|
||||
dt = a[1] ? a[1] : "+";
|
||||
for (i in dta) {
|
||||
dt = dt " " dta[i] " " i;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
function fn(path, n, a) {
|
||||
n = split(path, a, "/");
|
||||
return a[n-1] "/" a[n];
|
||||
}
|
||||
|
||||
BEGIN { FS="[:;=]"; OFS="|" }
|
||||
BEGINFILE { inside = 0; dur = 0; start = "ERROR"; end = "ERROR" }
|
||||
/^END:VEVENT/ { print start, dur ? start " " end : end, fn(FILENAME, n, a); nextfile }
|
||||
/^DTSTART/ && inside { start = parse( dt) }
|
||||
/^DTEND/ && inside { end = parse( dt) }
|
||||
/^DURATION/ && inside { end = parse_duration( dt, dta, i, n, a, seps); dur = 1 }
|
||||
/^BEGIN:VEVENT/ { inside = 1 }
|
@@ -1,23 +1,34 @@
|
||||
## src/awk/weekview.awk
|
||||
## Print view of all appointments of the current week.
|
||||
##
|
||||
## @assign startofweek: Date of first day in the week
|
||||
|
||||
# Functions
|
||||
|
||||
# Compose line that will display a day in the week.
|
||||
#
|
||||
# @return: Single-line string
|
||||
function c() {
|
||||
return CYAN substr($0, index($0, ">") + 1) OFF " " RED "/" OFF
|
||||
}
|
||||
|
||||
# AWK program
|
||||
|
||||
BEGIN {
|
||||
GREEN = "\033[1;32m";
|
||||
RED = "\033[1;31m";
|
||||
WHITE = "\033[1;97m";
|
||||
CYAN = "\033[1;36m";
|
||||
FAINT = "\033[2m";
|
||||
OFF = "\033[m";
|
||||
GREEN = "\033[1;32m"
|
||||
RED = "\033[1;31m"
|
||||
CYAN = "\033[1;36m"
|
||||
OFF = "\033[m"
|
||||
OFS = "|"
|
||||
}
|
||||
/^[0-7] 00:00 -- 00:00/ { dayline = dayline " " c(); next }
|
||||
/^[0-7] 00:00 -- / { dayline = dayline " <--" $4 " " c(); next }
|
||||
/^[0-7] [0-9]{2}:[0-9]{2} -- 00:00/ { dayline = dayline " " $2 "--> " c(); next }
|
||||
/^[0-7] [0-9]{2}:[0-9]{2} -- 00:00/ { dayline = dayline " " $2 "→" c(); next }
|
||||
/^[0-7] [0-9]{2}:[0-9]{2} -- [0-9]{2}:[0-9]{2}/ { dayline = dayline " " $2 " - " $4 " " c(); next }
|
||||
/^[0-7]$/ && dayline { print "+", startofweek " +" $0-1 " days", "", dayline; }
|
||||
/^[0-7]$/ && dayline { print "+", startofweek " +" $0-1 " days", "", dayline }
|
||||
/^[0-7]$/ {
|
||||
cmd = "date -d '" startofweek " +" $0 " days' +\"%a %e %b %Y\"";
|
||||
cmd | getline dayline;
|
||||
close(cmd);
|
||||
cmd = "date -d '" startofweek " +" $0 " days' +\"%a %e %b %Y\""
|
||||
cmd | getline dayline
|
||||
close(cmd)
|
||||
dayline = GREEN dayline ": " OFF
|
||||
}
|
||||
|
1409
src/main.sh
1409
src/main.sh
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user