mirror of
https://github.com/tstack/lnav.git
synced 2024-08-17 00:40:30 +03:00
[logfile] improve handling of ansi escapes
I think this covers the rest of the functionality that needs to deal with ansi escapes. Related to #1057
This commit is contained in:
parent
9185518bda
commit
e0ecbdff10
@ -48,6 +48,68 @@ ansi_regex()
|
||||
return retval;
|
||||
}
|
||||
|
||||
size_t
|
||||
erase_ansi_escapes(string_fragment input)
|
||||
{
|
||||
const auto& regex = ansi_regex();
|
||||
auto md = regex.create_match_data();
|
||||
|
||||
auto matcher = regex.capture_from(input).into(md);
|
||||
while (true) {
|
||||
auto match_res = matcher.matches(PCRE2_NO_UTF_CHECK);
|
||||
|
||||
if (match_res.is<lnav::pcre2pp::matcher::not_found>()) {
|
||||
break;
|
||||
}
|
||||
if (match_res.is<lnav::pcre2pp::matcher::error>()) {
|
||||
log_error("ansi scrub regex failure");
|
||||
break;
|
||||
}
|
||||
|
||||
auto sf = md[0].value();
|
||||
auto bs_index_res = sf.codepoint_to_byte_index(1);
|
||||
|
||||
if (sf.length() >= 3 && bs_index_res.isOk()
|
||||
&& sf[bs_index_res.unwrap()] == '\b')
|
||||
{
|
||||
static const auto OVERSTRIKE_RE
|
||||
= lnav::pcre2pp::code::from_const(R"((\X)\x08(\X))");
|
||||
|
||||
size_t fill_index = 0;
|
||||
auto loop_res = OVERSTRIKE_RE.capture_from(sf).for_each(
|
||||
[&fill_index, &sf](lnav::pcre2pp::match_data& over_md) {
|
||||
auto lhs = over_md[1].value();
|
||||
if (lhs == "_") {
|
||||
auto rhs = over_md[2].value();
|
||||
memmove(sf.writable_data(fill_index),
|
||||
rhs.data(),
|
||||
rhs.length());
|
||||
fill_index += rhs.length();
|
||||
} else {
|
||||
memmove(sf.writable_data(fill_index),
|
||||
lhs.data(),
|
||||
lhs.length());
|
||||
fill_index += lhs.length();
|
||||
}
|
||||
});
|
||||
|
||||
memmove(input.writable_data(sf.sf_begin + fill_index),
|
||||
md.remaining().data(),
|
||||
md.remaining().length());
|
||||
input = input.erase(input.sf_string, sf.length() - fill_index);
|
||||
} else {
|
||||
memmove(const_cast<char*>(sf.data()),
|
||||
md.remaining().data(),
|
||||
md.remaining().length());
|
||||
input = input.erase(input.sf_string, sf.length());
|
||||
}
|
||||
|
||||
matcher.reload_input(input, sf.sf_begin);
|
||||
}
|
||||
|
||||
return input.length();
|
||||
}
|
||||
|
||||
void
|
||||
scrub_ansi_string(std::string& str, string_attrs_t* sa)
|
||||
{
|
||||
|
@ -64,6 +64,8 @@
|
||||
*/
|
||||
void scrub_ansi_string(std::string& str, string_attrs_t* sa);
|
||||
|
||||
size_t erase_ansi_escapes(string_fragment input);
|
||||
|
||||
/**
|
||||
* Populate a variable map with strings that contain escape sequences that
|
||||
* might be useful to script writers.
|
||||
|
@ -40,8 +40,14 @@ using file_ssize_t = int64_t;
|
||||
|
||||
class file_range {
|
||||
public:
|
||||
struct metadata {
|
||||
bool m_valid_utf{true};
|
||||
bool m_has_ansi{false};
|
||||
};
|
||||
|
||||
file_off_t fr_offset{0};
|
||||
file_ssize_t fr_size{0};
|
||||
metadata fr_metadata;
|
||||
|
||||
void clear()
|
||||
{
|
||||
@ -49,15 +55,9 @@ public:
|
||||
this->fr_size = 0;
|
||||
}
|
||||
|
||||
ssize_t next_offset() const
|
||||
{
|
||||
return this->fr_offset + this->fr_size;
|
||||
}
|
||||
ssize_t next_offset() const { return this->fr_offset + this->fr_size; }
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return this->fr_size == 0;
|
||||
}
|
||||
bool empty() const { return this->fr_size == 0; }
|
||||
};
|
||||
|
||||
struct source_location {
|
||||
|
@ -144,6 +144,11 @@ struct string_fragment {
|
||||
return (const unsigned char*) &this->sf_string[this->sf_begin];
|
||||
}
|
||||
|
||||
char* writable_data(int offset = 0)
|
||||
{
|
||||
return (char*) &this->sf_string[this->sf_begin + offset];
|
||||
}
|
||||
|
||||
char front() const { return this->sf_string[this->sf_begin]; }
|
||||
|
||||
uint32_t front_codepoint() const
|
||||
|
@ -56,7 +56,7 @@ using namespace lnav::roles::literals;
|
||||
|
||||
class logline_helper {
|
||||
public:
|
||||
logline_helper(logfile_sub_source& lss) : lh_sub_source(lss) {}
|
||||
explicit logline_helper(logfile_sub_source& lss) : lh_sub_source(lss) {}
|
||||
|
||||
logline& move_to_msg_start()
|
||||
{
|
||||
@ -71,7 +71,7 @@ public:
|
||||
return (*lf)[cl];
|
||||
}
|
||||
|
||||
logline& current_line()
|
||||
logline& current_line() const
|
||||
{
|
||||
content_line_t cl = this->lh_sub_source.at(this->lh_current_line);
|
||||
std::shared_ptr<logfile> lf = this->lh_sub_source.find(cl);
|
||||
@ -84,10 +84,11 @@ public:
|
||||
this->lh_string_attrs.clear();
|
||||
this->lh_line_values.clear();
|
||||
content_line_t cl = this->lh_sub_source.at(this->lh_current_line);
|
||||
std::shared_ptr<logfile> lf = this->lh_sub_source.find(cl);
|
||||
auto lf = this->lh_sub_source.find(cl);
|
||||
auto ll = lf->begin() + cl;
|
||||
auto format = lf->get_format();
|
||||
lf->read_full_message(ll, this->lh_line_values.lvv_sbr);
|
||||
this->lh_line_values.lvv_sbr.erase_ansi();
|
||||
format->annotate(
|
||||
cl, this->lh_string_attrs, this->lh_line_values, false);
|
||||
}
|
||||
@ -389,7 +390,8 @@ handle_paging_key(int ch)
|
||||
tc->shift_top(1_vl);
|
||||
}
|
||||
if (lnav_data.ld_last_user_mark[tc] + 1
|
||||
>= tc->get_inner_height()) {
|
||||
>= tc->get_inner_height())
|
||||
{
|
||||
break;
|
||||
}
|
||||
lnav_data.ld_last_user_mark[tc] += 1;
|
||||
@ -435,7 +437,8 @@ handle_paging_key(int ch)
|
||||
|
||||
case 'M':
|
||||
if (lnav_data.ld_last_user_mark.find(tc)
|
||||
== lnav_data.ld_last_user_mark.end()) {
|
||||
== lnav_data.ld_last_user_mark.end())
|
||||
{
|
||||
alerter::singleton().chime("no lines have been marked");
|
||||
} else {
|
||||
int start_line = std::min((int) tc->get_top(),
|
||||
@ -479,7 +482,8 @@ handle_paging_key(int ch)
|
||||
while (next_top < tc->get_inner_height()) {
|
||||
if (!lss->find_line(lss->at(next_top))->is_message()) {
|
||||
} else if (lss->get_line_accel_direction(next_top)
|
||||
== log_accel::A_DECEL) {
|
||||
== log_accel::A_DECEL)
|
||||
{
|
||||
--next_top;
|
||||
tc->set_top(next_top);
|
||||
break;
|
||||
@ -502,7 +506,8 @@ handle_paging_key(int ch)
|
||||
while (0 <= next_top && next_top < tc->get_inner_height()) {
|
||||
if (!lss->find_line(lss->at(next_top))->is_message()) {
|
||||
} else if (lss->get_line_accel_direction(next_top)
|
||||
== log_accel::A_DECEL) {
|
||||
== log_accel::A_DECEL)
|
||||
{
|
||||
--next_top;
|
||||
tc->set_top(next_top);
|
||||
break;
|
||||
@ -589,11 +594,11 @@ handle_paging_key(int ch)
|
||||
|
||||
case 'o':
|
||||
case 'O':
|
||||
if (lss) {
|
||||
if (lss != nullptr) {
|
||||
logline_helper start_helper(*lss);
|
||||
|
||||
start_helper.lh_current_line = tc->get_top();
|
||||
logline& start_line = start_helper.move_to_msg_start();
|
||||
auto& start_line = start_helper.move_to_msg_start();
|
||||
start_helper.annotate();
|
||||
|
||||
struct line_range opid_range = find_string_attr_range(
|
||||
@ -615,7 +620,8 @@ handle_paging_key(int ch)
|
||||
while (true) {
|
||||
if (ch == 'o') {
|
||||
if (++next_helper.lh_current_line
|
||||
>= tc->get_inner_height()) {
|
||||
>= tc->get_inner_height())
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -771,7 +777,8 @@ handle_paging_key(int ch)
|
||||
for (row = 0; row < dls.dls_rows.size(); row++) {
|
||||
if (strcmp(dls.dls_rows[row][log_line_index.value()],
|
||||
linestr.data())
|
||||
== 0) {
|
||||
== 0)
|
||||
{
|
||||
vis_line_t db_line(row);
|
||||
|
||||
db_tc->set_top(db_line);
|
||||
@ -809,7 +816,8 @@ handle_paging_key(int ch)
|
||||
size_t col_len = strlen(col_value);
|
||||
|
||||
if (dts.scan(col_value, col_len, nullptr, &tm, tv)
|
||||
!= nullptr) {
|
||||
!= nullptr)
|
||||
{
|
||||
lnav_data.ld_log_source.find_from_time(tv) |
|
||||
[tc](auto vl) {
|
||||
tc->set_top(vl);
|
||||
@ -890,9 +898,9 @@ handle_paging_key(int ch)
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
if (lss) {
|
||||
auto& last_time = injector::get<const relative_time&,
|
||||
last_relative_time_tag>();
|
||||
if (lss != nullptr) {
|
||||
const auto& last_time = injector::get<const relative_time&,
|
||||
last_relative_time_tag>();
|
||||
|
||||
if (last_time.empty()) {
|
||||
lnav_data.ld_rl_view->set_value(
|
||||
|
@ -1193,6 +1193,7 @@ line_buffer::read_range(const file_range fr)
|
||||
FMT_STRING("short-read (need: {}; avail: {})"), fr.fr_size, avail));
|
||||
}
|
||||
retval.share(this->lb_share_manager, line_start, fr.fr_size);
|
||||
retval.get_metadata() = fr.fr_metadata;
|
||||
|
||||
return Ok(std::move(retval));
|
||||
}
|
||||
|
@ -122,6 +122,7 @@ eval_with(logfile& lf, logfile::iterator ll)
|
||||
shared_buffer_ref raw_sbr;
|
||||
logline_value_vector values;
|
||||
lf.read_full_message(ll, values.lvv_sbr);
|
||||
values.lvv_sbr.erase_ansi();
|
||||
auto format = lf.get_format();
|
||||
string_attrs_t sa;
|
||||
auto line_number = std::distance(lf.begin(), ll);
|
||||
@ -275,8 +276,11 @@ eval_with(logfile& lf, logfile::iterator ll)
|
||||
|
||||
string_fragment sf = gen.to_string_fragment();
|
||||
|
||||
sqlite3_bind_text(
|
||||
stmt, lpc + 1, sf.data(), sf.length(), SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt,
|
||||
lpc + 1,
|
||||
sf.data(),
|
||||
sf.length(),
|
||||
SQLITE_TRANSIENT);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ log_data_helper::parse_line(content_line_t line, bool allow_middle)
|
||||
this->ldh_line_attrs.clear();
|
||||
this->ldh_line_values.clear();
|
||||
this->ldh_file->read_full_message(ll, this->ldh_line_values.lvv_sbr);
|
||||
this->ldh_line_values.lvv_sbr.erase_ansi();
|
||||
format->annotate(this->ldh_line_index, sa, this->ldh_line_values);
|
||||
|
||||
body = find_string_attr_range(sa, &SA_BODY);
|
||||
|
@ -63,6 +63,7 @@ log_data_table::get_columns_int()
|
||||
this->ldt_format_impl->get_columns(cols);
|
||||
}
|
||||
lf->read_full_message(lf->begin() + cl_copy, line_values.lvv_sbr);
|
||||
line_values.lvv_sbr.erase_ansi();
|
||||
format->annotate(cl_copy, sa, line_values, false);
|
||||
body = find_string_attr_range(sa, &SA_BODY);
|
||||
if (body.lr_end == -1) {
|
||||
@ -134,6 +135,7 @@ log_data_table::next(log_cursor& lc, logfile_sub_source& lss)
|
||||
logline_value_vector line_values;
|
||||
|
||||
lf->read_full_message(lf_iter, line_values.lvv_sbr);
|
||||
line_values.lvv_sbr.erase_ansi();
|
||||
lf->get_format()->annotate(cl, sa, line_values, false);
|
||||
body = find_string_attr_range(sa, &SA_BODY);
|
||||
if (body.lr_end == -1) {
|
||||
|
@ -1057,6 +1057,7 @@ external_log_format::annotate(uint64_t line_number,
|
||||
auto& line = values.lvv_sbr;
|
||||
struct line_range lr;
|
||||
|
||||
line.erase_ansi();
|
||||
if (this->elf_type != elf_type_t::ELF_TYPE_TEXT) {
|
||||
values = this->jlf_line_values;
|
||||
sa = this->jlf_line_attrs;
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "log_search_table.hh"
|
||||
|
||||
#include "base/ansi_scrubber.hh"
|
||||
#include "column_namer.hh"
|
||||
#include "config.h"
|
||||
#include "sql_util.hh"
|
||||
@ -166,7 +167,9 @@ log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
|
||||
}
|
||||
|
||||
// log_debug("%d: doing message", (int) lc.lc_curr_line);
|
||||
lf->read_full_message(lf_iter, this->lst_line_values_cache.lvv_sbr);
|
||||
auto& sbr = this->lst_line_values_cache.lvv_sbr;
|
||||
lf->read_full_message(lf_iter, sbr);
|
||||
sbr.erase_ansi();
|
||||
lf->get_format()->annotate(
|
||||
cl, this->vi_attrs, this->lst_line_values_cache, false);
|
||||
this->lst_content
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "log_vtab_impl.hh"
|
||||
|
||||
#include "base/ansi_scrubber.hh"
|
||||
#include "base/itertools.hh"
|
||||
#include "base/lnav_log.hh"
|
||||
#include "base/string_util.hh"
|
||||
@ -298,7 +299,9 @@ struct vtab_cursor {
|
||||
if (this->log_msg_line == this->log_cursor.lc_curr_line) {
|
||||
return;
|
||||
}
|
||||
lf->read_full_message(ll, this->line_values.lvv_sbr);
|
||||
auto& sbr = this->line_values.lvv_sbr;
|
||||
lf->read_full_message(ll, sbr);
|
||||
sbr.erase_ansi();
|
||||
this->log_msg_line = this->log_cursor.lc_curr_line;
|
||||
}
|
||||
|
||||
@ -871,6 +874,7 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
|
||||
shared_buffer_ref line;
|
||||
|
||||
lf->read_full_message(ll, line);
|
||||
line.erase_ansi();
|
||||
sqlite3_result_text(ctx,
|
||||
line.get_data(),
|
||||
line.length(),
|
||||
|
@ -464,12 +464,15 @@ logfile::rebuild_index(nonstd::optional<ui_clock::time_point> deadline)
|
||||
auto last_line = this->lf_index.end();
|
||||
--last_line;
|
||||
auto check_line_off = last_line->get_offset();
|
||||
auto last_length = ssize_t(this->line_length(last_line, false));
|
||||
auto last_length_res
|
||||
= this->message_byte_length(last_line, false);
|
||||
log_debug("flushing at %d", check_line_off);
|
||||
this->lf_line_buffer.flush_at(check_line_off);
|
||||
|
||||
auto read_result = this->lf_line_buffer.read_range(
|
||||
{check_line_off, last_length});
|
||||
auto read_result = this->lf_line_buffer.read_range({
|
||||
check_line_off,
|
||||
last_length_res.mlr_length,
|
||||
});
|
||||
|
||||
if (read_result.isErr()) {
|
||||
log_info("overwritten file detected, closing -- %s (%s)",
|
||||
@ -785,11 +788,13 @@ Result<shared_buffer_ref, std::string>
|
||||
logfile::read_line(logfile::iterator ll)
|
||||
{
|
||||
try {
|
||||
return this->lf_line_buffer.read_range(this->get_file_range(ll, false))
|
||||
.map([&ll, this](auto sbr) {
|
||||
auto get_range_res = this->get_file_range(ll, false);
|
||||
return this->lf_line_buffer.read_range(get_range_res)
|
||||
.map([&ll, &get_range_res, this](auto sbr) {
|
||||
sbr.rtrim(is_line_ending);
|
||||
if (!ll->is_valid_utf()) {
|
||||
if (!get_range_res.fr_metadata.m_valid_utf) {
|
||||
scrub_to_utf8(sbr.get_writable_data(), sbr.length());
|
||||
sbr.get_metadata().m_valid_utf = true;
|
||||
}
|
||||
|
||||
if (this->lf_format != nullptr) {
|
||||
@ -798,7 +803,7 @@ logfile::read_line(logfile::iterator ll)
|
||||
|
||||
return sbr;
|
||||
});
|
||||
} catch (line_buffer::error& e) {
|
||||
} catch (const line_buffer::error& e) {
|
||||
return Err(std::string(strerror(e.e_err)));
|
||||
}
|
||||
}
|
||||
@ -840,6 +845,7 @@ logfile::read_full_message(logfile::const_iterator ll,
|
||||
return;
|
||||
}
|
||||
msg_out = read_result.unwrap();
|
||||
msg_out.get_metadata() = range_for_line.fr_metadata;
|
||||
if (this->lf_format.get() != nullptr) {
|
||||
this->lf_format->get_subline(*ll, msg_out, true);
|
||||
}
|
||||
@ -898,19 +904,25 @@ logfile::get_path() const
|
||||
return this->lf_filename;
|
||||
}
|
||||
|
||||
size_t
|
||||
logfile::line_length(logfile::const_iterator ll, bool include_continues)
|
||||
logfile::message_length_result
|
||||
logfile::message_byte_length(logfile::const_iterator ll, bool include_continues)
|
||||
{
|
||||
auto next_line = ll;
|
||||
file_range::metadata meta;
|
||||
size_t retval;
|
||||
|
||||
if (!include_continues && this->lf_next_line_cache) {
|
||||
if (ll->get_offset() == (*this->lf_next_line_cache).first) {
|
||||
return this->lf_next_line_cache->second;
|
||||
return {
|
||||
(file_ssize_t) this->lf_next_line_cache->second,
|
||||
{ll->is_valid_utf(), ll->has_ansi()},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
meta.m_has_ansi = meta.m_has_ansi || next_line->has_ansi();
|
||||
meta.m_valid_utf = meta.m_valid_utf && next_line->is_valid_utf();
|
||||
++next_line;
|
||||
} while ((next_line != this->end())
|
||||
&& ((ll->get_offset() == next_line->get_offset())
|
||||
@ -932,7 +944,7 @@ logfile::line_length(logfile::const_iterator ll, bool include_continues)
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
return {(file_ssize_t) retval, meta};
|
||||
}
|
||||
|
||||
Result<shared_buffer_ref, std::string>
|
||||
|
@ -264,13 +264,22 @@ public:
|
||||
return retval;
|
||||
}
|
||||
|
||||
size_t line_length(const_iterator ll, bool include_continues = true);
|
||||
struct message_length_result {
|
||||
file_ssize_t mlr_length;
|
||||
file_range::metadata mlr_metadata;
|
||||
};
|
||||
|
||||
message_length_result message_byte_length(const_iterator ll,
|
||||
bool include_continues = true);
|
||||
|
||||
file_range get_file_range(const_iterator ll, bool include_continues = true)
|
||||
{
|
||||
auto mlr = this->message_byte_length(ll, include_continues);
|
||||
|
||||
return {
|
||||
ll->get_offset(),
|
||||
(file_ssize_t) this->line_length(ll, include_continues),
|
||||
mlr.mlr_length,
|
||||
mlr.mlr_metadata,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,10 @@ logfile_sub_source::text_value_for_line(textview_curses& tc,
|
||||
|
||||
this->lss_token_file->read_full_message(this->lss_token_line, sbr);
|
||||
this->lss_token_value = to_string(sbr);
|
||||
if (sbr.get_metadata().m_has_ansi) {
|
||||
scrub_ansi_string(this->lss_token_value, &this->lss_token_attrs);
|
||||
sbr.get_metadata().m_has_ansi = false;
|
||||
}
|
||||
} else {
|
||||
this->lss_token_value
|
||||
= this->lss_token_file->read_line(this->lss_token_line)
|
||||
@ -1407,6 +1411,7 @@ logfile_sub_source::eval_sql_filter(sqlite3_stmt* stmt,
|
||||
logline_value_vector values;
|
||||
auto& sbr = values.lvv_sbr;
|
||||
lf->read_full_message(ll, sbr);
|
||||
sbr.erase_ansi();
|
||||
auto format = lf->get_format();
|
||||
string_attrs_t sa;
|
||||
auto line_number = std::distance(lf->cbegin(), ll);
|
||||
@ -2061,6 +2066,13 @@ logline_window::logmsg_info::load_msg() const
|
||||
auto format = this->li_file->get_format();
|
||||
this->li_file->read_full_message(this->li_logline,
|
||||
this->li_line_values.lvv_sbr);
|
||||
if (this->li_line_values.lvv_sbr.get_metadata().m_has_ansi) {
|
||||
auto* writable_data = this->li_line_values.lvv_sbr.get_writable_data();
|
||||
auto str
|
||||
= std::string{writable_data, this->li_line_values.lvv_sbr.length()};
|
||||
scrub_ansi_string(str, &this->li_string_attrs);
|
||||
this->li_line_values.lvv_sbr.get_metadata().m_has_ansi = false;
|
||||
}
|
||||
format->annotate(std::distance(this->li_file->cbegin(), this->li_logline),
|
||||
this->li_string_attrs,
|
||||
this->li_line_values,
|
||||
@ -2204,6 +2216,7 @@ logfile_sub_source::text_crumbs_for_line(int line,
|
||||
auto& sbr = values.lvv_sbr;
|
||||
|
||||
lf->read_full_message(msg_start_iter, sbr);
|
||||
sbr.erase_ansi();
|
||||
attr_line_t al(to_string(sbr));
|
||||
format->annotate(file_line_number, al.get_attrs(), values);
|
||||
|
||||
|
@ -258,6 +258,7 @@ add_filter_expr_possibilities(readline_curses* rlc,
|
||||
logline_value_vector values;
|
||||
|
||||
lf->read_full_message(ll, values.lvv_sbr);
|
||||
values.lvv_sbr.erase_ansi();
|
||||
format->annotate(cl, sa, values);
|
||||
for (auto& lv : values.lvv_values) {
|
||||
if (!lv.lv_meta.lvm_struct_name.empty()) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/ansi_scrubber.hh"
|
||||
#include "shared_buffer.hh"
|
||||
|
||||
static const bool DEBUG_TRACE = false;
|
||||
@ -163,6 +164,7 @@ shared_buffer_ref::copy_ref(const shared_buffer_ref& other)
|
||||
const_cast<char*>(this->sb_data), other.sb_data, other.sb_length);
|
||||
this->sb_length = other.sb_length;
|
||||
}
|
||||
this->sb_metadata = other.sb_metadata;
|
||||
}
|
||||
|
||||
shared_buffer_ref::narrow_result
|
||||
@ -179,3 +181,18 @@ shared_buffer_ref::widen(narrow_result old_data_length)
|
||||
this->sb_data = old_data_length.first;
|
||||
this->sb_length = old_data_length.second;
|
||||
}
|
||||
|
||||
void
|
||||
shared_buffer_ref::erase_ansi()
|
||||
{
|
||||
if (!this->sb_metadata.m_has_ansi) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* writable_data = this->get_writable_data();
|
||||
auto new_len = erase_ansi_escapes(
|
||||
string_fragment::from_bytes(writable_data, this->sb_length));
|
||||
|
||||
this->sb_length = new_len;
|
||||
this->sb_metadata.m_has_ansi = false;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "base/attr_line.hh"
|
||||
#include "base/auto_mem.hh"
|
||||
#include "base/file_range.hh"
|
||||
#include "base/intern_string.hh"
|
||||
#include "base/lnav_log.hh"
|
||||
#include "scn/util/string_view.h"
|
||||
@ -61,6 +62,7 @@ public:
|
||||
this->sb_owner = nullptr;
|
||||
this->sb_data = nullptr;
|
||||
this->sb_length = 0;
|
||||
this->sb_metadata = file_range::metadata{};
|
||||
|
||||
this->copy_ref(other);
|
||||
}
|
||||
@ -108,6 +110,8 @@ public:
|
||||
return (this->sb_data <= ptr && ptr < buffer_end);
|
||||
}
|
||||
|
||||
file_range::metadata& get_metadata() { return this->sb_metadata; }
|
||||
|
||||
char* get_writable_data()
|
||||
{
|
||||
if (this->take_ownership()) {
|
||||
@ -145,6 +149,8 @@ public:
|
||||
|
||||
bool subset(shared_buffer_ref& other, off_t offset, size_t len);
|
||||
|
||||
void erase_ansi();
|
||||
|
||||
bool take_ownership();
|
||||
|
||||
void disown();
|
||||
@ -153,6 +159,7 @@ private:
|
||||
void copy_ref(const shared_buffer_ref& other);
|
||||
|
||||
auto_mem<char*> sb_backtrace;
|
||||
file_range::metadata sb_metadata;
|
||||
shared_buffer* sb_owner;
|
||||
const char* sb_data;
|
||||
size_t sb_length;
|
||||
|
@ -301,6 +301,7 @@ log_spectro_value_source::spectro_mark(textview_curses& tc,
|
||||
|
||||
values.clear();
|
||||
lf->read_full_message(ll, values.lvv_sbr);
|
||||
values.lvv_sbr.erase_ansi();
|
||||
sa.clear();
|
||||
format->annotate(cl, sa, values, false);
|
||||
|
||||
|
@ -128,8 +128,10 @@ textfile_sub_source::text_size_for_line(textview_curses& tc,
|
||||
lf->get_logline_observer());
|
||||
if (line < 0 || line >= lfo->lfo_filter_state.tfs_index.size()) {
|
||||
} else {
|
||||
retval = lf->line_length(
|
||||
lf->begin() + lfo->lfo_filter_state.tfs_index[line]);
|
||||
retval
|
||||
= lf->message_byte_length(
|
||||
lf->begin() + lfo->lfo_filter_state.tfs_index[line])
|
||||
.mlr_length;
|
||||
}
|
||||
} else {
|
||||
retval = rend_iter->second.rf_text_source->text_size_for_line(
|
||||
|
@ -296,12 +296,16 @@ EXPECTED_FILES = \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_3fc6bfd8a6160817211f3e14fde957af75b9dbe7.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_4a2a907fcb069b8d6e65961a7b2e796d6c3a87b1.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_4a2a907fcb069b8d6e65961a7b2e796d6c3a87b1.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_6602faf7817c494c33e32da7ee95f13aa9210d01.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_6602faf7817c494c33e32da7ee95f13aa9210d01.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_7c2e11488bccc59458b5775db4b90de964858259.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_7c2e11488bccc59458b5775db4b90de964858259.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_a7037efd0c4bbf51940137a44e57d94e9307e83e.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_a7037efd0c4bbf51940137a44e57d94e9307e83e.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_c18e14a26d8261c9f72747118a469266121d5459.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_c18e14a26d8261c9f72747118a469266121d5459.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_e840b674cd65936a72bd64b1dac1524d16fe44c3.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_e840b674cd65936a72bd64b1dac1524d16fe44c3.out \
|
||||
$(srcdir)/%reldir%/test_meta.sh_154047fb52e4831aabf7d36512247bad6a6a2cf7.err \
|
||||
$(srcdir)/%reldir%/test_meta.sh_154047fb52e4831aabf7d36512247bad6a6a2cf7.out \
|
||||
$(srcdir)/%reldir%/test_meta.sh_3c9b5940f7533c5fc3d4956a6efce50a9e7132d4.err \
|
||||
@ -350,58 +354,6 @@ EXPECTED_FILES = \
|
||||
$(srcdir)/%reldir%/test_pretty_print.sh_cd361eeca7e91bfab942b75d6c3422c7a456a111.out \
|
||||
$(srcdir)/%reldir%/test_pretty_print.sh_f8feb52a321026d9562b271eb37a2c56dfaed329.err \
|
||||
$(srcdir)/%reldir%/test_pretty_print.sh_f8feb52a321026d9562b271eb37a2c56dfaed329.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_0fa3663a45aca6a328cb728872af7ed7ee896f1c.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_0fa3663a45aca6a328cb728872af7ed7ee896f1c.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_182ae9244db314a953af2bee969726e381bc5a32.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_182ae9244db314a953af2bee969726e381bc5a32.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_2158f1f011ba8e1b152396c072790c076fdb8ce8.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_2158f1f011ba8e1b152396c072790c076fdb8ce8.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_281af24141680330791db7f7c5fa70833ce08a6b.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_281af24141680330791db7f7c5fa70833ce08a6b.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_35703b13990785632cca82123fb3883797959c0b.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_35703b13990785632cca82123fb3883797959c0b.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_366730cac50b4a09b7de4b84641791470b1cb9a3.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_366730cac50b4a09b7de4b84641791470b1cb9a3.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_3d18474a3e472fff6e23e0c41337ec9188fee591.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_3d18474a3e472fff6e23e0c41337ec9188fee591.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_442cc58676590a3604d5c2183f5fe0a75c98351a.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_442cc58676590a3604d5c2183f5fe0a75c98351a.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_566fd88d216a44bc1c6e23f2d6f2d0caf99d42f9.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_566fd88d216a44bc1c6e23f2d6f2d0caf99d42f9.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_5f2f7ecb6ab9cbec4b41385b91bd038906b8a7b2.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_5f2f7ecb6ab9cbec4b41385b91bd038906b8a7b2.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_629bde30483e0a6461076e9058f3a5eb81ae0425.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_629bde30483e0a6461076e9058f3a5eb81ae0425.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_630db454054cf92ec9bd0f4e3e83300047f583ff.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_630db454054cf92ec9bd0f4e3e83300047f583ff.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_771af6f3d29b8350542d5c6e98bdbf4c223cd531.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_771af6f3d29b8350542d5c6e98bdbf4c223cd531.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_7991a5b617867cf37c9f7baa85ffa425f7d455a2.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_7991a5b617867cf37c9f7baa85ffa425f7d455a2.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_79ee3f5fe71ccec97b2619d8c1f74ca97ffd2243.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_79ee3f5fe71ccec97b2619d8c1f74ca97ffd2243.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_7de76c174c58d67bf93e8f01d6d55ebb6a023f10.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_7de76c174c58d67bf93e8f01d6d55ebb6a023f10.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_8a43e6657d4f60e68d31eb8302542ca28e80d077.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_8a43e6657d4f60e68d31eb8302542ca28e80d077.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_8e93a3b6b941847c71409a297779fbb0a6666a51.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_8e93a3b6b941847c71409a297779fbb0a6666a51.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_95c56a9d146ec9a7c2196559d316f928b2ae6ae9.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_95c56a9d146ec9a7c2196559d316f928b2ae6ae9.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_9d101ee29c45cdb8c0f117ad736c9a5dd5da5839.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_9d101ee29c45cdb8c0f117ad736c9a5dd5da5839.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_c43e07df9b3068696fdc8759c7561135db981b38.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_c43e07df9b3068696fdc8759c7561135db981b38.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_cbd859487e4ea011cd6e0f0f114d70158bfd8b43.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_cbd859487e4ea011cd6e0f0f114d70158bfd8b43.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_cf6c0a9f0f04e24ce1fae7a0a434830b14447f83.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_cf6c0a9f0f04e24ce1fae7a0a434830b14447f83.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_d84597760285c3964b258726341e018f6cd49954.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_d84597760285c3964b258726341e018f6cd49954.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_f23e393dbf23d0d8e276e9b7610c7b74d79980f8.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_f23e393dbf23d0d8e276e9b7610c7b74d79980f8.out \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_fc41b6ee90cbf038620151f16d164b361acf82dd.err \
|
||||
$(srcdir)/%reldir%/test_regex101.sh_fc41b6ee90cbf038620151f16d164b361acf82dd.out \
|
||||
$(srcdir)/%reldir%/test_sessions.sh_0300a1391c33b1c45ddfa90198a6bd0a5404a77f.err \
|
||||
$(srcdir)/%reldir%/test_sessions.sh_0300a1391c33b1c45ddfa90198a6bd0a5404a77f.out \
|
||||
$(srcdir)/%reldir%/test_sessions.sh_17b85654b929b2a8fc1705a170ced544783292fa.err \
|
||||
|
@ -0,0 +1,10 @@
|
||||
[32mSep 19 [0m[33m09:24:04[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mAMPDeviceDiscoveryAgent[0m[34m[[0m[34m17600[0m[34m][0m: ti[33md:1d1f[0m - Mux ID not found in mapping dictionary
|
||||
[32mSep 19 [0m[33m09:24:04[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mAMPDeviceDiscoveryAgent[0m[34m[[0m[34m17600[0m[34m][0m: ti[33md:1d1f[0m - Can't handle dis[41mconnect[0m with invalid ecid
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mMobileDeviceUpdater[0m[34m[[0m[34m17530[0m[34m][0m: Entered:_AMMuxedDeviceDis[41mconnect[0med, mux-devi[33mce:1003[0m
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mAMPDeviceDiscoveryAgent[0m[34m[[0m[34m17600[0m[34m][0m: Entered:_AMMuxedDeviceDis[41mconnect[0med, mux-devi[33mce:1003[0m
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mMobileDeviceUpdater[0m[34m[[0m[34m17530[0m[34m][0m: Entered:__thr_AMMuxedDeviceDis[41mconnect[0med, mux-devi[33mce:1003[0m
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mAMPDeviceDiscoveryAgent[0m[34m[[0m[34m17600[0m[34m][0m: Entered:__thr_AMMuxedDeviceDis[41mconnect[0med, mux-devi[33mce:1003[0m
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mMobileDeviceUpdater[0m[34m[[0m[34m17530[0m[34m][0m: ti[33md:191f[0m - Mux ID not found in mapping dictionary
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mAMPDeviceDiscoveryAgent[0m[34m[[0m[34m17600[0m[34m][0m: ti[33md:1d1f[0m - Mux ID not found in mapping dictionary
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mMobileDeviceUpdater[0m[34m[[0m[34m17530[0m[34m][0m: ti[33md:191f[0m - Can't handle dis[41mconnect[0m with invalid ecid
|
||||
[32mSep 19 [0m[33m09:24:20[0m[31m [0m[31mTims-MacBook-Air[0m[31m [0m[31mAMPDeviceDiscoveryAgent[0m[34m[[0m[34m17600[0m[34m][0m: ti[33md:1d1f[0m - Can't handle dis[41mconnect[0m with invalid ecid
|
@ -0,0 +1,11 @@
|
||||
[1m[4m log_time [0m[1m[4m log_body [0m
|
||||
[1m2022-09-19 09:24:04.000[0m[1m [0m[1mtid:1d1f - Mux ID not found in mapping dictionary [0m
|
||||
2022-09-19 09:24:04.000 tid:1d1f - Can't handle disconnect with invalid ecid
|
||||
[1m2022-09-19 09:24:20.000[0m[1m [0m[1mEntered:_AMMuxedDeviceDisconnected, mux-device:1003 [0m
|
||||
2022-09-19 09:24:20.000 Entered:_AMMuxedDeviceDisconnected, mux-device:1003
|
||||
[1m2022-09-19 09:24:20.000[0m[1m [0m[1mEntered:__thr_AMMuxedDeviceDisconnected, mux-device:1003 [0m
|
||||
2022-09-19 09:24:20.000 Entered:__thr_AMMuxedDeviceDisconnected, mux-device:1003
|
||||
[1m2022-09-19 09:24:20.000[0m[1m [0m[1mtid:191f - Mux ID not found in mapping dictionary [0m
|
||||
2022-09-19 09:24:20.000 tid:1d1f - Mux ID not found in mapping dictionary
|
||||
[1m2022-09-19 09:24:20.000[0m[1m [0m[1mtid:191f - Can't handle disconnect with invalid ecid [0m
|
||||
2022-09-19 09:24:20.000 tid:1d1f - Can't handle disconnect with invalid ecid
|
10
test/logfile_ansi.1
Normal file
10
test/logfile_ansi.1
Normal file
@ -0,0 +1,10 @@
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:04[0m[31m Tims-MacBook-Air [0m[1m[31mAMPDeviceDiscoveryAgent[0m[1m[34m[17600][0m: ti[0m[1m[33md:1d1f[0m - Mux ID not found in mapping dictionary[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:04[0m[31m Tims-MacBook-Air [0m[1m[31mAMPDeviceDiscoveryAgent[0m[1m[34m[17600][0m: ti[0m[1m[33md:1d1f[0m - Can't handle dis[0m[41mconnect[0m with invalid ecid[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mMobileDeviceUpdater[0m[1m[34m[17530][0m: Entered:_AMMuxedDeviceDis[0m[41mconnect[0med, mux-devi[0m[1m[33mce:1003[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mAMPDeviceDiscoveryAgent[0m[1m[34m[17600][0m: Entered:_AMMuxedDeviceDis[0m[41mconnect[0med, mux-devi[0m[1m[33mce:1003[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mMobileDeviceUpdater[0m[1m[34m[17530][0m: Entered:__thr_AMMuxedDeviceDis[0m[41mconnect[0med, mux-devi[0m[1m[33mce:1003[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mAMPDeviceDiscoveryAgent[0m[1m[34m[17600][0m: Entered:__thr_AMMuxedDeviceDis[0m[41mconnect[0med, mux-devi[0m[1m[33mce:1003[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mMobileDeviceUpdater[0m[1m[34m[17530][0m: ti[0m[1m[33md:191f[0m - Mux ID not found in mapping dictionary[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mAMPDeviceDiscoveryAgent[0m[1m[34m[17600][0m: ti[0m[1m[33md:1d1f[0m - Mux ID not found in mapping dictionary[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mMobileDeviceUpdater[0m[1m[34m[17530][0m: ti[0m[1m[33md:191f[0m - Can't handle dis[0m[41mconnect[0m with invalid ecid[0m
|
||||
[0m[32mSep 19 [0m[1m[33m09:24:20[0m[31m Tims-MacBook-Air [0m[1m[31mAMPDeviceDiscoveryAgent[0m[1m[34m[17600][0m: ti[0m[1m[33md:1d1f[0m - Can't handle dis[0m[41mconnect[0m with invalid ecid[0m
|
@ -45,16 +45,31 @@ using namespace std;
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
{
|
||||
char input[] = "Hello, \x1b[33;mWorld\x1b[0;m!";
|
||||
|
||||
auto new_len = erase_ansi_escapes(string_fragment::from_const(input));
|
||||
|
||||
assert(new_len == 13);
|
||||
}
|
||||
|
||||
{
|
||||
std::string boldish
|
||||
= "\u2022\b\u2022\u2023\b\u2023 h\bhe\bel\blo\bo _\ba_\bb_\bc a\b_ "
|
||||
"b";
|
||||
auto boldish2 = boldish;
|
||||
string_attrs_t sa;
|
||||
|
||||
sa.clear();
|
||||
scrub_ansi_string(boldish, &sa);
|
||||
printf("boldish %s\n", boldish.c_str());
|
||||
assert(boldish == "\u2022\u2023 helo abc a b");
|
||||
|
||||
auto new_len = erase_ansi_escapes(boldish2);
|
||||
boldish2.resize(new_len);
|
||||
printf("boldish2 %s\n", boldish2.c_str());
|
||||
assert(boldish2 == "\u2022\u2023 helo abc a b");
|
||||
|
||||
for (const auto& attr : sa) {
|
||||
printf("attr %d:%d %s\n",
|
||||
attr.sa_range.lr_start,
|
||||
|
@ -685,3 +685,13 @@ EOF
|
||||
# 192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
# 192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
# EOF
|
||||
|
||||
export YES_COLOR=1
|
||||
|
||||
run_cap_test ${lnav_test} -n \
|
||||
-c ';SELECT log_time, log_body FROM syslog_log' \
|
||||
${test_dir}/logfile_ansi.1
|
||||
|
||||
run_cap_test ${lnav_test} -n \
|
||||
-c ':switch-to-view pretty' \
|
||||
${test_dir}/logfile_ansi.1
|
||||
|
Loading…
Reference in New Issue
Block a user