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

tstack / lnav / 17589970077-2502

09 Sep 2025 05:00PM UTC coverage: 65.196% (-5.0%) from 70.225%
17589970077-2502

push

github

tstack
[format] add fields for source file/line

Knowing the source file/line context in a log
message can help find log messages when using
log2src.

56 of 70 new or added lines in 2 files covered. (80.0%)

13954 existing lines in 210 files now uncovered.

45516 of 69814 relevant lines covered (65.2%)

404154.37 hits per line

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

68.97
/src/document.sections.hh
1
/**
2
 * Copyright (c) 2022, 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
#ifndef lnav_attr_line_breadcrumbs_hh
31
#define lnav_attr_line_breadcrumbs_hh
32

33
#include <map>
34
#include <set>
35
#include <string>
36
#include <vector>
37

38
#include "base/attr_line.hh"
39
#include "base/file_range.hh"
40
#include "breadcrumb.hh"
41
#include "intervaltree/IntervalTree.h"
42
#include "mapbox/variant.hpp"
43
#include "text_format.hh"
44

45
namespace lnav::document {
46

47
using section_key_t = mapbox::util::variant<std::string, size_t>;
48
using section_interval_t = interval_tree::Interval<file_off_t, section_key_t>;
49
using sections_tree_t = interval_tree::IntervalTree<file_off_t, section_key_t>;
50

51
enum class section_types_t {
52
    comment,
53
    multiline_string,
54
};
55

56
using section_type_interval_t
57
    = interval_tree::Interval<file_off_t, section_types_t>;
58
using section_types_tree_t
59
    = interval_tree::IntervalTree<file_off_t, section_types_t>;
60

61
struct hier_node {
62
    hier_node* hn_parent{nullptr};
63
    file_off_t hn_start{0};
64
    size_t hn_line_number{0};
65
    std::multimap<std::string, hier_node*> hn_named_children;
66
    std::vector<std::unique_ptr<hier_node>> hn_children;
67

68
    std::optional<hier_node*> lookup_child(section_key_t key) const;
69

70
    std::optional<size_t> child_index(const hier_node* hn) const;
71

72
    std::optional<section_key_t> child_key(const hier_node *hn) const;
73

74
    struct child_neighbors_result {
75
        std::optional<const hier_node*> cnr_previous;
76
        std::optional<const hier_node*> cnr_next;
77
    };
78

79
    std::optional<child_neighbors_result> child_neighbors(
80
        const hier_node* hn, file_off_t offset) const;
81

82
    std::optional<child_neighbors_result> line_neighbors(size_t ln) const;
83

UNCOV
84
    std::optional<size_t> find_line_number(const std::string& str) const
×
85
    {
86
        const auto iter = this->hn_named_children.find(str);
×
87
        if (iter != this->hn_named_children.end()) {
×
UNCOV
88
            return std::make_optional(iter->second->hn_line_number);
×
89
        }
90

UNCOV
91
        return std::nullopt;
×
92
    }
93

UNCOV
94
    std::optional<size_t> find_line_number(size_t index) const
×
95
    {
96
        if (index < this->hn_children.size()) {
×
97
            return std::make_optional(this->hn_children[index]->hn_line_number);
×
98
        }
99
        return std::nullopt;
×
100
    }
101

102
    bool is_named_only() const
2✔
103
    {
104
        return this->hn_children.size() == this->hn_named_children.size();
2✔
105
    }
106

107
    static std::optional<const hier_node*> lookup_path(
108
        const hier_node* root, const std::vector<section_key_t>& path);
109

110
    template<typename F>
111
    static void depth_first(hier_node* root, F func)
6,566✔
112
    {
113
        if (root == nullptr) {
6,566✔
114
            return;
42✔
115
        }
116

117
        for (auto& child : root->hn_children) {
12,462✔
118
            depth_first(child.get(), func);
5,938✔
119
        }
120
        func(root);
6,524✔
121
    }
122
};
123

124
struct metadata {
125
    sections_tree_t m_sections_tree;
126
    std::unique_ptr<hier_node> m_sections_root;
127
    section_types_tree_t m_section_types_tree;
128
    std::set<size_t> m_indents;
129
    text_format_t m_text_format{text_format_t::TF_UNKNOWN};
130
    std::set<std::string> m_words;
131

132
    std::vector<section_key_t> path_for_range(size_t start, size_t stop);
133

134
    std::vector<breadcrumb::possibility> possibility_provider(
135
        const std::vector<section_key_t>& path);
136
};
137

138
metadata discover_metadata(const attr_line_t& al);
139

140
struct discover_builder {
141
    explicit discover_builder(attr_line_t& al) : db_line(al) {}
150✔
142

143
    discover_builder& over_range(line_range lr)
1✔
144
    {
145
        this->db_range = lr;
1✔
146
        return *this;
1✔
147
    }
148

149
    discover_builder& with_text_format(text_format_t tf)
149✔
150
    {
151
        this->db_text_format = tf;
149✔
152
        return *this;
149✔
153
    }
154

155
    discover_builder& save_words()
28✔
156
    {
157
        this->db_save_words = true;
28✔
158
        return *this;
28✔
159
    }
160

161
    metadata perform();
162

163
    attr_line_t& db_line;
164
    line_range db_range{0, -1};
165
    text_format_t db_text_format{text_format_t::TF_UNKNOWN};
166
    bool db_save_words{false};
167
};
168

169
inline discover_builder
170
discover(attr_line_t& al)
150✔
171
{
172
    return discover_builder(al);
150✔
173
}
174

175
}  // namespace lnav::document
176

177
namespace fmt {
178
template<>
179
struct formatter<lnav::document::section_key_t> : formatter<string_view> {
180
    auto format(const lnav::document::section_key_t& p, format_context& ctx)
181
        -> decltype(ctx.out()) const;
182
};
183

184
template<>
185
struct formatter<std::vector<lnav::document::section_key_t>>
186
    : formatter<string_view> {
187
    auto format(const std::vector<lnav::document::section_key_t>& p,
188
                format_context& ctx) -> decltype(ctx.out()) const;
189
};
190
}  // namespace fmt
191

192
#endif
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