[Remind-Fans] Weekly Planner?

Tim Chase remind at tim.thechases.com
Wed Dec 18 16:22:16 EST 2019


here's a modest script to generate output akin to what you described.
A few caveats:

1) if an event begins before your START_TIME or after your END_TIME,
it doesn't get printed

2) it prints whole-day events at the top

3) if something has a DURATION specified, only its start gets
noted, it doesn't extend 

4) it doesn't respect start-of-week, so it really only creates one
column/entry for each date output, so if "rem" outputs more than one
week, you'll get that many columns (the `rem -s` is REALLY wide)

The actual generation portion is moved out to functions, so if you
wanted to emit LaTeX or some other markup instead, it shouldn't be as
taxing.

Usage:

 $ rem -s+ | awk -f planner.awk > this_week.html

or, if you want to override the START_TIME/END_TIME for your day

 $ rem -s+ | awk -vSTART_TIME=7:00 -vEND_TIME=16:00 -vNO_WRAP=1 -f
 planner.awk > this_week_as_fragment.html

the NO_WRAP=1 controls whether it gets wrapped in some basic HTML to
form a whole page (the default behavior if NO_WRAP is unset) or just
the <table> is emitted (any non-blank value for NO_WRAP).

If wrapped (the default) you can then point your favorite browser at
it to print if you want:

  $ firefox this_week.html &

Hope this helps.

-tim

------[>8 planner.awk >8]-------------------------  
#!/usr/bin/awk -f
function err(s) {
  print s >> "/dev/stderr"
  exit
}

function hm2time(timestr) {
  if (split(timestr, hm, /:/) > 1) {
    h = int(hm[1])
    m = int(hm[2])
    return h * 60 + m
  } else {
    err(sprintf("Invalid time: [%s]", timestr))
  }
}

function time2hm(t) {
  h = int(t / 60)
  m = t % 60
  return sprintf("%02i:%02i", h, m)
}

function htmlescape(s) {
  gsub(/&/, "&", s)
  gsub(/</, "<", s)
  gsub(/>/, ">", s)  
  return s
}

# to change the output type,
# adjust these functions:
function wrap_header(title) {
  printf("<html><head><title>Calendar for %s</title></head><body>\n",
title) }
function wrap_footer() {
  printf("</body></html>\n")
}
function headers_start() {
  printf("<table><thead><tr>")
}
function emit_header(h) {
  printf("<th>%s</th>", h)
}
function headers_end() {
  printf("</tr></thead>\n")
}
function body_begin() {
  printf("<tbody>\n")
}
function body_end() {
  printf("</tbody></table>\n")
}
function row_start(time) {
  printf("<tr><th>%s</th>", time)
}
function row_end() {
  printf("</tr>\n")
}
function emit_cell(s) {
  printf("<td>%s</td>", s)
}
function emit_list(items) {
  printf("<td><ul>")
  for (i in items) printf("<li>%s</li>", htmlescape(items[i]))
  print "</ul></td>"
}

BEGIN {
  if (START_TIME !~ /[0-9]+:[0-9]+/) START_TIME="7:00"
  if (END_TIME !~ /[0-9]+:[0-9]+/) END_TIME="17:00"

  START_TIME = hm2time(START_TIME)
  END_TIME = hm2time(END_TIME)

  if (INTERVAL=="") INTERVAL=30
  else INTERVAL=int(INTERVAL)

  WRAP = (NO_WRAP=="")
}

{
  DATE = $1
  SPECIAL = $2
  TAG = $3
  DUR = $4
  TIME = $5
  msg = $6
  for (i=7; i<= NF; i++) msg = msg " " $i
}

SPECIAL != "*" { next }

DATE != last_date {
  i2d[col_count++] = last_date = $1
}

TIME == "*" {
  # all day
  if (DATE in allday) allday[DATE]=allday[DATE] SUBSEP msg
  else allday[DATE] = msg
}

TIME != "*" {
  # a timed event
  if (DATE in times) {
    times[DATE]=times[DATE] SUBSEP TIME
  } else {
    times[DATE] = TIME
  }
  if ((DATE SUBSEP TIME) in dt2msg)
    dt2msg[DATE, TIME] = dt2msg[DATE, TIME] SUBSEP  msg
  else
    dt2msg[DATE, TIME] = msg
}

END {
  if (WRAP) wrap_header(i2d[0])
  headers_start()
  emit_header("")
  for (i=0; i<col_count; i++) {
    date = i2d[i]
    emit_header(date)
  }
  headers_end()
  body_begin()
  row_start("All day")
  for (col=0; col<col_count; col++) {
    if (col in i2d) {
      date = i2d[col]
      split(allday[i2d[col]], msgs, SUBSEP)
      if (length(msgs) > 1) {
        emit_list(msgs)
      } else {
        emit_cell(msgs[1])
      }
    }
  }
  row_end()

  currently_printing_time = START_TIME
  while (currently_printing_time <= END_TIME) {
    row_start(time2hm(currently_printing_time))
    for (col=0; col<col_count; col++) {
      if (col in i2d) {
        date = i2d[col]
        split(times[date], subset_of_times, SUBSEP)
        delete msgs_to_print
        msg_index = 1
        for (time_index in subset_of_times) {
          item_time = subset_of_times[time_index]
          if (item_time >= currently_printing_time &&
              item_time < currently_printing_time + INTERVAL) {
            if ((date, item_time) in dt2msg) {
              msgs_to_print[msg_index++] = dt2msg[date, item_time]
            }
          }
        }
      
        if (length(msgs_to_print) > 1) {
          emit_list(msgs_to_print)
        } else {
          emit_cell(msgs_to_print[1])
        }
      } else emit_cell("")
    }
    row_end()
    currently_printing_time += INTERVAL
  }
  body_end()
  if (WRAP) wrap_footer()
}


More information about the Remind-fans mailing list