entries_sort :: (entries: [..]Entry) -> (by_update: []Entry, by_published: []Entry) { sorted_by_update_time := entries_sorted_by(.UPDATED, entries); sorted_by_publish_time := entries_sorted_by(.PUBLISHED, entries); return sorted_by_update_time, sorted_by_publish_time; } entries_make_html :: (by_update: []Entry, by_published: []Entry) -> by_update_diet: [..][]string, by_published: [..][]string { make_html :: (sorted: []Entry, dont_show_images: bool) -> [..][]string { temp: [..][]string; for sorted { cal_published := to_calendar(it.published); cal_updated := to_calendar(it.updated); /** Note: It's not optimal to propagate `dont_show_images` in that way and create multiple versions of the html. If this is an issue at some point, we need an better idea. */ post := replace_tags(it.uri, it.post, dont_show_images); entry: [ENTRIES_MAX_FIELDS]string; entry[0] = it.title; entry[1] = post; entry[2] = make_date(cal_published); entry[3] = make_date(cal_updated); entry[4] = it.uri; array_add(*temp, array_copy(entry)); } return temp; } update_diet := make_html(by_update, true); published := make_html(by_published, false); return update_diet, published; } entries_make :: (posts: [..]Markdown_File) -> [..]Entry { if !posts { log_error("There are no posts."); exit(1); } rendered: [..]Entry; for posts { entry: Entry; metadata, post := entries_make_header_and_body(it.content); should_skip := entries_parse_metadata(*entry, metadata); if should_skip continue; entry.post = post; entry.uri = make_url(entry.published); array_add(*rendered, entry); } return rendered; } entries_make_header_and_body :: (post: string) -> (header: string, body: string) { max_preview_count :: 255; if !contains(post, METADATA_MARKER) { log_error( "Entry has no metadata marker. Preview:\n% ...", slice(post, 0, max_preview_count) ); exit(1); } splitted := split(post, METADATA_MARKER); if splitted.count != 2 { log_error( "Couldn't create header and body in post. Preview:\n%", slice(post, 0, max_preview_count) ); exit(1); } metadata := splitted[0]; body := splitted[1]; body_trimmed := trim(body); return metadata, body_trimmed; } entries_parse_metadata :: (entry: *Entry, metadata: string) -> skip: bool { invalid_field_error_and_exit :: (metadata: string, s: string) { log_error("Field is invalid: '%'\n---\n%", s, metadata); exit(1); } to_apollo_time_or_exit :: (metadata: string, digits: string) -> Apollo_Time { if !is_correct_field_date_format(digits) then invalid_field_error_and_exit(metadata, digits); left := find_index_from_left(digits, "("); right := find_index_from_left(digits, ")"); if left == -1 || right == -1 then invalid_field_error_and_exit(metadata, digits); left += 1; length := right - left; value := slice(digits, left, length); time := parse_to_int(value, s64); return milliseconds_to_apollo(time); } dispatch_metadata :: (entry: *Entry, metadata: string, m: string, id: int) { match := find_index_from_left(metadata, m); if match == -1 return; // Note: Maybe handling? value := parser_consume_till(match + m.count, metadata, #char "\n"); trimmed := trim(value, " \r\n\t"); if id == { case 0; entry.title = trimmed; case 1; entry.width = trimmed; case 2; entry.published = to_apollo_time_or_exit(metadata, trimmed); case 3; entry.updated = to_apollo_time_or_exit(metadata, trimmed); } } hidden_tag, remainder := contains_nocase(metadata, "hidden:"); if hidden_tag { trimmed := trim_left(remainder); if begins_with_nocase(trimmed, "true") return true; } for KEYWORDS dispatch_metadata(entry, metadata, it, it_index); return false; } entries_sorted_by :: ($mode: enum { PUBLISHED; UPDATED; }, entries: [..]Entry) -> []Entry { compare_by_updated :: (a: Entry, b: Entry) -> s64 { aa := a.updated; bb := b.updated; return compare_apollo_times(bb, aa); } compare_by_published :: (a: Entry, b: Entry) -> s64 { aa := a.published; bb := b.published; return compare_apollo_times(bb, aa); } // quick_sort sorts in-place entries_local := array_copy(entries); #if mode == { case .PUBLISHED; sorted := quick_sort(entries_local, compare_by_published); case .UPDATED; sorted := quick_sort(entries_local, compare_by_updated); } return array_copy(sorted); } entries_dump_data_or_exit :: (entries: []Entry, dest: string) { copy := array_copy(entries); // TODO: do we really need a copy? Why? ok := marshal_and_save_to_disk(dest, *copy); if !ok then exit(1); } entry_make :: (post: string) -> Entry { entry: Entry; metadata, post := entries_make_header_and_body(post); entries_parse_metadata(*entry, metadata); entry.post = post; entry.uri = make_url(entry.published); return entry; } #scope_file #load "entries.h";