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

tstack / lnav / 11927164159-1768

20 Nov 2024 05:11AM UTC coverage: 70.195% (-0.04%) from 70.233%
11927164159-1768

push

github

tstack
skip parsing really long log messages

3 of 4 new or added lines in 2 files covered. (75.0%)

25 existing lines in 5 files now uncovered.

46296 of 65953 relevant lines covered (70.2%)

467535.34 hits per line

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

77.02
/src/filter_status_source.cc
1
/**
2
 * Copyright (c) 2018, 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 "filter_status_source.hh"
31

32
#include "base/ansi_scrubber.hh"
33
#include "base/opt_util.hh"
34
#include "config.h"
35
#include "files_sub_source.hh"
36
#include "filter_sub_source.hh"
37
#include "lnav.hh"
38

39
static auto TOGGLE_MSG = "Press " ANSI_BOLD("TAB") " to edit ";
40
static auto EXIT_MSG = "Press " ANSI_BOLD("ESC") " to exit ";
41

42
static auto CREATE_HELP = ANSI_BOLD("i") "/" ANSI_BOLD("o") ": Create in/out";
43
static auto ENABLE_HELP = ANSI_BOLD("SPC") ": ";
44
static auto EDIT_HELP = ANSI_BOLD("ENTER") ": Edit";
45
static auto TOGGLE_HELP = ANSI_BOLD("t") ": To ";
46
static auto DELETE_HELP = ANSI_BOLD("D") ": Delete";
47
static auto FILTERING_HELP = ANSI_BOLD("f") ": ";
48
static auto JUMP_HELP = ANSI_BOLD("ENTER") ": Jump To";
49
static auto CLOSE_HELP = ANSI_BOLD("X") ": Close";
50
static auto FOCUS_DETAILS_HELP = ANSI_BOLD("CTRL-]") ": Focus on details view";
51

52
filter_status_source::
1,021✔
53
filter_status_source()
8,168✔
54
{
55
    this->tss_fields[TSF_TITLE].set_width(14);
1,021✔
56
    this->tss_fields[TSF_TITLE].set_role(role_t::VCR_STATUS_TITLE);
1,021✔
57
    this->tss_fields[TSF_TITLE].set_value(" " ANSI_ROLE("T") "ext Filters ",
1,021✔
58
                                          role_t::VCR_STATUS_TITLE_HOTKEY);
59
    this->tss_fields[TSF_TITLE].on_click
60
        = [](status_field&) { set_view_mode(ln_mode_t::FILTER); };
1,021✔
61

62
    this->tss_fields[TSF_STITCH_TITLE].set_width(2);
1,021✔
63
    this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
1,021✔
64
        role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
65
        role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
66

67
    this->tss_fields[TSF_COUNT].set_min_width(16);
1,021✔
68
    this->tss_fields[TSF_COUNT].set_share(1);
1,021✔
69
    this->tss_fields[TSF_COUNT].set_role(role_t::VCR_STATUS);
1,021✔
70

71
    this->tss_fields[TSF_FILTERED].set_min_width(20);
1,021✔
72
    this->tss_fields[TSF_FILTERED].set_share(1);
1,021✔
73
    this->tss_fields[TSF_FILTERED].set_role(role_t::VCR_STATUS);
1,021✔
74

75
    this->tss_fields[TSF_FILES_TITLE].set_width(7);
1,021✔
76
    this->tss_fields[TSF_FILES_TITLE].set_role(
1,021✔
77
        role_t::VCR_STATUS_DISABLED_TITLE);
78
    this->tss_fields[TSF_FILES_TITLE].set_value(" " ANSI_ROLE("F") "iles ",
1,021✔
79
                                                role_t::VCR_STATUS_HOTKEY);
80
    this->tss_fields[TSF_FILES_TITLE].on_click
81
        = [](status_field&) { set_view_mode(ln_mode_t::FILES); };
1,021✔
82

83
    this->tss_fields[TSF_FILES_RIGHT_STITCH].set_width(2);
1,021✔
84
    this->tss_fields[TSF_FILES_RIGHT_STITCH].set_stitch_value(
1,021✔
85
        role_t::VCR_STATUS, role_t::VCR_STATUS);
86

87
    this->tss_fields[TSF_HELP].right_justify(true);
1,021✔
88
    this->tss_fields[TSF_HELP].set_width(20);
1,021✔
89
    this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
1,021✔
90
    this->tss_fields[TSF_HELP].set_left_pad(1);
1,021✔
91

92
    this->tss_error.set_min_width(20);
1,021✔
93
    this->tss_error.set_share(1);
1,021✔
94
    this->tss_error.set_role(role_t::VCR_ALERT_STATUS);
1,021✔
95
}
1,021✔
96

97
size_t
98
filter_status_source::statusview_fields()
156✔
99
{
100
    switch (lnav_data.ld_mode) {
156✔
101
        case ln_mode_t::SEARCH_FILTERS:
×
102
        case ln_mode_t::SEARCH_FILES:
103
            this->tss_fields[TSF_HELP].set_value("");
×
104
            break;
×
105
        case ln_mode_t::FILTER:
54✔
106
        case ln_mode_t::FILES:
107
        case ln_mode_t::FILE_DETAILS:
108
            this->tss_fields[TSF_HELP].set_value(EXIT_MSG);
54✔
109
            break;
54✔
110
        default:
102✔
111
            this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
102✔
112
            break;
102✔
113
    }
114

115
    if (lnav_data.ld_mode == ln_mode_t::FILES
156✔
116
        || lnav_data.ld_mode == ln_mode_t::FILE_DETAILS
114✔
117
        || lnav_data.ld_mode == ln_mode_t::SEARCH_FILES)
114✔
118
    {
119
        this->tss_fields[TSF_FILES_TITLE].set_value(
42✔
120
            " " ANSI_ROLE("F") "iles ", role_t::VCR_STATUS_TITLE_HOTKEY);
121
        this->tss_fields[TSF_FILES_TITLE].set_role(role_t::VCR_STATUS_TITLE);
42✔
122
        this->tss_fields[TSF_FILES_RIGHT_STITCH].set_stitch_value(
42✔
123
            role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
124
            role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
125
        this->tss_fields[TSF_TITLE].set_value(" " ANSI_ROLE("T") "ext Filters ",
42✔
126
                                              role_t::VCR_STATUS_HOTKEY);
127
        this->tss_fields[TSF_TITLE].set_role(role_t::VCR_STATUS_DISABLED_TITLE);
42✔
128
        this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(role_t::VCR_STATUS,
42✔
129
                                                            role_t::VCR_STATUS);
130
    } else {
131
        this->tss_fields[TSF_FILES_TITLE].set_value(" " ANSI_ROLE("F") "iles ",
114✔
132
                                                    role_t::VCR_STATUS_HOTKEY);
133
        if (lnav_data.ld_active_files.fc_name_to_errors->readAccess()->empty())
114✔
134
        {
135
            this->tss_fields[TSF_FILES_TITLE].set_role(
114✔
136
                role_t::VCR_STATUS_DISABLED_TITLE);
137
        } else {
138
            this->tss_fields[TSF_FILES_TITLE].set_role(
×
139
                role_t::VCR_ALERT_STATUS);
140

141
            auto& fc = lnav_data.ld_active_files;
×
142
            if (fc.fc_name_to_errors->readAccess()->size() == 1) {
×
143
                this->tss_error.set_value(" error: a file cannot be opened ");
×
144
            } else {
145
                this->tss_error.set_value(
×
146
                    " error: %u files cannot be opened ",
147
                    lnav_data.ld_active_files.fc_name_to_errors->readAccess()
×
148
                        ->size());
149
            }
150
        }
151
        this->tss_fields[TSF_FILES_RIGHT_STITCH].set_stitch_value(
114✔
152
            role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE,
153
            role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL);
154
        this->tss_fields[TSF_TITLE].set_value(" " ANSI_ROLE("T") "ext Filters ",
114✔
155
                                              role_t::VCR_STATUS_TITLE_HOTKEY);
156
        this->tss_fields[TSF_TITLE].set_role(role_t::VCR_STATUS_TITLE);
114✔
157
        this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
114✔
158
            role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
159
            role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
160
    }
161

162
    lnav_data.ld_view_stack.top() | [this](auto tc) {
156✔
163
        text_sub_source* tss = tc->get_sub_source();
124✔
164
        if (tss == nullptr) {
124✔
165
            return;
×
166
        }
167

168
        filter_stack& fs = tss->get_filters();
124✔
169
        auto enabled_count = 0, filter_count = 0;
124✔
170

171
        for (const auto& tf : fs) {
167✔
172
            if (tf->is_enabled()) {
43✔
173
                enabled_count += 1;
10✔
174
            }
175
            filter_count += 1;
43✔
176
        }
177
        if (filter_count == 0) {
124✔
178
            this->tss_fields[TSF_COUNT].set_value("");
81✔
179
        } else {
180
            this->tss_fields[TSF_COUNT].set_value(
43✔
181
                " " ANSI_BOLD("%d") " of " ANSI_BOLD("%d") " enabled ",
182
                enabled_count,
183
                filter_count);
184
        }
185
    };
186

187
    return TSF__MAX;
156✔
188
}
189

190
status_field&
191
filter_status_source::statusview_value_for_field(int field)
1,092✔
192
{
193
    if (field == TSF_FILTERED
1,092✔
194
        && !lnav_data.ld_active_files.fc_name_to_errors->readAccess()->empty())
1,092✔
195
    {
196
        return this->tss_error;
×
197
    }
198

199
    return this->tss_fields[field];
1,092✔
200
}
201

202
void
203
filter_status_source::update_filtered(text_sub_source* tss)
2,504✔
204
{
205
    if (tss == nullptr) {
2,504✔
206
        return;
9✔
207
    }
208

209
    auto& sf = this->tss_fields[TSF_FILTERED];
2,495✔
210

211
    if (tss->get_filtered_count() == 0) {
2,495✔
212
        if (tss->tss_apply_filters) {
2,352✔
213
            sf.clear();
2,349✔
214
        } else {
215
            sf.set_value(
3✔
216
                " \u2718 Filtering disabled, re-enable with " ANSI_BOLD_START
217
                ":toggle-filtering" ANSI_NORM);
218
        }
219
    } else {
220
        auto& timer = ui_periodic_timer::singleton();
143✔
221
        auto& al = sf.get_value();
143✔
222

223
        if (tss->get_filtered_count() == this->bss_last_filtered_count) {
143✔
224
            if (timer.fade_diff(this->bss_filter_counter) == 0) {
91✔
225
                this->tss_fields[TSF_FILTERED].set_role(role_t::VCR_STATUS);
×
226
                al.with_attr(string_attr(line_range{0, -1},
×
227
                                         VC_STYLE.value(text_attrs{A_BOLD})));
×
228
            }
229
        } else {
230
            this->tss_fields[TSF_FILTERED].set_role(role_t::VCR_ALERT_STATUS);
52✔
231
            this->bss_last_filtered_count = tss->get_filtered_count();
52✔
232
            timer.start_fade(this->bss_filter_counter, 3);
52✔
233
        }
234
        sf.set_value("%'9d Lines not shown ", tss->get_filtered_count());
143✔
235
    }
236
}
237

238
filter_help_status_source::
1,021✔
239
filter_help_status_source()
1,021✔
240
{
241
    this->fss_help.set_min_width(10);
1,021✔
242
    this->fss_help.set_share(1);
1,021✔
243
    this->fss_prompt.set_left_pad(1);
1,021✔
244
    this->fss_prompt.set_min_width(35);
1,021✔
245
    this->fss_prompt.set_share(1);
1,021✔
246
    this->fss_error.set_left_pad(25);
1,021✔
247
    this->fss_error.set_min_width(35);
1,021✔
248
    this->fss_error.set_share(1);
1,021✔
249
}
1,021✔
250

251
size_t
252
filter_help_status_source::statusview_fields()
72✔
253
{
254
    lnav_data.ld_view_stack.top() | [this](auto tc) {
72✔
255
        text_sub_source* tss = tc->get_sub_source();
64✔
256
        if (tss == nullptr) {
64✔
257
            return;
×
258
        }
259

260
        if (lnav_data.ld_mode == ln_mode_t::FILTER) {
64✔
261
            static auto* editor = injector::get<filter_sub_source*>();
12✔
262
            auto& lv = lnav_data.ld_filter_view;
12✔
263
            auto& fs = tss->get_filters();
12✔
264

265
            if (editor->fss_editing) {
12✔
266
                auto tf = *(fs.begin() + lv.get_selection());
10✔
267
                auto lang = tf->get_lang() == filter_lang_t::SQL ? "an SQL"
10✔
268
                                                                 : "a regular";
269

270
                if (tf->get_type() == text_filter::type_t::INCLUDE) {
10✔
271
                    this->fss_help.set_value(
×
272
                        "                        "
273
                        "Enter %s expression to match lines to filter in:",
274
                        lang);
275
                } else {
276
                    this->fss_help.set_value(
10✔
277
                        "                        "
278
                        "Enter %s expression to match lines to filter out:",
279
                        lang);
280
                }
281
            } else if (fs.empty()) {
12✔
282
                this->fss_help.set_value("  %s", CREATE_HELP);
2✔
283
            } else {
UNCOV
284
                auto tf = *(fs.begin() + lv.get_selection());
×
285

UNCOV
286
                this->fss_help.set_value(
×
287
                    "  %s  %s%s  %s  %s%s  %s  %s%s",
288
                    CREATE_HELP,
289
                    ENABLE_HELP,
UNCOV
290
                    tf->is_enabled() ? "Disable" : "Enable ",
×
291
                    EDIT_HELP,
292
                    TOGGLE_HELP,
UNCOV
293
                    tf->get_type() == text_filter::type_t::INCLUDE ? "OUT"
×
294
                                                                   : "IN ",
295
                    DELETE_HELP,
296
                    FILTERING_HELP,
UNCOV
297
                    tss->tss_apply_filters ? "Disable Filtering"
×
298
                                           : "Enable Filtering");
299
            }
300
        } else if ((lnav_data.ld_mode == ln_mode_t::FILES
52✔
301
                    || lnav_data.ld_mode == ln_mode_t::FILE_DETAILS)
10✔
302
                   && lnav_data.ld_session_loaded)
42✔
303
        {
304
            const auto& lv = lnav_data.ld_files_view;
10✔
305
            auto sel = files_model::from_selection(lv.get_selection());
10✔
306

307
            sel.match(
10✔
308
                [this](files_model::no_selection) { this->fss_help.clear(); },
10✔
309
                [this](files_model::error_selection) {
×
310
                    this->fss_help.set_value("  %s", CLOSE_HELP);
×
311
                },
312
                [this](files_model::other_selection) {
×
313
                    this->fss_help.clear();
×
314
                },
315
                [this](files_model::file_selection& fs) {
×
316
                    auto& lss = lnav_data.ld_log_source;
×
317
                    auto vis_help = "Hide";
×
318
                    auto ld_opt = lss.find_data(*fs.sb_iter);
×
319
                    if (ld_opt && !ld_opt.value()->ld_visible) {
×
320
                        vis_help = "Show";
×
321
                    }
322
                    const auto* focus_details_help
×
323
                        = lnav_data.ld_mode == ln_mode_t::FILES
×
324
                        ? FOCUS_DETAILS_HELP
×
325
                        : "";
326

327
                    this->fss_help.set_value("  %s%s  %s  %s",
×
328
                                             ENABLE_HELP,
329
                                             vis_help,
330
                                             JUMP_HELP,
331
                                             focus_details_help);
332
                });
333
        }
10✔
334
    };
335

336
    return 1;
72✔
337
}
338

339
status_field&
340
filter_help_status_source::statusview_value_for_field(int field)
72✔
341
{
342
    if (!this->fss_error.empty()) {
72✔
343
        return this->fss_error;
×
344
    }
345

346
    if (!this->fss_prompt.empty()) {
72✔
347
        return this->fss_prompt;
×
348
    }
349

350
    return this->fss_help;
72✔
351
}
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