mirror of
https://github.com/tstack/lnav.git
synced 2024-09-11 13:05:51 +03:00
[search-table] improve preview highlighting
This commit is contained in:
parent
3b9bc57ab0
commit
e2e491ec41
8
NEWS
8
NEWS
@ -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;
|
||||
auto regex_res
|
||||
= pcrepp::shared_from_str(new_value, PCRE_CASELESS | PCRE_UTF8);
|
||||
|
||||
if ((code = pcre_compile(new_value.c_str(),
|
||||
PCRE_CASELESS | PCRE_UTF8,
|
||||
&errptr,
|
||||
&eoff,
|
||||
nullptr))
|
||||
== nullptr)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
off = matches[1];
|
||||
} else {
|
||||
off += 1;
|
||||
}
|
||||
this->annotate_capture(al, lr);
|
||||
} else {
|
||||
off = str.size();
|
||||
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);
|
||||
|
||||
ident_attrs.ta_attrs |= role_attrs.ta_attrs;
|
||||
}
|
||||
sa.emplace_back(lr, VC_STYLE.value(ident_attrs));
|
||||
} else {
|
||||
this->annotate_capture(al, lr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
73
src/lnav.cc
73
src/lnav.cc
@ -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;
|
||||
}
|
||||
|
||||
hl.with_attrs(hl_attrs);
|
||||
|
||||
if (ec.ec_dry_run) {
|
||||
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
|
||||
|
||||
lnav_data.ld_preview_status_source.get_description().set_value(
|
||||
"Matches are highlighted in the view");
|
||||
|
||||
retval = "";
|
||||
} else {
|
||||
hm[{highlight_source_t::INTERACTIVE, args[1]}] = hl;
|
||||
|
||||
if (lnav_data.ld_rl_view != nullptr) {
|
||||
lnav_data.ld_rl_view->add_possibility(
|
||||
ln_mode_t::COMMAND, "highlight", args[1]);
|
||||
}
|
||||
|
||||
retval = "info: highlight pattern now active";
|
||||
}
|
||||
tc->reload_data();
|
||||
}
|
||||
highlighter hl(compile_res.unwrap());
|
||||
auto hl_attrs = view_colors::singleton().attrs_for_ident(args[1]);
|
||||
|
||||
if (ec.ec_dry_run) {
|
||||
hl_attrs.ta_attrs |= A_BLINK;
|
||||
}
|
||||
|
||||
hl.with_attrs(hl_attrs);
|
||||
|
||||
if (ec.ec_dry_run) {
|
||||
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
|
||||
|
||||
lnav_data.ld_preview_status_source.get_description().set_value(
|
||||
"Matches are highlighted in the view");
|
||||
|
||||
retval = "";
|
||||
} else {
|
||||
hm[{highlight_source_t::INTERACTIVE, args[1]}] = hl;
|
||||
|
||||
if (lnav_data.ld_rl_view != nullptr) {
|
||||
lnav_data.ld_rl_view->add_possibility(
|
||||
ln_mode_t::COMMAND, "highlight", args[1]);
|
||||
}
|
||||
|
||||
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;
|
||||
auto regex = pcrepp::shared_from_str(hl_pair.second.hc_regex);
|
||||
|
||||
if ((code = pcre_compile(hl_pair.second.hc_regex.c_str(),
|
||||
PCRE_CASELESS | PCRE_UTF8,
|
||||
&errptr,
|
||||
&eoff,
|
||||
nullptr))
|
||||
== nullptr)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
auto compile_res
|
||||
= pcrepp::shared_from_str(regex, PCRE_CASELESS | PCRE_UTF8);
|
||||
|
||||
regex = pcrepp::quote(regex);
|
||||
if (compile_res.isErr()) {
|
||||
auto ce = compile_res.unwrapErr();
|
||||
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());
|
||||
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 @@
|
||||
[7m[31m [0m[31m2009-07-20 22:59:30[0m[7m[31m,221:[0m[7m[31mE[0m[7m[31mRROR[0m[7m[31m:[0m[31mGo[0m[7m[31modbye[0m[31m, World![0m
|
||||
[7m[31m [0m[31m2009-07-20 22:59:30[0m[7m[31m,221:[0m[7m[31mE[0m[7m[31mRROR[0m[7m[31m:[0m[7m[31mGo[0m[7m[31modbye[0m[31m, World![0m
|
||||
|
@ -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 @@
|
||||
[33m2014-10-08 16:56:38,344:[0m[33mWARN[0m[33m:foo bar baz[0m
|
||||
[33m2014-10-08 16:56:38,344:[0m[7m[33mWARN[0m[33m:foo bar baz[0m
|
||||
|
Loading…
Reference in New Issue
Block a user