From 890f9b6142cfa336d4ca77be3ff884086199e7e7 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 18 Mar 2017 22:06:42 -0700 Subject: 3800 --- 100trace_browser.cc | 20 + html/100trace_browser.cc.html | 918 +++++++++++++++++++++--------------------- 2 files changed, 489 insertions(+), 449 deletions(-) diff --git a/100trace_browser.cc b/100trace_browser.cc index ba48513b..42a4d848 100644 --- a/100trace_browser.cc +++ b/100trace_browser.cc @@ -60,6 +60,8 @@ //: `right-arrow`: move cursor right. //: `ctrl-a` or `home`: move cursor to start of search pattern. //: `ctrl-e` or `end`: move cursor to end of search pattern. +//: `ctrl-u`: clear search pattern before cursor +//: `ctrl-k`: clear search pattern at and after cursor :(before "End Primitive Recipe Declarations") _BROWSE_TRACE, @@ -331,6 +333,24 @@ bool start_search_editor(search_direction dir) { tb_present(); } } + else if (key == TB_KEY_CTRL_K) { + int old_pattern_size = SIZE(pattern); + pattern.erase(col-/*slash*/1, SIZE(pattern) - (col-/*slash*/1)); + for (int x = col; x < old_pattern_size+/*slash*/1; ++x) + tb_change_cell(x, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); + tb_set_cursor(col, bottom_screen_line); + tb_present(); + } + else if (key == TB_KEY_CTRL_U) { + int old_pattern_size = SIZE(pattern); + pattern.erase(0, col-/*slash*/1); + for (int x = /*slash*/1; x < SIZE(pattern)+/*skip slash*/1; ++x) + tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); + for (int x = SIZE(pattern)+/*slash*/1; x < old_pattern_size+/*skip slash*/1; ++x) + tb_change_cell(x, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); + tb_set_cursor(/*start of pattern skipping slash*/1, bottom_screen_line); + tb_present(); + } else if (key < 128) { // ascii only // update pattern char c = static_cast(key); diff --git a/html/100trace_browser.cc.html b/html/100trace_browser.cc.html index 4d3fdf7a..fe5b0eb4 100644 --- a/html/100trace_browser.cc.html +++ b/html/100trace_browser.cc.html @@ -120,458 +120,478 @@ if ('onhashchange' in window) { 60 //: `right-arrow`: move cursor right. 61 //: `ctrl-a` or `home`: move cursor to start of search pattern. 62 //: `ctrl-e` or `end`: move cursor to end of search pattern. - 63 - 64 :(before "End Primitive Recipe Declarations") - 65 _BROWSE_TRACE, - 66 :(before "End Primitive Recipe Numbers") - 67 put(Recipe_ordinal, "$browse-trace", _BROWSE_TRACE); - 68 :(before "End Primitive Recipe Checks") - 69 case _BROWSE_TRACE: { - 70 break; - 71 } - 72 :(before "End Primitive Recipe Implementations") - 73 case _BROWSE_TRACE: { - 74 start_trace_browser(); - 75 break; - 76 } - 77 - 78 //: browse a trace loaded from a file - 79 :(after "Commandline Parsing") - 80 if (argc == 3 && is_equal(argv[1], "browse-trace")) { - 81 load_trace(argv[2]); - 82 start_trace_browser(); - 83 return 0; - 84 } - 85 - 86 :(before "End Globals") - 87 set<int> Visible; - 88 int Top_of_screen = 0; - 89 int Left_of_screen = 0; - 90 int Last_printed_row = 0; - 91 map<int, int> Trace_index; // screen row -> trace index - 92 string Current_search_pattern = ""; - 93 :(before "End Types") - 94 enum search_direction { FORWARD, BACKWARD }; - 95 :(before "End Globals") - 96 search_direction Current_search_direction = FORWARD; - 97 - 98 :(code) - 99 void start_trace_browser() { -100 if (!Trace_stream) return; -101 cerr << "computing min depth to display\n"; -102 int min_depth = 9999; -103 for (int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { -104 ¦ trace_line& curr_line = Trace_stream->past_lines.at(i); -105 ¦ if (curr_line.depth < min_depth) min_depth = curr_line.depth; -106 } -107 cerr << "min depth is " << min_depth << '\n'; -108 cerr << "computing lines to display\n"; -109 for (int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { -110 ¦ if (Trace_stream->past_lines.at(i).depth == min_depth) -111 ¦ ¦ Visible.insert(i); -112 } -113 tb_init(); -114 Display_row = Display_column = 0; -115 Top_of_screen = 0; -116 refresh_screen_rows(); -117 while (true) { -118 ¦ render(); -119 ¦ int key = read_key(); -120 ¦ if (key == 'q' || key == 'Q' || key == TB_KEY_CTRL_C) break; -121 ¦ if (key == 'j' || key == TB_KEY_ARROW_DOWN) { -122 ¦ ¦ // move cursor one line down -123 ¦ ¦ if (Display_row < Last_printed_row) ++Display_row; -124 ¦ } -125 ¦ else if (key == 'k' || key == TB_KEY_ARROW_UP) { -126 ¦ ¦ // move cursor one line up -127 ¦ ¦ if (Display_row > 0) --Display_row; -128 ¦ } -129 ¦ else if (key == 't') { -130 ¦ ¦ // move cursor to top of screen -131 ¦ ¦ Display_row = 0; -132 ¦ } -133 ¦ else if (key == 'c') { -134 ¦ ¦ // move cursor to center of screen -135 ¦ ¦ Display_row = tb_height()/2; -136 ¦ ¦ while (!contains_key(Trace_index, Display_row)) -137 ¦ ¦ ¦ --Display_row; -138 ¦ } -139 ¦ else if (key == 'b') { -140 ¦ ¦ // move cursor to bottom of screen -141 ¦ ¦ Display_row = tb_height()-1; -142 ¦ ¦ while (!contains_key(Trace_index, Display_row)) -143 ¦ ¦ ¦ --Display_row; -144 ¦ } -145 ¦ else if (key == 'T') { -146 ¦ ¦ // scroll line at cursor to top of screen -147 ¦ ¦ Top_of_screen = get(Trace_index, Display_row); -148 ¦ ¦ Display_row = 0; -149 ¦ ¦ refresh_screen_rows(); -150 ¦ } -151 ¦ else if (key == 'h' || key == TB_KEY_ARROW_LEFT) { -152 ¦ ¦ // pan screen one character left -153 ¦ ¦ if (Left_of_screen > 0) --Left_of_screen; -154 ¦ } -155 ¦ else if (key == 'l' || key == TB_KEY_ARROW_RIGHT) { -156 ¦ ¦ // pan screen one character right -157 ¦ ¦ ++Left_of_screen; -158 ¦ } -159 ¦ else if (key == 'H') { -160 ¦ ¦ // pan screen one screen-width left -161 ¦ ¦ Left_of_screen -= (tb_width() - 5); -162 ¦ ¦ if (Left_of_screen < 0) Left_of_screen = 0; -163 ¦ } -164 ¦ else if (key == 'L') { -165 ¦ ¦ // pan screen one screen-width right -166 ¦ ¦ Left_of_screen += (tb_width() - 5); -167 ¦ } -168 ¦ else if (key == 'J' || key == TB_KEY_PGDN || key == TB_KEY_CTRL_F) { -169 ¦ ¦ // page-down -170 ¦ ¦ if (Trace_index.find(tb_height()-1) != Trace_index.end()) { -171 ¦ ¦ ¦ Top_of_screen = get(Trace_index, tb_height()-1) + 1; -172 ¦ ¦ ¦ refresh_screen_rows(); -173 ¦ ¦ } -174 ¦ } -175 ¦ else if (key == 'K' || key == TB_KEY_PGUP || key == TB_KEY_CTRL_B) { -176 ¦ ¦ // page-up is more convoluted -177 ¦ ¦ for (int screen_row = tb_height(); screen_row > 0 && Top_of_screen > 0; --screen_row) { -178 ¦ ¦ ¦ --Top_of_screen; -179 ¦ ¦ ¦ if (Top_of_screen <= 0) break; -180 ¦ ¦ ¦ while (Top_of_screen > 0 && !contains_key(Visible, Top_of_screen)) -181 ¦ ¦ ¦ ¦ --Top_of_screen; -182 ¦ ¦ } -183 ¦ ¦ if (Top_of_screen >= 0) -184 ¦ ¦ ¦ refresh_screen_rows(); -185 ¦ } -186 ¦ else if (key == 'g' || key == TB_KEY_HOME) { -187 ¦ ¦ ¦ Top_of_screen = 0; -188 ¦ ¦ ¦ Last_printed_row = 0; -189 ¦ ¦ ¦ Display_row = 0; -190 ¦ ¦ ¦ refresh_screen_rows(); -191 ¦ } -192 ¦ else if (key == 'G' || key == TB_KEY_END) { -193 ¦ ¦ // go to bottom of screen; largely like page-up, interestingly -194 ¦ ¦ Top_of_screen = SIZE(Trace_stream->past_lines)-1; -195 ¦ ¦ for (int screen_row = tb_height(); screen_row > 0 && Top_of_screen > 0; --screen_row) { -196 ¦ ¦ ¦ --Top_of_screen; -197 ¦ ¦ ¦ if (Top_of_screen <= 0) break; -198 ¦ ¦ ¦ while (Top_of_screen > 0 && !contains_key(Visible, Top_of_screen)) -199 ¦ ¦ ¦ ¦ --Top_of_screen; -200 ¦ ¦ } -201 ¦ ¦ refresh_screen_rows(); -202 ¦ ¦ // move cursor to bottom -203 ¦ ¦ Display_row = Last_printed_row; -204 ¦ ¦ refresh_screen_rows(); -205 ¦ } -206 ¦ else if (key == TB_KEY_CARRIAGE_RETURN) { -207 ¦ ¦ // expand lines under current by one level -208 ¦ ¦ assert(contains_key(Trace_index, Display_row)); -209 ¦ ¦ int start_index = get(Trace_index, Display_row); -210 ¦ ¦ int index = 0; -211 ¦ ¦ // simultaneously compute end_index and min_depth -212 ¦ ¦ int min_depth = 9999; -213 ¦ ¦ for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { -214 ¦ ¦ ¦ if (contains_key(Visible, index)) break; -215 ¦ ¦ ¦ trace_line& curr_line = Trace_stream->past_lines.at(index); -216 ¦ ¦ ¦ assert(curr_line.depth > Trace_stream->past_lines.at(start_index).depth); -217 ¦ ¦ ¦ if (curr_line.depth < min_depth) min_depth = curr_line.depth; -218 ¦ ¦ } -219 ¦ ¦ int end_index = index; -220 ¦ ¦ // mark as visible all intervening indices at min_depth -221 ¦ ¦ for (index = start_index; index < end_index; ++index) { -222 ¦ ¦ ¦ trace_line& curr_line = Trace_stream->past_lines.at(index); -223 ¦ ¦ ¦ if (curr_line.depth == min_depth) { -224 ¦ ¦ ¦ ¦ Visible.insert(index); -225 ¦ ¦ ¦ } -226 ¦ ¦ } -227 ¦ ¦ refresh_screen_rows(); -228 ¦ } -229 ¦ else if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { -230 ¦ ¦ // collapse all lines under current -231 ¦ ¦ assert(contains_key(Trace_index, Display_row)); -232 ¦ ¦ int start_index = get(Trace_index, Display_row); -233 ¦ ¦ int index = 0; -234 ¦ ¦ // end_index is the next line at a depth same as or lower than start_index -235 ¦ ¦ int initial_depth = Trace_stream->past_lines.at(start_index).depth; -236 ¦ ¦ for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { -237 ¦ ¦ ¦ if (!contains_key(Visible, index)) continue; -238 ¦ ¦ ¦ trace_line& curr_line = Trace_stream->past_lines.at(index); -239 ¦ ¦ ¦ if (curr_line.depth <= initial_depth) break; -240 ¦ ¦ } -241 ¦ ¦ int end_index = index; -242 ¦ ¦ // mark as visible all intervening indices at min_depth -243 ¦ ¦ for (index = start_index+1; index < end_index; ++index) { -244 ¦ ¦ ¦ Visible.erase(index); -245 ¦ ¦ } -246 ¦ ¦ refresh_screen_rows(); -247 ¦ } -248 ¦ else if (key == '/') { -249 ¦ ¦ if (start_search_editor(FORWARD)) -250 ¦ ¦ ¦ search(Current_search_pattern, Current_search_direction); -251 ¦ } -252 ¦ else if (key == '?') { -253 ¦ ¦ if (start_search_editor(BACKWARD)) -254 ¦ ¦ ¦ search(Current_search_pattern, Current_search_direction); -255 ¦ } -256 ¦ else if (key == 'n') { -257 ¦ ¦ if (!Current_search_pattern.empty()) -258 ¦ ¦ ¦ search(Current_search_pattern, Current_search_direction); -259 ¦ } -260 ¦ else if (key == 'N') { -261 ¦ ¦ if (!Current_search_pattern.empty()) -262 ¦ ¦ ¦ search(Current_search_pattern, opposite(Current_search_direction)); -263 ¦ } -264 } -265 tb_shutdown(); -266 } -267 -268 bool start_search_editor(search_direction dir) { -269 const int bottom_screen_line = tb_height()-1; -270 // run a little editor just in the last line of the screen -271 clear_line(bottom_screen_line); -272 tb_set_cursor(0, bottom_screen_line); -273 int col = 0; // screen column of cursor on bottom line. also used to update pattern. -274 tb_change_cell(col, bottom_screen_line, '/', TB_WHITE, TB_BLACK); -275 ++col; -276 tb_set_cursor(col, bottom_screen_line); -277 tb_present(); -278 string pattern; -279 while (true) { -280 ¦ int key = read_key(); -281 ¦ if (key == TB_KEY_ENTER) { -282 ¦ ¦ if (!pattern.empty()) { -283 ¦ ¦ ¦ Current_search_pattern = pattern; -284 ¦ ¦ ¦ Current_search_direction = dir; -285 ¦ ¦ } -286 ¦ ¦ return true; -287 ¦ } -288 ¦ else if (key == TB_KEY_ESC || key == TB_KEY_CTRL_C) { -289 ¦ ¦ return false; -290 ¦ } -291 ¦ else if (key == TB_KEY_ARROW_LEFT) { -292 ¦ ¦ if (col > /*slash*/1) { -293 ¦ ¦ ¦ --col; -294 ¦ ¦ ¦ tb_set_cursor(col, bottom_screen_line); -295 ¦ ¦ ¦ tb_present(); -296 ¦ ¦ } -297 ¦ } -298 ¦ else if (key == TB_KEY_ARROW_RIGHT) { -299 ¦ ¦ if (col-/*slash*/1 < SIZE(pattern)) { -300 ¦ ¦ ¦ ++col; -301 ¦ ¦ ¦ tb_set_cursor(col, bottom_screen_line); -302 ¦ ¦ ¦ tb_present(); -303 ¦ ¦ } -304 ¦ } -305 ¦ else if (key == TB_KEY_HOME || key == TB_KEY_CTRL_A) { -306 ¦ ¦ col = /*skip slash*/1; -307 ¦ ¦ tb_set_cursor(col, bottom_screen_line); -308 ¦ ¦ tb_present(); -309 ¦ } -310 ¦ else if (key == TB_KEY_END || key == TB_KEY_CTRL_E) { -311 ¦ ¦ col = SIZE(pattern)+/*skip slash*/1; -312 ¦ ¦ tb_set_cursor(col, bottom_screen_line); -313 ¦ ¦ tb_present(); -314 ¦ } -315 ¦ else if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { -316 ¦ ¦ if (col > /*slash*/1) { -317 ¦ ¦ ¦ --col; -318 ¦ ¦ ¦ // update pattern -319 ¦ ¦ ¦ pattern.erase(col-/*slash*/1, /*len*/1); -320 ¦ ¦ ¦ // update screen -321 ¦ ¦ ¦ if (col > SIZE(pattern)) { -322 ¦ ¦ ¦ ¦ tb_change_cell(col, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); -323 ¦ ¦ ¦ } -324 ¦ ¦ ¦ else { -325 ¦ ¦ ¦ ¦ assert(col <= SIZE(pattern)); -326 ¦ ¦ ¦ ¦ for (int x = col; x < SIZE(pattern)+/*skip slash*/1; ++x) -327 ¦ ¦ ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); -328 ¦ ¦ ¦ ¦ tb_change_cell(SIZE(pattern)+/*skip slash*/1, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); -329 ¦ ¦ ¦ } -330 ¦ ¦ ¦ tb_set_cursor(col, bottom_screen_line); -331 ¦ ¦ ¦ tb_present(); -332 ¦ ¦ } -333 ¦ } -334 ¦ else if (key < 128) { // ascii only -335 ¦ ¦ // update pattern -336 ¦ ¦ char c = static_cast<char>(key); -337 ¦ ¦ pattern.insert(col-/*slash*/1, /*num*/1, c); -338 ¦ ¦ // update screen -339 ¦ ¦ for (int x = col; x < SIZE(pattern)+/*skip slash*/1; ++x) -340 ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); -341 ¦ ¦ ++col; -342 ¦ ¦ tb_set_cursor(col, bottom_screen_line); -343 ¦ ¦ tb_present(); -344 ¦ } -345 } -346 } -347 -348 void search(const string& pat, search_direction dir) { -349 if (dir == FORWARD) search_next(pat); -350 else search_previous(pat); -351 } -352 -353 search_direction opposite(search_direction dir) { -354 if (dir == FORWARD) return BACKWARD; -355 else return FORWARD; -356 } -357 -358 void search_next(const string& pat) { -359 for (int trace_index = get(Trace_index, Display_row)+1; trace_index < SIZE(Trace_stream->past_lines); ++trace_index) { -360 ¦ if (!contains_key(Visible, trace_index)) continue; -361 ¦ const trace_line& line = Trace_stream->past_lines.at(trace_index); -362 ¦ if (line.label.find(pat) == string::npos && line.contents.find(pat) == string::npos) continue; -363 ¦ Top_of_screen = trace_index; -364 ¦ Display_row = 0; -365 ¦ refresh_screen_rows(); -366 ¦ return; -367 } -368 } -369 -370 void search_previous(const string& pat) { -371 for (int trace_index = get(Trace_index, Display_row)-1; trace_index >= 0; --trace_index) { -372 ¦ if (!contains_key(Visible, trace_index)) continue; -373 ¦ const trace_line& line = Trace_stream->past_lines.at(trace_index); -374 ¦ if (line.label.find(pat) == string::npos && line.contents.find(pat) == string::npos) continue; -375 ¦ Top_of_screen = trace_index; -376 ¦ Display_row = 0; -377 ¦ refresh_screen_rows(); -378 ¦ return; -379 } -380 } -381 -382 void clear_line(int screen_row) { -383 for (int col = 0; col < tb_width(); ++col) -384 ¦ tb_change_cell(col, screen_row, ' ', TB_WHITE, TB_BLACK); -385 } -386 -387 // update Trace_indices for each screen_row on the basis of Top_of_screen and Visible -388 void refresh_screen_rows() { -389 int screen_row = 0, index = 0; -390 Trace_index.clear(); -391 for (screen_row = 0, index = Top_of_screen; screen_row < tb_height() && index < SIZE(Trace_stream->past_lines); ++screen_row, ++index) { -392 ¦ // skip lines without depth for now -393 ¦ while (!contains_key(Visible, index)) { -394 ¦ ¦ ++index; -395 ¦ ¦ if (index >= SIZE(Trace_stream->past_lines)) goto done; -396 ¦ } -397 ¦ assert(index < SIZE(Trace_stream->past_lines)); -398 ¦ put(Trace_index, screen_row, index); + 63 //: `ctrl-u`: clear search pattern before cursor + 64 //: `ctrl-k`: clear search pattern at and after cursor + 65 + 66 :(before "End Primitive Recipe Declarations") + 67 _BROWSE_TRACE, + 68 :(before "End Primitive Recipe Numbers") + 69 put(Recipe_ordinal, "$browse-trace", _BROWSE_TRACE); + 70 :(before "End Primitive Recipe Checks") + 71 case _BROWSE_TRACE: { + 72 break; + 73 } + 74 :(before "End Primitive Recipe Implementations") + 75 case _BROWSE_TRACE: { + 76 start_trace_browser(); + 77 break; + 78 } + 79 + 80 //: browse a trace loaded from a file + 81 :(after "Commandline Parsing") + 82 if (argc == 3 && is_equal(argv[1], "browse-trace")) { + 83 load_trace(argv[2]); + 84 start_trace_browser(); + 85 return 0; + 86 } + 87 + 88 :(before "End Globals") + 89 set<int> Visible; + 90 int Top_of_screen = 0; + 91 int Left_of_screen = 0; + 92 int Last_printed_row = 0; + 93 map<int, int> Trace_index; // screen row -> trace index + 94 string Current_search_pattern = ""; + 95 :(before "End Types") + 96 enum search_direction { FORWARD, BACKWARD }; + 97 :(before "End Globals") + 98 search_direction Current_search_direction = FORWARD; + 99 +100 :(code) +101 void start_trace_browser() { +102 if (!Trace_stream) return; +103 cerr << "computing min depth to display\n"; +104 int min_depth = 9999; +105 for (int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { +106 ¦ trace_line& curr_line = Trace_stream->past_lines.at(i); +107 ¦ if (curr_line.depth < min_depth) min_depth = curr_line.depth; +108 } +109 cerr << "min depth is " << min_depth << '\n'; +110 cerr << "computing lines to display\n"; +111 for (int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { +112 ¦ if (Trace_stream->past_lines.at(i).depth == min_depth) +113 ¦ ¦ Visible.insert(i); +114 } +115 tb_init(); +116 Display_row = Display_column = 0; +117 Top_of_screen = 0; +118 refresh_screen_rows(); +119 while (true) { +120 ¦ render(); +121 ¦ int key = read_key(); +122 ¦ if (key == 'q' || key == 'Q' || key == TB_KEY_CTRL_C) break; +123 ¦ if (key == 'j' || key == TB_KEY_ARROW_DOWN) { +124 ¦ ¦ // move cursor one line down +125 ¦ ¦ if (Display_row < Last_printed_row) ++Display_row; +126 ¦ } +127 ¦ else if (key == 'k' || key == TB_KEY_ARROW_UP) { +128 ¦ ¦ // move cursor one line up +129 ¦ ¦ if (Display_row > 0) --Display_row; +130 ¦ } +131 ¦ else if (key == 't') { +132 ¦ ¦ // move cursor to top of screen +133 ¦ ¦ Display_row = 0; +134 ¦ } +135 ¦ else if (key == 'c') { +136 ¦ ¦ // move cursor to center of screen +137 ¦ ¦ Display_row = tb_height()/2; +138 ¦ ¦ while (!contains_key(Trace_index, Display_row)) +139 ¦ ¦ ¦ --Display_row; +140 ¦ } +141 ¦ else if (key == 'b') { +142 ¦ ¦ // move cursor to bottom of screen +143 ¦ ¦ Display_row = tb_height()-1; +144 ¦ ¦ while (!contains_key(Trace_index, Display_row)) +145 ¦ ¦ ¦ --Display_row; +146 ¦ } +147 ¦ else if (key == 'T') { +148 ¦ ¦ // scroll line at cursor to top of screen +149 ¦ ¦ Top_of_screen = get(Trace_index, Display_row); +150 ¦ ¦ Display_row = 0; +151 ¦ ¦ refresh_screen_rows(); +152 ¦ } +153 ¦ else if (key == 'h' || key == TB_KEY_ARROW_LEFT) { +154 ¦ ¦ // pan screen one character left +155 ¦ ¦ if (Left_of_screen > 0) --Left_of_screen; +156 ¦ } +157 ¦ else if (key == 'l' || key == TB_KEY_ARROW_RIGHT) { +158 ¦ ¦ // pan screen one character right +159 ¦ ¦ ++Left_of_screen; +160 ¦ } +161 ¦ else if (key == 'H') { +162 ¦ ¦ // pan screen one screen-width left +163 ¦ ¦ Left_of_screen -= (tb_width() - 5); +164 ¦ ¦ if (Left_of_screen < 0) Left_of_screen = 0; +165 ¦ } +166 ¦ else if (key == 'L') { +167 ¦ ¦ // pan screen one screen-width right +168 ¦ ¦ Left_of_screen += (tb_width() - 5); +169 ¦ } +170 ¦ else if (key == 'J' || key == TB_KEY_PGDN || key == TB_KEY_CTRL_F) { +171 ¦ ¦ // page-down +172 ¦ ¦ if (Trace_index.find(tb_height()-1) != Trace_index.end()) { +173 ¦ ¦ ¦ Top_of_screen = get(Trace_index, tb_height()-1) + 1; +174 ¦ ¦ ¦ refresh_screen_rows(); +175 ¦ ¦ } +176 ¦ } +177 ¦ else if (key == 'K' || key == TB_KEY_PGUP || key == TB_KEY_CTRL_B) { +178 ¦ ¦ // page-up is more convoluted +179 ¦ ¦ for (int screen_row = tb_height(); screen_row > 0 && Top_of_screen > 0; --screen_row) { +180 ¦ ¦ ¦ --Top_of_screen; +181 ¦ ¦ ¦ if (Top_of_screen <= 0) break; +182 ¦ ¦ ¦ while (Top_of_screen > 0 && !contains_key(Visible, Top_of_screen)) +183 ¦ ¦ ¦ ¦ --Top_of_screen; +184 ¦ ¦ } +185 ¦ ¦ if (Top_of_screen >= 0) +186 ¦ ¦ ¦ refresh_screen_rows(); +187 ¦ } +188 ¦ else if (key == 'g' || key == TB_KEY_HOME) { +189 ¦ ¦ ¦ Top_of_screen = 0; +190 ¦ ¦ ¦ Last_printed_row = 0; +191 ¦ ¦ ¦ Display_row = 0; +192 ¦ ¦ ¦ refresh_screen_rows(); +193 ¦ } +194 ¦ else if (key == 'G' || key == TB_KEY_END) { +195 ¦ ¦ // go to bottom of screen; largely like page-up, interestingly +196 ¦ ¦ Top_of_screen = SIZE(Trace_stream->past_lines)-1; +197 ¦ ¦ for (int screen_row = tb_height(); screen_row > 0 && Top_of_screen > 0; --screen_row) { +198 ¦ ¦ ¦ --Top_of_screen; +199 ¦ ¦ ¦ if (Top_of_screen <= 0) break; +200 ¦ ¦ ¦ while (Top_of_screen > 0 && !contains_key(Visible, Top_of_screen)) +201 ¦ ¦ ¦ ¦ --Top_of_screen; +202 ¦ ¦ } +203 ¦ ¦ refresh_screen_rows(); +204 ¦ ¦ // move cursor to bottom +205 ¦ ¦ Display_row = Last_printed_row; +206 ¦ ¦ refresh_screen_rows(); +207 ¦ } +208 ¦ else if (key == TB_KEY_CARRIAGE_RETURN) { +209 ¦ ¦ // expand lines under current by one level +210 ¦ ¦ assert(contains_key(Trace_index, Display_row)); +211 ¦ ¦ int start_index = get(Trace_index, Display_row); +212 ¦ ¦ int index = 0; +213 ¦ ¦ // simultaneously compute end_index and min_depth +214 ¦ ¦ int min_depth = 9999; +215 ¦ ¦ for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { +216 ¦ ¦ ¦ if (contains_key(Visible, index)) break; +217 ¦ ¦ ¦ trace_line& curr_line = Trace_stream->past_lines.at(index); +218 ¦ ¦ ¦ assert(curr_line.depth > Trace_stream->past_lines.at(start_index).depth); +219 ¦ ¦ ¦ if (curr_line.depth < min_depth) min_depth = curr_line.depth; +220 ¦ ¦ } +221 ¦ ¦ int end_index = index; +222 ¦ ¦ // mark as visible all intervening indices at min_depth +223 ¦ ¦ for (index = start_index; index < end_index; ++index) { +224 ¦ ¦ ¦ trace_line& curr_line = Trace_stream->past_lines.at(index); +225 ¦ ¦ ¦ if (curr_line.depth == min_depth) { +226 ¦ ¦ ¦ ¦ Visible.insert(index); +227 ¦ ¦ ¦ } +228 ¦ ¦ } +229 ¦ ¦ refresh_screen_rows(); +230 ¦ } +231 ¦ else if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { +232 ¦ ¦ // collapse all lines under current +233 ¦ ¦ assert(contains_key(Trace_index, Display_row)); +234 ¦ ¦ int start_index = get(Trace_index, Display_row); +235 ¦ ¦ int index = 0; +236 ¦ ¦ // end_index is the next line at a depth same as or lower than start_index +237 ¦ ¦ int initial_depth = Trace_stream->past_lines.at(start_index).depth; +238 ¦ ¦ for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { +239 ¦ ¦ ¦ if (!contains_key(Visible, index)) continue; +240 ¦ ¦ ¦ trace_line& curr_line = Trace_stream->past_lines.at(index); +241 ¦ ¦ ¦ if (curr_line.depth <= initial_depth) break; +242 ¦ ¦ } +243 ¦ ¦ int end_index = index; +244 ¦ ¦ // mark as visible all intervening indices at min_depth +245 ¦ ¦ for (index = start_index+1; index < end_index; ++index) { +246 ¦ ¦ ¦ Visible.erase(index); +247 ¦ ¦ } +248 ¦ ¦ refresh_screen_rows(); +249 ¦ } +250 ¦ else if (key == '/') { +251 ¦ ¦ if (start_search_editor(FORWARD)) +252 ¦ ¦ ¦ search(Current_search_pattern, Current_search_direction); +253 ¦ } +254 ¦ else if (key == '?') { +255 ¦ ¦ if (start_search_editor(BACKWARD)) +256 ¦ ¦ ¦ search(Current_search_pattern, Current_search_direction); +257 ¦ } +258 ¦ else if (key == 'n') { +259 ¦ ¦ if (!Current_search_pattern.empty()) +260 ¦ ¦ ¦ search(Current_search_pattern, Current_search_direction); +261 ¦ } +262 ¦ else if (key == 'N') { +263 ¦ ¦ if (!Current_search_pattern.empty()) +264 ¦ ¦ ¦ search(Current_search_pattern, opposite(Current_search_direction)); +265 ¦ } +266 } +267 tb_shutdown(); +268 } +269 +270 bool start_search_editor(search_direction dir) { +271 const int bottom_screen_line = tb_height()-1; +272 // run a little editor just in the last line of the screen +273 clear_line(bottom_screen_line); +274 tb_set_cursor(0, bottom_screen_line); +275 int col = 0; // screen column of cursor on bottom line. also used to update pattern. +276 tb_change_cell(col, bottom_screen_line, '/', TB_WHITE, TB_BLACK); +277 ++col; +278 tb_set_cursor(col, bottom_screen_line); +279 tb_present(); +280 string pattern; +281 while (true) { +282 ¦ int key = read_key(); +283 ¦ if (key == TB_KEY_ENTER) { +284 ¦ ¦ if (!pattern.empty()) { +285 ¦ ¦ ¦ Current_search_pattern = pattern; +286 ¦ ¦ ¦ Current_search_direction = dir; +287 ¦ ¦ } +288 ¦ ¦ return true; +289 ¦ } +290 ¦ else if (key == TB_KEY_ESC || key == TB_KEY_CTRL_C) { +291 ¦ ¦ return false; +292 ¦ } +293 ¦ else if (key == TB_KEY_ARROW_LEFT) { +294 ¦ ¦ if (col > /*slash*/1) { +295 ¦ ¦ ¦ --col; +296 ¦ ¦ ¦ tb_set_cursor(col, bottom_screen_line); +297 ¦ ¦ ¦ tb_present(); +298 ¦ ¦ } +299 ¦ } +300 ¦ else if (key == TB_KEY_ARROW_RIGHT) { +301 ¦ ¦ if (col-/*slash*/1 < SIZE(pattern)) { +302 ¦ ¦ ¦ ++col; +303 ¦ ¦ ¦ tb_set_cursor(col, bottom_screen_line); +304 ¦ ¦ ¦ tb_present(); +305 ¦ ¦ } +306 ¦ } +307 ¦ else if (key == TB_KEY_HOME || key == TB_KEY_CTRL_A) { +308 ¦ ¦ col = /*skip slash*/1; +309 ¦ ¦ tb_set_cursor(col, bottom_screen_line); +310 ¦ ¦ tb_present(); +311 ¦ } +312 ¦ else if (key == TB_KEY_END || key == TB_KEY_CTRL_E) { +313 ¦ ¦ col = SIZE(pattern)+/*skip slash*/1; +314 ¦ ¦ tb_set_cursor(col, bottom_screen_line); +315 ¦ ¦ tb_present(); +316 ¦ } +317 ¦ else if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { +318 ¦ ¦ if (col > /*slash*/1) { +319 ¦ ¦ ¦ --col; +320 ¦ ¦ ¦ // update pattern +321 ¦ ¦ ¦ pattern.erase(col-/*slash*/1, /*len*/1); +322 ¦ ¦ ¦ // update screen +323 ¦ ¦ ¦ if (col > SIZE(pattern)) { +324 ¦ ¦ ¦ ¦ tb_change_cell(col, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); +325 ¦ ¦ ¦ } +326 ¦ ¦ ¦ else { +327 ¦ ¦ ¦ ¦ assert(col <= SIZE(pattern)); +328 ¦ ¦ ¦ ¦ for (int x = col; x < SIZE(pattern)+/*skip slash*/1; ++x) +329 ¦ ¦ ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); +330 ¦ ¦ ¦ ¦ tb_change_cell(SIZE(pattern)+/*skip slash*/1, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); +331 ¦ ¦ ¦ } +332 ¦ ¦ ¦ tb_set_cursor(col, bottom_screen_line); +333 ¦ ¦ ¦ tb_present(); +334 ¦ ¦ } +335 ¦ } +336 ¦ else if (key == TB_KEY_CTRL_K) { +337 ¦ ¦ int old_pattern_size = SIZE(pattern); +338 ¦ ¦ pattern.erase(col-/*slash*/1, SIZE(pattern) - (col-/*slash*/1)); +339 ¦ ¦ for (int x = col; x < old_pattern_size+/*slash*/1; ++x) +340 ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); +341 ¦ ¦ tb_set_cursor(col, bottom_screen_line); +342 ¦ ¦ tb_present(); +343 ¦ } +344 ¦ else if (key == TB_KEY_CTRL_U) { +345 ¦ ¦ int old_pattern_size = SIZE(pattern); +346 ¦ ¦ pattern.erase(0, col-/*slash*/1); +347 ¦ ¦ for (int x = /*slash*/1; x < SIZE(pattern)+/*skip slash*/1; ++x) +348 ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); +349 ¦ ¦ for (int x = SIZE(pattern)+/*slash*/1; x < old_pattern_size+/*skip slash*/1; ++x) +350 ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); +351 ¦ ¦ tb_set_cursor(/*start of pattern skipping slash*/1, bottom_screen_line); +352 ¦ ¦ tb_present(); +353 ¦ } +354 ¦ else if (key < 128) { // ascii only +355 ¦ ¦ // update pattern +356 ¦ ¦ char c = static_cast<char>(key); +357 ¦ ¦ pattern.insert(col-/*slash*/1, /*num*/1, c); +358 ¦ ¦ // update screen +359 ¦ ¦ for (int x = col; x < SIZE(pattern)+/*skip slash*/1; ++x) +360 ¦ ¦ ¦ tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); +361 ¦ ¦ ++col; +362 ¦ ¦ tb_set_cursor(col, bottom_screen_line); +363 ¦ ¦ tb_present(); +364 ¦ } +365 } +366 } +367 +368 void search(const string& pat, search_direction dir) { +369 if (dir == FORWARD) search_next(pat); +370 else search_previous(pat); +371 } +372 +373 search_direction opposite(search_direction dir) { +374 if (dir == FORWARD) return BACKWARD; +375 else return FORWARD; +376 } +377 +378 void search_next(const string& pat) { +379 for (int trace_index = get(Trace_index, Display_row)+1; trace_index < SIZE(Trace_stream->past_lines); ++trace_index) { +380 ¦ if (!contains_key(Visible, trace_index)) continue; +381 ¦ const trace_line& line = Trace_stream->past_lines.at(trace_index); +382 ¦ if (line.label.find(pat) == string::npos && line.contents.find(pat) == string::npos) continue; +383 ¦ Top_of_screen = trace_index; +384 ¦ Display_row = 0; +385 ¦ refresh_screen_rows(); +386 ¦ return; +387 } +388 } +389 +390 void search_previous(const string& pat) { +391 for (int trace_index = get(Trace_index, Display_row)-1; trace_index >= 0; --trace_index) { +392 ¦ if (!contains_key(Visible, trace_index)) continue; +393 ¦ const trace_line& line = Trace_stream->past_lines.at(trace_index); +394 ¦ if (line.label.find(pat) == string::npos && line.contents.find(pat) == string::npos) continue; +395 ¦ Top_of_screen = trace_index; +396 ¦ Display_row = 0; +397 ¦ refresh_screen_rows(); +398 ¦ return; 399 } -400 done:; -401 } -402 -403 void render() { -404 int screen_row = 0; -405 for (screen_row = 0; screen_row < tb_height(); ++screen_row) { -406 ¦ if (!contains_key(Trace_index, screen_row)) break; -407 ¦ trace_line& curr_line = Trace_stream->past_lines.at(get(Trace_index, screen_row)); -408 ¦ ostringstream out; -409 ¦ out << std::setw(4) << curr_line.depth << ' ' << curr_line.label << ": " << curr_line.contents; -410 ¦ if (screen_row < tb_height()-1) { -411 ¦ ¦ int delta = lines_hidden(screen_row); -412 ¦ ¦ // home-brew escape sequence for red -413 ¦ ¦ if (delta > 1) { -414 ¦ ¦ ¦ if (delta > 999) out << static_cast<char>(1); -415 ¦ ¦ ¦ out << " (" << delta << ")"; -416 ¦ ¦ ¦ if (delta > 999) out << static_cast<char>(2); -417 ¦ ¦ } -418 ¦ } -419 ¦ render_line(screen_row, out.str(), screen_row == Display_row); -420 } -421 // clear rest of screen -422 Last_printed_row = screen_row-1; -423 for (; screen_row < tb_height(); ++screen_row) -424 ¦ render_line(screen_row, "~", /*cursor_line?*/false); -425 // move cursor back to display row at the end -426 tb_set_cursor(0, Display_row); -427 tb_present(); -428 } -429 -430 int lines_hidden(int screen_row) { -431 assert(contains_key(Trace_index, screen_row)); -432 if (!contains_key(Trace_index, screen_row+1)) -433 ¦ return SIZE(Trace_stream->past_lines) - get(Trace_index, screen_row); -434 else -435 ¦ return get(Trace_index, screen_row+1) - get(Trace_index, screen_row); -436 } -437 -438 void render_line(int screen_row, const string& s, bool cursor_line) { -439 int col = 0; -440 int color = TB_WHITE; -441 int background_color = cursor_line ? /*subtle grey*/240 : TB_BLACK; -442 vector<pair<size_t, size_t> > highlight_ranges = find_all_occurrences(s, Current_search_pattern); -443 for (col = 0; col < tb_width() && col+Left_of_screen < SIZE(s); ++col) { -444 ¦ char c = s.at(col+Left_of_screen); // todo: unicode -445 ¦ if (c == '\n') c = ';'; // replace newlines with semi-colons -446 ¦ // escapes. hack: can't start a line with them. -447 ¦ if (c == '\1') { color = /*red*/1; c = ' '; } -448 ¦ if (c == '\2') { color = TB_WHITE; c = ' '; } -449 ¦ if (in_range(highlight_ranges, col+Left_of_screen)) -450 ¦ ¦ tb_change_cell(col, screen_row, c, TB_BLACK, /*yellow*/11); -451 ¦ else -452 ¦ ¦ tb_change_cell(col, screen_row, c, color, background_color); -453 } -454 for (; col < tb_width(); ++col) -455 ¦ tb_change_cell(col, screen_row, ' ', TB_WHITE, background_color); +400 } +401 +402 void clear_line(int screen_row) { +403 for (int col = 0; col < tb_width(); ++col) +404 ¦ tb_change_cell(col, screen_row, ' ', TB_WHITE, TB_BLACK); +405 } +406 +407 // update Trace_indices for each screen_row on the basis of Top_of_screen and Visible +408 void refresh_screen_rows() { +409 int screen_row = 0, index = 0; +410 Trace_index.clear(); +411 for (screen_row = 0, index = Top_of_screen; screen_row < tb_height() && index < SIZE(Trace_stream->past_lines); ++screen_row, ++index) { +412 ¦ // skip lines without depth for now +413 ¦ while (!contains_key(Visible, index)) { +414 ¦ ¦ ++index; +415 ¦ ¦ if (index >= SIZE(Trace_stream->past_lines)) goto done; +416 ¦ } +417 ¦ assert(index < SIZE(Trace_stream->past_lines)); +418 ¦ put(Trace_index, screen_row, index); +419 } +420 done:; +421 } +422 +423 void render() { +424 int screen_row = 0; +425 for (screen_row = 0; screen_row < tb_height(); ++screen_row) { +426 ¦ if (!contains_key(Trace_index, screen_row)) break; +427 ¦ trace_line& curr_line = Trace_stream->past_lines.at(get(Trace_index, screen_row)); +428 ¦ ostringstream out; +429 ¦ out << std::setw(4) << curr_line.depth << ' ' << curr_line.label << ": " << curr_line.contents; +430 ¦ if (screen_row < tb_height()-1) { +431 ¦ ¦ int delta = lines_hidden(screen_row); +432 ¦ ¦ // home-brew escape sequence for red +433 ¦ ¦ if (delta > 1) { +434 ¦ ¦ ¦ if (delta > 999) out << static_cast<char>(1); +435 ¦ ¦ ¦ out << " (" << delta << ")"; +436 ¦ ¦ ¦ if (delta > 999) out << static_cast<char>(2); +437 ¦ ¦ } +438 ¦ } +439 ¦ render_line(screen_row, out.str(), screen_row == Display_row); +440 } +441 // clear rest of screen +442 Last_printed_row = screen_row-1; +443 for (; screen_row < tb_height(); ++screen_row) +444 ¦ render_line(screen_row, "~", /*cursor_line?*/false); +445 // move cursor back to display row at the end +446 tb_set_cursor(0, Display_row); +447 tb_present(); +448 } +449 +450 int lines_hidden(int screen_row) { +451 assert(contains_key(Trace_index, screen_row)); +452 if (!contains_key(Trace_index, screen_row+1)) +453 ¦ return SIZE(Trace_stream->past_lines) - get(Trace_index, screen_row); +454 else +455 ¦ return get(Trace_index, screen_row+1) - get(Trace_index, screen_row); 456 } 457 -458 vector<pair<size_t, size_t> > find_all_occurrences(const string& s, const string& pat) { -459 vector<pair<size_t, size_t> > result; -460 if (pat.empty()) return result; -461 size_t idx = 0; -462 while (true) { -463 ¦ size_t next_idx = s.find(pat, idx); -464 ¦ if (next_idx == string::npos) break; -465 ¦ result.push_back(pair<size_t, size_t>(next_idx, next_idx+SIZE(pat))); -466 ¦ idx = next_idx+SIZE(pat); -467 } -468 return result; -469 } -470 -471 bool in_range(const vector<pair<size_t, size_t> >& highlight_ranges, size_t idx) { -472 for (int i = 0; i < SIZE(highlight_ranges); ++i) { -473 ¦ if (idx >= highlight_ranges.at(i).first && idx < highlight_ranges.at(i).second) -474 ¦ ¦ return true; -475 ¦ if (idx < highlight_ranges.at(i).second) break; -476 } -477 return false; -478 } -479 -480 void load_trace(const char* filename) { -481 ifstream tin(filename); -482 if (!tin) { -483 ¦ cerr << "no such file: " << filename << '\n'; -484 ¦ exit(1); -485 } -486 Trace_stream = new trace_stream; -487 while (has_data(tin)) { -488 ¦ tin >> std::noskipws; -489 ¦ ¦ skip_whitespace_but_not_newline(tin); -490 ¦ ¦ if (!isdigit(tin.peek())) { -491 ¦ ¦ ¦ string dummy; -492 ¦ ¦ ¦ getline(tin, dummy); -493 ¦ ¦ ¦ continue; -494 ¦ ¦ } -495 ¦ tin >> std::skipws; -496 ¦ int depth; -497 ¦ tin >> depth; -498 ¦ string label; -499 ¦ tin >> label; -500 ¦ if (*--label.end() == ':') label.erase(--label.end()); -501 ¦ string line; -502 ¦ getline(tin, line); -503 ¦ Trace_stream->past_lines.push_back(trace_line(depth, label, line)); -504 } -505 cerr << "lines read: " << Trace_stream->past_lines.size() << '\n'; -506 } -507 -508 int read_key() { -509 tb_event event; -510 do { -511 ¦ tb_poll_event(&event); -512 } while (event.type != TB_EVENT_KEY); -513 return event.key ? event.key : event.ch; -514 } +458 void render_line(int screen_row, const string& s, bool cursor_line) { +459 int col = 0; +460 int color = TB_WHITE; +461 int background_color = cursor_line ? /*subtle grey*/240 : TB_BLACK; +462 vector<pair<size_t, size_t> > highlight_ranges = find_all_occurrences(s, Current_search_pattern); +463 for (col = 0; col < tb_width() && col+Left_of_screen < SIZE(s); ++col) { +464 ¦ char c = s.at(col+Left_of_screen); // todo: unicode +465 ¦ if (c == '\n') c = ';'; // replace newlines with semi-colons +466 ¦ // escapes. hack: can't start a line with them. +467 ¦ if (c == '\1') { color = /*red*/1; c = ' '; } +468 ¦ if (c == '\2') { color = TB_WHITE; c = ' '; } +469 ¦ if (in_range(highlight_ranges, col+Left_of_screen)) +470 ¦ ¦ tb_change_cell(col, screen_row, c, TB_BLACK, /*yellow*/11); +471 ¦ else +472 ¦ ¦ tb_change_cell(col, screen_row, c, color, background_color); +473 } +474 for (; col < tb_width(); ++col) +475 ¦ tb_change_cell(col, screen_row, ' ', TB_WHITE, background_color); +476 } +477 +478 vector<pair<size_t, size_t> > find_all_occurrences(const string& s, const string& pat) { +479 vector<pair<size_t, size_t> > result; +480 if (pat.empty()) return result; +481 size_t idx = 0; +482 while (true) { +483 ¦ size_t next_idx = s.find(pat, idx); +484 ¦ if (next_idx == string::npos) break; +485 ¦ result.push_back(pair<size_t, size_t>(next_idx, next_idx+SIZE(pat))); +486 ¦ idx = next_idx+SIZE(pat); +487 } +488 return result; +489 } +490 +491 bool in_range(const vector<pair<size_t, size_t> >& highlight_ranges, size_t idx) { +492 for (int i = 0; i < SIZE(highlight_ranges); ++i) { +493 ¦ if (idx >= highlight_ranges.at(i).first && idx < highlight_ranges.at(i).second) +494 ¦ ¦ return true; +495 ¦ if (idx < highlight_ranges.at(i).second) break; +496 } +497 return false; +498 } +499 +500 void load_trace(const char* filename) { +501 ifstream tin(filename); +502 if (!tin) { +503 ¦ cerr << "no such file: " << filename << '\n'; +504 ¦ exit(1); +505 } +506 Trace_stream = new trace_stream; +507 while (has_data(tin)) { +508 ¦ tin >> std::noskipws; +509 ¦ ¦ skip_whitespace_but_not_newline(tin); +510 ¦ ¦ if (!isdigit(tin.peek())) { +511 ¦ ¦ ¦ string dummy; +512 ¦ ¦ ¦ getline(tin, dummy); +513 ¦ ¦ ¦ continue; +514 ¦ ¦ } +515 ¦ tin >> std::skipws; +516 ¦ int depth; +517 ¦ tin >> depth; +518 ¦ string label; +519 ¦ tin >> label; +520 ¦ if (*--label.end() == ':') label.erase(--label.end()); +521 ¦ string line; +522 ¦ getline(tin, line); +523 ¦ Trace_stream->past_lines.push_back(trace_line(depth, label, line)); +524 } +525 cerr << "lines read: " << Trace_stream->past_lines.size() << '\n'; +526 } +527 +528 int read_key() { +529 tb_event event; +530 do { +531 ¦ tb_poll_event(&event); +532 } while (event.type != TB_EVENT_KEY); +533 return event.key ? event.key : event.ch; +534 } -- cgit 1.4.1-2-gfad0