Exemplo n.º 1
0
def __parse_files(base_path):
    try:
        f_settings = open(base_path + ".todocalrc", 'r')
        data_path = base_path + ".todocal/"
        f_colorcode = open(data_path + "color-code", 'r')
        f_yearly = open(data_path + "yearly", 'r')
        f_monthly = open(data_path + "monthly", 'r')
        f_weekly = open(data_path + "weekly", 'r')
        f_daily = open(data_path + "daily", 'r')
        f_norepeat = open(data_path + "no-repeat", 'r')
    except:
        tc_meta.raise_ERROR("TodoCal: data file path invalid.")

    raw_settings = [line.strip() for line in f_settings]
    raw_colorcode = [line.strip() for line in f_colorcode]
    raw_yearly = [line.strip() for line in f_yearly]
    raw_monthly = [line.strip() for line in f_monthly]
    raw_weekly = [line.strip() for line in f_weekly]
    raw_daily = [line.strip() for line in f_daily]
    raw_norepeat = [line.strip() for line in f_norepeat]

    # filter out empty lines and commented lines
    filter_settings = [s for s in raw_settings if len(s) != 0 and s[0] != '#']
    filter_colorcode = [
        s for s in raw_colorcode if len(s) != 0 and s[0] != '#'
    ]
    filter_yearly = [s for s in raw_yearly if len(s) != 0 and s[0] != '#']
    filter_monthly = [s for s in raw_monthly if len(s) != 0 and s[0] != '#']
    filter_weekly = [s for s in raw_weekly if len(s) != 0 and s[0] != '#']
    filter_daily = [s for s in raw_daily if len(s) != 0 and s[0] != '#']
    filter_norepeat = [s for s in raw_norepeat if len(s) != 0 and s[0] != '#']

    return (filter_settings, filter_colorcode, filter_yearly, filter_monthly,
            filter_weekly, filter_daily, filter_norepeat)
Exemplo n.º 2
0
 def get_categorizers(L):
     try:
         default_index = L.index("__default")
         todo_index = L.index("__todo")
     except:
         tc_meta.raise_ERROR("TodoCal: event data storage problem.")
     return (default_index, todo_index)
Exemplo n.º 3
0
def __prepare_events(
        E, TIME_INFO):  # synthesize event information, return new list
    synthesis = []
    current_year = TIME_INFO["year"]
    for e in E:
        new_info = {}
        new_info["name"] = e["name"]  # new_info -> name
        if e["mark"] != '':
            new_info["name"] += (' ' + e["mark"]
                                 )  # include todo mark in event name
        event_date_object = datetime.datetime(year=current_year,
                                              month=int(e["month"]),
                                              day=int(e["day"]))
        weekday = event_date_object.isoweekday()
        if weekday == 7:
            weekday = 0
        weekday = str(weekday)
        new_info["weekday"] = int(weekday)  # new_info -> weekday (int)
        new_info["color-code"] = e["color"]  # new_info -> color-code (str)

        # code segment copy ---------------------------------------------------
        if ' ' not in e["hour"]:
            e["hour"] += " 00"
        e["time-start-code"] = int(e["hour"].replace(' ', ''))
        try:
            start_time = [int(s) for s in e["hour"].split(' ')]
            start_hour = start_time[0]
            start_minute = start_time[1]
        except:
            tc_meta.raise_ERROR("TodoCal: time convertion error.")
        start_time_object = datetime.time(hour=start_hour, minute=start_minute)
        start_time_object = datetime.datetime(
            year=2000,
            month=1,
            day=1,
            hour=start_time_object.hour,
            minute=start_time_object.minute)  # convert time to datetime
        try:
            if e["length"] == "":
                end_time_object = start_time_object
            else:
                end_time_object = start_time_object + datetime.timedelta(
                    minutes=int(e["length"]))
        except:
            tc_meta.raise_ERROR("TodoCal: time calculation error.")
        time_end_code = end_time_object.hour * 100 + end_time_object.minute
        if time_end_code < e["time-start-code"]:
            time_end_code = 2359
        if time_end_code != 0 and time_end_code % 100 == 0:
            time_end_code -= 41  # reduce to past hour
        e["time-end-code"] = time_end_code
        # code segment copy end -----------------------------------------------

        new_info["time-start-code"] = e["time-start-code"]
        new_info["time-end-code"] = e["time-end-code"]
        # new_info -> name, weekday (int), color-code (str), time-start-code (int), time-end-code (int)

        synthesis.append(new_info)
    return synthesis  # synthesized new event list
Exemplo n.º 4
0
 def parse_event(line):
     if line[0] != '{' or line[-1] != '}':
         tc_meta.raise_ERROR("TodoCal: event data storage corrupted.")
     line = line[1:-1].strip()  # remove line container
     kv_pairs = [s.strip() for s in line.split(',')]
     E = {}
     for kv in kv_pairs:
         kv_l = [s.strip() for s in kv.split(':')]
         key = kv_l[0]
         value = kv_l[1]
         E[key] = value
     return E
Exemplo n.º 5
0
 def make_main_display(col_width, span_height, DICT, T):
     # ensure span_height allow all events normal display
     for (span_hour, E) in DICT.items():
         if len(E) > span_height:
             tc_meta.raise_ERROR("TodoCal: calendar height too small.")
         else:
             continue
     COL = []  # make list of strings for this column display
     for span_hour in sorted(DICT):  # access span hour event lists in order
         E = DICT[span_hour]  # access to event list
         if len(E) == 0:
             for _ in range(
                     span_height):  # fill span hour height with white space
                 COL.append(' ' * col_width)
             continue
         # handle actual events
         individual_span = span_height // (len(E))
         assert (individual_span >= 1)
         count_use_span = 0
         for e in E:
             if '\u001b[37m\u2713\u001b[0m' in e["name"]:
                 e["name"] = e["name"].replace('\u001b[37m\u2713\u001b[0m',
                                               '^')  # forbidden character 1
             if '\u001b[31m\u2717\u001b[0m' in e["name"]:
                 e["name"] = e["name"].replace('\u001b[31m\u2717\u001b[0m',
                                               '%')  # forbidden character 2
             e_display = T.wrap(
                 e["name"])  # return string list of <= col_width
             if len(e_display) > individual_span:  # event overflows height
                 e_display = e_display[:individual_span]  # slice excess
                 last_line = e_display[-1]
                 if ' ' not in last_line:
                     last_line = "..."
                 else:
                     white_space_index = last_line.rfind(' ')
                     last_line = last_line[:white_space_index] + "..."
                 e_display[-1] = last_line  # update last line in display
                 assert (len(e_display) == individual_span)
             for line in e_display:
                 COL.append('\u001b[38;5;' + e["color-code"] + 'm' +
                            ('{line_str:<' + str(col_width) + '}').format(
                                line_str=line) + tc_meta.color_reset)
                 count_use_span += 1
         for _ in range(span_height -
                        count_use_span):  # fill un-used height
             COL.append(' ' * col_width)
         continue
     assert (len(COL) == span_height * len(spans))
     return COL  # encoded with color information
Exemplo n.º 6
0
def __get_dimension_info(raw_info):  # dimension raw info passed from pass_info
    try:
        cell_width = int(raw_info["cell-width"])
    except:
        try:
            cell_width = int(raw_info["max-width"]) // 8
        except:
            tc_meta.raise_ERROR("Error: calendar dimensions not well defined.")

    if cell_width <= 7:
        tc_meta.raise_ERROR("TodoCal: unimplemented situation.")
    # assert (cell_width >= 8)

    time_col_width = 7  # allow full time display
    between_col_width = 1
    col_width = cell_width

    calendar_width = time_col_width + col_width * 7 + between_col_width * 7

    try:
        max_height = int(raw_info["max-height"])
    except:
        tc_meta.raise_ERROR("Error: calendar dimensions not well defined.")

    return (calendar_width, max_height, (time_col_width, between_col_width,
                                         col_width))
Exemplo n.º 7
0
def __get_calendar_height(max_height,
                          E):  # max_height passed from __get_dimension_info
    # information in e in E (passed from pass_info)
    # name, month, day, hour, length, (done), mark (0/1 char), color (str)

    for e in E:

        # code segment first copy ---------------------------------------------
        if ' ' not in e["hour"]:
            e["hour"] += " 00"
        e["time-start-code"] = int(e["hour"].replace(' ', ''))
        try:
            start_time = [int(s) for s in e["hour"].split(' ')]
            start_hour = start_time[0]
            start_minute = start_time[1]
        except:
            tc_meta.raise_ERROR("TodoCal: time convertion error.")
        start_time_object = datetime.time(hour=start_hour, minute=start_minute)
        start_time_object = datetime.datetime(
            year=2000,
            month=1,
            day=1,
            hour=start_time_object.hour,
            minute=start_time_object.minute)  # convert time to datetime
        try:
            if e["length"] == "":
                end_time_object = start_time_object
            else:
                end_time_object = start_time_object + datetime.timedelta(
                    minutes=int(e["length"]))
        except:
            tc_meta.raise_ERROR("TodoCal: time calculation error.")
        time_end_code = end_time_object.hour * 100 + end_time_object.minute
        if time_end_code < e["time-start-code"]:
            time_end_code = 2359
        if time_end_code != 0 and time_end_code % 100 == 0:
            time_end_code -= 41  # reduce to past hour
        e["time-end-code"] = time_end_code
        # code segment end ----------------------------------------------------
    # e.g. hour = "15 20", length = "30"
    # time-start-code = 1520, time-end-code = 1550

    span_mark = []
    for _ in range(24):
        span_mark.append(0)
        # span_mark [i] => time from i hour to (i + 1) hour
    for e in E:
        for i in range(e["time-start-code"] // 100,
                       e["time-end-code"] // 100 + 1):
            span_mark[i] = 1
    spans = []
    for i in range(24):
        if span_mark[i] == 1:
            spans.append(i)
    # e.g. spans = [0, 7, 8, 10, 15]
    # => exist events in 0-1, 7-9, 10-11, 15-16

    available_height = max_height - 3  # reserve top rows for calendar header
    span_height = available_height // (len(spans))

    if span_height <= 1:
        tc_meta.raise_ERROR("TodoCal: unimplemented situation.")
    # assert (span_height >= 2)

    calendar_height = span_height * (len(spans)) + 3
    return (calendar_height, span_height, spans)
Exemplo n.º 8
0
def __parse_DATA(base_path):
    (settings, colorcode, yearly, monthly, weekly, daily,
     norepeat) = __parse_files(base_path)

    DATA = {
        "meta": {
            "color-code": {},
            "color": {},
            "dimension": {}
        },
        "events": {
            "yearly": {
                "default": [],
                "todo": []
            },
            "monthly": {
                "default": [],
                "todo": []
            },
            "weekly": {
                "default": [],
                "todo": []
            },
            "daily": {
                "default": [],
                "todo": []
            },
            "no-repeat": {
                "default": [],
                "todo": []
            }
        }
    }  # initialize DATA

    # parse settings
    try:
        color_settings_index = settings.index("__color")
    except:
        tc_meta.raise_ERROR("TodoCal: color settings not defined.")
    try:
        dimension_settings_index = settings.index("__dimension")
    except:
        tc_meta.raise_ERROR("TodoCal: dimension settings not defined.")
    for i in range(color_settings_index + 1, dimension_settings_index):
        line = settings[i]
        (key, value) = [s.strip() for s in line.split(':')]
        DATA["meta"]["color"][key] = value
    for i in range(dimension_settings_index + 1, len(settings)):
        line = settings[i]
        (key, value) = [s.strip() for s in line.split(':')]
        DATA["meta"]["dimension"][key] = value

    # regularized event parser
    def parse_event(line):
        if line[0] != '{' or line[-1] != '}':
            tc_meta.raise_ERROR("TodoCal: event data storage corrupted.")
        line = line[1:-1].strip()  # remove line container
        kv_pairs = [s.strip() for s in line.split(',')]
        E = {}
        for kv in kv_pairs:
            kv_l = [s.strip() for s in kv.split(':')]
            key = kv_l[0]
            value = kv_l[1]
            E[key] = value
        return E

    # categorize events
    def get_categorizers(L):
        try:
            default_index = L.index("__default")
            todo_index = L.index("__todo")
        except:
            tc_meta.raise_ERROR("TodoCal: event data storage problem.")
        return (default_index, todo_index)

    y_indices = get_categorizers(yearly)
    m_indices = get_categorizers(monthly)
    w_indices = get_categorizers(weekly)
    d_indices = get_categorizers(daily)
    n_indices = get_categorizers(norepeat)
    (yearly_default, yearly_todo) = (yearly[y_indices[0] + 1:y_indices[1]],
                                     yearly[y_indices[1] + 1:len(yearly)])
    (monthly_default, monthly_todo) = (monthly[m_indices[0] + 1:m_indices[1]],
                                       monthly[m_indices[1] + 1:len(monthly)])
    (weekly_default, weekly_todo) = (weekly[w_indices[0] + 1:w_indices[1]],
                                     weekly[w_indices[1] + 1:len(weekly)])
    (daily_default, daily_todo) = (daily[d_indices[0] + 1:d_indices[1]],
                                   daily[d_indices[1] + 1:len(daily)])
    (norepeat_default,
     norepeat_todo) = (norepeat[n_indices[0] + 1:n_indices[1]],
                       norepeat[n_indices[1] + 1:len(norepeat)])

    # parse events and update DATA
    DATA["events"]["yearly"]["default"] = [
        parse_event(line) for line in yearly_default
    ]
    DATA["events"]["monthly"]["default"] = [
        parse_event(line) for line in monthly_default
    ]
    DATA["events"]["weekly"]["default"] = [
        parse_event(line) for line in weekly_default
    ]
    DATA["events"]["daily"]["default"] = [
        parse_event(line) for line in daily_default
    ]
    DATA["events"]["no-repeat"]["default"] = [
        parse_event(line) for line in norepeat_default
    ]
    DATA["events"]["yearly"]["todo"] = [
        parse_event(line) for line in yearly_todo
    ]
    DATA["events"]["monthly"]["todo"] = [
        parse_event(line) for line in monthly_todo
    ]
    DATA["events"]["weekly"]["todo"] = [
        parse_event(line) for line in weekly_todo
    ]
    DATA["events"]["daily"]["todo"] = [
        parse_event(line) for line in daily_todo
    ]
    DATA["events"]["no-repeat"]["todo"] = [
        parse_event(line) for line in norepeat_todo
    ]

    # parse color codes
    for line in colorcode:
        kv_l = [s.strip() for s in line.split(':')]
        DATA["meta"]["color-code"][kv_l[0]] = kv_l[1]

    return DATA