• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tstack / lnav / 19470117905-2676

18 Nov 2025 02:44PM UTC coverage: 68.876% (+0.001%) from 68.875%
19470117905-2676

push

github

tstack
[notcurses][input] handle non-matches in escape trie properly

https://github.com/dankamongmen/notcurses/commit/dadd5d39d

51046 of 74113 relevant lines covered (68.88%)

432212.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.29
/src/hist_source.cc
1
/**
2
 * Copyright (c) 2007-2012, Timothy Stack
3
 *
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * * Redistributions of source code must retain the above copyright notice, this
10
 * list of conditions and the following disclaimer.
11
 * * Redistributions in binary form must reproduce the above copyright notice,
12
 * this list of conditions and the following disclaimer in the documentation
13
 * and/or other materials provided with the distribution.
14
 * * Neither the name of Timothy Stack nor the names of its contributors
15
 * may be used to endorse or promote products derived from this software
16
 * without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29

30
#include <optional>
31

32
#include "hist_source.hh"
33

34
#include "base/math_util.hh"
35
#include "config.h"
36
#include "fmt/chrono.h"
37
#include "hist_source_T.hh"
38
#include "textinput_curses.hh"
39

40
std::optional<vis_line_t>
41
hist_source2::row_for_time(timeval tv_bucket)
156✔
42
{
43
    int retval = 0;
156✔
44
    auto time_bucket = rounddown(to_us(tv_bucket), this->hs_time_slice);
156✔
45

46
    for (auto& bb : this->hs_blocks) {
160✔
47
        if (time_bucket < bb.bb_buckets[0].b_time) {
156✔
48
            break;
16✔
49
        }
50
        if (time_bucket > bb.bb_buckets[bb.bb_used].b_time) {
140✔
51
            retval += bb.bb_used + 1;
4✔
52
            continue;
4✔
53
        }
54

55
        for (unsigned int lpc = 0; lpc <= bb.bb_used; lpc++, retval++) {
142✔
56
            if (time_bucket <= bb.bb_buckets[lpc].b_time) {
142✔
57
                return vis_line_t(retval);
136✔
58
            }
59
        }
60
    }
61
    return vis_line_t(retval);
20✔
62
}
63

64
line_info
65
hist_source2::text_value_for_line(textview_curses& tc,
11✔
66
                                  int row,
67
                                  std::string& value_out,
68
                                  line_flags_t flags)
69
{
70
    auto& bucket = this->find_bucket(row);
11✔
71
    struct tm bucket_tm;
72

73
    if (this->hs_needs_flush) {
11✔
74
        this->end_of_row();
11✔
75
    }
76

77
    value_out.clear();
11✔
78
    auto secs = to_time_t(bucket.b_time);
11✔
79
    if (gmtime_r(&secs, &bucket_tm) != nullptr) {
11✔
80
        fmt::format_to(std::back_inserter(value_out),
11✔
81
                       FMT_STRING(" {:%a %b %d %H:%M:%S %Y}  "),
44✔
82
                       bucket_tm);
83
    } else {
84
        log_error("no time?");
×
85
    }
86
    fmt::format_to(
11✔
87
        std::back_inserter(value_out),
88
        FMT_STRING(" {:8L} normal  {:8L} errors  {:8L} warnings  {:8L} marks"),
22✔
89
        rint(bucket.value_for(hist_type_t::HT_NORMAL).hv_value),
11✔
90
        rint(bucket.value_for(hist_type_t::HT_ERROR).hv_value),
11✔
91
        rint(bucket.value_for(hist_type_t::HT_WARNING).hv_value),
11✔
92
        rint(bucket.value_for(hist_type_t::HT_MARK).hv_value));
11✔
93

94
    return {};
22✔
95
}
96

97
void
98
hist_source2::text_attrs_for_line(textview_curses& tc,
11✔
99
                                  int row,
100
                                  string_attrs_t& value_out)
101
{
102
    auto& bucket = this->find_bucket(row);
11✔
103
    auto dim = tc.get_dimensions();
11✔
104
    auto width = dim.second;
11✔
105
    int left = 0;
11✔
106

107
    if (width > 0 && tc.get_show_scrollbar()) {
11✔
108
        width -= 1;
2✔
109
    }
110
    for (int lpc = 0; lpc < lnav::enums::to_underlying(hist_type_t::HT__MAX);
55✔
111
         lpc++)
112
    {
113
        this->hs_chart.chart_attrs_for_value(tc,
44✔
114
                                             left,
115
                                             width,
116
                                             (const hist_type_t) lpc,
44✔
117
                                             bucket.b_values[lpc].hv_value,
118
                                             value_out);
119
    }
120
    auto alt_row_index = row % 4;
11✔
121
    if (alt_row_index == 2 || alt_row_index == 3) {
11✔
122
        value_out.emplace_back(line_range{0, -1},
2✔
123
                               VC_ROLE.value(role_t::VCR_ALT_ROW));
4✔
124
    }
125
}
11✔
126

127
void
128
hist_source2::add_value(std::chrono::microseconds ts,
12,657✔
129
                        hist_type_t htype,
130
                        double value)
131
{
132
    require_ge(ts.count(), this->hs_last_ts.count());
12,657✔
133

134
    ts = rounddown(ts, this->hs_time_slice);
12,657✔
135
    if (ts != this->hs_last_ts) {
12,657✔
136
        this->end_of_row();
968✔
137

138
        this->hs_current_row += 1;
968✔
139
        this->hs_last_ts = ts;
968✔
140
    }
141

142
    auto& bucket = this->find_bucket(this->hs_current_row);
12,657✔
143
    bucket.b_time = ts;
12,657✔
144
    bucket.value_for(htype).hv_value += value;
12,657✔
145

146
    this->hs_needs_flush = true;
12,657✔
147
}
12,657✔
148

149
void
150
hist_source2::init()
5,507✔
151
{
152
    auto& vc = view_colors::singleton();
5,507✔
153

154
    this->hs_chart.with_show_state(stacked_bar_chart_base::show_all{})
5,507✔
155
        .with_attrs_for_ident(hist_type_t::HT_NORMAL,
5,507✔
156
                              vc.attrs_for_role(role_t::VCR_TEXT))
157
        .with_attrs_for_ident(hist_type_t::HT_WARNING,
5,507✔
158
                              vc.attrs_for_role(role_t::VCR_WARNING))
159
        .with_attrs_for_ident(hist_type_t::HT_ERROR,
5,507✔
160
                              vc.attrs_for_role(role_t::VCR_ERROR))
161
        .with_attrs_for_ident(hist_type_t::HT_MARK,
5,507✔
162
                              vc.attrs_for_role(role_t::VCR_COMMENT));
163
}
5,507✔
164

165
size_t
166
hist_source2::text_line_width(textview_curses& curses)
5,235✔
167
{
168
    return 63 + 8 * 4;
5,235✔
169
}
170

171
void
172
hist_source2::clear()
4,875✔
173
{
174
    this->hs_line_count = 0;
4,875✔
175
    this->hs_current_row = -1;
4,875✔
176
    this->hs_last_ts = std::chrono::microseconds::min();
4,875✔
177
    this->hs_blocks.clear();
4,875✔
178
    this->hs_chart.clear();
4,875✔
179
    if (this->tss_view != nullptr) {
4,875✔
180
        this->tss_view->get_bookmarks().clear();
3,709✔
181
    }
182
    this->init();
4,875✔
183
}
4,875✔
184

185
void
186
hist_source2::end_of_row()
979✔
187
{
188
    if (this->hs_current_row >= 0) {
979✔
189
        auto& last_bucket = this->find_bucket(this->hs_current_row);
365✔
190

191
        for (size_t lpc = 0;
1,825✔
192
             lpc < lnav::enums::to_underlying(hist_type_t::HT__MAX);
1,825✔
193
             lpc++)
194
        {
195
            auto& hv = last_bucket.b_values[lpc];
1,460✔
196
            this->hs_chart.add_value((const hist_type_t) lpc, hv.hv_value);
1,460✔
197

198
            if (hv.hv_value > 0.0) {
1,460✔
199
                const bookmark_type_t* bt = nullptr;
511✔
200
                switch ((hist_type_t) lpc) {
511✔
201
                    case hist_type_t::HT_WARNING: {
6✔
202
                        bt = &textview_curses::BM_WARNINGS;
6✔
203
                        break;
6✔
204
                    }
205
                    case hist_type_t::HT_ERROR: {
179✔
206
                        bt = &textview_curses::BM_ERRORS;
179✔
207
                        break;
179✔
208
                    }
209
                    case hist_type_t::HT_MARK: {
16✔
210
                        bt = &textview_curses::BM_META;
16✔
211
                        break;
16✔
212
                    }
213
                    default:
310✔
214
                        break;
310✔
215
                }
216
                if (bt != nullptr) {
511✔
217
                    auto& bm = this->tss_view->get_bookmarks();
201✔
218
                    bm[bt].insert_once(vis_line_t(this->hs_current_row));
201✔
219
                }
220
            }
221
        }
222
        this->hs_chart.next_row();
365✔
223
    }
224
}
979✔
225

226
std::optional<text_time_translator::row_info>
227
hist_source2::time_for_row(vis_line_t row)
629✔
228
{
229
    if (row < 0 || row > this->hs_line_count) {
629✔
230
        return std::nullopt;
×
231
    }
232

233
    const auto& bucket = this->find_bucket(row);
629✔
234

235
    return row_info{timeval{to_time_t(bucket.b_time), 0}, row};
629✔
236
}
237

238
hist_source2::bucket_t&
239
hist_source2::find_bucket(int64_t index)
13,673✔
240
{
241
    const auto block_index = index / BLOCK_SIZE;
13,673✔
242
    if (block_index >= (ssize_t) this->hs_blocks.size()) {
13,673✔
243
        this->hs_blocks.resize(block_index + 1);
614✔
244
    }
245
    auto& bb = this->hs_blocks[block_index];
13,673✔
246
    const unsigned int intra_block_index = index % BLOCK_SIZE;
13,673✔
247
    bb.bb_used = std::max(intra_block_index, bb.bb_used);
13,673✔
248
    this->hs_line_count = std::max(this->hs_line_count, index + 1);
13,673✔
249
    return bb.bb_buckets[intra_block_index];
13,673✔
250
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc