about summary refs log tree commit diff stats
path: root/html/100trace_browser.cc.html
blob: a2aee17e9ea32f7ba261da7eccc3fd3f7b4fff28 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weigh
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 100trace_browser.cc</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="cpp">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 12pt; font-size: 1em; }
.Constant { color: #00a0a0; }
.Comment { color: #9090ff; }
.Delimiter { color: #800080; }
.cSpecial { color: #008000; }
.Identifier { color: #fcb165; }
.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
-->
</style>

<script type='text/javascript'>
<!--

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment">//: A debugging helper that lets you zoom in/out on a trace.</span>

<span class="Comment">//: browse the trace we just created</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span>
_BROWSE_TRACE<span class="Delimiter">,</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span>
put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;$browse-trace&quot;</span><span class="Delimiter">,</span> _BROWSE_TRACE<span class="Delimiter">);</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span>
<span class="Normal">case</span> _BROWSE_TRACE: <span class="Delimiter">{</span>
  <span class="Identifier">break</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
<span class="Normal">case</span> _BROWSE_TRACE: <span class="Delimiter">{</span>
  start_trace_browser<span class="Delimiter">();</span>
  <span class="Identifier">break</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Comment">//: browse a trace loaded from a file</span>
<span class="Delimiter">:(after &quot;Commandline Parsing&quot;)</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>argc == <span class="Constant">3</span> &amp;&amp; is_equal<span class="Delimiter">(</span>argv[<span class="Constant">1</span>]<span class="Delimiter">,</span> <span class="Constant">&quot;browse-trace&quot;</span><span class="Delimiter">))</span> <span class="Delimiter">{</span>
  load_trace<span class="Delimiter">(</span>argv[<span class="Constant">2</span>]<span class="Delimiter">);</span>
  start_trace_browser<span class="Delimiter">();</span>
  <span class="Identifier">return</span> <span class="Constant">0</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
set&lt;<span class="Normal">int</span>&gt; Visible<span class="Delimiter">;</span>
<span class="Normal">int</span> Top_of_screen = <span class="Constant">0</span><span class="Delimiter">;</span>
<span class="Normal">int</span> Last_printed_row = <span class="Constant">0</span><span class="Delimiter">;</span>
map&lt;<span class="Normal">int</span><span class="Delimiter">,</span> <span class="Normal">int</span>&gt; Trace_index<span class="Delimiter">;</span>  <span class="Comment">// screen row -&gt; trace index</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> start_trace_browser<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  cerr &lt;&lt; <span class="Constant">&quot;computing min depth to display</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span>
  <span class="Normal">int</span> min_depth = <span class="Constant">9999</span><span class="Delimiter">;</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    trace_line&amp; curr_line = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>curr_line<span class="Delimiter">.</span>depth &lt; min_depth<span class="Delimiter">)</span> min_depth = curr_line<span class="Delimiter">.</span>depth<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  cerr &lt;&lt; <span class="Constant">&quot;min depth is &quot;</span> &lt;&lt; min_depth &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
  cerr &lt;&lt; <span class="Constant">&quot;computing lines to display</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>depth == min_depth<span class="Delimiter">)</span>
      Visible<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  tb_init<span class="Delimiter">();</span>
  Display_row = Display_column = <span class="Constant">0</span><span class="Delimiter">;</span>
  tb_event event<span class="Delimiter">;</span>
  Top_of_screen = <span class="Constant">0</span><span class="Delimiter">;</span>
  refresh_screen_rows<span class="Delimiter">();</span>
  <span class="Normal">while</span> <span class="Delimiter">(</span><span class="Constant">true</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    render<span class="Delimiter">();</span>
    <span class="Normal">do</span> <span class="Delimiter">{</span>
      tb_poll_event<span class="Delimiter">(</span>&amp;event<span class="Delimiter">);</span>
    <span class="Delimiter">}</span> <span class="Normal">while</span> <span class="Delimiter">(</span>event<span class="Delimiter">.</span>type != TB_EVENT_KEY<span class="Delimiter">);</span>
    <span class="Normal">int</span> key = event<span class="Delimiter">.</span>key ? event<span class="Delimiter">.</span>key : event<span class="Delimiter">.</span>ch<span class="Delimiter">;</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'q'</span> || key == <span class="Constant">'Q'</span><span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'j'</span> || key == TB_KEY_ARROW_DOWN<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// move cursor one line down</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>Display_row &lt; Last_printed_row<span class="Delimiter">)</span> ++Display_row<span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'k'</span> || key == TB_KEY_ARROW_UP<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// move cursor one line up</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>Display_row &gt; <span class="Constant">0</span><span class="Delimiter">)</span> --Display_row<span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'H'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// move cursor to top of screen</span>
      Display_row = <span class="Constant">0</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'M'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// move cursor to center of screen</span>
      Display_row = tb_height<span class="Delimiter">()</span>/<span class="Constant">2</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'L'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// move cursor to bottom of screen</span>
      Display_row = tb_height<span class="Delimiter">()</span>-<span class="Constant">1</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'J'</span> || key == TB_KEY_PGDN<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// page-down</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>Trace_index<span class="Delimiter">.</span>find<span class="Delimiter">(</span>tb_height<span class="Delimiter">()</span>-<span class="Constant">1</span><span class="Delimiter">)</span> != Trace_index<span class="Delimiter">.</span>end<span class="Delimiter">())</span> <span class="Delimiter">{</span>
        Top_of_screen = get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> tb_height<span class="Delimiter">()</span>-<span class="Constant">1</span><span class="Delimiter">)</span> + <span class="Constant">1</span><span class="Delimiter">;</span>
        refresh_screen_rows<span class="Delimiter">();</span>
      <span class="Delimiter">}</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'K'</span> || key == TB_KEY_PGUP<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// page-up is more convoluted</span>
      <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> screen_row = tb_height<span class="Delimiter">();</span> screen_row &gt; <span class="Constant">0</span> &amp;&amp; Top_of_screen &gt; <span class="Constant">0</span><span class="Delimiter">;</span> --screen_row<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        --Top_of_screen<span class="Delimiter">;</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>Top_of_screen &lt;= <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
        <span class="Normal">while</span> <span class="Delimiter">(</span>Top_of_screen &gt; <span class="Constant">0</span> &amp;&amp; !contains_key<span class="Delimiter">(</span>Visible<span class="Delimiter">,</span> Top_of_screen<span class="Delimiter">))</span>
          --Top_of_screen<span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>Top_of_screen &gt;= <span class="Constant">0</span><span class="Delimiter">)</span>
        refresh_screen_rows<span class="Delimiter">();</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == <span class="Constant">'G'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// go to bottom of screen; largely like page-up, interestingly</span>
      Top_of_screen = SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">)</span>-<span class="Constant">1</span><span class="Delimiter">;</span>
      <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> screen_row = tb_height<span class="Delimiter">();</span> screen_row &gt; <span class="Constant">0</span> &amp;&amp; Top_of_screen &gt; <span class="Constant">0</span><span class="Delimiter">;</span> --screen_row<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        --Top_of_screen<span class="Delimiter">;</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>Top_of_screen &lt;= <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
        <span class="Normal">while</span> <span class="Delimiter">(</span>Top_of_screen &gt; <span class="Constant">0</span> &amp;&amp; !contains_key<span class="Delimiter">(</span>Visible<span class="Delimiter">,</span> Top_of_screen<span class="Delimiter">))</span>
          --Top_of_screen<span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      refresh_screen_rows<span class="Delimiter">();</span>
      <span class="Comment">// move cursor to bottom</span>
      Display_row = Last_printed_row<span class="Delimiter">;</span>
      refresh_screen_rows<span class="Delimiter">();</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == TB_KEY_CARRIAGE_RETURN<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// expand lines under current by one level</span>
      assert<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> Display_row<span class="Delimiter">));</span>
      <span class="Normal">int</span> start_index = get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> Display_row<span class="Delimiter">);</span>
      <span class="Normal">int</span> index = <span class="Constant">0</span><span class="Delimiter">;</span>
      <span class="Comment">// simultaneously compute end_index and min_depth</span>
      <span class="Normal">int</span> min_depth = <span class="Constant">9999</span><span class="Delimiter">;</span>
      <span class="Normal">for</span> <span class="Delimiter">(</span>index = start_index+<span class="Constant">1</span><span class="Delimiter">;</span> index &lt; SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">);</span> ++index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Visible<span class="Delimiter">,</span> index<span class="Delimiter">))</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
        trace_line&amp; curr_line = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>index<span class="Delimiter">);</span>
        assert<span class="Delimiter">(</span>curr_line<span class="Delimiter">.</span>depth &gt; Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>start_index<span class="Delimiter">).</span>depth<span class="Delimiter">);</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>curr_line<span class="Delimiter">.</span>depth &lt; min_depth<span class="Delimiter">)</span> min_depth = curr_line<span class="Delimiter">.</span>depth<span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      <span class="Normal">int</span> end_index = index<span class="Delimiter">;</span>
      <span class="Comment">// mark as visible all intervening indices at min_depth</span>
      <span class="Normal">for</span> <span class="Delimiter">(</span>index = start_index<span class="Delimiter">;</span> index &lt; end_index<span class="Delimiter">;</span> ++index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        trace_line&amp; curr_line = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>index<span class="Delimiter">);</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>curr_line<span class="Delimiter">.</span>depth == min_depth<span class="Delimiter">)</span> <span class="Delimiter">{</span>
          Visible<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>index<span class="Delimiter">);</span>
        <span class="Delimiter">}</span>
      <span class="Delimiter">}</span>
      refresh_screen_rows<span class="Delimiter">();</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Comment">// collapse all lines under current</span>
      assert<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> Display_row<span class="Delimiter">));</span>
      <span class="Normal">int</span> start_index = get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> Display_row<span class="Delimiter">);</span>
      <span class="Normal">int</span> index = <span class="Constant">0</span><span class="Delimiter">;</span>
      <span class="Comment">// end_index is the next line at a depth same as or lower than start_index</span>
      <span class="Normal">int</span> initial_depth = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>start_index<span class="Delimiter">).</span>depth<span class="Delimiter">;</span>
      <span class="Normal">for</span> <span class="Delimiter">(</span>index = start_index+<span class="Constant">1</span><span class="Delimiter">;</span> index &lt; SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">);</span> ++index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Visible<span class="Delimiter">,</span> index<span class="Delimiter">))</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
        trace_line&amp; curr_line = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>index<span class="Delimiter">);</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>curr_line<span class="Delimiter">.</span>depth &lt;= initial_depth<span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      <span class="Normal">int</span> end_index = index<span class="Delimiter">;</span>
      <span class="Comment">// mark as visible all intervening indices at min_depth</span>
      <span class="Normal">for</span> <span class="Delimiter">(</span>index = start_index+<span class="Constant">1</span><span class="Delimiter">;</span> index &lt; end_index<span class="Delimiter">;</span> ++index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        Visible<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>index<span class="Delimiter">);</span>
      <span class="Delimiter">}</span>
      refresh_screen_rows<span class="Delimiter">();</span>
    <span class="Delimiter">}</span>
  <span class="Delimiter">}</span>
  tb_shutdown<span class="Delimiter">();</span>
<span class="Delimiter">}</span>

<span class="Comment">// update Trace_indices for each screen_row on the basis of Top_of_screen and Visible</span>
<span class="Normal">void</span> refresh_screen_rows<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  <span class="Normal">int</span> screen_row = <span class="Constant">0</span><span class="Delimiter">,</span> index = <span class="Constant">0</span><span class="Delimiter">;</span>
  Trace_index<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span>screen_row = <span class="Constant">0</span><span class="Delimiter">,</span> index = Top_of_screen<span class="Delimiter">;</span> screen_row &lt; tb_height<span class="Delimiter">()</span> &amp;&amp; index &lt; SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">);</span> ++screen_row<span class="Delimiter">,</span> ++index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Comment">// skip lines without depth for now</span>
    <span class="Normal">while</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Visible<span class="Delimiter">,</span> index<span class="Delimiter">))</span> <span class="Delimiter">{</span>
      ++index<span class="Delimiter">;</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>index &gt;= SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">))</span> <span class="Identifier">goto</span> done<span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    assert<span class="Delimiter">(</span>index &lt; SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">));</span>
    put<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row<span class="Delimiter">,</span> index<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
<span class="Normal">done</span>:<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> render<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  <span class="Normal">int</span> screen_row = <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span>screen_row = <span class="Constant">0</span><span class="Delimiter">;</span> screen_row &lt; tb_height<span class="Delimiter">();</span> ++screen_row<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row<span class="Delimiter">))</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
    trace_line&amp; curr_line = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row<span class="Delimiter">));</span>
    ostringstream out<span class="Delimiter">;</span>
    out &lt;&lt; std::setw<span class="Delimiter">(</span><span class="Constant">4</span><span class="Delimiter">)</span> &lt;&lt; curr_line<span class="Delimiter">.</span>depth &lt;&lt; <span class="Constant">' '</span> &lt;&lt; curr_line<span class="Delimiter">.</span>label &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; curr_line<span class="Delimiter">.</span>contents<span class="Delimiter">;</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>screen_row &lt; tb_height<span class="Delimiter">()</span>-<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Normal">int</span> delta = lines_hidden<span class="Delimiter">(</span>screen_row<span class="Delimiter">);</span>
      <span class="Comment">// home-brew escape sequence for red</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>delta &gt; <span class="Constant">999</span><span class="Delimiter">)</span> out &lt;&lt; <span class="Constant">&quot;{&quot;</span><span class="Delimiter">;</span>
      out &lt;&lt; <span class="Constant">&quot; (&quot;</span> &lt;&lt; delta &lt;&lt; <span class="Constant">&quot;)&quot;</span><span class="Delimiter">;</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>delta &gt; <span class="Constant">999</span><span class="Delimiter">)</span> out &lt;&lt; <span class="Constant">&quot;}&quot;</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    render_line<span class="Delimiter">(</span>screen_row<span class="Delimiter">,</span> out<span class="Delimiter">.</span>str<span class="Delimiter">());</span>
  <span class="Delimiter">}</span>
  <span class="Comment">// clear rest of screen</span>
  Last_printed_row = screen_row-<span class="Constant">1</span><span class="Delimiter">;</span>
  <span class="Normal">for</span> <span class="Delimiter">(;</span> screen_row &lt; tb_height<span class="Delimiter">();</span> ++screen_row<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    render_line<span class="Delimiter">(</span>screen_row<span class="Delimiter">,</span> <span class="Constant">&quot;~&quot;</span><span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  <span class="Comment">// move cursor back to display row at the end</span>
  tb_set_cursor<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> Display_row<span class="Delimiter">);</span>
  tb_present<span class="Delimiter">();</span>
<span class="Delimiter">}</span>

<span class="Normal">int</span> lines_hidden<span class="Delimiter">(</span><span class="Normal">int</span> screen_row<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  assert<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row<span class="Delimiter">));</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row+<span class="Constant">1</span><span class="Delimiter">))</span>
    <span class="Identifier">return</span> SIZE<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">)</span> - get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row<span class="Delimiter">);</span>
  <span class="Normal">else</span>
    <span class="Identifier">return</span> get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row+<span class="Constant">1</span><span class="Delimiter">)</span> - get<span class="Delimiter">(</span>Trace_index<span class="Delimiter">,</span> screen_row<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> render_line<span class="Delimiter">(</span><span class="Normal">int</span> screen_row<span class="Delimiter">,</span> <span class="Normal">const</span> string&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">int</span> col = <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Normal">int</span> color = TB_WHITE<span class="Delimiter">;</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span>col = <span class="Constant">0</span><span class="Delimiter">;</span> col &lt; tb_width<span class="Delimiter">()</span> &amp;&amp; col &lt; SIZE<span class="Delimiter">(</span>s<span class="Delimiter">);</span> ++col<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">char</span> c = s<span class="Delimiter">.</span>at<span class="Delimiter">(</span>col<span class="Delimiter">);</span>  <span class="Comment">// todo: unicode</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>c == <span class="cSpecial">'\n'</span><span class="Delimiter">)</span> c = <span class="Constant">';'</span><span class="Delimiter">;</span>  <span class="Comment">// replace newlines with semi-colons</span>
    <span class="Comment">// escapes. hack: can't start a line with them.</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>c == <span class="Constant">'{'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> color = <span class="Comment">/*</span><span class="Comment">red</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">;</span> c = <span class="Constant">' '</span><span class="Delimiter">;</span> <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>c == <span class="Constant">'}'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> color = TB_WHITE<span class="Delimiter">;</span> c = <span class="Constant">' '</span><span class="Delimiter">;</span> <span class="Delimiter">}</span>
    tb_change_cell<span class="Delimiter">(</span>col<span class="Delimiter">,</span> screen_row<span class="Delimiter">,</span> c<span class="Delimiter">,</span> color<span class="Delimiter">,</span> TB_BLACK<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  <span class="Normal">for</span> <span class="Delimiter">(;</span> col &lt; tb_width<span class="Delimiter">();</span> ++col<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    tb_change_cell<span class="Delimiter">(</span>col<span class="Delimiter">,</span> screen_row<span class="Delimiter">,</span> <span class="Constant">' '</span><span class="Delimiter">,</span> TB_WHITE<span class="Delimiter">,</span> TB_BLACK<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> load_trace<span class="Delimiter">(</span><span class="Normal">const</span> <span class="Normal">char</span>* filename<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  ifstream tin<span class="Delimiter">(</span>filename<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!tin<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    cerr &lt;&lt; <span class="Constant">&quot;no such file: &quot;</span> &lt;&lt; filename &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
    exit<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  Trace_stream = <span class="Normal">new</span> trace_stream<span class="Delimiter">;</span>
  <span class="Normal">while</span> <span class="Delimiter">(</span>has_data<span class="Delimiter">(</span>tin<span class="Delimiter">))</span> <span class="Delimiter">{</span>
    tin &gt;&gt; std::noskipws<span class="Delimiter">;</span>
      skip_whitespace_but_not_newline<span class="Delimiter">(</span>tin<span class="Delimiter">);</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>!isdigit<span class="Delimiter">(</span>tin<span class="Delimiter">.</span>peek<span class="Delimiter">()))</span> <span class="Delimiter">{</span>
        string dummy<span class="Delimiter">;</span>
        getline<span class="Delimiter">(</span>tin<span class="Delimiter">,</span> dummy<span class="Delimiter">);</span>
        <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
    tin &gt;&gt; std::skipws<span class="Delimiter">;</span>
    <span class="Normal">int</span> depth<span class="Delimiter">;</span>
    tin &gt;&gt; depth<span class="Delimiter">;</span>
    string label<span class="Delimiter">;</span>
    tin &gt;&gt; label<span class="Delimiter">;</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>*--label<span class="Delimiter">.</span>end<span class="Delimiter">()</span> == <span class="Constant">':'</span><span class="Delimiter">)</span> label<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>--label<span class="Delimiter">.</span>end<span class="Delimiter">());</span>
    string line<span class="Delimiter">;</span>
    getline<span class="Delimiter">(</span>tin<span class="Delimiter">,</span> line<span class="Delimiter">);</span>
    Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>trace_line<span class="Delimiter">(</span>depth<span class="Delimiter">,</span> label<span class="Delimiter">,</span> line<span class="Delimiter">));</span>
  <span class="Delimiter">}</span>
  cerr &lt;&lt; <span class="Constant">&quot;lines read: &quot;</span> &lt;&lt; Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>size<span class="Delimiter">()</span> &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->