[search-table] improve preview highlighting

pull/1031/head
Tim Stack 2 years ago
parent 3b9bc57ab0
commit e2e491ec41

@ -69,6 +69,14 @@ lnav v0.11.0:
* Added the "echoln()" SQL function that behaves similarly to the
":echo" command, writing its first argument to the current
output.
* Added "encode()" and "decode()" SQL functions for transcoding
blobs or text values using one of the following algorithms:
base64, hex, or uri.
* In regular expressions, capture group names are now semantically
highlighted (e.g. in the capture, (?<name>\w+), "name" would
have a unique color). Also, operations or previews that use
that regular expression will highlight the matched data with
the same color.
Breaking Changes:
* Added a 'language' column to the lnav_view_filters table that

@ -109,18 +109,20 @@ struct line_range {
{
if (this->lr_start < rhs.lr_start) {
return true;
} else if (this->lr_start > rhs.lr_start) {
}
if (this->lr_start > rhs.lr_start) {
return false;
}
// this->lr_start == rhs.lr_start
if (this->lr_end == rhs.lr_end) {
return false;
}
if (this->lr_end < rhs.lr_end) {
return true;
return false;
}
return false;
return true;
}
bool operator==(const struct line_range& rhs) const
@ -382,13 +384,9 @@ class attr_line_t {
public:
attr_line_t() = default;
attr_line_t(std::string str) : al_string(std::move(str))
{
}
attr_line_t(std::string str) : al_string(std::move(str)) {}
attr_line_t(const char* str) : al_string(str)
{
}
attr_line_t(const char* str) : al_string(str) {}
static inline attr_line_t from_ansi_str(const char* str)
{
@ -398,26 +396,14 @@ public:
}
/** @return The string itself. */
std::string& get_string()
{
return this->al_string;
}
std::string& get_string() { return this->al_string; }
const std::string& get_string() const
{
return this->al_string;
}
const std::string& get_string() const { return this->al_string; }
/** @return The attributes for the string. */
string_attrs_t& get_attrs()
{
return this->al_attrs;
}
string_attrs_t& get_attrs() { return this->al_attrs; }
const string_attrs_t& get_attrs() const
{
return this->al_attrs;
}
const string_attrs_t& get_attrs() const { return this->al_attrs; }
attr_line_t& with_string(const std::string& str)
{
@ -706,15 +692,9 @@ public:
return find_string_attr(this->al_attrs, near);
}
bool empty() const
{
return this->length() == 0;
}
bool empty() const { return this->length() == 0; }
bool blank() const
{
return is_blank(this->al_string);
}
bool blank() const { return is_blank(this->al_string); }
/** Clear the string and the attributes for the string. */
attr_line_t& clear()

@ -273,7 +273,8 @@ println(FILE* file, const attr_line_t& al)
for (const auto& attr : al.get_attrs()) {
if (!attr.sa_range.contains(start)
&& !attr.sa_range.contains(point - 1)) {
&& !attr.sa_range.contains(point - 1))
{
continue;
}
@ -339,6 +340,12 @@ println(FILE* file, const attr_line_t& al)
auto role = saw.get();
switch (role) {
case role_t::VCR_TEXT:
case role_t::VCR_IDENTIFIER:
break;
case role_t::VCR_SEARCH:
line_style |= fmt::emphasis::reverse;
break;
case role_t::VCR_ERROR:
line_style |= fmt::fg(fmt::terminal_color::red)
| fmt::emphasis::bold;
@ -410,6 +417,7 @@ println(FILE* file, const attr_line_t& al)
line_style |= fmt::bg(fmt::terminal_color::red);
break;
default:
// log_debug("missing role handler %d", (int) role);
break;
}
}

@ -180,7 +180,8 @@ regex_highlighter(attr_line_t& al, int x, line_range sub)
lpc, VC_ROLE.value(role_t::VCR_RE_SPECIAL));
if ((line[lpc] == '*' || line[lpc] == '+')
&& check_re_prev(line, lpc)) {
&& check_re_prev(line, lpc))
{
alb.overlay_attr_for_char(
lpc - 1, VC_ROLE.value(role_t::VCR_RE_REPEAT));
}
@ -231,6 +232,11 @@ regex_highlighter(attr_line_t& al, int x, line_range sub)
pcre_input pi(capture_start);
if (CAP_RE.match(pc, pi)) {
alb.overlay_attr(
line_range(
capture_start.sf_begin + pc.all()->c_begin + 3,
capture_start.sf_begin + pc.all()->c_end),
VC_ROLE.value(role_t::VCR_IDENTIFIER));
alb.overlay_attr(line_range(lpc, lpc + 1),
VC_ROLE.value(role_t::VCR_RE_SPECIAL));
}

@ -345,8 +345,7 @@ filter_sub_source::text_attrs_for_line(textview_curses& tc,
= lnav_data.ld_mode == ln_mode_t::FILTER && line == tc.get_selection();
if (selected) {
value_out.emplace_back(line_range{0, 1},
VC_GRAPHIC.value(ACS_RARROW));
value_out.emplace_back(line_range{0, 1}, VC_GRAPHIC.value(ACS_RARROW));
}
chtype enabled = tf->is_enabled() ? ACS_DIAMOND : ' ';
@ -422,22 +421,16 @@ filter_sub_source::rl_change(readline_curses* rc)
case filter_lang_t::NONE:
break;
case filter_lang_t::REGEX: {
auto_mem<pcre> code;
const char* errptr;
int eoff;
if ((code = pcre_compile(new_value.c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr))
== nullptr)
{
auto regex_res
= pcrepp::shared_from_str(new_value, PCRE_CASELESS | PCRE_UTF8);
if (regex_res.isErr()) {
auto pe = regex_res.unwrapErr();
lnav_data.ld_filter_help_status_source.fss_error.set_value(
"error: %s", errptr);
"error: %s", pe.ce_msg);
} else {
auto& hm = top_view->get_highlights();
highlighter hl(code.release());
highlighter hl(regex_res.unwrap());
auto role = tf->get_type() == text_filter::EXCLUDE
? role_t::VCR_DIFF_DELETE
: role_t::VCR_DIFF_ADD;

@ -31,21 +31,6 @@
#include "config.h"
highlighter::highlighter(const highlighter& other)
{
this->h_pattern = other.h_pattern;
this->h_fg = other.h_fg;
this->h_bg = other.h_bg;
this->h_role = other.h_role;
this->h_code = other.h_code;
pcre_refcount(this->h_code, 1);
this->study();
this->h_attrs = other.h_attrs;
this->h_text_formats = other.h_text_formats;
this->h_format_name = other.h_format_name;
this->h_nestable = other.h_nestable;
}
highlighter&
highlighter::operator=(const highlighter& other)
{
@ -53,19 +38,11 @@ highlighter::operator=(const highlighter& other)
return *this;
}
if (this->h_code != nullptr && pcre_refcount(this->h_code, -1) == 0) {
free(this->h_code);
this->h_code = nullptr;
}
free(this->h_code_extra);
this->h_pattern = other.h_pattern;
this->h_fg = other.h_fg;
this->h_bg = other.h_bg;
this->h_role = other.h_role;
this->h_code = other.h_code;
pcre_refcount(this->h_code, 1);
this->study();
this->h_regex = other.h_regex;
this->h_format_name = other.h_format_name;
this->h_attrs = other.h_attrs;
this->h_text_formats = other.h_text_formats;
@ -75,21 +52,34 @@ highlighter::operator=(const highlighter& other)
}
void
highlighter::study()
highlighter::annotate_capture(attr_line_t& al, const line_range& lr) const
{
const char* errptr;
auto& vc = view_colors::singleton();
auto& sa = al.get_attrs();
this->h_code_extra = pcre_study(this->h_code, 0, &errptr);
if (!this->h_code_extra && errptr) {
log_error("pcre_study error: %s", errptr);
if (!(lr.lr_start < lr.lr_end
&& (this->h_nestable
|| find_string_attr_containing(sa, &VC_STYLE, lr) == sa.end())))
{
return;
}
if (this->h_code_extra != nullptr) {
pcre_extra* extra = this->h_code_extra;
extra->flags
|= (PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION);
extra->match_limit = 10000;
extra->match_limit_recursion = 500;
if (!this->h_fg.empty()) {
sa.emplace_back(lr,
VC_FOREGROUND.value(
vc.match_color(this->h_fg)
.value_or(view_colors::MATCH_COLOR_DEFAULT)));
}
if (!this->h_bg.empty()) {
sa.emplace_back(lr,
VC_BACKGROUND.value(
vc.match_color(this->h_bg)
.value_or(view_colors::MATCH_COLOR_DEFAULT)));
}
if (this->h_role != role_t::VCR_NONE) {
sa.emplace_back(lr, VC_ROLE.value(this->h_role));
}
if (!this->h_attrs.empty()) {
sa.emplace_back(lr, VC_STYLE.value(this->h_attrs));
}
}
@ -99,69 +89,36 @@ highlighter::annotate(attr_line_t& al, int start) const
auto& vc = view_colors::singleton();
const auto& str = al.get_string();
auto& sa = al.get_attrs();
// The line we pass to pcre_exec will be treated as the start when the
// carat (^) operator is used.
const char* line_start = &(str.c_str()[start]);
size_t re_end;
auto sf = string_fragment::from_substr(
str, start, std::min(size_t{8192}, str.size()));
if ((str.length() - start) > 8192)
re_end = 8192;
else
re_end = str.length() - start;
for (int off = 0; off < (int) str.size() - start;) {
int rc, matches[60];
rc = pcre_exec(this->h_code,
this->h_code_extra,
line_start,
re_end,
off,
0,
matches,
60);
if (rc > 0) {
struct line_range lr;
pcre_context_static<60> pc;
pcre_input pi(sf);
if (rc == 2) {
lr.lr_start = start + matches[2];
lr.lr_end = start + matches[3];
} else {
lr.lr_start = start + matches[0];
lr.lr_end = start + matches[1];
}
while (this->h_regex->match(pc, pi)) {
if (pc.get_count() == 1) {
line_range lr{start + pc.all()->c_begin, start + pc.all()->c_end};
if (lr.lr_end > lr.lr_start
&& (this->h_nestable
|| find_string_attr_containing(
sa, &VC_STYLE, lr)
== sa.end()))
{
if (!this->h_fg.empty()) {
sa.emplace_back(
lr,
VC_FOREGROUND.value(
vc.match_color(this->h_fg)
.value_or(view_colors::MATCH_COLOR_DEFAULT)));
}
if (!this->h_bg.empty()) {
sa.emplace_back(
lr,
VC_BACKGROUND.value(
vc.match_color(this->h_bg)
.value_or(view_colors::MATCH_COLOR_DEFAULT)));
}
if (this->h_role != role_t::VCR_NONE) {
sa.emplace_back(lr, VC_ROLE.value(this->h_role));
}
if (!this->h_attrs.empty()) {
sa.emplace_back(lr, VC_STYLE.value(this->h_attrs));
}
this->annotate_capture(al, lr);
} else {
for (size_t lpc = 0; lpc < pc.get_count() - 1; lpc++) {
line_range lr{start + pc[lpc]->c_begin, start + pc[lpc]->c_end};
const auto* name = this->h_regex->name_for_capture(lpc);
if (name != nullptr && name[0]) {
auto ident_attrs = vc.attrs_for_ident(name);
ident_attrs.ta_attrs |= this->h_attrs.ta_attrs;
if (this->h_role != role_t::VCR_NONE) {
auto role_attrs = vc.attrs_for_role(this->h_role);
off = matches[1];
} else {
off += 1;
ident_attrs.ta_attrs |= role_attrs.ta_attrs;
}
sa.emplace_back(lr, VC_STYLE.value(ident_attrs));
} else {
this->annotate_capture(al, lr);
}
}
} else {
off = str.size();
}
}
}

@ -33,6 +33,7 @@
#define highlighter_hh
#include <set>
#include <utility>
#include "optional.hpp"
#include "pcrepp/pcrepp.hh"
@ -40,35 +41,18 @@
#include "view_curses.hh"
struct highlighter {
highlighter() : h_code(nullptr), h_code_extra(nullptr) {}
highlighter() = default;
explicit highlighter(pcre* code) : h_code(code)
explicit highlighter(std::shared_ptr<pcrepp> regex)
: h_regex(std::move(regex))
{
pcre_refcount(this->h_code, 1);
this->study();
}
highlighter(const highlighter& other);
highlighter(const highlighter& other) = default;
highlighter& operator=(const highlighter& other);
virtual ~highlighter()
{
if (this->h_code != nullptr && pcre_refcount(this->h_code, -1) == 0) {
free(this->h_code);
this->h_code = nullptr;
}
free(this->h_code_extra);
}
void study();
highlighter& with_pattern(const std::string& pattern)
{
this->h_pattern = pattern;
return *this;
}
virtual ~highlighter() = default;
highlighter& with_role(role_t role)
{
@ -117,12 +101,13 @@ struct highlighter {
void annotate(attr_line_t& al, int start) const;
void annotate_capture(attr_line_t& al, const line_range& lr) const;
std::string h_pattern;
role_t h_role{role_t::VCR_NONE};
styling::color_unit h_fg{styling::color_unit::make_empty()};
styling::color_unit h_bg{styling::color_unit::make_empty()};
pcre* h_code;
pcre_extra* h_code_extra;
std::shared_ptr<pcrepp> h_regex;
text_attrs h_attrs;
std::set<text_format_t> h_text_formats;
intern_string_t h_format_name;

@ -430,29 +430,28 @@ static bool
append_default_files()
{
bool retval = true;
auto cwd = ghc::filesystem::current_path();
auto cwd = ghc::filesystem::current_path();
for (const auto& path : DEFAULT_FILES) {
if (access(path.c_str(), R_OK) == 0) {
auto_mem<char> abspath;
for (const auto& path : DEFAULT_FILES) {
if (access(path.c_str(), R_OK) == 0) {
auto_mem<char> abspath;
auto full_path = cwd / path;
if ((abspath = realpath(full_path.c_str(), nullptr)) == nullptr)
{
perror("Unable to resolve path");
} else {
lnav_data.ld_active_files.fc_file_names[abspath.in()];
}
} else if (lnav::filesystem::stat_file(path).isOk()) {
lnav::console::print(
stderr,
lnav::console::user_message::error(
attr_line_t("default syslog file is not readable -- ")
.append(lnav::roles::file(cwd))
.append(lnav::roles::file(path))));
retval = false;
auto full_path = cwd / path;
if ((abspath = realpath(full_path.c_str(), nullptr)) == nullptr) {
perror("Unable to resolve path");
} else {
lnav_data.ld_active_files.fc_file_names[abspath.in()];
}
} else if (lnav::filesystem::stat_file(path).isOk()) {
lnav::console::print(
stderr,
lnav::console::user_message::error(
attr_line_t("default syslog file is not readable -- ")
.append(lnav::roles::file(cwd))
.append(lnav::roles::file(path))));
retval = false;
}
}
return retval;
}
@ -973,7 +972,8 @@ gather_pipers()
iter != lnav_data.ld_child_pollers.end();)
{
if (iter->poll(lnav_data.ld_active_files)
== child_poll_result_t::FINISHED) {
== child_poll_result_t::FINISHED)
{
iter = lnav_data.ld_child_pollers.erase(iter);
} else {
++iter;
@ -1631,7 +1631,8 @@ UPDATE lnav_views_echo
case ln_mode_t::BUSY:
if (old_gen
== lnav_data.ld_active_files
.fc_files_generation) {
.fc_files_generation)
{
next_rescan_time = next_status_update_time + 1s;
} else {
next_rescan_time = next_status_update_time;
@ -1674,7 +1675,8 @@ UPDATE lnav_views_echo
}
}
if (old_file_names_size
!= lnav_data.ld_active_files.fc_file_names.size()) {
!= lnav_data.ld_active_files.fc_file_names.size())
{
next_rescan_time = ui_clock::now();
next_rebuild_time = next_rescan_time;
next_status_update_time = next_rescan_time;
@ -1786,7 +1788,8 @@ UPDATE lnav_views_echo
|| !lnav_data.ld_active_files.fc_other_files.empty()))
{
for (size_t view_index = 0; view_index < LNV__MAX;
view_index++) {
view_index++)
{
const auto& vs
= session_data.sd_view_states[view_index];
@ -2657,11 +2660,12 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
retval = EXIT_FAILURE;
}
} else if (access(file_path.c_str(), R_OK) == -1) {
lnav::console::print(stderr,
lnav::console::user_message::error(
lnav::console::print(
stderr,
lnav::console::user_message::error(
attr_line_t("file exists, but is not readable: ")
.append(lnav::roles::file(file_path)))
.with_errno_reason());
.with_errno_reason());
retval = EXIT_FAILURE;
} else if (S_ISFIFO(st.st_mode)) {
auto_fd fifo_fd;
@ -2731,7 +2735,8 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
continue;
}
for (auto line_iter = lf->begin(); line_iter != lf->end();
++line_iter) {
++line_iter)
{
if (line_iter->get_msg_level() != log_level_t::LEVEL_INVALID) {
continue;
}
@ -2905,7 +2910,8 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
rescan_files(true);
if (!lnav_data.ld_active_files.fc_name_to_errors.empty()) {
for (const auto& pair :
lnav_data.ld_active_files.fc_name_to_errors) {
lnav_data.ld_active_files.fc_name_to_errors)
{
lnav::console::print(
stderr,
lnav::console::user_message::error(
@ -2926,6 +2932,7 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
// Read all of stdin
wait_for_pipers();
rebuild_indexes_repeatedly();
wait_for_children();
log_tc->set_top(0_vl);
text_tc = &lnav_data.ld_views[LNV_TEXT];
@ -2947,9 +2954,11 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
.send_and_wait(
[](auto& clooper) { clooper.process_all(); });
rebuild_indexes_repeatedly();
wait_for_children();
if (!lnav_data.ld_active_files.fc_name_to_errors.empty()) {
for (const auto& pair :
lnav_data.ld_active_files.fc_name_to_errors) {
lnav_data.ld_active_files.fc_name_to_errors)
{
fprintf(stderr,
"error: unable to open file: %s -- %s\n",
pair.first.c_str(),
@ -3000,7 +3009,8 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
vis_line_t vl;
for (vl = tc->get_top(); vl < tc->get_inner_height();
++vl, ++y) {
++vl, ++y)
{
attr_line_t al;
while (los != nullptr
@ -3063,7 +3073,8 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
ghc::filesystem::perms::owner_read);
auto stdin_size = ghc::filesystem::file_size(stdin_tmp_path);
if (verbosity == verbosity_t::quiet
|| stdin_size > MAX_STDIN_CAPTURE_SIZE) {
|| stdin_size > MAX_STDIN_CAPTURE_SIZE)
{
log_info("not saving large stdin capture -- %s",
stdin_tmp_path.c_str());
ghc::filesystem::remove(stdin_tmp_path);

@ -58,7 +58,6 @@
#include "field_overlay_source.hh"
#include "fmt/printf.h"
#include "lnav.indexing.hh"
#include "session.export.hh"
#include "lnav_commands.hh"
#include "lnav_config.hh"
#include "lnav_util.hh"
@ -70,11 +69,12 @@
#include "readline_highlighters.hh"
#include "readline_possibilities.hh"
#include "relative_time.hh"
#include "scn/scn.h"
#include "service_tags.hh"
#include "session.export.hh"
#include "session_data.hh"
#include "shlex.hh"
#include "spectro_impls.hh"
#include "scn/scn.h"
#include "sqlite-extension-func.hh"
#include "sysclip.hh"
#include "tailer/tailer.looper.hh"
@ -128,7 +128,8 @@ remaining_args_frag(const std::string& cmdline,
require(index_in_cmdline != std::string::npos);
return string_fragment::from_str_range(cmdline, index_in_cmdline, cmdline.size());
return string_fragment::from_str_range(
cmdline, index_in_cmdline, cmdline.size());
}
static nonstd::optional<std::string>
@ -389,7 +390,8 @@ com_goto(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
dst_vl = vl;
if (!ec.ec_dry_run && !rt.is_absolute()
&& lnav_data.ld_rl_view != nullptr) {
&& lnav_data.ld_rl_view != nullptr)
{
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
r, R, "to move forward/backward the same amount of time"));
}
@ -839,7 +841,8 @@ json_write_row(yajl_gen handle, int row)
= (const unsigned char*) dls.dls_rows[row][col];
switch (yajl_parse(parse_handle.in(),
json_in,
strlen((const char*) json_in))) {
strlen((const char*) json_in)))
{
case yajl_status_error:
case yajl_status_client_canceled: {
err = yajl_get_error(
@ -1160,7 +1163,8 @@ com_save_to(exec_context& ec,
vis_line_t top = tc->get_top();
vis_line_t bottom = tc->get_bottom();
if (lnav_data.ld_flags & LNF_HEADLESS && tc->get_inner_height() > 0_vl) {
if (lnav_data.ld_flags & LNF_HEADLESS && tc->get_inner_height() > 0_vl)
{
bottom = tc->get_inner_height() - 1_vl;
}
auto y = 0_vl;
@ -1204,7 +1208,8 @@ com_save_to(exec_context& ec,
++row_iter)
{
if (ec.ec_dry_run
&& distance(dls.dls_rows.begin(), row_iter) > 10) {
&& distance(dls.dls_rows.begin(), row_iter) > 10)
{
break;
}
@ -1422,7 +1427,8 @@ com_pipe_to(exec_context& ec,
}
auto iter = ldh.ldh_parser->dp_pairs.begin();
for (size_t lpc = 0; lpc < ldh.ldh_parser->dp_pairs.size();
lpc++, ++iter) {
lpc++, ++iter)
{
std::string colname = ldh.ldh_parser->get_element_string(
iter->e_sub_elements->front());
colname = ldh.ldh_namer->add_column(colname).to_string();
@ -1464,7 +1470,8 @@ com_pipe_to(exec_context& ec,
lf->read_full_message(lf->message_start(lf->begin() + cl),
sbr);
if (write(in_pipe.write_end(), sbr.get_data(), sbr.length())
== -1) {
== -1)
{
return ec.make_error("Unable to write to pipe -- {}",
strerror(errno));
}
@ -1472,7 +1479,8 @@ com_pipe_to(exec_context& ec,
} else {
tc->grep_value_for_line(tc->get_top(), line);
if (write(in_pipe.write_end(), line.c_str(), line.size())
== -1) {
== -1)
{
return ec.make_error("Unable to write to pipe -- {}",
strerror(errno));
}
@ -1482,7 +1490,8 @@ com_pipe_to(exec_context& ec,
for (iter = bv.begin(); iter != bv.end(); iter++) {
tc->grep_value_for_line(*iter, line);
if (write(in_pipe.write_end(), line.c_str(), line.size())
== -1) {
== -1)
{
return ec.make_error("Unable to write to pipe -- {}",
strerror(errno));
}
@ -1549,12 +1558,14 @@ com_redirect_to(exec_context& ec,
auto out = sysclip::open(sysclip::type_t::GENERAL);
if (out.isErr()) {
alerter::singleton().chime();
return ec.make_error(
"Unable to copy to clipboard: {}", out.unwrapErr());
return ec.make_error("Unable to copy to clipboard: {}",
out.unwrapErr());
}
auto holder = out.unwrap();
ec.set_output(split_args[0], holder.release(), holder.get_free_func<int(*)(FILE*)>());
ec.set_output(split_args[0],
holder.release(),
holder.get_free_func<int (*)(FILE*)>());
} else if (lnav_data.ld_flags & LNF_SECURE_MODE) {
return ec.make_error("{} -- unavailable in secure mode", args[0]);
} else {
@ -1579,62 +1590,57 @@ com_highlight(exec_context& ec,
if (args.empty()) {
args.emplace_back("filter");
} else if (args.size() > 1) {
textview_curses* tc = *lnav_data.ld_view_stack.top();
auto* tc = *lnav_data.ld_view_stack.top();
auto& hm = tc->get_highlights();
const char* errptr;
auto_mem<pcre> code;
int eoff;
auto re_frag = remaining_args_frag(cmdline, args);
args[1] = re_frag.to_string();
if (hm.find({highlight_source_t::INTERACTIVE, args[1]}) != hm.end()) {
return ec.make_error("highlight already exists -- {}", args[1]);
} else if ((code = pcre_compile(args[1].c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr))
== nullptr)
{
}
auto compile_res
= pcrepp::shared_from_str(args[1], PCRE_CASELESS | PCRE_UTF8);
if (compile_res.isErr()) {
auto ce = compile_res.unwrapErr();
auto um = lnav::console::user_message::error(
"invalid regular expression")
.with_reason(errptr)
.with_reason(ce.ce_msg)
.with_snippets(ec.ec_source);
um.um_snippets.back()
.s_content.append("\n")
.append(re_frag.sf_begin + eoff, ' ')
.append(re_frag.sf_begin + ce.ce_offset, ' ')
.append("^ "_comment)
.append(lnav::roles::comment(errptr));
.append(lnav::roles::comment(ce.ce_msg));
return Err(um);
} else {
highlighter hl(code.release());
auto hl_attrs = view_colors::singleton().attrs_for_ident(args[1]);
if (ec.ec_dry_run) {
hl_attrs.ta_attrs |= A_BLINK;
}
}
highlighter hl(compile_res.unwrap());
auto hl_attrs = view_colors::singleton().attrs_for_ident(args[1]);
hl.with_attrs(hl_attrs);
if (ec.ec_dry_run) {
hl_attrs.ta_attrs |= A_BLINK;
}
if (ec.ec_dry_run) {
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
hl.with_attrs(hl_attrs);
lnav_data.ld_preview_status_source.get_description().set_value(
"Matches are highlighted in the view");
if (ec.ec_dry_run) {
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
retval = "";
} else {
hm[{highlight_source_t::INTERACTIVE, args[1]}] = hl;
lnav_data.ld_preview_status_source.get_description().set_value(
"Matches are highlighted in the view");
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->add_possibility(
ln_mode_t::COMMAND, "highlight", args[1]);
}
retval = "";
} else {
hm[{highlight_source_t::INTERACTIVE, args[1]}] = hl;
retval = "info: highlight pattern now active";
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->add_possibility(
ln_mode_t::COMMAND, "highlight", args[1]);
}
tc->reload_data();
retval = "info: highlight pattern now active";
}
tc->reload_data();
} else {
return ec.make_error("expecting a regular expression to highlight");
}
@ -1714,38 +1720,36 @@ com_filter(exec_context& ec,
return ec.make_error("{} view does not support filtering",
lnav_view_strings[tc - lnav_data.ld_views]);
} else if (args.size() > 1) {
text_sub_source* tss = tc->get_sub_source();
filter_stack& fs = tss->get_filters();
const char* errptr;
auto_mem<pcre> code;
int eoff;
auto* tss = tc->get_sub_source();
auto& fs = tss->get_filters();
auto re_frag = remaining_args_frag(cmdline, args);
args[1] = re_frag.to_string();
if (fs.get_filter(args[1]) != NULL) {
if (fs.get_filter(args[1]) != nullptr) {
return com_enable_filter(ec, cmdline, args);
} else if (fs.full()) {
}
if (fs.full()) {
return ec.make_error(
"filter limit reached, try combining "
"filters with a pipe symbol (e.g. foo|bar)");
} else if ((code = pcre_compile(args[1].c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr))
== NULL)
{
}
auto compile_res = pcrepp::shared_from_str(args[1], PCRE_CASELESS | PCRE_UTF8);
if (compile_res.isErr()) {
auto ce = compile_res.unwrapErr();
auto um = lnav::console::user_message::error(
"invalid regular expression")
.with_reason(errptr)
.with_reason(ce.ce_msg)
.with_snippets(ec.ec_source);
um.um_snippets.back()
.s_content.append("\n")
.append(re_frag.sf_begin + eoff, ' ')
.append(re_frag.sf_begin + ce.ce_offset, ' ')
.append("^ "_comment)
.append(lnav::roles::comment(errptr));
.append(lnav::roles::comment(ce.ce_msg));
return Err(um);
} else if (ec.ec_dry_run) {
}
if (ec.ec_dry_run) {
if (args[0] == "filter-in" && !fs.empty()) {
lnav_data.ld_preview_status_source.get_description().set_value(
"Match preview for :filter-in only works if there are no "
@ -1753,10 +1757,9 @@ com_filter(exec_context& ec,
retval = "";
} else {
auto& hm = tc->get_highlights();
highlighter hl(code.release());
auto role = (args[0] == "filter-out") ?
role_t::VCR_DIFF_DELETE :
role_t::VCR_DIFF_ADD;
highlighter hl(compile_res.unwrap());
auto role = (args[0] == "filter-out") ? role_t::VCR_DIFF_DELETE
: role_t::VCR_DIFF_ADD;
hl.with_attrs(text_attrs{A_BLINK});
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
@ -1777,7 +1780,7 @@ com_filter(exec_context& ec,
return ec.make_error("too many filters");
}
auto pf = std::make_shared<pcre_filter>(
lt, args[1], *filter_index, code.release());
lt, args[1], *filter_index, compile_res.unwrap()->release());
log_debug("%s [%d] %s",
args[0].c_str(),
@ -2154,7 +2157,7 @@ com_create_search_table(exec_context& ec,
}
auto re_res
= pcrepp::from_str(regex, log_search_table::pattern_options());
= pcrepp::shared_from_str(regex, log_search_table::pattern_options());
if (re_res.isErr()) {
auto re_err = re_res.unwrapErr();
@ -2174,11 +2177,11 @@ com_create_search_table(exec_context& ec,
auto re = re_res.unwrap();
auto tab_name = intern_string::lookup(args[1]);
auto lst = std::make_shared<log_search_table>(re, tab_name);
auto lst = std::make_shared<log_search_table>(*re, tab_name);
if (ec.ec_dry_run) {
auto* tc = &lnav_data.ld_views[LNV_LOG];
auto& hm = tc->get_highlights();
highlighter hl(re.p_code);
highlighter hl(re);
hl.with_role(role_t::VCR_INFO);
hl.with_attrs(text_attrs{A_BLINK});
@ -2377,7 +2380,8 @@ com_open(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
auto file_iter = lnav_data.ld_active_files.fc_files.begin();
for (; file_iter != lnav_data.ld_active_files.fc_files.end();
++file_iter) {
++file_iter)
{
auto lf = *file_iter;
if (lf->get_filename() == fn) {
@ -2553,7 +2557,8 @@ com_open(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
}
if (gl->gl_pathc > 10) {
al.append(" ... ")
.append(lnav::roles::number(std::to_string(gl->gl_pathc - 10)))
.append(lnav::roles::number(
std::to_string(gl->gl_pathc - 10)))
.append(" files not shown ...");
}
lnav_data.ld_preview_status_source.get_description()
@ -3269,7 +3274,8 @@ com_summarize(exec_context& ec,
query = "SELECT";
for (auto iter = other_columns.begin(); iter != other_columns.end();
++iter) {
++iter)
{
if (iter != other_columns.begin()) {
query += ",";
}
@ -3312,7 +3318,8 @@ com_summarize(exec_context& ec,
"startswith(logline.log_part, '.') = 0) ");
for (auto iter = other_columns.begin(); iter != other_columns.end();
++iter) {
++iter)
{
if (iter == other_columns.begin()) {
query += " GROUP BY ";
} else {
@ -3323,7 +3330,8 @@ com_summarize(exec_context& ec,
}
for (auto iter = other_columns.begin(); iter != other_columns.end();
++iter) {
++iter)
{
if (iter == other_columns.begin()) {
query += " ORDER BY ";
} else {
@ -3502,7 +3510,8 @@ com_zoom_to(exec_context& ec,
for (int lpc = 0; lpc < lnav_zoom_strings.size() && !found; lpc++) {
if (strcasecmp(args[1].c_str(), lnav_zoom_strings[lpc].c_str())
== 0) {
== 0)
{
auto& ss = *lnav_data.ld_spectro_source;
struct timeval old_time;
@ -3606,8 +3615,8 @@ com_save_session(exec_context& ec,
static Result<std::string, lnav::console::user_message>
com_export_session_to(exec_context& ec,
std::string cmdline,
std::vector<std::string>& args)
std::string cmdline,
std::vector<std::string>& args)
{
std::string retval;
@ -3631,9 +3640,10 @@ com_export_session_to(exec_context& ec,
tcsetattr(1, TCSANOW, &curr_termios);
setvbuf(stdout, nullptr, _IONBF, 0);
to_term = true;
fprintf(outfile,
"\n---------------- Press any key to exit lo-fi display "
"----------------\n\n");
fprintf(
outfile,
"\n---------------- Press any key to exit lo-fi display "
"----------------\n\n");
} else {
outfile = auto_mem<FILE>::leak(ec_out.value());
}
@ -3667,7 +3677,8 @@ com_export_session_to(exec_context& ec,
return Err(export_res.unwrapErr());
}
retval = fmt::format(FMT_STRING("info: wrote session commands to -- {}"), fn);
retval = fmt::format(
FMT_STRING("info: wrote session commands to -- {}"), fn);
}
return Ok(retval);
@ -4215,9 +4226,11 @@ com_config(exec_context& ec,
retval = fmt::format(
FMT_STRING("{} = {}"), option, trim(old_value));
}
} else if (lnav_data.ld_flags & LNF_SECURE_MODE &&
!startswith(option, "/ui/")) {
return ec.make_error(":config {} -- unavailable in secure mode", option);
} else if (lnav_data.ld_flags & LNF_SECURE_MODE
&& !startswith(option, "/ui/"))
{
return ec.make_error(":config {} -- unavailable in secure mode",
option);
} else {
auto value = remaining_args(cmdline, args, 2);
bool changed = false;
@ -5482,9 +5495,8 @@ readline_context::command_t STD_COMMANDS[] = {
"Variable substitution is performed on the message. Use a "
"backslash to escape any special characters, like '$'")
.with_parameter(
help_text(
"-n",
"Do not print a line-feed at the end of the output")
help_text("-n",
"Do not print a line-feed at the end of the output")
.optional())
.with_parameter(help_text("msg", "The message to display"))
.with_tags({"io", "scripting"})

@ -2279,11 +2279,9 @@ external_log_format::build(std::vector<lnav::console::user_message>& errors)
for (auto& hd_pair : this->elf_highlighter_patterns) {
external_log_format::highlighter_def& hd = hd_pair.second;
const char* errptr;
auto fg = styling::color_unit::make_empty();
auto bg = styling::color_unit::make_empty();
text_attrs attrs;
int eoff;
if (!hd.hd_color.pp_value.empty()) {
fg = styling::color_unit::from_str(hd.hd_color.pp_value)
@ -2330,18 +2328,14 @@ external_log_format::build(std::vector<lnav::console::user_message>& errors)
}
if (hd.hd_pattern != nullptr) {
auto* code = pcre_compile(hd.hd_pattern->get_pattern().c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr);
auto regex = pcrepp::shared_from_str(hd.hd_pattern->get_pattern(),
PCRE_CASELESS | PCRE_UTF8);
if (code == nullptr) {
if (regex.isErr()) {
log_error("unable to recompile highlighter pattern");
} else {
this->lf_highlighters.emplace_back(code);
this->lf_highlighters.emplace_back(regex.unwrap());
this->lf_highlighters.back()
.with_pattern(hd.hd_pattern->get_pattern())
.with_format_name(this->elf_name)
.with_color(fg, bg)
.with_attrs(attrs);

@ -406,7 +406,8 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv,
}
if (!line_value.lv_meta.lvm_identifier
|| !line_value.lv_origin.is_valid()) {
|| !line_value.lv_origin.is_valid())
{
continue;
}
@ -455,7 +456,8 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv,
if (binary_search(std::begin(bv_search),
std::end(bv_search),
vis_line_t(row))) {
vis_line_t(row)))
{
lr.lr_start = 0;
lr.lr_end = 1;
value_out.emplace_back(lr,
@ -693,7 +695,8 @@ logfile_sub_source::rebuild_index(
lf->get_filename().c_str(),
lf->size());
if (!this->lss_index.empty()
&& lf->size() > ld.ld_lines_indexed) {
&& lf->size() > ld.ld_lines_indexed)
{
logline& new_file_line = (*lf)[ld.ld_lines_indexed];
content_line_t cl = this->lss_index.back();
logline* last_indexed_line = this->find_line(cl);
@ -716,12 +719,14 @@ logfile_sub_source::rebuild_index(
: last_indexed_line
->get_time_in_millis());
if (retval
<= rebuild_result::rr_partial_rebuild) {
<= rebuild_result::rr_partial_rebuild)
{
retval = rebuild_result::rr_partial_rebuild;
if (!lowest_tv) {
lowest_tv = new_file_line.get_timeval();
} else if (new_file_line.get_timeval()
< lowest_tv.value()) {
< lowest_tv.value())
{
lowest_tv = new_file_line.get_timeval();
}
}
@ -756,7 +761,8 @@ logfile_sub_source::rebuild_index(
if (force) {
for (iter = this->lss_files.begin(); iter != this->lss_files.end();
iter++) {
iter++)
{
(*iter)->ld_lines_indexed = 0;
}
@ -772,7 +778,8 @@ logfile_sub_source::rebuild_index(
log_debug("partial rebuild with lowest time: %ld",
lowest_tv.value().tv_sec);
for (iter = this->lss_files.begin(); iter != this->lss_files.end();
iter++) {
iter++)
{
logfile_data& ld = *(*iter);
auto* lf = ld.get_file_ptr();
@ -860,7 +867,8 @@ logfile_sub_source::rebuild_index(
}
for (size_t line_index = 0; line_index < lf->size();
line_index++) {
line_index++)
{
if ((*lf)[line_index].is_ignored()) {
continue;
}
@ -888,7 +896,8 @@ logfile_sub_source::rebuild_index(
file_count);
for (iter = this->lss_files.begin(); iter != this->lss_files.end();
iter++) {
iter++)
{
auto* ld = iter->get();
auto* lf = ld->get_file_ptr();
if (lf == nullptr) {
@ -934,7 +943,8 @@ logfile_sub_source::rebuild_index(
}
for (iter = this->lss_files.begin(); iter != this->lss_files.end();
iter++) {
iter++)
{
auto* lf = (*iter)->get_file_ptr();
if (lf == nullptr) {

@ -65,7 +65,8 @@ pcrepp::quote(const char* unquoted)
for (int lpc = 0; unquoted[lpc]; lpc++) {
if (isalnum(unquoted[lpc]) || unquoted[lpc] == '_'
|| unquoted[lpc] & 0x80) {
|| unquoted[lpc] & 0x80)
{
retval.push_back(unquoted[lpc]);
} else {
retval.push_back('\\');
@ -81,7 +82,7 @@ pcrepp::from_str(std::string pattern, int options)
{
const char* errptr;
int eoff;
auto code = pcre_compile(
auto* code = pcre_compile(
pattern.c_str(), options | PCRE_UTF8, &errptr, &eoff, nullptr);
if (!code) {
@ -91,6 +92,21 @@ pcrepp::from_str(std::string pattern, int options)
return Ok(pcrepp(std::move(pattern), code));
}
Result<std::shared_ptr<pcrepp>, pcrepp::compile_error>
pcrepp::shared_from_str(std::string pattern, int options)
{
const char* errptr;
int eoff;
auto* code = pcre_compile(
pattern.c_str(), options | PCRE_UTF8, &errptr, &eoff, nullptr);
if (!code) {
return Err(compile_error{errptr, eoff});
}
return Ok(std::make_shared<pcrepp>(std::move(pattern), code));
}
void
pcrepp::find_captures(const char* pattern)
{
@ -147,7 +163,8 @@ pcrepp::find_captures(const char* pattern)
is_cap = true;
}
if (second == '<'
&& (isalpha(third) || third == '_')) {
&& (isalpha(third) || third == '_'))
{
is_cap = true;
}
if (second == 'P' && third == '<') {

@ -398,6 +398,9 @@ public:
static Result<pcrepp, compile_error> from_str(std::string pattern,
int options = 0);
static Result<std::shared_ptr<pcrepp>, compile_error> shared_from_str(
std::string pattern, int options = 0);
pcrepp(pcre* code) : p_code(code), p_code_extra(pcre_free_study)
{
pcre_refcount(this->p_code, 1);
@ -492,15 +495,9 @@ public:
return *this;
}
const std::string& get_pattern() const
{
return this->p_pattern;
}
const std::string& get_pattern() const { return this->p_pattern; }
bool empty() const
{
return this->p_pattern.empty();
}
bool empty() const { return this->p_pattern.empty(); }
void clear()
{
@ -578,6 +575,13 @@ public:
size_t match_partial(pcre_input& pi) const;
pcre* release() {
auto retval = std::exchange(this->p_code, nullptr);
this->clear();
return retval;
}
// #undef PCRE_STUDY_JIT_COMPILE
#ifdef PCRE_STUDY_JIT_COMPILE
static pcre_jit_stack* jit_stack();

@ -33,24 +33,21 @@
#include "config.h"
static pcre*
static std::shared_ptr<pcrepp>
xpcre_compile(const char* pattern, int options = 0)
{
const char* errptr;
pcre* retval;
int eoff;
auto compile_res = pcrepp::shared_from_str(pattern, options);
if (compile_res.isErr()) {
auto ce = compile_res.unwrapErr();
if ((retval
= pcre_compile(pattern, options | PCRE_UTF8, &errptr, &eoff, nullptr))
== nullptr)
{
fprintf(stderr, "internal error: failed to compile -- %s\n", pattern);
fprintf(stderr, "internal error: %s\n", errptr);
fprintf(stderr, "internal error: %s\n", ce.ce_msg);
exit(1);
}
return retval;
return compile_res.unwrap();
}
void
@ -406,8 +403,7 @@ setup_highlights(highlight_map_t& hm)
= highlighter(xpcre_compile("`(?:\\\\.|[^`])*`"))
.with_role(role_t::VCR_STRING);
hm[{highlight_source_t::INTERNAL, "diffp"}]
= highlighter(xpcre_compile("^\\+.*"))
.with_role(role_t::VCR_DIFF_ADD);
= highlighter(xpcre_compile("^\\+.*")).with_role(role_t::VCR_DIFF_ADD);
hm[{highlight_source_t::INTERNAL, "diffm"}]
= highlighter(xpcre_compile("^(?:--- .*|-$|-[^-].*)"))
.with_role(role_t::VCR_DIFF_DELETE);

@ -175,22 +175,15 @@ textview_curses::reload_config(error_reporter& reporter)
continue;
}
const char* errptr;
pcre* code;
int eoff;
if ((code = pcre_compile(hl_pair.second.hc_regex.c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr))
== nullptr)
{
auto regex = pcrepp::shared_from_str(hl_pair.second.hc_regex);
if (regex.isErr()) {
auto ce = regex.unwrapErr();
reporter(&hl_pair.second.hc_regex,
lnav::console::user_message::error(fmt::format(
FMT_STRING("invalid highlight regex: {} at {}"),
errptr,
eoff)));
ce.ce_msg,
ce.ce_offset)));
continue;
}
@ -235,8 +228,7 @@ textview_curses::reload_config(error_reporter& reporter)
attrs.ta_attrs |= A_UNDERLINE;
}
this->tc_highlights[{highlight_source_t::THEME, hl_pair.first}]
= highlighter(code)
.with_pattern(hl_pair.second.hc_regex)
= highlighter(regex.unwrap())
.with_attrs(attrs)
.with_color(fg, bg);
}
@ -295,7 +287,8 @@ void
textview_curses::grep_end_batch(grep_proc<vis_line_t>& gp)
{
if (this->tc_follow_deadline.tv_sec
&& this->tc_follow_top == this->get_top()) {
&& this->tc_follow_top == this->get_top())
{
struct timeval now;
gettimeofday(&now, nullptr);
@ -391,7 +384,8 @@ textview_curses::handle_mouse(mouse_event& me)
mouse_line = this->get_top();
}
if (me.me_y >= height
&& this->get_top() < this->get_top_for_last_row()) {
&& this->get_top() < this->get_top_for_last_row())
{
this->shift_top(1_vl);
me.me_y = height;
mouse_line = this->get_bottom();
@ -563,13 +557,11 @@ void
textview_curses::execute_search(const std::string& regex_orig)
{
std::string regex = regex_orig;
pcre* code = nullptr;
std::shared_ptr<pcrepp> code;
if ((this->tc_search_child == nullptr)
|| (regex != this->tc_current_search)) {
const char* errptr;
int eoff;
|| (regex != this->tc_current_search))
{
this->match_reset();
this->tc_search_child.reset();
@ -578,26 +570,28 @@ textview_curses::execute_search(const std::string& regex_orig)
log_debug("start search for: '%s'", regex.c_str());
if (regex.empty()) {
} else if ((code = pcre_compile(regex.c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr))
== nullptr)
{
auto errmsg = std::string(errptr);
regex = pcrepp::quote(regex);
log_info("invalid search regex, using quoted: %s", regex.c_str());
if ((code = pcre_compile(regex.c_str(),
PCRE_CASELESS | PCRE_UTF8,
&errptr,
&eoff,
nullptr))
== nullptr)
{
log_error("Unable to compile quoted regex: %s", regex.c_str());
} else {
auto compile_res
= pcrepp::shared_from_str(regex, PCRE_CASELESS | PCRE_UTF8);
if (compile_res.isErr()) {
auto ce = compile_res.unwrapErr();
regex = pcrepp::quote(regex);
log_info("invalid search regex (%s), using quoted: %s",
ce.ce_msg,
regex.c_str());
auto compile_quote_res
= pcrepp::shared_from_str(regex, PCRE_CASELESS | PCRE_UTF8);
if (compile_quote_res.isErr()) {
log_error("Unable to compile quoted regex: %s",
regex.c_str());
} else {
code = compile_quote_res.unwrap();
}
} else {
code = compile_res.unwrap();
}
}
@ -606,11 +600,11 @@ textview_curses::execute_search(const std::string& regex_orig)
hl.with_role(role_t::VCR_SEARCH);
highlight_map_t& hm = this->get_highlights();
auto& hm = this->get_highlights();
hm[{highlight_source_t::PREVIEW, "search"}] = hl;
auto gp = injector::get<std::shared_ptr<grep_proc<vis_line_t>>>(
code, *this);
code->p_code, *this);
gp->set_sink(this);
auto top = this->get_top();
@ -632,7 +626,7 @@ textview_curses::execute_search(const std::string& regex_orig)
this->tc_sub_source->get_grepper() | [this, code](auto pair) {
auto sgp
= injector::get<std::shared_ptr<grep_proc<vis_line_t>>>(
code, *pair.first);
code->p_code, *pair.first);
sgp->set_sink(pair.second);
sgp->queue_request(0_vl);
@ -661,45 +655,16 @@ textview_curses::horiz_shift(vis_line_t start,
for (; start < end; ++start) {
std::vector<attr_line_t> rows(1);
int off;
this->listview_value_for_rows(*this, start, rows);
const std::string& str = rows[0].get_string();
for (off = 0; off < (int) str.size();) {
int rc, matches[128];
rc = pcre_exec(hl.h_code,
hl.h_code_extra,
str.c_str(),
str.size(),
off,
0,
matches,
128);
if (rc > 0) {
struct line_range lr;
if (rc == 2) {
lr.lr_start = matches[2];
lr.lr_end = matches[3];
} else {
lr.lr_start = matches[0];
lr.lr_end = matches[1];
}
if (lr.lr_start < off_start) {
prev_hit = std::max(prev_hit, lr.lr_start);
} else if (lr.lr_start > off_start) {
next_hit = std::min(next_hit, lr.lr_start);
}
if (lr.lr_end > lr.lr_start) {
off = matches[1];
} else {
off += 1;
}
} else {
off = str.size();
const auto& str = rows[0].get_string();
pcre_context_static<60> pc;
pcre_input pi(str);
while (hl.h_regex->match(pc, pi)) {
if (pc.all()->c_begin < off_start) {
prev_hit = std::max(prev_hit, pc.all()->c_begin);
} else if (pc.all()->c_begin > off_start) {
next_hit = std::min(next_hit, pc.all()->c_begin);
}
}
}

@ -176,7 +176,8 @@ view_curses::mvwattrline(WINDOW* window,
exp_offset += offset;
utf_adjustments.emplace_back(lpc, offset);
for (; offset && (lpc + 1) < line.size();
lpc++, offset++) {
lpc++, offset++)
{
expanded_line.push_back(line[lpc + 1]);
}
}
@ -207,7 +208,7 @@ view_curses::mvwattrline(WINDOW* window,
stable_sort(sa.begin(), sa.end());
for (auto iter = sa.begin(); iter != sa.end(); ++iter) {
struct line_range attr_range = iter->sa_range;
auto attr_range = iter->sa_range;
require(attr_range.lr_start >= 0);
require(attr_range.lr_end >= -1);
@ -285,7 +286,7 @@ view_curses::mvwattrline(WINDOW* window,
continue;
}
if (attr_range.lr_end > attr_range.lr_start) {
if (attr_range.lr_start < attr_range.lr_end) {
int awidth = attr_range.length();
nonstd::optional<char> graphic;
@ -349,7 +350,8 @@ view_curses::mvwattrline(WINDOW* window,
row_ch[lpc].attr |= A_ALTCHARSET;
}
if (row_ch[lpc].attr & A_REVERSE
&& attrs.ta_attrs & A_REVERSE) {
&& attrs.ta_attrs & A_REVERSE)
{
clear_rev = true;
}
row_ch[lpc].attr |= attrs.ta_attrs;
@ -950,8 +952,8 @@ view_colors::init_roles(const lnav_theme& lt,
auto level_iter = lt.lt_level_styles.find(level);
if (level_iter == lt.lt_level_styles.end()) {
this->vc_level_attrs[level] = this->to_attrs(
lt, lt.lt_style_text, lt.lt_style_text, reporter);
this->vc_level_attrs[level]
= std::make_pair(text_attrs{}, text_attrs{});
} else {
this->vc_level_attrs[level] = this->to_attrs(
lt, level_iter->second, lt.lt_style_text, reporter);

@ -1 +1 @@
 2009-07-20 22:59:30,221:ERROR:Goodbye, World!
 2009-07-20 22:59:30,221:ERROR:Goodbye, World!

@ -1,6 +1,6 @@
SELECT lower(abc
sql_keyword ------
sql_ident -----
sql_func ---------
sql_ident -----
sql_ident ---
lower: Returns a copy of the given string with all ASCII characters converted to lower case.

@ -1,6 +1,6 @@
SELECT lower(abc)
sql_keyword ------
sql_ident -----
sql_func ---------
sql_ident -----
sql_ident ---
SELECT: Query the database and return zero or more rows of data.

@ -1,9 +1,9 @@
SELECT instr(lower(abc), '123') FROM bar
sql_keyword ------
sql_ident -----
sql_func -----------------------
sql_ident -----
sql_ident -----
sql_func ---------
sql_ident -----
sql_ident ---
sql_comma -
sql_string -----

@ -1,7 +1,7 @@
SELECT foo(bar())
sql_keyword ------
sql_ident ---
sql_func ---------
sql_ident ---
sql_ident ---
sql_func ----
sql_ident ---
SELECT: Query the database and return zero or more rows of data.

@ -1,9 +1,9 @@
SELECT instr(lower(abc), '123')
sql_keyword ------
sql_ident -----
sql_func -----------------------
sql_ident -----
sql_ident -----
sql_func ---------
sql_ident -----
sql_ident ---
sql_comma -
sql_string -----

@ -1,6 +1,6 @@
SELECT lower( abc )
sql_keyword ------
sql_ident -----
sql_func ----------------
sql_ident -----
sql_ident ---
lower: Returns a copy of the given string with all ASCII characters converted to lower case.

@ -1,9 +1,9 @@
SELECT instr(lower(abc), '123')
sql_keyword ------
sql_ident -----
sql_func -----------------------
sql_ident -----
sql_ident -----
sql_func ---------
sql_ident -----
sql_ident ---
sql_comma -
sql_string -----

@ -1,6 +1,6 @@
SELECT foo(bar())
sql_keyword ------
sql_ident ---
sql_func ---------
sql_ident ---
sql_ident ---
sql_func ----
sql_ident ---

@ -4,8 +4,8 @@
sql_keyword ----
sql_ident -------
sql_comma -
sql_ident --------------
sql_func --------------------------------------------------------------------------------
sql_ident --------------
sql_ident --------
sql_comma -
sql_string -------------------------------------------------------

@ -1 +1 @@
2014-10-08 16:56:38,344:WARN:foo bar baz
2014-10-08 16:56:38,344:WARN:foo bar baz

Loading…
Cancel
Save