[readline] highlight pcre syntax in the search prompt

pull/97/head
Timothy Stack 10 years ago
parent c780ddb9af
commit f94015e5b5

@ -19,6 +19,7 @@ lnav v0.6.3:
* Added a 'log_mark' column to the log tables that indicates whether or
not a log message is bookmarked. The field is writable, so you can
bookmark lines using an SQL UPDATE query.
* Added syntax-highlighting when editing SQL queries or search regexes.
Fixes:
* Performance improvements.
@ -27,6 +28,8 @@ lnav v0.6.3:
so that you can write expressions like "log_level > 'warning'".
* The log_time datetime format now matches what is returned by
"datetime('now')" so that collating works correctly.
* If a search string is not valid PCRE syntax, a search is done for
the exact string instead of just returning an error.
* Static-linking has been cleaned up.
* OpenSSL is no longer a requirement.
* Alpha support for Windows/cygwin.

@ -81,6 +81,7 @@ noinst_HEADERS = \
pcrepp.hh \
piper_proc.hh \
readline_curses.hh \
readline_highlighters.hh \
sequence_matcher.hh \
sequence_sink.hh \
session_data.hh \
@ -139,6 +140,7 @@ libdiag_a_SOURCES = \
data_scanner.cc \
data_parser.cc \
readline_curses.cc \
readline_highlighters.cc \
session_data.cc \
sequence_matcher.cc \
shared_buffer.cc \

@ -119,9 +119,9 @@ am_libdiag_a_OBJECTS = ansi_scrubber.$(OBJEXT) bookmarks.$(OBJEXT) \
logfile.$(OBJEXT) logfile_sub_source.$(OBJEXT) \
network-extension-functions.$(OBJEXT) data_scanner.$(OBJEXT) \
data_parser.$(OBJEXT) readline_curses.$(OBJEXT) \
session_data.$(OBJEXT) sequence_matcher.$(OBJEXT) \
shared_buffer.$(OBJEXT) sqlite-extension-func.$(OBJEXT) \
statusview_curses.$(OBJEXT) \
readline_highlighters.$(OBJEXT) session_data.$(OBJEXT) \
sequence_matcher.$(OBJEXT) shared_buffer.$(OBJEXT) \
sqlite-extension-func.$(OBJEXT) statusview_curses.$(OBJEXT) \
string-extension-functions.$(OBJEXT) pcrepp.$(OBJEXT) \
piper_proc.$(OBJEXT) sql_util.$(OBJEXT) \
state-extension-functions.$(OBJEXT) strnatcmp.$(OBJEXT) \
@ -407,6 +407,7 @@ noinst_HEADERS = \
pcrepp.hh \
piper_proc.hh \
readline_curses.hh \
readline_highlighters.hh \
sequence_matcher.hh \
sequence_sink.hh \
session_data.hh \
@ -465,6 +466,7 @@ libdiag_a_SOURCES = \
data_scanner.cc \
data_parser.cc \
readline_curses.cc \
readline_highlighters.cc \
session_data.cc \
sequence_matcher.cc \
shared_buffer.cc \
@ -708,6 +710,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcrepp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/piper_proc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readline_curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readline_highlighters.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sequence_matcher.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_data.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shared_buffer.Po@am__quote@

@ -200,7 +200,7 @@ public:
new_role = view_colors::VCR_STATUS;
sf.set_cylon(false);
}
this->bss_error.clear();
// this->bss_error.clear();
sf.set_role(new_role);
this->update_marks(tc);
};

@ -255,6 +255,10 @@ through the file.
http://perldoc.perl.org/perlre.html
If the search string is not valid PCRE, a search
is done for the exact string instead of doing a
regex search.
:<command> Execute an internal command. The commands are
listed below. History is also supported in this
context as well as tab-completion for commands and

@ -107,6 +107,7 @@
#include "sqlite-extension-func.h"
#include "term_extra.hh"
#include "log_data_helper.hh"
#include "readline_highlighters.hh"
#include "yajlpp.hh"
@ -254,6 +255,8 @@ public:
vis_line_t y,
attr_line_t &value_out)
{
view_colors &vc = view_colors::singleton();
if (!this->fos_active || this->fos_log_helper.ldh_parser.get() == NULL) {
return false;
}
@ -317,10 +320,16 @@ public:
}
if (row < (int)this->fos_log_helper.ldh_line_values.size()) {
str = " " + this->fos_log_helper.ldh_line_values[row].lv_name;
string &name = this->fos_log_helper.ldh_line_values[row].lv_name;
str = " " + name;
int padding = this->fos_key_size - str.length() + 3;
value_out.get_attrs().push_back(string_attr(
line_range(3, 3 + name.length()),
&view_curses::VC_STYLE,
vc.attrs_for_ident(name)));
str.append(padding, ' ');
str += " = " + this->fos_log_helper.ldh_line_values[row].to_string();
}
@ -332,9 +341,15 @@ public:
iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
std::advance(iter, row);
str = " " + this->fos_log_helper.ldh_namer->cn_names[row];
string &name = this->fos_log_helper.ldh_namer->cn_names[row];
str = " " + name;
int padding = this->fos_key_size - str.length() + 3;
value_out.get_attrs().push_back(string_attr(
line_range(3, 3 + name.length()),
&view_curses::VC_STYLE,
vc.attrs_for_ident(name)));
str.append(padding, ' ');
str += " = " + this->fos_log_helper.ldh_parser->get_element_string(
iter->e_sub_elements->back());
@ -1292,6 +1307,7 @@ static void handle_paging_key(int ch)
case 'n':
tc->set_top(bm[&textview_curses::BM_SEARCH].next(tc->get_top()));
lnav_data.ld_bottom_source.grep_error("");
lnav_data.ld_rl_view->set_alt_value(
"Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<")
"' to scroll horizontally to a search result");
@ -1299,6 +1315,7 @@ static void handle_paging_key(int ch)
case 'N':
tc->set_top(bm[&textview_curses::BM_SEARCH].prev(tc->get_top()));
lnav_data.ld_bottom_source.grep_error("");
lnav_data.ld_rl_view->set_alt_value(
"Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<")
"' to scroll horizontally to a search result");
@ -2332,15 +2349,17 @@ int sql_callback(sqlite3_stmt *stmt)
return retval;
}
void execute_search(lnav_view_t view, const std::string &regex)
void execute_search(lnav_view_t view, const std::string &regex_orig)
{
auto_ptr<grep_highlighter> &gc = lnav_data.ld_search_child[view];
textview_curses & tc = lnav_data.ld_views[view];
std::string regex = regex_orig;
if ((gc.get() == NULL) || (regex != lnav_data.ld_last_search[view])) {
const char *errptr;
pcre * code;
pcre * code = NULL;
int eoff;
bool quoted = false;
tc.match_reset();
@ -2360,35 +2379,50 @@ void execute_search(lnav_view_t view, const std::string &regex)
&errptr,
&eoff,
NULL)) == NULL) {
lnav_data.ld_bottom_source.
grep_error("regexp error: " + string(errptr));
lnav_data.ld_bottom_source.grep_error(
"regexp error: " + string(errptr));
quoted = true;
regex = pcrecpp::RE::QuoteMeta(regex);
log_info("invalid search regex, using quoted: %s", regex.c_str());
if ((code = pcre_compile(regex.c_str(),
PCRE_CASELESS,
&errptr,
&eoff,
NULL)) == NULL) {
log_error("Unable to compile quoted regex: %s", regex.c_str());
}
}
else {
textview_curses::highlighter
hl(code, false, view_colors::VCR_SEARCH);
if (code != NULL) {
textview_curses::highlighter hl(
code, false, view_colors::VCR_SEARCH);
if (!quoted) {
lnav_data.ld_bottom_source.grep_error("");
}
lnav_data.ld_bottom_source.set_prompt("");
textview_curses::highlight_map_t &hm = tc.get_highlights();
hm["$search"] = hl;
auto_ptr<grep_proc> gp(new grep_proc(code,
tc,
lnav_data.ld_max_fd,
lnav_data.ld_read_fds));
tc,
lnav_data.ld_max_fd,
lnav_data.ld_read_fds));
gp->queue_request(grep_line_t(tc.get_top()));
if (tc.get_top() > 0) {
gp->queue_request(grep_line_t(0),
grep_line_t(tc.get_top()));
gp->queue_request(grep_line_t(0), grep_line_t(tc.get_top()));
}
gp->start();
gp->set_sink(&tc);
tc.set_follow_search(true);
auto_ptr<grep_highlighter> gh(new grep_highlighter(gp, "$search",
hm));
auto_ptr<grep_highlighter> gh(
new grep_highlighter(gp, "$search", hm));
gc = gh;
}
}
@ -3121,7 +3155,10 @@ static void looper(void)
readline_curses rlc;
int lpc;
search_context.set_append_character(0);
search_context
.set_append_character(0)
.set_highlighter(readline_regex_highlighter);
sql_context.set_highlighter(readline_sqlite_highlighter);
listview_curses::action::broadcaster &sb =
lnav_data.ld_scroll_broadcaster;

@ -31,6 +31,8 @@
#include "config.h"
#include <pcrecpp.h>
#include "pcrepp.hh"
const int JIT_STACK_MIN_SIZE = 32 * 1024;

@ -125,6 +125,16 @@ public:
return (*this)[name.c_str()];
};
capture_t *first_valid(void) const {
for (int lpc = 1; lpc < this->pc_count; lpc++) {
if (this->pc_captures[lpc].is_valid()) {
return &this->pc_captures[lpc];
}
}
return NULL;
};
protected:
pcre_context(capture_t *captures, int max_count)
: pc_pcre(NULL), pc_captures(captures), pc_max_count(max_count), pc_count(0) { };
@ -484,4 +494,5 @@ private:
int p_name_len;
pcre_named_capture *p_named_entries;
};
#endif

@ -55,6 +55,7 @@
#include <string>
#include "pcrepp.hh"
#include "auto_mem.hh"
#include "lnav_log.hh"
#include "ansi_scrubber.hh"
@ -697,4 +698,67 @@ void readline_curses::do_update(void)
this->set_x(0);
}
vt52_curses::do_update();
if (this->rc_active_context != -1) {
readline_context *rc = this->rc_contexts[this->rc_active_context];
readline_highlighter_t hl = rc->get_highlighter();
if (hl != NULL) {
char line[1024];
attr_line_t al;
string &str = al.get_string();
int rc;
rc = mvwinnstr(this->vc_window,
this->get_actual_y(), 0,
line, sizeof(line));
str = string(line, rc);
hl(al, this->vc_x);
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(), 0, al, line_range(0, rc));
wmove(this->vc_window, this->get_actual_y(), this->vc_x);
}
}
#if 0
{
static pcrepp captures("(?<!\\\\)\\((?:\\\\\\)|[^)])+$");
pcre_context_static<30> pc;
pcre_input pi(line, 0, rc);
while (captures.match(pc, pi)) {
pcre_context::capture_t *cap = pc.all();
mvwchgat(this->vc_window, this->get_actual_y(), cap->c_begin, 1, 0,
view_colors::ansi_color_pair_index(COLOR_RED, COLOR_BLACK),
NULL);
}
if (line[this->vc_x] == ')' && line[this->vc_x - 1] != '\\') {
for (int lpc = this->vc_x; lpc > 0; lpc--) {
if (line[lpc] == '(' && line[lpc - 1] != '\\') {
mvwchgat(this->vc_window, this->get_actual_y(), lpc, 1, A_BOLD | A_REVERSE,
view_colors::ansi_color_pair_index(COLOR_CYAN, COLOR_BLACK),
NULL);
break;
}
}
}
if (line[this->vc_x] == '(' && line[this->vc_x - 1] != '\\') {
for (int lpc = this->vc_x; lpc < rc; lpc++) {
if (line[lpc] == ')' && line[lpc - 1] != '\\') {
mvwchgat(this->vc_window, this->get_actual_y(), lpc, 1, A_BOLD | A_REVERSE,
view_colors::ansi_color_pair_index(COLOR_CYAN, COLOR_BLACK),
NULL);
break;
}
}
}
}
#endif
}

@ -52,6 +52,8 @@
#include "auto_fd.hh"
#include "vt52_curses.hh"
typedef void (*readline_highlighter_t)(attr_line_t &line, int x);
/**
* Container for information related to different readline contexts. Since
* lnav uses readline for different inputs, we need a way to keep things like
@ -147,8 +149,19 @@ public:
return this->rc_case_sensitive;
};
void set_append_character(int ch) {
readline_context &set_append_character(int ch) {
this->rc_append_character = ch;
return *this;
};
readline_context &set_highlighter(readline_highlighter_t hl) {
this->rc_highlighter = hl;
return *this;
};
readline_highlighter_t get_highlighter() const {
return this->rc_highlighter;
};
private:
@ -164,6 +177,7 @@ private:
std::map<std::string, std::vector<std::string> > rc_prototypes;
bool rc_case_sensitive;
int rc_append_character;
readline_highlighter_t rc_highlighter;
};
/**

@ -0,0 +1,361 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file readline_highlighters.cc
*/
#include "config.h"
#include "pcrepp.hh"
#include "sql_util.hh"
#include "readline_highlighters.hh"
using namespace std;
static bool check_re_prev(const string &line, int x)
{
bool retval = false;
if ((x > 0 && line[x - 1] != ')' && line[x - 1] != ']') &&
(x < 2 || line[x - 2] != '\\')) {
retval = true;
}
return retval;
}
static void find_matching_bracket(attr_line_t &al, int x, char left, char right)
{
static int matching_bracket_attrs = (
A_BOLD|A_REVERSE|view_colors::ansi_color_pair(COLOR_GREEN, COLOR_BLACK));
static int missing_bracket_attrs = (
A_BOLD|A_REVERSE|view_colors::ansi_color_pair(COLOR_RED, COLOR_BLACK));
const string &line = al.get_string();
if (line[x] == right && line[x - 1] != '\\') {
for (int lpc = x; lpc > 0; lpc--) {
if (line[lpc] == left && line[lpc - 1] != '\\') {
al.get_attrs().push_back(string_attr(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
matching_bracket_attrs));
break;
}
}
}
if (line[x] == left && line[x - 1] != '\\') {
for (int lpc = x; lpc < line.length(); lpc++) {
if (line[lpc] == right && line[lpc - 1] != '\\') {
al.get_attrs().push_back(string_attr(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
matching_bracket_attrs));
break;
}
}
}
int depth = 0, last_left = -1;
for (int lpc = 1; lpc < line.length(); lpc++) {
if (line[lpc] == left && line[lpc - 1] != '\\') {
depth += 1;
last_left = lpc;
}
else if (line[lpc] == right && line[lpc - 1] != '\\') {
if (depth > 0) {
depth -= 1;
}
else {
al.get_attrs().push_back(string_attr(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
missing_bracket_attrs));
}
}
}
if (depth > 0) {
al.get_attrs().push_back(string_attr(
line_range(last_left, last_left + 1),
&view_curses::VC_STYLE,
missing_bracket_attrs));
}
}
void readline_regex_highlighter(attr_line_t &al, int x)
{
static int special_char = (
A_BOLD|view_colors::ansi_color_pair(COLOR_CYAN, COLOR_BLACK));
static int class_attrs = (
A_BOLD|view_colors::ansi_color_pair(COLOR_MAGENTA, COLOR_BLACK));
static int repeated_char_attrs = (
view_colors::ansi_color_pair(COLOR_YELLOW, COLOR_BLACK));
static int bracket_attrs = (
view_colors::ansi_color_pair(COLOR_GREEN, COLOR_BLACK));
static int error_attrs = (
A_BOLD|A_REVERSE|view_colors::ansi_color_pair(COLOR_RED, COLOR_BLACK));
static const char *brackets[] = {
"[]",
"{}",
"()",
NULL
};
string &line = al.get_string();
for (int lpc = 1; lpc < line.length(); lpc++) {
if (line[lpc - 1] != '\\') {
switch (line[lpc]) {
case '^':
case '$':
case '*':
case '+':
case '|':
case '.':
al.get_attrs().push_back(string_attr(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
special_char));
if ((line[lpc] == '*' || line[lpc] == '+') &&
check_re_prev(line, lpc)) {
al.get_attrs().push_back(string_attr(
line_range(lpc - 1, lpc),
&view_curses::VC_STYLE,
repeated_char_attrs));
}
break;
case '?': {
struct line_range lr(lpc, lpc + 1);
if (line[lpc - 1] == '(') {
switch (line[lpc + 1]) {
case ':':
case '!':
case '>':
case '<':
case '#':
lr.lr_end += 1;
break;
}
al.get_attrs().push_back(string_attr(
lr,
&view_curses::VC_STYLE,
bracket_attrs));
}
else {
al.get_attrs().push_back(string_attr(
lr,
&view_curses::VC_STYLE,
special_char));
if (check_re_prev(line, lpc)) {
al.get_attrs().push_back(string_attr(
line_range(lpc - 1, lpc),
&view_curses::VC_STYLE,
repeated_char_attrs));
}
}
break;
}
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
al.get_attrs().push_back(string_attr(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
bracket_attrs));
break;
}
}
if (line[lpc - 1] == '\\') {
switch (line[lpc]) {
case 'A':
case 'b':
case 'w':
case 'W':
case 's':
case 'S':
case 'd':
case 'D':
case 'Z':
case 'z':
al.get_attrs().push_back(string_attr(
line_range(lpc - 1, lpc + 1),
&view_curses::VC_STYLE,
class_attrs));
break;
case ' ':
al.get_attrs().push_back(string_attr(
line_range(lpc - 1, lpc + 1),
&view_curses::VC_STYLE,
error_attrs));
break;
default:
if (isdigit(line[lpc])) {
al.get_attrs().push_back(string_attr(
line_range(lpc - 1, lpc + 1),
&view_curses::VC_STYLE,
special_char));
}
break;
}
}
}
for (int lpc = 0; brackets[lpc]; lpc++) {
find_matching_bracket(al, x, brackets[lpc][0], brackets[lpc][1]);
}
}
static string sql_keyword_re(void)
{
string retval = "(?:";
for (int lpc = 0; sql_keywords[lpc]; lpc++) {
if (lpc > 0) {
retval.append("|");
}
retval.append("\\b");
retval.append(sql_keywords[lpc]);
retval.append("\\b");
}
retval += ")";
return retval;
}
void readline_sqlite_highlighter(attr_line_t &al, int x)
{
static int keyword_attrs = (
A_BOLD|view_colors::ansi_color_pair(COLOR_CYAN, COLOR_BLACK));
static int symbol_attrs = (
view_colors::ansi_color_pair(COLOR_MAGENTA, COLOR_BLACK));
static int string_attrs = (
view_colors::ansi_color_pair(COLOR_GREEN, COLOR_BLACK));
static int error_attrs = (
A_BOLD|A_REVERSE|view_colors::ansi_color_pair(COLOR_RED, COLOR_BLACK));
static string keyword_re_str = sql_keyword_re();
static pcrepp keyword_pcre(keyword_re_str.c_str(), PCRE_CASELESS);
static pcrepp string_literal_pcre("'[^']*('(?:'[^']*')*|$)");
static pcrepp ident_pcre("(\\b[a-z_]\\w*)|\"([^\"]+)\"|\\[([^\\]]+)]", PCRE_CASELESS);
static const char *brackets[] = {
"[]",
"()",
NULL
};
view_colors &vc = view_colors::singleton();
pcre_context_static<30> pc;
pcre_input pi(al.get_string());
string &line = al.get_string();
while (ident_pcre.match(pc, pi)) {
pcre_context::capture_t *cap = pc.first_valid();
int attrs = vc.attrs_for_ident(pi.get_substr_start(cap), cap->length());
struct line_range lr(cap->c_begin, cap->c_end);
if (line[cap->c_end] == '(') {
}
else if (!lr.contains(x) && !lr.contains(x - 1)) {
al.get_attrs().push_back(string_attr(
lr, &view_curses::VC_STYLE, attrs));
}
}
pi.reset(line);
while (keyword_pcre.match(pc, pi)) {
pcre_context::capture_t *cap = pc.all();
al.get_attrs().push_back(string_attr(
line_range(cap->c_begin, cap->c_end),
&view_curses::VC_STYLE,
keyword_attrs));
}
for (int lpc = 0; lpc < line.length(); lpc++) {
switch (line[lpc]) {
case '*':
case '<':
case '>':
case '=':
case '!':
case '-':
case '+':
al.get_attrs().push_back(string_attr(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
symbol_attrs));
break;
}
}
pi.reset(line);
while (string_literal_pcre.match(pc, pi)) {
pcre_context::capture_t *cap = pc.all();
struct line_range lr(cap->c_begin, cap->c_end);
string_attrs_t &sa = al.get_attrs();
string_attrs_t::const_iterator iter;
while ((iter = find_string_attr(sa, lr)) != sa.end()) {
sa.erase(iter);
}
if (line[cap->c_end - 1] != '\'') {
sa.push_back(string_attr(
line_range(cap->c_begin, cap->c_begin + 1),
&view_curses::VC_STYLE,
error_attrs));
lr.lr_start += 1;
}
sa.push_back(string_attr(
lr,
&view_curses::VC_STYLE,
string_attrs));
}
for (int lpc = 0; brackets[lpc]; lpc++) {
find_matching_bracket(al, x, brackets[lpc][0], brackets[lpc][1]);
}
}

@ -0,0 +1,41 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file readline_highlighters.hh
*/
#ifndef __readline_highlighters_hh
#define __readline_highlighters_hh
#include "view_curses.hh"
void readline_regex_highlighter(attr_line_t &line, int x);
void readline_sqlite_highlighter(attr_line_t &line, int x);
#endif

@ -34,6 +34,7 @@
#include <string>
#include <algorithm>
#include "lnav_log.hh"
#include "view_curses.hh"
using namespace std;
@ -76,7 +77,7 @@ void view_curses::mvwattrline(WINDOW *window,
int y,
int x,
attr_line_t &al,
struct line_range &lr,
const struct line_range &lr,
view_colors::role_t base_role)
{
int text_attrs, attrs, line_width;

@ -61,6 +61,8 @@
#include <functional>
#include <algorithm>
#include "lnav_log.hh"
#define KEY_CTRL_G 7
#define KEY_CTRL_R 18
#define KEY_CTRL_W 23
@ -161,6 +163,10 @@ struct line_range {
return this->lr_start <= pos && pos < this->lr_end;
};
bool contains(const struct line_range &other) const {
return this->contains(other.lr_start) && other.lr_end <= this->lr_end;
};
bool operator<(const struct line_range &rhs) const
{
if (this->lr_start < rhs.lr_start) { return true; }
@ -189,12 +195,12 @@ class string_attr_type { };
typedef string_attr_type *string_attr_type_t;
struct string_attr {
string_attr(struct line_range &lr, string_attr_type_t type, void *val)
string_attr(const struct line_range &lr, string_attr_type_t type, void *val)
: sa_range(lr), sa_type(type) {
this->sa_value.sav_ptr = val;
};
string_attr(struct line_range &lr, string_attr_type_t type, int val = 0)
string_attr(const struct line_range &lr, string_attr_type_t type, int val = 0)
: sa_range(lr), sa_type(type) {
this->sa_value.sav_int = val;
};
@ -229,6 +235,21 @@ find_string_attr(const string_attrs_t &sa, string_attr_type_t type)
return iter;
}
inline string_attrs_t::const_iterator
find_string_attr(const string_attrs_t &sa, const struct line_range &lr)
{
string_attrs_t::const_iterator iter;
struct line_range retval;
for (iter = sa.begin(); iter != sa.end(); ++iter) {
if (lr.contains(iter->sa_range)) {
break;
}
}
return iter;
}
inline struct line_range
find_string_attr_range(const string_attrs_t &sa, string_attr_type_t type)
{
@ -490,6 +511,10 @@ public:
return this->vc_role_colors[VCR_HIGHLIGHT_START + (abs(index) % HL_COLOR_COUNT)];
};
int attrs_for_ident(const std::string &str) const {
return this->attrs_for_ident(str.c_str(), str.length());
};
static inline int ansi_color_pair_index(int fg, int bg)
{
return VC_ANSI_START + ((fg * 8) + bg);
@ -569,7 +594,7 @@ public:
int y,
int x,
attr_line_t &al,
struct line_range &lr,
const struct line_range &lr,
view_colors::role_t base_role =
view_colors::VCR_TEXT);
};

Loading…
Cancel
Save