display :: ( todo: [..]Token, note: [..]Token, idea: [..]Token, cont: [..]Token, other: [..]Token, file_name: string ) { push_allocator(temp); term := terminal_info_size(); // Hack. See TODO @TERMINAL_MIN_WIDTH if term.col < TERMINAL_MIN_WIDTH then term.col = TERMINAL_MIN_WIDTH; section_title(file_name, term); tokens_print(todo, " TODO ", term); tokens_print(note, " NOTE ", term); tokens_print(idea, " IDEA ", term); tokens_print(cont, " CONTINUE ", term); tokens_print(other, " OTHER ", term); } #scope_file PADDING :: 4; /** TODO(adam): This is a fugly hack. Below 88 columns I see on _my_ terminal bazillions of hyphens. This is worth investigating. */ TERMINAL_MIN_WIDTH :: 88; COLUMN_LABEL_COLOR_LINE: Color_Foreground: .MAGENTA; COLUMN_LABEL_COLOR_PRIORITY: Color_Foreground: .GREEN; COLUMN_LABEL_COLOR_AUTHOR: Color_Foreground: .BLUE; COLUMN_LABEL_COLOR_KEYWORD: Color_Foreground: .RED; COLUMN_LABEL_LINE :: " Line "; COLUMN_LABEL_PRIORITY :: " Priority "; COLUMN_LABEL_AUTHOR :: " Author "; COLUMN_PADDING_LINE :: 3; COLUMN_PADDING_PRIORITY :: 1; COLUMN_PADDING_AUTHOR :: 5; COLUMN_WIDTH_LINE :: #run COLUMN_LABEL_LINE.count + COLUMN_PADDING_LINE; COLUMN_WIDTH_PRIORITY :: #run COLUMN_LABEL_PRIORITY.count + COLUMN_PADDING_PRIORITY; COLUMN_WIDTH_AUTHOR :: #run COLUMN_LABEL_AUTHOR.count + COLUMN_PADDING_AUTHOR; SEPARATOR_FIRST :: "|"; SEPARATOR_CORNER :: "+-"; SEPARATOR :: " | "; HLINE :: "-"; #no_reset table_header_visual_count: int; TABLE_HEADER :: #run -> string { create_column_title :: ( label: string, padding: int, fgc: Color_Foreground, bgc: Color_Background ) -> vcount: int #expand { append(*`buf, SEPARATOR_CORNER); out, vcount := paint( label, fg = fgc, bg = bgc ); append(*`buf, out); for 0..padding append(*`buf, HLINE); return vcount; } buf: String_Builder; init_string_builder(*buf); vcount_line := create_column_title( COLUMN_LABEL_LINE, COLUMN_PADDING_LINE - 1, COLUMN_LABEL_COLOR_LINE, .BLACK ); vcount_prio := create_column_title( COLUMN_LABEL_PRIORITY, COLUMN_PADDING_PRIORITY, COLUMN_LABEL_COLOR_PRIORITY, .BLACK ); vcount_author := create_column_title( COLUMN_LABEL_AUTHOR, COLUMN_PADDING_AUTHOR, COLUMN_LABEL_COLOR_AUTHOR, .BLACK ); append(*buf, SEPARATOR_CORNER); table_header_visual_count += vcount_line + vcount_prio + vcount_author; return builder_to_string(*buf); } Winsize :: struct { row: u16 = 0; // not in use col: u16 = TERMINAL_MIN_WIDTH; xpixel: u16 = 0; // not in use ypixel: u16 = 0; // not in use } section_title :: (label: string, term: Winsize) { title, vcount_title := paint( tprint(" File: % ", label), .ITALIC, fg = .CYAN, bg = .BLACK ); pref, vcount_pref := paint("o-", fg = .CYAN); header := string_pad_right( tprint("%%", pref, title), term.col + vcount_title + vcount_pref - (PADDING - 1), paint(HLINE, fg = .CYAN, no_termination = true) ); print("\n"); print(header); print(paint_reset()); print("\n"); } tokens_print :: (tokens: [..]Token, label: string, term: Winsize) { if !tokens return; header_print(label, term); for tokens print("%\n", lines_assemble(it, term)); print("\n"); } header_print :: (label: string, term: Winsize) { title, title_vcount := paint( tprint("%", label), fg = COLUMN_LABEL_COLOR_KEYWORD, bg = .BLACK ); width_adapted := table_header_visual_count + title_vcount; header := string_pad_right( title, term.col - PADDING - TABLE_HEADER.count + width_adapted + 1, HLINE ); print("%%\n", TABLE_HEADER, header); } word_wrap_and_append :: ( buf: *String_Builder, field: string, columns_count: int, current_width: int ) { tab_to_keyword_column :: () #expand { append(`buf, "\n"); for 0..`columns_count-1 append(`buf, " "); `current_line_width = `columns_count; } find_whitespace :: (s: string, pos: int) -> int { c: int; for i: pos..s.count-1 { c += 1; if is_space(s[i]) then return c; } return c; } comment := field; legal_term_width := current_width - PADDING; idx_column: int = columns_count; idx_field: int; while idx_field < comment.count { ws_pos := find_whitespace(comment, idx_field); word_length := (idx_field + ws_pos) - idx_field; if idx_column + word_length >= legal_term_width { append(buf, "\n"); for 0..columns_count-1 append(buf, " "); idx_column = columns_count; } if idx_column + word_length >= legal_term_width { for idx_column..legal_term_width { append(buf, comment[idx_field]); idx_field += 1; idx_column += 1; } } append(buf, comment[idx_field]); idx_field += 1; idx_column += 1; } } lines_assemble :: (token: Token, terminal: Winsize) -> string { make_string :: ( elem: Any, filler: string, fgc: Color_Foreground, width: int, pad_proc: (string, int, string) -> string ) -> string, int { str, vcount := paint(tprint("%", elem), fg = fgc); out := pad_proc(str, width + vcount, filler); return out, vcount; } buf: String_Builder; init_string_builder(*buf); line, vcount_line := make_string( token.line, ".", COLUMN_LABEL_COLOR_LINE, COLUMN_WIDTH_LINE, string_pad_left ); priority, vcount_prio := make_string( token.priority, " ", COLUMN_LABEL_COLOR_PRIORITY, COLUMN_WIDTH_PRIORITY, string_pad_left ); author, vcount_author := make_string( token.author, " ", COLUMN_LABEL_COLOR_AUTHOR, COLUMN_WIDTH_AUTHOR, string_pad_right ); current_width := terminal.col - PADDING; columns_author_count := SEPARATOR_FIRST.count + (SEPARATOR.count * 2) + abs(line.count - vcount_line) + abs(priority.count - vcount_prio); columns_comment_count := columns_author_count + SEPARATOR.count + abs(author.count - vcount_author); append(*buf, SEPARATOR_FIRST); append(*buf, line); append(*buf, SEPARATOR); append(*buf, priority); append(*buf, SEPARATOR); append(*buf, author); append(*buf, SEPARATOR); word_wrap_and_append( *buf, token.comment, columns_comment_count, current_width ); return builder_to_string(*buf); } terminal_info_size :: () -> term: Winsize { w: Winsize; error_code := ioctl(STDOUT_FILENO, TIOCGWINSZ, *w); if error_code != 0 { log_error( "[Warning]: Could not get terminal information. Falling back to defaults." ); return {}; } return w; }