Compare commits

..

22 Commits

Author SHA1 Message Date
bcbd2a9077 feat: non-interactive imports 2025-06-15 21:42:45 +02:00
0b8066923b improvement: Calendar preview: weeks start on Mondays 2025-06-15 21:07:15 +02:00
06020740cc improvements: presentation
- collection label before time
- UTF8 arrow insead of `->`
2025-06-14 23:11:55 +02:00
903c870dba improvement: rearranged keys 2025-06-14 22:30:21 +02:00
4a17512819 bugfix: status was from vjournal not vevent 2025-06-13 23:07:31 +02:00
16193b5554 bug fix: recognize all-day events, improvment: view source with v 2025-06-13 22:39:23 +02:00
e09c38ee29 ctrl-g in dayview 2025-06-13 15:44:11 +02:00
7ed2df2399 feat: git support 2025-06-13 15:31:59 +02:00
23cbe26d94 improvement: week view with ctrl-h and ctrl-l 2025-06-13 14:58:49 +02:00
13aebae71f bug fix: return from dayview 2025-06-13 14:57:17 +02:00
93317350f1 bugfix: cleanup at tend 2025-06-13 14:51:56 +02:00
e67fcca02c feat: import 2025-06-13 14:47:01 +02:00
735665bb92 extended description of configuration 2025-06-13 14:12:29 +02:00
0ffa57373a feat:change tz from within application 2025-06-13 14:07:44 +02:00
6d8520a016 non-recursive, clean 2025-06-13 13:04:35 +02:00
ff898c84c8 feat:location support 2025-06-12 21:47:30 +02:00
dc88d5a965 feat: dayview: jump to next/previous day 2025-06-12 15:22:27 +02:00
cdc008e361 bugfix: corrected week calculation (iso) 2025-06-12 14:57:36 +02:00
7549acb20c bugfix: handle wrong date input in entry creation 2025-06-12 12:44:55 +02:00
aee1a1bf24 improvement: no jump to "day" line in search view 2025-06-12 11:40:47 +02:00
4ebcbe36e3 bugfix: disable up/down limits in search view 2025-06-12 11:39:14 +02:00
acc231027b update readme 2025-06-11 22:27:53 +02:00
11 changed files with 1217 additions and 544 deletions

View File

@@ -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,77 @@ 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 |
| --- | ------ |
| `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 +141,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).

19
src/awk/calshift.awk Normal file
View File

@@ -0,0 +1,19 @@
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"
}

View File

@@ -1,26 +1,25 @@
# 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
# $s|$e|$starttime|$endtime|$fpath|$collection|$description
function allday(collection, desc) {
return collection " " ITALIC FAINT " (allday) " OFF desc
}
function endstoday(stop, desc) {
return CYAN " -- " stop OFF ": " desc
function endstoday(stop, collection, desc) {
return collection " " CYAN " -- " stop OFF ": " desc
}
function slice(start, stop, desc) {
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
}
function hrline(hour) {
hour = hour < 10 ? "0"hour : hour
print hour, "", "", "", FAINT hour ":00 ----------------------" OFF
print today, hour, "", "", "", " " FAINT hour ":00 ----------------------" OFF
}
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)
@@ -39,11 +38,11 @@ BEGIN {
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)
print today, $1, $3, $4, $5, slice($1, $2, $6, $7)
}
END {
hrlines(dayend":00", 0, daystart, starth, stoph, tmp, i)

View File

@@ -1,17 +1,27 @@
BEGIN { FS="|"; i=0; dlt = -259200; spw = 604800; }
BEGIN { FS="|" }
NR == FNR {
i = i + 1;
from[i] = int(($1 + dlt)/ spw);
from_year[i] = $1
from_week[i] = $2
getline;
to[i] = int(($1 + dlt) / spw);
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_ = 1
year_i++
}
}
}
END { for (i in week) print i week[i]; }
END { for (label in week) print label week[label]; }

View File

@@ -27,10 +27,18 @@ BEGIN {
desc { desc = desc "\\n" $0; next; }
{
from = substr($0, 1, 6) == "::: |>" ? substr($0, 8) : "";
if (!from)
exit 1
getline
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;
@@ -41,36 +49,53 @@ END {
# If nanoseconds are not 0, then we assume user enterd "tomorrow" or
# something the like, and we make this a date entry, as opposed to a
# date-time entry.
from = from ? from : "now"
# Similalry, 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) {
from_type = "DATE-TIME"
cmd = "date -d \"" from "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
} else {
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"
}
cmd | getline from
suc = cmd | getline from
close(cmd)
if (suc != 1) {
exit 1
}
#
to = to ? to : "now"
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) {
to_type = "DATE-TIME"
cmd = "date -d \"" to "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
} else {
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"
}
cmd | getline to
suc = cmd | getline to
close(cmd)
if (suc != 1) {
exit 1
}
escape(summary);
escape(location);
escape(desc);
# print ical
@@ -85,11 +110,12 @@ END {
print "CREATED:" zulu;
print "SEQUENCE:1";
print "LAST-MODIFIED:" zulu;
print "STATUS:FINAL";
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 (location) print_fold("LOCATION:", location, i, s);
print "END:VEVENT"
print "END:VCALENDAR"
}

16
src/awk/set.awk Normal file
View File

@@ -0,0 +1,16 @@
function escape(str)
{
gsub("\\\\", "\\\\", str)
gsub(";", "\\\\;", str)
gsub(",", "\\\\,", str)
return str
}
BEGIN { FS = "[:;]"; }
/^BEGIN:VEVENT$/ { inside = 1 }
/^END:VEVENT$/ { inside = 0 }
$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 }

View File

@@ -36,47 +36,70 @@ ENDFILE {
# If nanoseconds are not 0, then we assume user enterd "tomorrow" or
# something the like, and we make this a date entry, as opposed to a
# date-time entry.
from = from ? from : "now"
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) {
from_type = "DATE-TIME"
cmd = "date -d \"" from "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
} else {
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"
}
cmd | getline from
suc = cmd | getline from
close(cmd)
if (suc != 1) {
exit 1
}
#
to = to ? to : "now"
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) {
to_type = "DATE-TIME"
cmd = "date -d \"" to "\" +\"@%s\" | xargs date -u +\"%Y%m%dT%H%M00Z\" -d"
} else {
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"
}
cmd | getline to
suc = cmd | getline to
close(cmd)
if (suc != 1) {
exit 1
}
escape(summary);
escape(location);
escape(desc);
}
escape(summary);
escape(desc);
}
NR == FNR && desc { desc = desc "\\n" $0; next; }
NR == FNR {
from = substr($0, 1, 6) == "::: |>" ? substr($0, 8) : "";
if (!from)
exit 1
getline
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;
@@ -86,7 +109,7 @@ NR == FNR {
/^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
@@ -96,6 +119,7 @@ NR == FNR {
print "DTEND;VALUE=" to_type ":" to
print_fold("SUMMARY:", summary, i, s)
print_fold("DESCRIPTION:", desc, i, s)
print_fold("LOCATION:", location, i, s)
inside = ""
}
{ print }

View File

@@ -12,7 +12,7 @@ BEGIN {
}
/^[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]$/ {

File diff suppressed because it is too large Load Diff