mirror of https://github.com/tstack/lnav.git
parent
6f451eec35
commit
06d1098211
10
NEWS
10
NEWS
|
@ -1,3 +1,13 @@
|
|||
lnav v0.8.6:
|
||||
Features:
|
||||
* Added support for themes and included a few as well: default,
|
||||
night-owl, solarized-light, and solarized-dark. The theme can
|
||||
be changed using the ':config' command, like so:
|
||||
:config /ui/theme night-owl
|
||||
Consult the online documentation for defining a new theme.
|
||||
|
||||
Fixes:
|
||||
* Added 'notice' log level.
|
||||
|
||||
lnav v0.8.5:
|
||||
Features:
|
||||
|
|
|
@ -49,7 +49,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'lnav'
|
||||
copyright = u'2018, Tim Stack'
|
||||
copyright = u'2019, Tim Stack'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
|
|
@ -149,6 +149,7 @@ set(diag_STAT_SRCS
|
|||
readline_possibilities.hh
|
||||
regexp_vtab.hh
|
||||
relative_time.hh
|
||||
styling.hh
|
||||
ring_span.hh
|
||||
sequence_sink.hh
|
||||
shlex.hh
|
||||
|
|
|
@ -26,8 +26,19 @@ dump-pid-sh.c: $(srcdir)/dump-pid.sh bin2c
|
|||
default-log-formats-json.c: $(srcdir)/default-log-formats.json bin2c
|
||||
$(BIN2C_V)./bin2c -z -c $(srcdir)/default-log-formats.json $@
|
||||
|
||||
default-config-json.c: $(srcdir)/default-config.json bin2c
|
||||
$(BIN2C_V)./bin2c -z -c $(srcdir)/default-config.json $@
|
||||
CONFIG_FILES = \
|
||||
$(srcdir)/root-config.json \
|
||||
$(srcdir)/themes/default.json \
|
||||
$(srcdir)/themes/night-owl.json \
|
||||
$(srcdir)/themes/solarized-dark.json \
|
||||
$(srcdir)/themes/solarized-light.json \
|
||||
$()
|
||||
|
||||
default-config.json: $(CONFIG_FILES)
|
||||
cat $(CONFIG_FILES) > $@
|
||||
|
||||
default-config-json.c: default-config.json bin2c
|
||||
$(BIN2C_V)./bin2c -z -c default-config.json $@
|
||||
|
||||
init-sql.c: bin2c init.sql
|
||||
$(BIN2C_V)./bin2c -z -c $(srcdir)/init.sql $@
|
||||
|
@ -125,13 +136,17 @@ LDADD = \
|
|||
dist_noinst_DATA = \
|
||||
alpha-release.sh \
|
||||
default-log-formats.json \
|
||||
default-config.json \
|
||||
dhclient-summary.lnav \
|
||||
dump-pid.sh \
|
||||
lnav-pop-view.lnav \
|
||||
keymap-default.json \
|
||||
partition-by-boot.lnav \
|
||||
search-for.lnav
|
||||
root-config.json \
|
||||
search-for.lnav \
|
||||
themes/default.json \
|
||||
themes/night-owl.json \
|
||||
themes/solarized-dark.json \
|
||||
themes/solarized-light.json
|
||||
|
||||
noinst_HEADERS = \
|
||||
all_logs_vtab.hh \
|
||||
|
@ -226,6 +241,7 @@ noinst_HEADERS = \
|
|||
shlex.hh \
|
||||
simdutf8check.h \
|
||||
spectro_source.hh \
|
||||
styling.hh \
|
||||
sql_util.hh \
|
||||
sqlite-extension-func.hh \
|
||||
statusview_curses.hh \
|
||||
|
@ -275,6 +291,7 @@ endif
|
|||
|
||||
|
||||
libdiag_a_SOURCES = \
|
||||
ansi-palette.c \
|
||||
ansi_scrubber.cc \
|
||||
bookmarks.cc \
|
||||
bottom_status_source.cc \
|
||||
|
@ -379,6 +396,7 @@ libdiag_a_SOURCES += yajl/yajl.c \
|
|||
endif
|
||||
|
||||
TEXT2C_FILES = \
|
||||
ansi-palette.o \
|
||||
dump-pid-sh.o \
|
||||
help.o \
|
||||
init-sql.o \
|
||||
|
@ -408,7 +426,9 @@ ptimec_SOURCES = ptimec.cc
|
|||
ptimec_LDADD =
|
||||
|
||||
DISTCLEANFILES = \
|
||||
ansi-palette.c \
|
||||
data_scanner_re.cc \
|
||||
default-config.json \
|
||||
default-config-json.c \
|
||||
default-log-formats-json.c \
|
||||
dump-pid-sh.c \
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
[
|
||||
{
|
||||
"colorId": 0,
|
||||
"hexString": "#000000",
|
||||
"rgb": {
|
||||
"r": 0,
|
||||
"g": 0,
|
||||
"b": 0
|
||||
},
|
||||
"hsl": {
|
||||
"h": 0,
|
||||
"s": 0,
|
||||
"l": 0
|
||||
},
|
||||
"name": "Black"
|
||||
},
|
||||
{
|
||||
"colorId": 1,
|
||||
"hexString": "#800000",
|
||||
"rgb": {
|
||||
"r": 128,
|
||||
"g": 0,
|
||||
"b": 0
|
||||
},
|
||||
"hsl": {
|
||||
"h": 0,
|
||||
"s": 100,
|
||||
"l": 25
|
||||
},
|
||||
"name": "Maroon"
|
||||
},
|
||||
{
|
||||
"colorId": 2,
|
||||
"hexString": "#008000",
|
||||
"rgb": {
|
||||
"r": 0,
|
||||
"g": 128,
|
||||
"b": 0
|
||||
},
|
||||
"hsl": {
|
||||
"h": 120,
|
||||
"s": 100,
|
||||
"l": 25
|
||||
},
|
||||
"name": "Green"
|
||||
},
|
||||
{
|
||||
"colorId": 3,
|
||||
"hexString": "#808000",
|
||||
"rgb": {
|
||||
"r": 128,
|
||||
"g": 128,
|
||||
"b": 0
|
||||
},
|
||||
"hsl": {
|
||||
"h": 60,
|
||||
"s": 100,
|
||||
"l": 25
|
||||
},
|
||||
"name": "Olive"
|
||||
},
|
||||
{
|
||||
"colorId": 4,
|
||||
"hexString": "#000080",
|
||||
"rgb": {
|
||||
"r": 0,
|
||||
"g": 0,
|
||||
"b": 128
|
||||
},
|
||||
"hsl": {
|
||||
"h": 240,
|
||||
"s": 100,
|
||||
"l": 25
|
||||
},
|
||||
"name": "Navy"
|
||||
},
|
||||
{
|
||||
"colorId": 5,
|
||||
"hexString": "#800080",
|
||||
"rgb": {
|
||||
"r": 128,
|
||||
"g": 0,
|
||||
"b": 128
|
||||
},
|
||||
"hsl": {
|
||||
"h": 300,
|
||||
"s": 100,
|
||||
"l": 25
|
||||
},
|
||||
"name": "Purple"
|
||||
},
|
||||
{
|
||||
"colorId": 6,
|
||||
"hexString": "#008080",
|
||||
"rgb": {
|
||||
"r": 0,
|
||||
"g": 128,
|
||||
"b": 128
|
||||
},
|
||||
"hsl": {
|
||||
"h": 180,
|
||||
"s": 100,
|
||||
"l": 25
|
||||
},
|
||||
"name": "Teal"
|
||||
},
|
||||
{
|
||||
"colorId": 7,
|
||||
"hexString": "#c0c0c0",
|
||||
"rgb": {
|
||||
"r": 192,
|
||||
"g": 192,
|
||||
"b": 192
|
||||
},
|
||||
"hsl": {
|
||||
"h": 0,
|
||||
"s": 0,
|
||||
"l": 75
|
||||
},
|
||||
"name": "Silver"
|
||||
}
|
||||
]
|
|
@ -58,7 +58,7 @@ struct exec_context {
|
|||
ec_pipe_callback(pipe_callback) {
|
||||
this->ec_local_vars.push(std::map<std::string, std::string>());
|
||||
this->ec_path_stack.emplace_back(".");
|
||||
this->ec_source.emplace("unknown", 0);
|
||||
this->ec_source.emplace("command", 1);
|
||||
this->ec_output_stack.emplace_back(nonstd::nullopt);
|
||||
}
|
||||
|
||||
|
|
|
@ -577,7 +577,7 @@
|
|||
},
|
||||
{
|
||||
"line": "[Tue Apr 04 06:18:29.712806 2017] [mpm_prefork:notice] [pid 17725] AH00163: Apache/2.4.23 (Unix) configured -- resuming normal operations",
|
||||
"level" : "info"
|
||||
"level" : "notice"
|
||||
},
|
||||
{
|
||||
"line": "[Tue Apr 04 06:28:08.605341 2017] [core:error] [pid 17962] [client 127.0.0.1:60444] AH00135: Invalid method in request FOO /",
|
||||
|
@ -585,7 +585,7 @@
|
|||
},
|
||||
{
|
||||
"line": "[Thu Jan 17 02:42:49 2013] [notice] Digest: generating secret for digest authentication ...",
|
||||
"level" : "info"
|
||||
"level" : "notice"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -48,10 +48,11 @@ public:
|
|||
doc_status_source() {
|
||||
this->tss_fields[TSF_TITLE].set_width(14);
|
||||
this->tss_fields[TSF_TITLE].set_left_pad(1);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_VIEW_STATUS);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
view_colors::ansi_color_pair_index(COLOR_BLUE, COLOR_WHITE));
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
|
||||
this->tss_fields[TSF_DESCRIPTION].set_share(1);
|
||||
this->tss_fields[TSF_DESCRIPTION].set_role(view_colors::VCR_STATUS);
|
||||
};
|
||||
|
|
|
@ -45,12 +45,13 @@ static auto HOTKEY_HELP = " "
|
|||
filter_status_source::filter_status_source()
|
||||
{
|
||||
this->tss_fields[TSF_TITLE].set_width(9);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_VIEW_STATUS);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_TITLE].set_value(" Filters ");
|
||||
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
view_colors::ansi_color_pair_index(COLOR_BLUE, COLOR_WHITE));
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
|
||||
|
||||
this->tss_fields[TSF_COUNT].set_min_width(16);
|
||||
this->tss_fields[TSF_COUNT].set_share(1);
|
||||
|
@ -58,7 +59,7 @@ filter_status_source::filter_status_source()
|
|||
|
||||
this->tss_fields[TSF_FILTERED].set_min_width(20);
|
||||
this->tss_fields[TSF_FILTERED].set_share(1);
|
||||
this->tss_fields[TSF_FILTERED].set_role(view_colors::VCR_BOLD_STATUS);
|
||||
this->tss_fields[TSF_FILTERED].set_role(view_colors::VCR_STATUS);
|
||||
|
||||
this->tss_fields[TSF_HELP].right_justify(true);
|
||||
this->tss_fields[TSF_HELP].set_width(20);
|
||||
|
@ -139,12 +140,13 @@ void filter_status_source::update_filtered(text_sub_source *tss)
|
|||
}
|
||||
else {
|
||||
ui_periodic_timer &timer = ui_periodic_timer::singleton();
|
||||
attr_line_t &al = sf.get_value();
|
||||
|
||||
if (tss->get_filtered_count() == this->bss_last_filtered_count) {
|
||||
|
||||
if (timer.fade_diff(this->bss_filter_counter) == 0) {
|
||||
this->tss_fields[TSF_FILTERED].set_role(
|
||||
view_colors::VCR_BOLD_STATUS);
|
||||
view_colors::VCR_STATUS);
|
||||
al.with_attr(string_attr(line_range{0, -1}, &view_curses::VC_STYLE, A_BOLD));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -55,6 +55,7 @@ struct highlighter {
|
|||
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();
|
||||
|
@ -73,6 +74,7 @@ struct highlighter {
|
|||
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();
|
||||
|
@ -115,7 +117,7 @@ struct highlighter {
|
|||
}
|
||||
|
||||
highlighter &with_role(view_colors::role_t role) {
|
||||
this->h_attrs = view_colors::singleton().attrs_for_role(role);
|
||||
this->h_role = role;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
@ -187,7 +189,16 @@ struct highlighter {
|
|||
}
|
||||
|
||||
if (lr.lr_end > lr.lr_start) {
|
||||
sa.emplace_back(lr, &view_curses::VC_STYLE, this->h_attrs);
|
||||
int attrs = 0;
|
||||
|
||||
if (this->h_attrs != -1) {
|
||||
attrs = this->h_attrs;
|
||||
}
|
||||
if (this->h_role != view_colors::VCR_NONE) {
|
||||
attrs |= view_colors::singleton().attrs_for_role(
|
||||
this->h_role);
|
||||
}
|
||||
sa.emplace_back(lr, &view_curses::VC_STYLE, attrs);
|
||||
|
||||
off = matches[1];
|
||||
}
|
||||
|
@ -202,6 +213,7 @@ struct highlighter {
|
|||
};
|
||||
|
||||
std::string h_pattern;
|
||||
view_colors::role_t h_role{view_colors::VCR_NONE};
|
||||
rgb_color h_fg;
|
||||
rgb_color h_bg;
|
||||
pcre *h_code;
|
||||
|
|
|
@ -766,6 +766,7 @@ void handle_paging_key(int ch)
|
|||
}
|
||||
}
|
||||
|
||||
rollback_lnav_config = lnav_config;
|
||||
lnav_data.ld_doc_status_source.set_title("Command Help");
|
||||
add_view_text_possibilities(lnav_data.ld_rl_view, LNM_COMMAND, "filter", tc);
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_COMMAND, "filter", tc->get_last_search());
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "strnatcmp.h"
|
||||
|
||||
struct string_fragment {
|
||||
explicit string_fragment(const char *str, int begin = 0, int end = -1)
|
||||
: sf_string(str), sf_begin(begin), sf_end(end == -1 ? strlen(str) : end) {
|
||||
|
@ -91,6 +93,15 @@ struct string_fragment {
|
|||
return memcmp(this->data(), sf.data(), sf.length()) == 0;
|
||||
};
|
||||
|
||||
bool iequal(const string_fragment &sf) const {
|
||||
if (this->length() != sf.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strnatcasecmp(this->length(), this->data(),
|
||||
sf.length(), sf.data()) == 0;
|
||||
};
|
||||
|
||||
bool operator==(const char *str) const {
|
||||
size_t len = strlen(str);
|
||||
|
||||
|
|
|
@ -145,6 +145,10 @@
|
|||
#include "shlex.hh"
|
||||
#include "log_actions.hh"
|
||||
|
||||
#ifndef SYSCONFDIR
|
||||
#define SYSCONFDIR "/usr/etc"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
static multimap<lnav_flags_t, string> DEFAULT_FILES;
|
||||
|
@ -1855,6 +1859,9 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
lnav_data.ld_debug_log_name = "/dev/null";
|
||||
lnav_data.ld_config_paths.emplace_back("/etc/lnav");
|
||||
lnav_data.ld_config_paths.emplace_back(SYSCONFDIR "/lnav");
|
||||
lnav_data.ld_config_paths.emplace_back(dotlnav_path(""));
|
||||
while ((c = getopt(argc, argv, "hHarRCc:I:iuf:d:nqtw:vVW")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include <pcrecpp.h>
|
||||
#include <yajl/api/yajl_tree.h>
|
||||
|
||||
#include "lnav.hh"
|
||||
#include "lnav_config.hh"
|
||||
|
@ -3208,64 +3209,126 @@ static string com_config(exec_context &ec, string cmdline, vector<string> &args)
|
|||
yajlpp_parse_context ypc("input", lnav_config_handlers);
|
||||
string option = args[1];
|
||||
|
||||
lnav_config = rollback_lnav_config;
|
||||
ypc.set_path(option)
|
||||
.with_obj(lnav_config);
|
||||
ypc.ypc_active_paths.insert(option);
|
||||
ypc.update_callbacks();
|
||||
|
||||
if (ypc.ypc_current_handler != NULL) {
|
||||
if (args.size() == 2) {
|
||||
auto_mem<yajl_gen_t> handle(yajl_gen_free);
|
||||
const json_path_handler_base *jph = ypc.ypc_current_handler;
|
||||
|
||||
handle = yajl_gen_alloc(NULL);
|
||||
if (jph == nullptr && !ypc.ypc_handler_stack.empty()) {
|
||||
jph = ypc.ypc_handler_stack.back();
|
||||
}
|
||||
|
||||
const json_path_handler_base *jph = ypc.ypc_current_handler;
|
||||
yajlpp_gen_context ygc(handle, lnav_config_handlers);
|
||||
ygc.with_context(ypc);
|
||||
if (jph != nullptr) {
|
||||
auto_mem<yajl_gen_t> handle(yajl_gen_free);
|
||||
|
||||
handle = yajl_gen_alloc(nullptr);
|
||||
|
||||
yajlpp_gen_context ygc(handle, lnav_config_handlers);
|
||||
yajl_gen_config(handle, yajl_gen_beautify, 1);
|
||||
ygc.with_context(ypc);
|
||||
|
||||
if (ypc.ypc_current_handler == nullptr) {
|
||||
ygc.gen();
|
||||
} else {
|
||||
jph->gen(ygc, handle);
|
||||
}
|
||||
|
||||
const unsigned char *buffer;
|
||||
size_t len;
|
||||
const unsigned char *buffer;
|
||||
size_t len;
|
||||
|
||||
yajl_gen_get_buf(handle, &buffer, &len);
|
||||
yajl_gen_get_buf(handle, &buffer, &len);
|
||||
|
||||
retval = "info: " + option + " = " + string((char *) buffer, len);
|
||||
string old_value((char *) buffer, len);
|
||||
|
||||
if (args.size() == 2 || ypc.ypc_current_handler == nullptr) {
|
||||
vector<string> errors;
|
||||
|
||||
lnav_config = rollback_lnav_config;
|
||||
reload_config(errors);
|
||||
|
||||
if (ec.ec_dry_run) {
|
||||
attr_line_t al(old_value);
|
||||
|
||||
lnav_data.ld_preview_source
|
||||
.replace_with(al)
|
||||
.set_text_format(detect_text_format(old_value.c_str(),
|
||||
old_value.size()))
|
||||
.truncate_to(10);
|
||||
lnav_data.ld_preview_status_source.get_description()
|
||||
.set_value("Value of option: %s", option.c_str());
|
||||
|
||||
char help_text[1024];
|
||||
|
||||
snprintf(help_text, sizeof(help_text),
|
||||
ANSI_BOLD("%s") " " ANSI_UNDERLINE("%s") " -- %s",
|
||||
jph->jph_path,
|
||||
jph->jph_synopsis,
|
||||
jph->jph_description);
|
||||
|
||||
retval = help_text;
|
||||
} else {
|
||||
retval = "info: " + option + " = " + trim(old_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
string value = remaining_args(cmdline, args, 2);
|
||||
vector<string> errors;
|
||||
bool changed = false;
|
||||
|
||||
if (ec.ec_dry_run) {
|
||||
char help_text[1024];
|
||||
|
||||
snprintf(help_text, sizeof(help_text),
|
||||
ANSI_BOLD("%s %s") " -- %s",
|
||||
jph->jph_path,
|
||||
jph->jph_synopsis,
|
||||
jph->jph_description);
|
||||
|
||||
retval = help_text;
|
||||
}
|
||||
|
||||
if (ypc.ypc_current_handler->jph_callbacks.yajl_string) {
|
||||
if (ec.ec_dry_run) {
|
||||
retval = "";
|
||||
} else {
|
||||
ypc.ypc_callbacks.yajl_string(
|
||||
&ypc, (const unsigned char *) value.c_str(),
|
||||
value.size());
|
||||
retval = "info: changed config option -- " + option;
|
||||
}
|
||||
ypc.ypc_callbacks.yajl_string(
|
||||
&ypc, (const unsigned char *) value.c_str(),
|
||||
value.size());
|
||||
changed = true;
|
||||
}
|
||||
else if (ypc.ypc_current_handler->jph_callbacks.yajl_boolean) {
|
||||
if (ec.ec_dry_run) {
|
||||
retval = "";
|
||||
} else {
|
||||
bool bvalue = false;
|
||||
bool bvalue = false;
|
||||
|
||||
if (strcasecmp(value.c_str(), "true") == 0) {
|
||||
bvalue = true;
|
||||
}
|
||||
ypc.ypc_callbacks.yajl_boolean(&ypc, bvalue);
|
||||
retval = "info: changed config option -- " + option;
|
||||
if (strcasecmp(value.c_str(), "true") == 0) {
|
||||
bvalue = true;
|
||||
}
|
||||
ypc.ypc_callbacks.yajl_boolean(&ypc, bvalue);
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
retval = "error: unhandled type";
|
||||
}
|
||||
|
||||
reload_config();
|
||||
if (changed) {
|
||||
intern_string_t path = intern_string::lookup(option);
|
||||
|
||||
lnav_config_locations[path] = {
|
||||
intern_string::lookup(ec.ec_source.top().first),
|
||||
ec.ec_source.top().second
|
||||
};
|
||||
reload_config(errors);
|
||||
|
||||
if (!errors.empty()) {
|
||||
lnav_config = rollback_lnav_config;
|
||||
retval = "error:" + errors[0];
|
||||
reload_config(errors);
|
||||
} else if (!ec.ec_dry_run) {
|
||||
retval = "info: changed config option -- " + option;
|
||||
rollback_lnav_config = lnav_config;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
retval = "error: unknown configuration option -- " + option;
|
||||
}
|
||||
}
|
||||
|
@ -3293,22 +3356,27 @@ static string com_reset_config(exec_context &ec, string cmdline, vector<string>
|
|||
if (args.empty()) {
|
||||
args.emplace_back("config-option");
|
||||
}
|
||||
else if (!ec.ec_dry_run) {
|
||||
else {
|
||||
yajlpp_parse_context ypc("input", lnav_config_handlers);
|
||||
string option = args[1];
|
||||
|
||||
lnav_config = rollback_lnav_config;
|
||||
ypc.set_path(option)
|
||||
.with_obj(lnav_config);
|
||||
ypc.ypc_active_paths.insert(option);
|
||||
ypc.update_callbacks();
|
||||
|
||||
if (option == "*" || ypc.ypc_current_handler != NULL) {
|
||||
reset_config(option);
|
||||
if (option == "*" || (ypc.ypc_current_handler != NULL ||
|
||||
!ypc.ypc_handler_stack.empty())) {
|
||||
if (!ec.ec_dry_run) {
|
||||
reset_config(option);
|
||||
rollback_lnav_config = lnav_config;
|
||||
}
|
||||
if (option == "*") {
|
||||
retval = "info: reset all options";
|
||||
}
|
||||
else {
|
||||
retval = "info: reset option";
|
||||
retval = "info: reset option -- " + option;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -4348,7 +4416,7 @@ readline_context::command_t STD_COMMANDS[] = {
|
|||
|
||||
help_text(":config")
|
||||
.with_summary("Read or write a configuration option")
|
||||
.with_parameter(help_text("option", "The path to the option to read or write"))
|
||||
.with_parameter({"option", "The path to the option to read or write"})
|
||||
.with_parameter(help_text("value", "The value to write. If not given, the current value is returned")
|
||||
.optional())
|
||||
.with_example({"/ui/clock-format"})
|
||||
|
|
|
@ -41,17 +41,20 @@
|
|||
#include <libgen.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "pcrecpp.h"
|
||||
|
||||
#include "auto_fd.hh"
|
||||
#include "lnav_log.hh"
|
||||
#include "lnav_util.hh"
|
||||
#include "auto_mem.hh"
|
||||
#include "auto_pid.hh"
|
||||
#include "lnav_config.hh"
|
||||
#include "yajlpp.hh"
|
||||
#include "yajlpp_def.hh"
|
||||
#include "shlex.hh"
|
||||
#include "styling.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -63,8 +66,11 @@ extern const char keymap_default_json[];
|
|||
}
|
||||
|
||||
struct _lnav_config lnav_config;
|
||||
struct _lnav_config rollback_lnav_config;
|
||||
static struct _lnav_config lnav_default_config;
|
||||
|
||||
std::map<intern_string_t, source_location> lnav_config_locations;
|
||||
|
||||
lnav_config_listener *lnav_config_listener::LISTENER_LIST;
|
||||
|
||||
string dotlnav_path(const char *sub)
|
||||
|
@ -283,6 +289,19 @@ struct userdata {
|
|||
vector<string> &ud_errors;
|
||||
};
|
||||
|
||||
static void config_error_reporter(const yajlpp_parse_context &ypc,
|
||||
lnav_log_level_t level,
|
||||
const char *msg)
|
||||
{
|
||||
if (level >= LOG_LEVEL_ERROR) {
|
||||
struct userdata *ud = (userdata *) ypc.ypc_userdata;
|
||||
|
||||
ud->ud_errors.emplace_back(msg);
|
||||
} else {
|
||||
fprintf(stderr, "warning:%s\n", msg);
|
||||
}
|
||||
}
|
||||
|
||||
static struct json_path_handler keymap_def_handlers[] = {
|
||||
json_path_handler("(?<key_seq>(x[0-9a-f]{2})+)#")
|
||||
.with_synopsis("<command>")
|
||||
|
@ -290,7 +309,7 @@ static struct json_path_handler keymap_def_handlers[] = {
|
|||
.with_pattern("[:|;].*")
|
||||
.with_path_provider<key_map>([](key_map *km, vector<string> &paths_out) {
|
||||
for (const auto &iter : km->km_seq_to_cmd) {
|
||||
paths_out.push_back(iter.first);
|
||||
paths_out.emplace_back(iter.first);
|
||||
}
|
||||
})
|
||||
.FOR_FIELD(key_map, km_seq_to_cmd),
|
||||
|
@ -308,7 +327,7 @@ static struct json_path_handler keymap_defs_handlers[] = {
|
|||
})
|
||||
.with_path_provider<_lnav_config>([](struct _lnav_config *cfg, vector<string> &paths_out) {
|
||||
for (const auto &iter : cfg->lc_ui_keymaps) {
|
||||
paths_out.push_back(iter.first);
|
||||
paths_out.emplace_back(iter.first);
|
||||
}
|
||||
})
|
||||
.with_children(keymap_def_handlers),
|
||||
|
@ -322,7 +341,7 @@ static struct json_path_handler global_var_handlers[] = {
|
|||
.with_description("A global variable definition")
|
||||
.with_path_provider<_lnav_config>([](struct _lnav_config *cfg, vector<string> &paths_out) {
|
||||
for (const auto &iter : cfg->lc_global_vars) {
|
||||
paths_out.push_back(iter.first);
|
||||
paths_out.emplace_back(iter.first);
|
||||
}
|
||||
})
|
||||
.FOR_FIELD(_lnav_config, lc_global_vars),
|
||||
|
@ -340,32 +359,329 @@ static struct json_path_handler root_config_handlers[] = {
|
|||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler style_config_handlers[] = {
|
||||
json_path_handler("color")
|
||||
.with_synopsis("#hex|color_name")
|
||||
.with_description("Foreground color")
|
||||
.FOR_FIELD(style_config, sc_color),
|
||||
json_path_handler("background-color")
|
||||
.with_synopsis("#hex|color_name")
|
||||
.with_description("Background color")
|
||||
.FOR_FIELD(style_config, sc_background_color),
|
||||
json_path_handler("selected-color")
|
||||
.with_synopsis("#hex|color_name")
|
||||
.with_description("Background color when selected")
|
||||
.FOR_FIELD(style_config, sc_selected_color),
|
||||
json_path_handler("underline")
|
||||
.with_description("Underline")
|
||||
.FOR_FIELD(style_config, sc_underline),
|
||||
json_path_handler("bold")
|
||||
.with_description("Bold")
|
||||
.FOR_FIELD(style_config, sc_bold),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_styles_handlers[] = {
|
||||
json_path_handler("identifier/")
|
||||
.with_description("Styling for identifiers in logs")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_identifier;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("text/")
|
||||
.with_description("Styling for plain text")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_text;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("alt-text/")
|
||||
.with_description("Styling for plain text when alternating")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_alt_text;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("error/")
|
||||
.with_description("Styling for error messages")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_error;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("ok/")
|
||||
.with_description("Styling for success messages")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_ok;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("warning/")
|
||||
.with_description("Styling for warning messages")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_warning;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("hidden/")
|
||||
.with_description("Styling for hidden fields in logs")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_hidden;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("adjusted-time/")
|
||||
.with_description("Styling for timestamps that have been adjusted")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_adjusted_time;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("skewed-time/")
|
||||
.with_description("Styling for timestamps ")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_skewed_time;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("offset-time/")
|
||||
.with_description("Styling for hidden fields")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_offset_time;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("popup/")
|
||||
.with_description("Styling for popup windows")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_popup;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_syntax_styles_handlers[] = {
|
||||
json_path_handler("keyword/")
|
||||
.with_description("Styling for keywords in source files")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_keyword;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("string/")
|
||||
.with_description("Styling for single/double-quoted strings in text")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_string;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("comment/")
|
||||
.with_description("Styling for comments in source files")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_comment;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("variable/")
|
||||
.with_description("Styling for variables in text")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_variable;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("symbol/")
|
||||
.with_description("Styling for symbols in source files")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_symbol;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("number/")
|
||||
.with_description("Styling for numbers in source files")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_number;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("re-special/")
|
||||
.with_description("Styling for special characters in regular expressions")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_re_special;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("re-repeat/")
|
||||
.with_description("Styling for repeats in regular expressions")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_re_repeat;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
|
||||
json_path_handler("diff-delete/")
|
||||
.with_description("Styling for deleted lines in diffs")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_diff_delete;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("diff-add/")
|
||||
.with_description("Styling for added lines in diffs")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_diff_add;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("diff-section/")
|
||||
.with_description("Styling for diffs")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_diff_section;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("file/")
|
||||
.with_description("Styling for file names in source files")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_file;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_status_styles_handlers[] = {
|
||||
json_path_handler("text/")
|
||||
.with_description("Styling for status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("warn/")
|
||||
.with_description("Styling for warnings in status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_warn_status;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("alert/")
|
||||
.with_description("Styling for alerts in status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_alert_status;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("active/")
|
||||
.with_description("Styling for activity in status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_active_status;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("inactive/")
|
||||
.with_description("Styling for inactive status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_inactive_status;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("title/")
|
||||
.with_description("Styling for title sections of status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_title;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
json_path_handler("subtitle/")
|
||||
.with_description("Styling for subtitle sections of status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_subtitle;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_log_level_styles_handlers[] = {
|
||||
json_path_handler("(?<level>trace|debug5|debug4|debug3|debug2|debug|info|stats|notice|warning|error|critical|fatal)"
|
||||
"/")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
style_config &sc = root->lt_level_styles[
|
||||
string2level(ypc.ypc_extractor.get_substr_i("level").get())];
|
||||
|
||||
return ≻
|
||||
})
|
||||
.with_path_provider<lnav_theme>([](struct lnav_theme *cfg, vector<string> &paths_out) {
|
||||
for (int lpc = LEVEL_TRACE; lpc < LEVEL__MAX; lpc++) {
|
||||
paths_out.emplace_back(level_names[lpc]);
|
||||
}
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_vars_handlers[] = {
|
||||
json_path_handler("(?<var_name>\\w+)")
|
||||
.with_synopsis("name")
|
||||
.with_description("A theme variable definition")
|
||||
.with_path_provider<lnav_theme>([](struct lnav_theme *lt, vector<string> &paths_out) {
|
||||
for (const auto &iter : lt->lt_vars) {
|
||||
paths_out.emplace_back(iter.first);
|
||||
}
|
||||
})
|
||||
.FOR_FIELD(lnav_theme, lt_vars),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_def_handlers[] = {
|
||||
json_path_handler("vars/")
|
||||
.with_description("Variables definitions that are used in this theme")
|
||||
.with_children(theme_vars_handlers),
|
||||
|
||||
json_path_handler("styles/")
|
||||
.with_children(theme_styles_handlers),
|
||||
|
||||
json_path_handler("syntax-styles/")
|
||||
.with_children(theme_syntax_styles_handlers),
|
||||
|
||||
json_path_handler("status-styles/")
|
||||
.with_children(theme_status_styles_handlers),
|
||||
|
||||
json_path_handler("log-level-styles/")
|
||||
.with_children(theme_log_level_styles_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler theme_defs_handlers[] = {
|
||||
json_path_handler("(?<theme_name>[^/]+)/")
|
||||
.with_obj_provider<lnav_theme, _lnav_config>([](const yajlpp_provider_context &ypc, _lnav_config *root) {
|
||||
lnav_theme < = root->lc_ui_theme_defs[ypc.ypc_extractor.get_substr("theme_name")];
|
||||
|
||||
return <
|
||||
})
|
||||
.with_path_provider<_lnav_config>([](struct _lnav_config *cfg, vector<string> &paths_out) {
|
||||
for (const auto &iter : cfg->lc_ui_theme_defs) {
|
||||
paths_out.emplace_back(iter.first);
|
||||
}
|
||||
})
|
||||
.with_children(theme_def_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler ui_handlers[] = {
|
||||
json_path_handler("clock-format")
|
||||
.with_synopsis("<format>")
|
||||
.with_synopsis("format")
|
||||
.with_description(
|
||||
"The format for the clock displayed in "
|
||||
"the top-left corner using strftime(3) conversions")
|
||||
.FOR_FIELD(_lnav_config, lc_ui_clock_format),
|
||||
json_path_handler("dim-text")
|
||||
.with_synopsis("<bool>")
|
||||
.with_synopsis("bool")
|
||||
.with_description("Reduce the brightness of text (useful for xterms)")
|
||||
.FOR_FIELD(_lnav_config, lc_ui_dim_text),
|
||||
json_path_handler("default-colors")
|
||||
.with_synopsis("<bool>")
|
||||
.with_synopsis("bool")
|
||||
.with_description("Use default terminal fg/bg colors")
|
||||
.FOR_FIELD(_lnav_config, lc_ui_default_colors),
|
||||
json_path_handler("keymap")
|
||||
.with_synopsis("<name>")
|
||||
.with_synopsis("name")
|
||||
.with_description("The name of the keymap to use")
|
||||
.FOR_FIELD(_lnav_config, lc_ui_keymap),
|
||||
json_path_handler("theme")
|
||||
.with_synopsis("theme_name")
|
||||
.with_description("The name of the theme to use")
|
||||
.FOR_FIELD(_lnav_config, lc_ui_theme),
|
||||
json_path_handler("theme-defs/")
|
||||
.with_description("Theme definitions")
|
||||
.with_children(theme_defs_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
struct json_path_handler lnav_config_handlers[] = {
|
||||
json_path_handler("/ui/")
|
||||
.with_children(ui_handlers),
|
||||
.with_description("User-interface settings")
|
||||
.with_children(ui_handlers),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
@ -376,6 +692,7 @@ static void load_config_from(const string &path, vector<string> &errors)
|
|||
struct userdata ud(errors);
|
||||
auto_fd fd;
|
||||
|
||||
ypc.ypc_locations = &lnav_config_locations;
|
||||
ypc.with_obj(lnav_config);
|
||||
ypc.ypc_userdata = &ud;
|
||||
if ((fd = open(path.c_str(), O_RDONLY)) == -1) {
|
||||
|
@ -396,6 +713,8 @@ static void load_config_from(const string &path, vector<string> &errors)
|
|||
|
||||
handle = yajl_alloc(&ypc.ypc_callbacks, NULL, &ypc);
|
||||
yajl_config(handle, yajl_allow_comments, 1);
|
||||
yajl_config(handle, yajl_allow_multiple_values, 1);
|
||||
ypc.ypc_handle = handle;
|
||||
while (true) {
|
||||
rc = read(fd, buffer, sizeof(buffer));
|
||||
if (rc == 0) {
|
||||
|
@ -407,7 +726,7 @@ static void load_config_from(const string &path, vector<string> &errors)
|
|||
string(strerror(errno)));
|
||||
break;
|
||||
}
|
||||
if (yajl_parse(handle, (const unsigned char *)buffer, rc) != yajl_status_ok) {
|
||||
if (ypc.parse((const unsigned char *)buffer, rc) != yajl_status_ok) {
|
||||
errors.push_back(path +
|
||||
": invalid json -- " +
|
||||
string((char *)yajl_get_error(handle, 1, (unsigned char *)buffer, rc)));
|
||||
|
@ -416,7 +735,7 @@ static void load_config_from(const string &path, vector<string> &errors)
|
|||
offset += rc;
|
||||
}
|
||||
if (rc == 0) {
|
||||
if (yajl_complete_parse(handle) != yajl_status_ok) {
|
||||
if (ypc.complete_parse() != yajl_status_ok) {
|
||||
errors.push_back(path +
|
||||
": invalid json -- " +
|
||||
string((char *)yajl_get_error(handle, 0, NULL, 0)));
|
||||
|
@ -434,16 +753,18 @@ static void load_default_config(yajlpp_parse_context &ypc_builtin,
|
|||
struct userdata ud(errors);
|
||||
|
||||
handle = yajl_alloc(&ypc_builtin.ypc_callbacks, NULL, &ypc_builtin);
|
||||
ypc_builtin.with_handle(handle);
|
||||
ypc_builtin.with_obj(config_obj);
|
||||
ypc_builtin.with_error_reporter(config_error_reporter);
|
||||
ypc_builtin.ypc_userdata = &ud;
|
||||
yajl_config(handle, yajl_allow_comments, 1);
|
||||
if (yajl_parse(handle,
|
||||
(const unsigned char *) config_json,
|
||||
strlen(config_json)) != yajl_status_ok) {
|
||||
yajl_config(handle, yajl_allow_multiple_values, 1);
|
||||
if (ypc_builtin.parse((const unsigned char *) config_json,
|
||||
strlen(config_json)) != yajl_status_ok ||
|
||||
ypc_builtin.complete_parse() != yajl_status_ok) {
|
||||
errors.push_back("builtin: invalid json -- " +
|
||||
string((char *)yajl_get_error(handle, 1, (unsigned char *) config_json, strlen(config_json))));
|
||||
}
|
||||
yajl_complete_parse(handle);
|
||||
}
|
||||
|
||||
void load_config(const vector<string> &extra_paths, vector<string> &errors)
|
||||
|
@ -452,6 +773,7 @@ void load_config(const vector<string> &extra_paths, vector<string> &errors)
|
|||
|
||||
{
|
||||
yajlpp_parse_context ypc_builtin("keymap", root_config_handlers);
|
||||
ypc_builtin.ypc_locations = &lnav_config_locations;
|
||||
load_default_config(ypc_builtin, lnav_config, keymap_default_json,
|
||||
errors);
|
||||
}
|
||||
|
@ -464,16 +786,39 @@ void load_config(const vector<string> &extra_paths, vector<string> &errors)
|
|||
|
||||
{
|
||||
yajlpp_parse_context ypc_builtin("builtin", lnav_config_handlers);
|
||||
ypc_builtin.ypc_locations = &lnav_config_locations;
|
||||
ypc_builtin.reset(lnav_config_handlers);
|
||||
load_default_config(ypc_builtin, lnav_default_config,
|
||||
default_config_json, errors);
|
||||
ypc_builtin.reset(lnav_config_handlers);
|
||||
load_default_config(ypc_builtin, lnav_config, default_config_json,
|
||||
errors);
|
||||
|
||||
for (const auto &extra_path : extra_paths) {
|
||||
string format_path = extra_path + "/formats/*/*.json";
|
||||
static_root_mem<glob_t, globfree> gl;
|
||||
|
||||
if (glob(format_path.c_str(), 0, NULL, gl.inout()) == 0) {
|
||||
for (int lpc = 0; lpc < (int)gl->gl_pathc; lpc++) {
|
||||
const char *base = basename(gl->gl_pathv[lpc]);
|
||||
|
||||
if (!startswith(base, "config.")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string filename(gl->gl_pathv[lpc]);
|
||||
|
||||
load_config_from(filename, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load_config_from(user_config, errors);
|
||||
}
|
||||
|
||||
reload_config();
|
||||
reload_config(errors);
|
||||
|
||||
rollback_lnav_config = lnav_config;
|
||||
}
|
||||
|
||||
void reset_config(const std::string &path)
|
||||
|
@ -487,6 +832,8 @@ void reset_config(const std::string &path)
|
|||
}
|
||||
|
||||
load_default_config(ypc_builtin, lnav_config, default_config_json, errors);
|
||||
|
||||
reload_config(errors);
|
||||
}
|
||||
|
||||
string save_config()
|
||||
|
@ -537,12 +884,42 @@ string save_config()
|
|||
return "info: configuration saved";
|
||||
}
|
||||
|
||||
void reload_config()
|
||||
void reload_config(vector<string> &errors)
|
||||
{
|
||||
lnav_config_listener *curr = lnav_config_listener::LISTENER_LIST;
|
||||
|
||||
while (curr != NULL) {
|
||||
curr->reload_config();
|
||||
auto reporter = [&errors](const void *cfg_value, const std::string &errmsg) {
|
||||
auto cb = [&cfg_value, &errors, &errmsg](
|
||||
const json_path_handler_base &jph,
|
||||
const string &path,
|
||||
void *mem) {
|
||||
if (mem != cfg_value) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto loc_iter = lnav_config_locations.find(intern_string::lookup(path));
|
||||
if (loc_iter == lnav_config_locations.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char msg[1024];
|
||||
|
||||
snprintf(msg, sizeof(msg),
|
||||
"%s:%d:%s",
|
||||
loc_iter->second.sl_source.get(),
|
||||
loc_iter->second.sl_line_number,
|
||||
errmsg.c_str());
|
||||
|
||||
errors.emplace_back(msg);
|
||||
};
|
||||
|
||||
for (int lpc = 0; lnav_config_handlers[lpc].jph_path[0]; lpc++) {
|
||||
lnav_config_handlers[lpc].walk(cb, &lnav_config);
|
||||
}
|
||||
};
|
||||
|
||||
curr->reload_config(reporter);
|
||||
curr = curr->lcl_next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,17 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "yajlpp.hh"
|
||||
#include "log_level.hh"
|
||||
#include "styling.hh"
|
||||
|
||||
class lnav_config_listener {
|
||||
public:
|
||||
using error_reporter = const std::function<void(const void *, const std::string msg)>;
|
||||
|
||||
lnav_config_listener() {
|
||||
this->lcl_next = LISTENER_LIST;
|
||||
LISTENER_LIST = this;
|
||||
|
@ -49,7 +56,7 @@ public:
|
|||
virtual ~lnav_config_listener() {
|
||||
};
|
||||
|
||||
virtual void reload_config() {
|
||||
virtual void reload_config(error_reporter &reporter) {
|
||||
|
||||
};
|
||||
|
||||
|
@ -97,12 +104,16 @@ struct _lnav_config {
|
|||
bool lc_ui_dim_text;
|
||||
bool lc_ui_default_colors;
|
||||
std::string lc_ui_keymap;
|
||||
std::string lc_ui_theme;
|
||||
std::unordered_map<std::string, key_map> lc_ui_keymaps;
|
||||
std::map<std::string, std::string> lc_ui_key_overrides;
|
||||
std::map<std::string, std::string> lc_global_vars;
|
||||
std::map<std::string, lnav_theme> lc_ui_theme_defs;
|
||||
};
|
||||
|
||||
extern struct _lnav_config lnav_config;
|
||||
extern struct _lnav_config rollback_lnav_config;
|
||||
extern std::map<intern_string_t, source_location> lnav_config_locations;
|
||||
|
||||
extern struct json_path_handler lnav_config_handlers[];
|
||||
|
||||
|
@ -111,7 +122,7 @@ void load_config(const std::vector<std::string> &extra_paths,
|
|||
|
||||
void reset_config(const std::string &path);
|
||||
|
||||
void reload_config();
|
||||
void reload_config(std::vector<std::string> &errors);
|
||||
|
||||
std::string save_config();
|
||||
|
||||
|
|
|
@ -52,10 +52,6 @@
|
|||
|
||||
#include "log_format_loader.hh"
|
||||
|
||||
#ifndef SYSCONFDIR
|
||||
#define SYSCONFDIR "/usr/etc"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void extract_metadata(const char *contents, size_t len, struct script_metadata &meta_out);
|
||||
|
@ -552,6 +548,7 @@ static const json_path_handler_base::enum_value_t LEVEL_ENUM[] = {
|
|||
{ level_names[LEVEL_DEBUG], LEVEL_DEBUG },
|
||||
{ level_names[LEVEL_INFO], LEVEL_INFO },
|
||||
{ level_names[LEVEL_STATS], LEVEL_STATS },
|
||||
{ level_names[LEVEL_NOTICE], LEVEL_NOTICE },
|
||||
{ level_names[LEVEL_WARNING], LEVEL_WARNING },
|
||||
{ level_names[LEVEL_ERROR], LEVEL_ERROR },
|
||||
{ level_names[LEVEL_CRITICAL], LEVEL_CRITICAL },
|
||||
|
@ -741,7 +738,7 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
|
|||
"error:unable to open format file '%s' -- %s",
|
||||
filename.c_str(),
|
||||
strerror(errno));
|
||||
errors.push_back(errmsg);
|
||||
errors.emplace_back(errmsg);
|
||||
}
|
||||
else {
|
||||
auto_mem<yajl_handle_t> handle(yajl_free);
|
||||
|
@ -807,6 +804,12 @@ static void load_from_path(const string &path, std::vector<string> &errors)
|
|||
log_info("loading formats from path: %s", format_path.c_str());
|
||||
if (glob(format_path.c_str(), 0, NULL, gl.inout()) == 0) {
|
||||
for (int lpc = 0; lpc < (int)gl->gl_pathc; lpc++) {
|
||||
const char *base = basename(gl->gl_pathv[lpc]);
|
||||
|
||||
if (startswith(base, "config.")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string filename(gl->gl_pathv[lpc]);
|
||||
vector<intern_string_t> format_list;
|
||||
|
||||
|
@ -815,9 +818,9 @@ static void load_from_path(const string &path, std::vector<string> &errors)
|
|||
log_warning("Empty format file: %s", filename.c_str());
|
||||
}
|
||||
else {
|
||||
for (vector<intern_string_t>::iterator iter = format_list.begin();
|
||||
iter != format_list.end();
|
||||
++iter) {
|
||||
for (auto iter = format_list.begin();
|
||||
iter != format_list.end();
|
||||
++iter) {
|
||||
log_info(" found format: %s", iter->get());
|
||||
}
|
||||
}
|
||||
|
@ -854,14 +857,8 @@ void load_formats(const std::vector<std::string> &extra_paths,
|
|||
ypc_builtin.complete_parse();
|
||||
yajl_free(handle);
|
||||
|
||||
load_from_path("/etc/lnav", errors);
|
||||
load_from_path(SYSCONFDIR "/lnav", errors);
|
||||
load_from_path(dotlnav_path(""), errors);
|
||||
|
||||
for (vector<string>::const_iterator path_iter = extra_paths.begin();
|
||||
path_iter != extra_paths.end();
|
||||
++path_iter) {
|
||||
load_from_path(*path_iter, errors);
|
||||
for (const auto & extra_path : extra_paths) {
|
||||
load_from_path(extra_path, errors);
|
||||
}
|
||||
|
||||
if (!errors.empty()) {
|
||||
|
|
|
@ -42,6 +42,7 @@ const char *level_names[LEVEL__MAX + 1] = {
|
|||
"debug",
|
||||
"info",
|
||||
"stats",
|
||||
"notice",
|
||||
"warning",
|
||||
"error",
|
||||
"critical",
|
||||
|
@ -75,10 +76,11 @@ log_level_t abbrev2level(const char *levelstr, ssize_t len)
|
|||
}
|
||||
return LEVEL_DEBUG;
|
||||
case 'I':
|
||||
case 'N': // NOTICE
|
||||
return LEVEL_INFO;
|
||||
case 'S':
|
||||
return LEVEL_STATS;
|
||||
case 'N':
|
||||
return LEVEL_NOTICE;
|
||||
case 'W':
|
||||
return LEVEL_WARNING;
|
||||
case 'E':
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
/**
|
||||
* The logging level identifiers for a line(s).
|
||||
*/
|
||||
typedef enum {
|
||||
enum log_level_t : int {
|
||||
LEVEL_UNKNOWN,
|
||||
LEVEL_TRACE,
|
||||
LEVEL_DEBUG5,
|
||||
|
@ -45,6 +45,7 @@ typedef enum {
|
|||
LEVEL_DEBUG,
|
||||
LEVEL_INFO,
|
||||
LEVEL_STATS,
|
||||
LEVEL_NOTICE,
|
||||
LEVEL_WARNING,
|
||||
LEVEL_ERROR,
|
||||
LEVEL_CRITICAL,
|
||||
|
@ -62,7 +63,7 @@ typedef enum {
|
|||
LEVEL_MARK |
|
||||
LEVEL_CONTINUED
|
||||
)
|
||||
} log_level_t;
|
||||
};
|
||||
|
||||
extern const char *level_names[LEVEL__MAX + 1];
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Generated by re2c 1.1.1 on Tue Oct 16 06:58:50 2018 */
|
||||
/* Generated by re2c 1.1.1 on Thu Apr 18 18:55:08 2019 */
|
||||
#line 1 "../../lnav2/src/log_level_re.re"
|
||||
/**
|
||||
* Copyright (c) 2018, Timothy Stack
|
||||
|
@ -69,7 +69,7 @@ log_level_t string2level(const char *levelstr, ssize_t len, bool exact)
|
|||
const unsigned char *yyt1;
|
||||
loop:
|
||||
|
||||
#line 73 "log_level_re.cc"
|
||||
#line 73 "../../lnav2/src/log_level_re.cc"
|
||||
{
|
||||
YYCTYPE yych;
|
||||
unsigned int yyaccept = 0;
|
||||
|
@ -100,13 +100,13 @@ yy2:
|
|||
YYSKIP ();
|
||||
#line 75 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_UNKNOWN); }
|
||||
#line 104 "log_level_re.cc"
|
||||
#line 104 "../../lnav2/src/log_level_re.cc"
|
||||
yy4:
|
||||
YYSKIP ();
|
||||
yy5:
|
||||
#line 102 "../../lnav2/src/log_level_re.re"
|
||||
{ goto loop; }
|
||||
#line 110 "log_level_re.cc"
|
||||
#line 110 "../../lnav2/src/log_level_re.cc"
|
||||
yy6:
|
||||
yyaccept = 0;
|
||||
YYSKIP ();
|
||||
|
@ -315,7 +315,7 @@ yy28:
|
|||
yy29:
|
||||
#line 98 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_ERROR); }
|
||||
#line 319 "log_level_re.cc"
|
||||
#line 319 "../../lnav2/src/log_level_re.cc"
|
||||
yy30:
|
||||
YYSKIP ();
|
||||
yych = YYPEEK ();
|
||||
|
@ -408,7 +408,7 @@ yy41:
|
|||
YYSKIP ();
|
||||
#line 94 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_INFO); }
|
||||
#line 412 "log_level_re.cc"
|
||||
#line 412 "../../lnav2/src/log_level_re.cc"
|
||||
yy43:
|
||||
YYSKIP ();
|
||||
yych = YYPEEK ();
|
||||
|
@ -454,7 +454,7 @@ yy47:
|
|||
yy48:
|
||||
#line 97 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_WARNING); }
|
||||
#line 458 "log_level_re.cc"
|
||||
#line 458 "../../lnav2/src/log_level_re.cc"
|
||||
yy49:
|
||||
YYSKIP ();
|
||||
yych = YYPEEK ();
|
||||
|
@ -495,7 +495,7 @@ yy51:
|
|||
RET(LEVEL_DEBUG);
|
||||
}
|
||||
}
|
||||
#line 499 "log_level_re.cc"
|
||||
#line 499 "../../lnav2/src/log_level_re.cc"
|
||||
yy52:
|
||||
YYSKIP ();
|
||||
goto yy29;
|
||||
|
@ -503,7 +503,7 @@ yy53:
|
|||
YYSKIP ();
|
||||
#line 101 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_FATAL); }
|
||||
#line 507 "log_level_re.cc"
|
||||
#line 507 "../../lnav2/src/log_level_re.cc"
|
||||
yy55:
|
||||
YYSKIP ();
|
||||
yych = YYPEEK ();
|
||||
|
@ -524,12 +524,12 @@ yy57:
|
|||
YYSKIP ();
|
||||
#line 96 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_STATS); }
|
||||
#line 528 "log_level_re.cc"
|
||||
#line 528 "../../lnav2/src/log_level_re.cc"
|
||||
yy59:
|
||||
YYSKIP ();
|
||||
#line 76 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_TRACE); }
|
||||
#line 533 "log_level_re.cc"
|
||||
#line 533 "../../lnav2/src/log_level_re.cc"
|
||||
yy61:
|
||||
YYSKIP ();
|
||||
yych = YYPEEK ();
|
||||
|
@ -553,13 +553,13 @@ yy63:
|
|||
yy64:
|
||||
YYSKIP ();
|
||||
#line 95 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_INFO); }
|
||||
#line 558 "log_level_re.cc"
|
||||
{ RET(LEVEL_NOTICE); }
|
||||
#line 558 "../../lnav2/src/log_level_re.cc"
|
||||
yy66:
|
||||
YYSKIP ();
|
||||
#line 100 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_CRITICAL); }
|
||||
#line 563 "log_level_re.cc"
|
||||
#line 563 "../../lnav2/src/log_level_re.cc"
|
||||
yy68:
|
||||
YYSKIP ();
|
||||
yych = YYPEEK ();
|
||||
|
@ -583,7 +583,7 @@ yy71:
|
|||
YYSKIP ();
|
||||
#line 99 "../../lnav2/src/log_level_re.re"
|
||||
{ RET(LEVEL_CRITICAL); }
|
||||
#line 587 "log_level_re.cc"
|
||||
#line 587 "../../lnav2/src/log_level_re.cc"
|
||||
}
|
||||
#line 104 "../../lnav2/src/log_level_re.re"
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ log_level_t string2level(const char *levelstr, ssize_t len, bool exact)
|
|||
}
|
||||
}
|
||||
'info' { RET(LEVEL_INFO); }
|
||||
'notice' { RET(LEVEL_INFO); }
|
||||
'notice' { RET(LEVEL_NOTICE); }
|
||||
'stats' { RET(LEVEL_STATS); }
|
||||
'warn'|'warning' { RET(LEVEL_WARNING); }
|
||||
'err'|'error' { RET(LEVEL_ERROR); }
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "logfile_sub_source.hh"
|
||||
#include "command_executor.hh"
|
||||
#include "ansi_scrubber.hh"
|
||||
#include "lnav_config.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -326,21 +327,8 @@ void logfile_sub_source::text_attrs_for_line(textview_curses &lv,
|
|||
int attrs = 0;
|
||||
|
||||
value_out = this->lss_token_attrs;
|
||||
switch (this->lss_token_line->get_msg_level()) {
|
||||
case LEVEL_FATAL:
|
||||
case LEVEL_CRITICAL:
|
||||
case LEVEL_ERROR:
|
||||
attrs = vc.attrs_for_role(view_colors::VCR_ERROR);
|
||||
break;
|
||||
|
||||
case LEVEL_WARNING:
|
||||
attrs = vc.attrs_for_role(view_colors::VCR_WARNING);
|
||||
break;
|
||||
|
||||
default:
|
||||
attrs = vc.attrs_for_role(view_colors::VCR_TEXT);
|
||||
break;
|
||||
}
|
||||
attrs = vc.vc_level_attrs[this->lss_token_line->get_msg_level()].first;
|
||||
|
||||
if ((row + 1) < (int)this->lss_filtered_index.size()) {
|
||||
next_line = this->find_line(this->at(vis_line_t(row + 1)));
|
||||
|
|
|
@ -221,12 +221,16 @@ public:
|
|||
pi_length(s.length()),
|
||||
pi_string(s.data()) {};
|
||||
|
||||
pcre_input(const string_fragment &&) = delete;
|
||||
|
||||
pcre_input(const std::string &str, size_t off = 0)
|
||||
: pi_offset(off),
|
||||
pi_next_offset(off),
|
||||
pi_length(str.length()),
|
||||
pi_string(str.c_str()) {};
|
||||
|
||||
pcre_input(const std::string &&, size_t off = 0) = delete;
|
||||
|
||||
const char *get_string() const { return this->pi_string; };
|
||||
|
||||
const char *get_substr_start(pcre_context::const_iterator iter) const
|
||||
|
|
|
@ -50,15 +50,16 @@ public:
|
|||
static const char TOGGLE_MSG[] = "Press CTRL+P to show/hide";
|
||||
|
||||
this->tss_fields[TSF_TITLE].set_width(14);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_VIEW_STATUS);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_TITLE].set_value(" Preview Data ");
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
view_colors::ansi_color_pair_index(COLOR_BLUE, COLOR_WHITE));
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
|
||||
this->tss_fields[TSF_DESCRIPTION].set_share(1);
|
||||
this->tss_fields[TSF_TOGGLE].set_width(strlen(TOGGLE_MSG) + 1);
|
||||
this->tss_fields[TSF_TOGGLE].set_value(TOGGLE_MSG);
|
||||
this->tss_fields[TSF_TOGGLE].set_left_pad(1);
|
||||
this->tss_fields[TSF_TOGGLE].right_justify(true);
|
||||
};
|
||||
|
||||
size_t statusview_fields(void) { return TSF__MAX; };
|
||||
|
|
|
@ -507,6 +507,10 @@ void rl_abort(void *dummy, readline_curses *rc)
|
|||
tc->get_highlights().erase("$preview");
|
||||
tc->get_highlights().erase("$bodypreview");
|
||||
|
||||
vector<string> errors;
|
||||
lnav_config = rollback_lnav_config;
|
||||
reload_config(errors);
|
||||
|
||||
lnav_data.ld_bottom_source.grep_error("");
|
||||
switch (lnav_data.ld_mode) {
|
||||
case LNM_SEARCH:
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "pcrepp.hh"
|
||||
#include "shlex.hh"
|
||||
#include "auto_mem.hh"
|
||||
#include "lnav_log.hh"
|
||||
#include "lnav_util.hh"
|
||||
|
@ -312,31 +313,50 @@ char **readline_context::attempted_completion(const char *text,
|
|||
else {
|
||||
char * space;
|
||||
string cmd;
|
||||
|
||||
rl_completion_append_character = 0;
|
||||
space = strchr(rl_line_buffer, ' ');
|
||||
if (space == nullptr) {
|
||||
space = rl_line_buffer + strlen(rl_line_buffer);
|
||||
vector<string> prefix;
|
||||
int point = rl_point;
|
||||
while (point > 0 && rl_line_buffer[point] != ' ') {
|
||||
point -= 1;
|
||||
}
|
||||
cmd = string(rl_line_buffer, space - rl_line_buffer);
|
||||
shlex lexer(rl_line_buffer, point);
|
||||
map<string, string> scope;
|
||||
|
||||
auto iter = loaded_context->rc_prototypes.find(cmd);
|
||||
arg_possibilities = nullptr;
|
||||
rl_completion_append_character = 0;
|
||||
if (lexer.split(prefix, scope)) {
|
||||
string prefix2 = join(prefix.begin(), prefix.end(), "\x1f");
|
||||
auto prefix_iter = loaded_context->rc_prefixes.find(prefix2);
|
||||
|
||||
if (iter == loaded_context->rc_prototypes.end()) {
|
||||
if (loaded_context->rc_possibilities.find("*") !=
|
||||
loaded_context->rc_possibilities.end()) {
|
||||
arg_possibilities = &loaded_context->rc_possibilities["*"];
|
||||
rl_completion_append_character = loaded_context->rc_append_character;
|
||||
if (prefix_iter != loaded_context->rc_prefixes.end()) {
|
||||
arg_possibilities = &(loaded_context->rc_possibilities[prefix_iter->second]);
|
||||
}
|
||||
} else {
|
||||
vector<string> &proto = loaded_context->rc_prototypes[cmd];
|
||||
}
|
||||
|
||||
if (proto.empty()) {
|
||||
arg_possibilities = NULL;
|
||||
} else if (proto[0] == "filename") {
|
||||
return NULL; /* XXX */
|
||||
if (arg_possibilities == nullptr) {
|
||||
space = strchr(rl_line_buffer, ' ');
|
||||
if (space == nullptr) {
|
||||
space = rl_line_buffer + strlen(rl_line_buffer);
|
||||
}
|
||||
cmd = string(rl_line_buffer, space - rl_line_buffer);
|
||||
|
||||
auto iter = loaded_context->rc_prototypes.find(cmd);
|
||||
|
||||
if (iter == loaded_context->rc_prototypes.end()) {
|
||||
if (loaded_context->rc_possibilities.find("*") !=
|
||||
loaded_context->rc_possibilities.end()) {
|
||||
arg_possibilities = &loaded_context->rc_possibilities["*"];
|
||||
rl_completion_append_character = loaded_context->rc_append_character;
|
||||
}
|
||||
} else {
|
||||
arg_possibilities = &(loaded_context->rc_possibilities[proto[0]]);
|
||||
vector<string> &proto = loaded_context->rc_prototypes[cmd];
|
||||
|
||||
if (proto.empty()) {
|
||||
arg_possibilities = nullptr;
|
||||
} else if (proto[0] == "filename") {
|
||||
return nullptr; /* XXX */
|
||||
} else {
|
||||
arg_possibilities = &(loaded_context->rc_possibilities[proto[0]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -596,7 +616,7 @@ void readline_curses::start()
|
|||
}
|
||||
else {
|
||||
int context, prompt_start = 0;
|
||||
char type[32];
|
||||
char type[1024];
|
||||
|
||||
msg[rc] = '\0';
|
||||
if (sscanf(msg, "i:%d:%n", &rl_point, &prompt_start) == 1) {
|
||||
|
@ -640,6 +660,16 @@ void readline_curses::start()
|
|||
_exit(1);
|
||||
}
|
||||
}
|
||||
else if (sscanf(msg,
|
||||
"apre:%d:%1023[^\x1d]\x1d%n",
|
||||
&context,
|
||||
type,
|
||||
&prompt_start) == 2) {
|
||||
require(this->rc_contexts[context] != NULL);
|
||||
|
||||
this->rc_contexts[context]->rc_prefixes[string(type)] =
|
||||
string(&msg[prompt_start]);
|
||||
}
|
||||
else if (sscanf(msg,
|
||||
"ap:%d:%31[^:]:%n",
|
||||
&context,
|
||||
|
@ -662,6 +692,9 @@ void readline_curses::start()
|
|||
rem_possibility(string(type),
|
||||
string(&msg[prompt_start]));
|
||||
}
|
||||
else if (sscanf(msg, "cpre:%d", &context) == 1) {
|
||||
this->rc_contexts[context]->rc_prefixes.clear();
|
||||
}
|
||||
else if (sscanf(msg, "cp:%d:%s", &context, type)) {
|
||||
this->rc_contexts[context]->clear_possibilities(type);
|
||||
}
|
||||
|
@ -955,6 +988,37 @@ void readline_curses::abort()
|
|||
}
|
||||
}
|
||||
|
||||
void readline_curses::add_prefix(int context,
|
||||
const vector<string> &prefix,
|
||||
const string &value)
|
||||
{
|
||||
char buffer[1024];
|
||||
string prefix_wire = join(prefix.begin(), prefix.end(), "\x1f");
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"apre:%d:%s\x1d%s",
|
||||
context,
|
||||
prefix_wire.c_str(),
|
||||
value.c_str());
|
||||
if (sendstring(this->rc_command_pipe[RCF_MASTER],
|
||||
buffer,
|
||||
strlen(buffer) + 1) == -1) {
|
||||
perror("add_possibility: write failed");
|
||||
}
|
||||
}
|
||||
|
||||
void readline_curses::clear_prefixes(int context)
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "cpre:%d", context);
|
||||
if (sendstring(this->rc_command_pipe[RCF_MASTER],
|
||||
buffer,
|
||||
strlen(buffer) + 1) == -1) {
|
||||
perror("add_possibility: write failed");
|
||||
}
|
||||
}
|
||||
|
||||
void readline_curses::add_possibility(int context,
|
||||
const string &type,
|
||||
const string &value)
|
||||
|
@ -1015,9 +1079,11 @@ void readline_curses::do_update()
|
|||
int alt_start = -1;
|
||||
struct line_range lr(0, 0);
|
||||
attr_line_t al, alt_al;
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
wmove(this->vc_window, this->get_actual_y(), this->vc_left);
|
||||
wclrtoeol(this->vc_window);
|
||||
wattron(this->vc_window, vc.attrs_for_role(view_colors::VCR_TEXT));
|
||||
whline(this->vc_window, ' ', this->vc_width);
|
||||
|
||||
if (time(nullptr) > this->rc_value_expiration) {
|
||||
this->rc_value.clear();
|
||||
|
@ -1070,7 +1136,7 @@ void readline_curses::do_update()
|
|||
|
||||
std::string readline_curses::get_match_string() const
|
||||
{
|
||||
auto len = this->vc_x - this->rc_match_start;
|
||||
auto len = ::min((size_t) this->vc_x, this->rc_line_buffer.size()) - this->rc_match_start;
|
||||
auto context = this->get_active_context();
|
||||
|
||||
if (context->get_append_character() != 0 &&
|
||||
|
|
|
@ -209,6 +209,8 @@ public:
|
|||
};
|
||||
|
||||
static int command_complete(int, int);
|
||||
|
||||
std::map<std::string, std::string> rc_prefixes;
|
||||
private:
|
||||
static char **attempted_completion(const char *text, int start, int end);
|
||||
static char *completion_generator(const char *text, int state);
|
||||
|
@ -349,6 +351,12 @@ public:
|
|||
|
||||
void line_ready(const char *line);
|
||||
|
||||
void add_prefix(int context,
|
||||
const std::vector<std::string> &prefix,
|
||||
const std::string &value);
|
||||
|
||||
void clear_prefixes(int context);
|
||||
|
||||
void add_possibility(int context,
|
||||
const std::string &type,
|
||||
const std::string &value);
|
||||
|
|
|
@ -359,6 +359,8 @@ void readline_command_highlighter(attr_line_t &al, int x)
|
|||
R"(^:(filter-in|filter-out|delete-filter|enable-filter|disable-filter|highlight|clear-highlight|create-search-table\s+[^\s]+\s+))");
|
||||
static const pcrepp SH_PREFIXES("^:(eval|open|append-to|write-to|write-csv-to|write-json-to)");
|
||||
static const pcrepp IDENT_PREFIXES("^:(tag|untag|delete-tags)");
|
||||
static const pcrepp COLOR_PREFIXES("^:(config)");
|
||||
static const pcrepp COLOR_RE("(#(?:[a-fA-F0-9]{3}|[a-fA-F0-9]{6}))");
|
||||
|
||||
view_colors &vc = view_colors::singleton();
|
||||
int keyword_attrs = (
|
||||
|
@ -370,7 +372,6 @@ void readline_command_highlighter(attr_line_t &al, int x)
|
|||
size_t ws_index;
|
||||
|
||||
|
||||
|
||||
ws_index = line.find(' ');
|
||||
string command = line.substr(0, ws_index);
|
||||
if (ws_index != string::npos) {
|
||||
|
@ -387,6 +388,28 @@ void readline_command_highlighter(attr_line_t &al, int x)
|
|||
readline_shlex_highlighter(al, x);
|
||||
}
|
||||
pi.reset(line);
|
||||
if (COLOR_PREFIXES.match(pc, pi)) {
|
||||
pi.reset(line);
|
||||
if (COLOR_RE.match(pc, pi)) {
|
||||
pcre_context::capture_t *cap = pc[0];
|
||||
string hash_color = pi.get_substr(cap);
|
||||
string errmsg;
|
||||
rgb_color rgb_fg, rgb_bg;
|
||||
attr_t color_hint_attrs = vc.attrs_for_role(view_colors::VCR_COLOR_HINT);
|
||||
int pnum = PAIR_NUMBER(color_hint_attrs);
|
||||
|
||||
if (rgb_color::from_str(hash_color, rgb_bg, errmsg)) {
|
||||
pnum -= 1;
|
||||
vc.ensure_color_pair(pnum, rgb_fg, rgb_bg);
|
||||
|
||||
al.get_attrs().emplace_back(
|
||||
line_range{cap->c_begin, cap->c_begin + 1},
|
||||
&view_curses::VC_ROLE,
|
||||
view_colors::VCR_COLOR_HINT);
|
||||
}
|
||||
}
|
||||
}
|
||||
pi.reset(line);
|
||||
if (IDENT_PREFIXES.match(pc, pi) && ws_index != string::npos) {
|
||||
size_t start = ws_index, last;
|
||||
|
||||
|
|
|
@ -281,14 +281,35 @@ void add_mark_possibilities()
|
|||
void add_config_possibilities()
|
||||
{
|
||||
readline_curses *rc = lnav_data.ld_rl_view;
|
||||
vector<string> config_options;
|
||||
set<string> visited;
|
||||
auto cb = [rc, &visited](const json_path_handler_base &jph,
|
||||
const string &path,
|
||||
void *mem) {
|
||||
if (jph.jph_children) {
|
||||
for (auto named_iter = jph.jph_regex.named_begin();
|
||||
named_iter != jph.jph_regex.named_end();
|
||||
++named_iter) {
|
||||
if (visited.count(named_iter->pnc_name) == 0) {
|
||||
rc->clear_possibilities(LNM_COMMAND, named_iter->pnc_name);
|
||||
visited.insert(named_iter->pnc_name);
|
||||
}
|
||||
|
||||
rc->add_possibility(LNM_COMMAND, named_iter->pnc_name, path);
|
||||
}
|
||||
} else {
|
||||
rc->add_possibility(LNM_COMMAND, "config-option", path);
|
||||
if (jph.jph_synopsis) {
|
||||
rc->add_prefix(LNM_COMMAND,
|
||||
vector<string>{"config", path},
|
||||
jph.jph_synopsis);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rc->clear_possibilities(LNM_COMMAND, "config-option");
|
||||
|
||||
for (int lpc = 0; lnav_config_handlers[lpc].jph_path[0]; lpc++) {
|
||||
lnav_config_handlers[lpc].possibilities(config_options, &lnav_config);
|
||||
lnav_config_handlers[lpc].walk(cb, &lnav_config);
|
||||
}
|
||||
rc->add_possibility(LNM_COMMAND, "config-option", config_options);
|
||||
}
|
||||
|
||||
void add_tag_possibilities()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"ui" : {
|
||||
"clock-format": "%a %b %d %H:%M:%S %Z",
|
||||
"keymap": "default"
|
||||
"keymap": "default",
|
||||
"theme": "default"
|
||||
}
|
||||
}
|
|
@ -1280,7 +1280,6 @@ void save_session()
|
|||
continue;
|
||||
}
|
||||
|
||||
filter_stack::iterator filter_iter;
|
||||
filter_stack &fs = tss->get_filters();
|
||||
|
||||
view_map.gen("commands");
|
||||
|
|
|
@ -280,7 +280,7 @@ public:
|
|||
}
|
||||
while (this->tokenize(cap, token)) {
|
||||
if (start_new) {
|
||||
result.push_back("");
|
||||
result.emplace_back("");
|
||||
start_new = false;
|
||||
}
|
||||
result.back().append(&this->s_str[last_index], cap.c_begin - last_index);
|
||||
|
|
|
@ -49,9 +49,10 @@ void status_field::set_value(std::string value)
|
|||
|
||||
if (this->sf_cylon) {
|
||||
struct line_range lr(this->sf_cylon_pos, this->sf_width);
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE,
|
||||
view_colors::ansi_color_pair(COLOR_WHITE, COLOR_GREEN) | A_BOLD));
|
||||
sa.emplace_back(lr, &view_curses::VC_STYLE,
|
||||
vc.attrs_for_role(view_colors::VCR_ACTIVE_STATUS) | A_REVERSE);
|
||||
|
||||
this->sf_cylon_pos += 1;
|
||||
if (this->sf_cylon_pos > this->sf_width) {
|
||||
|
@ -98,6 +99,8 @@ void statusview_curses::do_update()
|
|||
for (auto &sa : val.get_attrs()) {
|
||||
if (sa.sa_type == &view_curses::VC_STYLE) {
|
||||
sa.sa_value.sav_int &= ~(A_REVERSE | A_COLOR);
|
||||
} else if (sa.sa_type == &view_curses::VC_ROLE) {
|
||||
sa.sa_value.sav_int = view_colors::VCR_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,17 +76,16 @@ public:
|
|||
va_end(args);
|
||||
};
|
||||
|
||||
void set_stitch_value(int color_pair)
|
||||
void set_stitch_value(view_colors::role_t left, view_colors::role_t right)
|
||||
{
|
||||
string_attrs_t &sa = this->sf_value.get_attrs();
|
||||
struct line_range lr(0, 1);
|
||||
|
||||
this->sf_value.get_string() = "::";
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE,
|
||||
A_REVERSE | COLOR_PAIR(color_pair)));
|
||||
sa.emplace_back(lr, &view_curses::VC_ROLE, left);
|
||||
lr.lr_start = 1;
|
||||
lr.lr_end = 2;
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE, COLOR_PAIR(color_pair)));
|
||||
sa.emplace_back(lr, &view_curses::VC_ROLE, right);
|
||||
};
|
||||
|
||||
void set_left_pad(size_t val) { this->sf_left_pad = val; };
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef styling_hh
|
||||
#define styling_hh
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "log_level.hh"
|
||||
#include "intern_string.hh"
|
||||
|
||||
struct rgb_color {
|
||||
static bool from_str(const string_fragment &color,
|
||||
rgb_color &rgb_out,
|
||||
std::string &errmsg);
|
||||
|
||||
explicit rgb_color(short r = -1, short g = -1, short b = -1)
|
||||
: rc_r(r), rc_g(g), rc_b(b) {
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return this->rc_r == -1 && this->rc_g == -1 && this->rc_b == -1;
|
||||
}
|
||||
|
||||
short rc_r;
|
||||
short rc_g;
|
||||
short rc_b;
|
||||
};
|
||||
|
||||
struct style_config {
|
||||
std::string sc_color;
|
||||
std::string sc_background_color;
|
||||
std::string sc_selected_color;
|
||||
bool sc_underline{false};
|
||||
bool sc_bold{false};
|
||||
};
|
||||
|
||||
struct lnav_theme {
|
||||
std::map<std::string, std::string> lt_vars;
|
||||
style_config lt_style_identifier;
|
||||
style_config lt_style_text;
|
||||
style_config lt_style_alt_text;
|
||||
style_config lt_style_ok;
|
||||
style_config lt_style_error;
|
||||
style_config lt_style_warning;
|
||||
style_config lt_style_popup;
|
||||
style_config lt_style_hidden;
|
||||
style_config lt_style_adjusted_time;
|
||||
style_config lt_style_skewed_time;
|
||||
style_config lt_style_offset_time;
|
||||
style_config lt_style_status_title;
|
||||
style_config lt_style_status_subtitle;
|
||||
style_config lt_style_keyword;
|
||||
style_config lt_style_string;
|
||||
style_config lt_style_comment;
|
||||
style_config lt_style_variable;
|
||||
style_config lt_style_symbol;
|
||||
style_config lt_style_number;
|
||||
style_config lt_style_re_special;
|
||||
style_config lt_style_re_repeat;
|
||||
style_config lt_style_diff_delete;
|
||||
style_config lt_style_diff_add;
|
||||
style_config lt_style_diff_section;
|
||||
style_config lt_style_low_threshold;
|
||||
style_config lt_style_med_threshold;
|
||||
style_config lt_style_high_threshold;
|
||||
style_config lt_style_status;
|
||||
style_config lt_style_warn_status;
|
||||
style_config lt_style_alert_status;
|
||||
style_config lt_style_active_status;
|
||||
style_config lt_style_inactive_status;
|
||||
style_config lt_style_file;
|
||||
std::map<log_level_t, style_config> lt_level_styles;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -322,10 +322,10 @@ void setup_highlights(textview_curses::highlight_map_t &hm)
|
|||
.with_text_format(TF_SQL)
|
||||
.with_role(view_colors::VCR_KEYWORD);
|
||||
|
||||
hm["$srcfile"] = static_highlighter(
|
||||
hm["$srcfile"] = highlighter(xpcre_compile(
|
||||
"[\\w\\-_]+\\."
|
||||
"(?:java|a|o|so|c|cc|cpp|cxx|h|hh|hpp|hxx|py|pyc|rb):"
|
||||
"\\d+")
|
||||
"\\d+"))
|
||||
.with_role(view_colors::VCR_FILE);
|
||||
hm["$xml"] = static_highlighter("<(/?[^ >=]+)[^>]*>");
|
||||
hm["$stringd"] = highlighter(xpcre_compile(
|
||||
|
@ -358,10 +358,18 @@ void setup_highlights(textview_curses::highlight_map_t &hm)
|
|||
"@(?:author|deprecated|exception|file|param|return|see|since|throws|todo|version)");
|
||||
hm["$var"] = highlighter(xpcre_compile(
|
||||
"(?:"
|
||||
"(?:var\\s+)?([\\-\\w]+)\\s*=|"
|
||||
"(?:var\\s+)?([\\-\\w]+)\\s*[!=+\\-*/|&^]?=|"
|
||||
"(?<!\\$)\\$(\\w+)|"
|
||||
"(?<!\\$)\\$\\((\\w+)\\)|"
|
||||
"(?<!\\$)\\$\\{(\\w+)\\}"
|
||||
")"))
|
||||
.with_role(view_colors::VCR_VARIABLE);
|
||||
hm["$sym"] = highlighter(xpcre_compile(
|
||||
"\\b[A-Z_][A-Z0-9_]+\\b"))
|
||||
.with_text_format(TF_C_LIKE)
|
||||
.with_role(view_colors::VCR_SYMBOL);
|
||||
hm["$num"] = highlighter(xpcre_compile(
|
||||
"\\b-?(?:\\d+|0x[a-zA-Z0-9]+)\\b"))
|
||||
.with_text_format(TF_C_LIKE)
|
||||
.with_role(view_colors::VCR_NUMBER);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
{
|
||||
"ui": {
|
||||
"theme-defs": {
|
||||
"default": {
|
||||
"styles": {
|
||||
"text": {
|
||||
"color": "Silver"
|
||||
},
|
||||
"alt-text": {
|
||||
"color": "Silver",
|
||||
"bold": true
|
||||
},
|
||||
"ok": {
|
||||
"color": "Green",
|
||||
"bold": true
|
||||
},
|
||||
"error": {
|
||||
"color": "Red",
|
||||
"bold": true
|
||||
},
|
||||
"warning": {
|
||||
"color": "Yellow",
|
||||
"bold": true
|
||||
},
|
||||
"hidden": {
|
||||
"color": "Yellow",
|
||||
"bold": true
|
||||
},
|
||||
"adjusted-time": {
|
||||
"color": "Maroon"
|
||||
},
|
||||
"skewed-time": {
|
||||
"color": "Yellow"
|
||||
},
|
||||
"offset-time": {
|
||||
"color": "Teal"
|
||||
},
|
||||
"popup": {
|
||||
"color": "Silver",
|
||||
"background-color": "Teal"
|
||||
}
|
||||
},
|
||||
"syntax-styles": {
|
||||
"keyword": {
|
||||
"color": "Blue"
|
||||
},
|
||||
"string": {
|
||||
"color": "Green",
|
||||
"bold": true
|
||||
},
|
||||
"comment": {
|
||||
"color": "Green"
|
||||
},
|
||||
"variable": {
|
||||
"color": "Teal"
|
||||
},
|
||||
"symbol": {
|
||||
"color": "Blue"
|
||||
},
|
||||
"re-special": {
|
||||
"color": "Teal"
|
||||
},
|
||||
"re-repeat": {
|
||||
"color": "Yellow"
|
||||
},
|
||||
"diff-delete": {
|
||||
"color": "Red"
|
||||
},
|
||||
"diff-add": {
|
||||
"color": "Green"
|
||||
},
|
||||
"diff-section": {
|
||||
"color": "Maroon"
|
||||
},
|
||||
"file": {
|
||||
"color": "Blue"
|
||||
}
|
||||
},
|
||||
"status-styles": {
|
||||
"title": {
|
||||
"color": "Silver",
|
||||
"background-color": "Blue",
|
||||
"bold": true
|
||||
},
|
||||
"subtitle": {
|
||||
"color": "Black",
|
||||
"background-color": "Teal"
|
||||
},
|
||||
"text": {
|
||||
"color": "Black",
|
||||
"background-color": "Silver"
|
||||
},
|
||||
"warn": {
|
||||
"color": "Yellow",
|
||||
"background-color": "Silver"
|
||||
},
|
||||
"alert": {
|
||||
"color": "Red",
|
||||
"background-color": "Silver"
|
||||
},
|
||||
"active": {
|
||||
"color": "Green",
|
||||
"background-color": "Silver"
|
||||
},
|
||||
"inactive": {
|
||||
"color": "Silver",
|
||||
"background-color": "Grey37"
|
||||
}
|
||||
},
|
||||
"log-level-styles": {
|
||||
"warning": {
|
||||
"color": "Yellow"
|
||||
},
|
||||
"error": {
|
||||
"color": "Red"
|
||||
},
|
||||
"critical": {
|
||||
"color": "Red"
|
||||
},
|
||||
"fatal": {
|
||||
"color": "Red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
{
|
||||
"ui": {
|
||||
"theme-defs": {
|
||||
"night-owl": {
|
||||
"vars": {
|
||||
"red": "#ff6868",
|
||||
"green": "#007f00",
|
||||
"yellow": "#cdcd00",
|
||||
"blue": "#5394ec",
|
||||
"magenta": "#ff70ff",
|
||||
"cyan": "#33cccc"
|
||||
},
|
||||
"styles": {
|
||||
"identifier": {
|
||||
"background-color": "#011627"
|
||||
},
|
||||
"text": {
|
||||
"color": "#d6deeb",
|
||||
"background-color": "#011627"
|
||||
},
|
||||
"alt-text": {
|
||||
"color": "#d6deeb",
|
||||
"background-color": "#011627",
|
||||
"bold": true
|
||||
},
|
||||
"ok": {
|
||||
"color": "$green",
|
||||
"bold": true
|
||||
},
|
||||
"error": {
|
||||
"color": "#ef5350",
|
||||
"bold": true
|
||||
},
|
||||
"warning": {
|
||||
"color": "#b39554",
|
||||
"bold": true
|
||||
},
|
||||
"hidden": {
|
||||
"color": "$yellow",
|
||||
"bold": true
|
||||
},
|
||||
"adjusted-time": {
|
||||
"color": "$magenta"
|
||||
},
|
||||
"skewed-time": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"offset-time": {
|
||||
"color": "$cyan"
|
||||
},
|
||||
"popup": {
|
||||
"color": "$base00",
|
||||
"background-color": "$base3"
|
||||
}
|
||||
},
|
||||
"syntax-styles": {
|
||||
"keyword": {
|
||||
"color": "#c792ea"
|
||||
},
|
||||
"string": {
|
||||
"color": "#ecc48d",
|
||||
"bold": true
|
||||
},
|
||||
"comment": {
|
||||
"color": "#676e95"
|
||||
},
|
||||
"variable": {
|
||||
"color": "#addb67"
|
||||
},
|
||||
"symbol": {
|
||||
"color": "#82aaff"
|
||||
},
|
||||
"number": {
|
||||
"color": "#f78c6c"
|
||||
},
|
||||
"re-special": {
|
||||
"color": "$cyan"
|
||||
},
|
||||
"re-repeat": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"diff-delete": {
|
||||
"color": "#b03435"
|
||||
},
|
||||
"diff-add": {
|
||||
"color": "#264b33"
|
||||
},
|
||||
"diff-section": {
|
||||
"color": "$magenta"
|
||||
},
|
||||
"file": {
|
||||
"color": "#82aaff"
|
||||
}
|
||||
},
|
||||
"status-styles": {
|
||||
"title": {
|
||||
"color": "#f8f0f0",
|
||||
"background-color": "#2d5a80",
|
||||
"bold": true
|
||||
},
|
||||
"subtitle": {
|
||||
"color": "#f8f8f0",
|
||||
"background-color": "#005f5f"
|
||||
},
|
||||
"text": {
|
||||
"color": "#f8f8f0",
|
||||
"background-color": "#162d40"
|
||||
},
|
||||
"warn": {
|
||||
"color": "#b39554",
|
||||
"background-color": "#162d40"
|
||||
},
|
||||
"alert": {
|
||||
"color": "#ef5350",
|
||||
"background-color": "#162d40"
|
||||
},
|
||||
"active": {
|
||||
"color": "#264b33",
|
||||
"background-color": "#162d40"
|
||||
},
|
||||
"inactive": {
|
||||
"color": "#f0f0f0",
|
||||
"background-color": "#0F1F2B"
|
||||
}
|
||||
},
|
||||
"log-level-styles": {
|
||||
"warning": {
|
||||
"color": "#b39554"
|
||||
},
|
||||
"error": {
|
||||
"color": "#ef5350"
|
||||
},
|
||||
"critical": {
|
||||
"color": "#ef5350"
|
||||
},
|
||||
"fatal": {
|
||||
"color": "#ef5350"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"ui": {
|
||||
"theme-defs": {
|
||||
"solarized-dark": {
|
||||
"vars": {
|
||||
"base03": "#002b36",
|
||||
"base02": "#073642",
|
||||
"base01": "#586e75",
|
||||
"base00": "#657b83",
|
||||
"base0": "#839496",
|
||||
"base1": "#93a1a1",
|
||||
"base2": "#eee8d5",
|
||||
"base3": "#fdf6e3",
|
||||
"black": "#002b36",
|
||||
"yellow": "#b58900",
|
||||
"orange": "#cb4b16",
|
||||
"red": "#dc322f",
|
||||
"magenta": "#d33682",
|
||||
"violet": "#6c71c4",
|
||||
"blue": "#268bd2",
|
||||
"cyan": "#2aa198",
|
||||
"green": "#859900"
|
||||
},
|
||||
"styles": {
|
||||
"identifier": {
|
||||
"background-color": "$base03"
|
||||
},
|
||||
"text": {
|
||||
"color": "$base0",
|
||||
"background-color": "$base03"
|
||||
},
|
||||
"alt-text": {
|
||||
"color": "$base0",
|
||||
"background-color": "$base03",
|
||||
"bold": true
|
||||
},
|
||||
"ok": {
|
||||
"color": "$green",
|
||||
"bold": true
|
||||
},
|
||||
"error": {
|
||||
"color": "$red",
|
||||
"bold": true
|
||||
},
|
||||
"warning": {
|
||||
"color": "$yellow",
|
||||
"bold": true
|
||||
},
|
||||
"hidden": {
|
||||
"color": "$yellow",
|
||||
"bold": true
|
||||
},
|
||||
"adjusted-time": {
|
||||
"color": "$magenta"
|
||||
},
|
||||
"skewed-time": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"offset-time": {
|
||||
"color": "$cyan"
|
||||
},
|
||||
"popup": {
|
||||
"color": "$base00",
|
||||
"background-color": "$base3"
|
||||
}
|
||||
},
|
||||
"syntax-styles": {
|
||||
"keyword": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"string": {
|
||||
"color": "$cyan",
|
||||
"bold": true
|
||||
},
|
||||
"comment": {
|
||||
"color": "$base01"
|
||||
},
|
||||
"variable": {
|
||||
"color": "$blue"
|
||||
},
|
||||
"symbol": {
|
||||
"color": "$blue"
|
||||
},
|
||||
"re-special": {
|
||||
"color": "$cyan"
|
||||
},
|
||||
"re-repeat": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"diff-delete": {
|
||||
"color": "$red"
|
||||
},
|
||||
"diff-add": {
|
||||
"color": "$green"
|
||||
},
|
||||
"diff-section": {
|
||||
"color": "$magenta"
|
||||
},
|
||||
"file": {
|
||||
"color": "$blue"
|
||||
}
|
||||
},
|
||||
"status-styles": {
|
||||
"title": {
|
||||
"color": "$base02",
|
||||
"background-color": "$blue",
|
||||
"bold": true
|
||||
},
|
||||
"subtitle": {
|
||||
"color": "$base00",
|
||||
"background-color": "$cyan",
|
||||
"bold": true
|
||||
},
|
||||
"text": {
|
||||
"color": "$base2",
|
||||
"background-color": "$base01"
|
||||
},
|
||||
"warn": {
|
||||
"color": "$yellow",
|
||||
"background-color": "$base01"
|
||||
},
|
||||
"alert": {
|
||||
"color": "$red",
|
||||
"background-color": "$base01"
|
||||
},
|
||||
"active": {
|
||||
"color": "$green",
|
||||
"background-color": "$base01"
|
||||
},
|
||||
"inactive": {
|
||||
"color": "$base1",
|
||||
"background-color": "$base02"
|
||||
}
|
||||
},
|
||||
"log-level-styles": {
|
||||
"warning": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"error": {
|
||||
"color": "$red"
|
||||
},
|
||||
"critical": {
|
||||
"color": "$red"
|
||||
},
|
||||
"fatal": {
|
||||
"color": "$red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"ui": {
|
||||
"theme-defs": {
|
||||
"solarized-light": {
|
||||
"vars": {
|
||||
"base03": "#002b36",
|
||||
"base02": "#073642",
|
||||
"base01": "#586e75",
|
||||
"base00": "#657b83",
|
||||
"base0": "#839496",
|
||||
"base1": "#93a1a1",
|
||||
"base2": "#eee8d5",
|
||||
"base3": "#fdf6e3",
|
||||
"black": "#002b36",
|
||||
"yellow": "#b58900",
|
||||
"orange": "#cb4b16",
|
||||
"red": "#dc322f",
|
||||
"magenta": "#d33682",
|
||||
"violet": "#6c71c4",
|
||||
"blue": "#268bd2",
|
||||
"cyan": "#2aa198",
|
||||
"green": "#859900"
|
||||
},
|
||||
"styles": {
|
||||
"identifier": {
|
||||
"background-color": "$base3"
|
||||
},
|
||||
"text": {
|
||||
"color": "$base00",
|
||||
"background-color": "$base3"
|
||||
},
|
||||
"alt-text": {
|
||||
"color": "$base00",
|
||||
"background-color": "$base3",
|
||||
"bold": true
|
||||
},
|
||||
"ok": {
|
||||
"color": "$green",
|
||||
"bold": true
|
||||
},
|
||||
"error": {
|
||||
"color": "$red",
|
||||
"bold": true
|
||||
},
|
||||
"warning": {
|
||||
"color": "$yellow",
|
||||
"bold": true
|
||||
},
|
||||
"hidden": {
|
||||
"color": "$yellow",
|
||||
"bold": true
|
||||
},
|
||||
"adjusted-time": {
|
||||
"color": "$magenta"
|
||||
},
|
||||
"skewed-time": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"offset-time": {
|
||||
"color": "$cyan"
|
||||
},
|
||||
"popup": {
|
||||
"color": "$base00",
|
||||
"background-color": "$base3"
|
||||
}
|
||||
},
|
||||
"syntax-styles": {
|
||||
"keyword": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"string": {
|
||||
"color": "$cyan",
|
||||
"bold": true
|
||||
},
|
||||
"comment": {
|
||||
"color": "$base1"
|
||||
},
|
||||
"variable": {
|
||||
"color": "$blue"
|
||||
},
|
||||
"symbol": {
|
||||
"color": "$blue"
|
||||
},
|
||||
"re-special": {
|
||||
"color": "$cyan"
|
||||
},
|
||||
"re-repeat": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"diff-delete": {
|
||||
"color": "$red"
|
||||
},
|
||||
"diff-add": {
|
||||
"color": "$green"
|
||||
},
|
||||
"diff-section": {
|
||||
"color": "$magenta"
|
||||
},
|
||||
"file": {
|
||||
"color": "$blue"
|
||||
}
|
||||
},
|
||||
"status-styles": {
|
||||
"title": {
|
||||
"color": "$base2",
|
||||
"background-color": "$base0",
|
||||
"bold": true
|
||||
},
|
||||
"subtitle": {
|
||||
"color": "$base2",
|
||||
"background-color": "$base01",
|
||||
"bold": true
|
||||
},
|
||||
"text": {
|
||||
"color": "$base2",
|
||||
"background-color": "$base03"
|
||||
},
|
||||
"warn": {
|
||||
"color": "$yellow",
|
||||
"background-color": "$base03"
|
||||
},
|
||||
"alert": {
|
||||
"color": "$red",
|
||||
"background-color": "$base03"
|
||||
},
|
||||
"active": {
|
||||
"color": "$green",
|
||||
"background-color": "$base03"
|
||||
},
|
||||
"inactive": {
|
||||
"color": "$base1",
|
||||
"background-color": "$base03"
|
||||
}
|
||||
},
|
||||
"log-level-styles": {
|
||||
"warning": {
|
||||
"color": "$yellow"
|
||||
},
|
||||
"error": {
|
||||
"color": "$red"
|
||||
},
|
||||
"critical": {
|
||||
"color": "$red"
|
||||
},
|
||||
"fatal": {
|
||||
"color": "$red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,17 +63,20 @@ public:
|
|||
this->tss_fields[TSF_PARTITION_NAME].set_width(34);
|
||||
this->tss_fields[TSF_PARTITION_NAME].set_left_pad(1);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_width(8);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_role(view_colors::VCR_VIEW_STATUS);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_VIEW_NAME].right_justify(true);
|
||||
this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_stitch_value(
|
||||
view_colors::ansi_color_pair_index(COLOR_CYAN, COLOR_BLUE));
|
||||
view_colors::VCR_STATUS_STITCH_SUB_TO_TITLE,
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_SUB);
|
||||
this->tss_fields[TSF_STITCH_VIEW_FORMAT].right_justify(true);
|
||||
this->tss_fields[TSF_FORMAT].set_width(20);
|
||||
this->tss_fields[TSF_FORMAT].set_role(view_colors::VCR_STATUS_SUBTITLE);
|
||||
this->tss_fields[TSF_FORMAT].right_justify(true);
|
||||
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_stitch_value(
|
||||
view_colors::ansi_color_pair_index(COLOR_WHITE, COLOR_CYAN));
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_SUB,
|
||||
view_colors::VCR_STATUS_STITCH_SUB_TO_NORMAL);
|
||||
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].right_justify(true);
|
||||
this->tss_fields[TSF_FILENAME].set_min_width(35); /* XXX */
|
||||
this->tss_fields[TSF_FILENAME].set_share(1);
|
||||
|
@ -165,9 +168,6 @@ public:
|
|||
sf_filename.set_value(lc->get_data_source()->listview_source_name(*lc));
|
||||
}
|
||||
}
|
||||
sf_format.get_value().get_attrs().push_back(
|
||||
string_attr(lr, &view_curses::VC_STYLE,
|
||||
A_REVERSE | view_colors::ansi_color_pair(COLOR_CYAN, COLOR_BLACK)));
|
||||
};
|
||||
|
||||
void update_view_name(listview_curses *lc) {
|
||||
|
|
|
@ -43,17 +43,18 @@
|
|||
#include "yajlpp_def.hh"
|
||||
#include "xterm-palette.hh"
|
||||
#include "attr_line.hh"
|
||||
#include "shlex.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct xterm_color {
|
||||
struct term_color {
|
||||
short xc_id;
|
||||
string xc_name;
|
||||
rgb_color xc_color;
|
||||
lab_color xc_lab_color;
|
||||
};
|
||||
|
||||
static struct json_path_handler xterm_color_rgb_handler[] = {
|
||||
static struct json_path_handler term_color_rgb_handler[] = {
|
||||
json_path_handler("r")
|
||||
.FOR_FIELD(rgb_color, rc_r),
|
||||
json_path_handler("g")
|
||||
|
@ -64,46 +65,47 @@ static struct json_path_handler xterm_color_rgb_handler[] = {
|
|||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler xterm_color_handler[] = {
|
||||
static struct json_path_handler term_color_handler[] = {
|
||||
json_path_handler("colorId")
|
||||
.FOR_FIELD(xterm_color, xc_id),
|
||||
.FOR_FIELD(term_color, xc_id),
|
||||
json_path_handler("name")
|
||||
.FOR_FIELD(xterm_color, xc_name),
|
||||
.FOR_FIELD(term_color, xc_name),
|
||||
json_path_handler("rgb/")
|
||||
.with_obj_provider<rgb_color, xterm_color>([](const auto &pc, xterm_color *xc) { return &xc->xc_color; })
|
||||
.with_children(xterm_color_rgb_handler),
|
||||
.with_obj_provider<rgb_color, term_color>([](const auto &pc, term_color *xc) { return &xc->xc_color; })
|
||||
.with_children(term_color_rgb_handler),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct json_path_handler root_color_handler[] = {
|
||||
json_path_handler("#/")
|
||||
.with_obj_provider<xterm_color, vector<xterm_color>>(
|
||||
[](const yajlpp_provider_context &ypc, vector<xterm_color> *palette) {
|
||||
.with_obj_provider<term_color, vector<term_color>>(
|
||||
[](const yajlpp_provider_context &ypc, vector<term_color> *palette) {
|
||||
palette->resize(ypc.ypc_index + 1);
|
||||
return &((*palette)[ypc.ypc_index]);
|
||||
})
|
||||
.with_children(xterm_color_handler),
|
||||
.with_children(term_color_handler),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static struct _xterm_colors {
|
||||
_xterm_colors() {
|
||||
yajlpp_parse_context ypc_xterm("xterm-palette.json", root_color_handler);
|
||||
struct term_color_palette {
|
||||
term_color_palette(const unsigned char *json) {
|
||||
yajlpp_parse_context ypc_xterm("palette.json", root_color_handler);
|
||||
yajl_handle handle;
|
||||
|
||||
handle = yajl_alloc(&ypc_xterm.ypc_callbacks, nullptr, &ypc_xterm);
|
||||
ypc_xterm
|
||||
.with_ignore_unused(true)
|
||||
.with_obj(this->xc_palette)
|
||||
.with_obj(this->tc_palette)
|
||||
.with_handle(handle);
|
||||
ypc_xterm.parse((const unsigned char *) xterm_palette_json,
|
||||
strlen(xterm_palette_json));
|
||||
ypc_xterm.complete_parse();
|
||||
yajl_status st = ypc_xterm.parse(json, strlen((const char *) json));
|
||||
ensure(st == yajl_status_ok);
|
||||
st = ypc_xterm.complete_parse();
|
||||
ensure(st == yajl_status_ok);
|
||||
yajl_free(handle);
|
||||
|
||||
for (auto &xc : this->xc_palette) {
|
||||
for (auto &xc : this->tc_palette) {
|
||||
xc.xc_lab_color = lab_color(xc.xc_color);
|
||||
}
|
||||
};
|
||||
|
@ -112,7 +114,7 @@ static struct _xterm_colors {
|
|||
double lowest = 1000.0;
|
||||
short lowest_id = -1;
|
||||
|
||||
for (auto &xc : this->xc_palette) {
|
||||
for (auto &xc : this->tc_palette) {
|
||||
double xc_delta = xc.xc_lab_color.deltaE(to_match);
|
||||
|
||||
if (lowest_id == -1) {
|
||||
|
@ -130,13 +132,22 @@ static struct _xterm_colors {
|
|||
return lowest_id;
|
||||
};
|
||||
|
||||
vector<xterm_color> xc_palette;
|
||||
} xterm_colors;
|
||||
vector<term_color> tc_palette;
|
||||
};
|
||||
|
||||
term_color_palette xterm_colors(xterm_palette_json);
|
||||
term_color_palette ansi_colors(ansi_palette_json);
|
||||
|
||||
term_color_palette *ACTIVE_PALETTE = &ansi_colors;
|
||||
|
||||
bool rgb_color::from_str(const string_fragment &color,
|
||||
rgb_color &rgb_out,
|
||||
std::string &errmsg)
|
||||
{
|
||||
if (color.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (color[0] == '#') {
|
||||
switch (color.length()) {
|
||||
case 4:
|
||||
|
@ -159,20 +170,22 @@ bool rgb_color::from_str(const string_fragment &color,
|
|||
return false;
|
||||
}
|
||||
|
||||
for (const auto &xc : xterm_colors.xc_palette) {
|
||||
if (color == xc.xc_name) {
|
||||
for (const auto &xc : xterm_colors.tc_palette) {
|
||||
if (color.iequal(xc.xc_name)) {
|
||||
rgb_out = xc.xc_color;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
errmsg = "Unknown color: " + color.to_string() +
|
||||
". See https://jonasjacek.github.io/colors/ for a list of supported color names";
|
||||
errmsg = "Unknown color: '" + color.to_string() +
|
||||
"'. See https://jonasjacek.github.io/colors/ for a list of supported color names";
|
||||
return false;
|
||||
}
|
||||
|
||||
string_attr_type view_curses::VC_ROLE("role");
|
||||
string_attr_type view_curses::VC_STYLE("style");
|
||||
string_attr_type view_curses::VC_GRAPHIC("graphic");
|
||||
string_attr_type view_curses::VC_SELECTED("selected");
|
||||
string_attr_type view_curses::VC_FOREGROUND("foreground");
|
||||
string_attr_type view_curses::VC_BACKGROUND("background");
|
||||
|
||||
|
@ -469,7 +482,8 @@ void view_curses::mvwattrline(WINDOW *window,
|
|||
expanded_line[exp_index] = '\0';
|
||||
full_line = string(expanded_line);
|
||||
|
||||
text_attrs = view_colors::singleton().attrs_for_role(base_role);
|
||||
view_colors &vc = view_colors::singleton();
|
||||
text_attrs = vc.attrs_for_role(base_role);
|
||||
attrs = text_attrs;
|
||||
wmove(window, y, x);
|
||||
wattron(window, attrs);
|
||||
|
@ -488,7 +502,8 @@ void view_curses::mvwattrline(WINDOW *window,
|
|||
require(attr_range.lr_start >= 0);
|
||||
require(attr_range.lr_end >= -1);
|
||||
|
||||
if (!(iter->sa_type == &VC_STYLE ||
|
||||
if (!(iter->sa_type == &VC_ROLE ||
|
||||
iter->sa_type == &VC_STYLE ||
|
||||
iter->sa_type == &VC_GRAPHIC ||
|
||||
iter->sa_type == &VC_FOREGROUND ||
|
||||
iter->sa_type == &VC_BACKGROUND)) {
|
||||
|
@ -520,7 +535,7 @@ void view_curses::mvwattrline(WINDOW *window,
|
|||
for (int index = attr_range.lr_start;
|
||||
index < attr_range.lr_end;
|
||||
index++) {
|
||||
mvwaddch(window, y, x + index, iter->sa_value.sav_int);
|
||||
mvwaddch(window, y, x + index, iter->sa_value.sav_int | text_attrs);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -547,8 +562,14 @@ void view_curses::mvwattrline(WINDOW *window,
|
|||
int awidth = attr_range.length();
|
||||
int color_pair;
|
||||
|
||||
attrs = iter->sa_value.sav_int & ~A_COLOR;
|
||||
color_pair = PAIR_NUMBER(iter->sa_value.sav_int);
|
||||
if (iter->sa_type == &VC_STYLE) {
|
||||
attrs = iter->sa_value.sav_int & ~A_COLOR;
|
||||
color_pair = PAIR_NUMBER(iter->sa_value.sav_int);
|
||||
} else {
|
||||
attrs = vc.attrs_for_role((view_colors::role_t) iter->sa_value.sav_int);
|
||||
color_pair = PAIR_NUMBER(attrs);
|
||||
attrs = attrs & ~A_COLOR;
|
||||
}
|
||||
|
||||
if (attrs || color_pair > 0) {
|
||||
int x_pos = x + attr_range.lr_start;
|
||||
|
@ -611,14 +632,6 @@ void view_curses::mvwattrline(WINDOW *window,
|
|||
#endif
|
||||
}
|
||||
|
||||
class color_listener : public lnav_config_listener {
|
||||
void reload_config() {
|
||||
view_colors::singleton().init_roles(0);
|
||||
}
|
||||
};
|
||||
|
||||
static color_listener _COLOR_LISTENER;
|
||||
|
||||
attr_t view_colors::BASIC_HL_PAIRS[view_colors::BASIC_COLOR_COUNT] = {
|
||||
ansi_color_pair(COLOR_BLUE, COLOR_BLACK),
|
||||
ansi_color_pair(COLOR_CYAN, COLOR_BLACK),
|
||||
|
@ -643,10 +656,44 @@ view_colors::view_colors() : vc_color_pair_end(0)
|
|||
|
||||
bool view_colors::initialized = false;
|
||||
|
||||
void view_colors::init(void)
|
||||
{
|
||||
int color_pair_base = VC_ANSI_END;
|
||||
static string COLOR_NAMES[] = {
|
||||
"black",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"blue",
|
||||
"magenta",
|
||||
"cyan",
|
||||
"white",
|
||||
};
|
||||
|
||||
class color_listener : public lnav_config_listener {
|
||||
public:
|
||||
void reload_config(error_reporter &reporter) {
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
for (const auto &pair : lnav_config.lc_ui_theme_defs) {
|
||||
vc.init_roles(pair.second, reporter);
|
||||
}
|
||||
|
||||
auto iter = lnav_config.lc_ui_theme_defs.find(lnav_config.lc_ui_theme);
|
||||
|
||||
if (iter == lnav_config.lc_ui_theme_defs.end()) {
|
||||
reporter(&lnav_config.lc_ui_theme,
|
||||
"unknown theme -- " + lnav_config.lc_ui_theme);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view_colors::initialized) {
|
||||
vc.init_roles(iter->second, reporter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static color_listener _COLOR_LISTENER;
|
||||
|
||||
void view_colors::init()
|
||||
{
|
||||
if (has_colors()) {
|
||||
static int ansi_colors_to_curses[] = {
|
||||
COLOR_BLACK,
|
||||
|
@ -673,26 +720,20 @@ void view_colors::init(void)
|
|||
ansi_colors_to_curses[bg]);
|
||||
}
|
||||
}
|
||||
|
||||
if (COLORS == 256) {
|
||||
int bg = (lnav_config.lc_ui_default_colors ? -1 : COLOR_BLACK);
|
||||
|
||||
for (int z = 0; z < 6; z++) {
|
||||
for (int x = 1; x < 6; x += 2) {
|
||||
for (int y = 1; y < 6; y += 2) {
|
||||
int fg = 16 + x + (y * 6) + (z * 6 * 6);
|
||||
|
||||
init_pair(color_pair_base, fg, bg);
|
||||
color_pair_base += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (COLORS >= 256) {
|
||||
ACTIVE_PALETTE = &xterm_colors;
|
||||
}
|
||||
}
|
||||
|
||||
singleton().init_roles(color_pair_base);
|
||||
|
||||
initialized = true;
|
||||
|
||||
{
|
||||
auto reporter = [](const void *, const std::string &) {
|
||||
|
||||
};
|
||||
|
||||
_COLOR_LISTENER.reload_config(reporter);
|
||||
}
|
||||
}
|
||||
|
||||
inline attr_t attr_for_colors(int &pair_base, short fg, short bg)
|
||||
|
@ -712,80 +753,329 @@ inline attr_t attr_for_colors(int &pair_base, short fg, short bg)
|
|||
|
||||
int pair = ++pair_base;
|
||||
|
||||
init_pair(pair, fg, bg);
|
||||
if (view_colors::initialized) {
|
||||
init_pair(pair, fg, bg);
|
||||
}
|
||||
|
||||
return COLOR_PAIR(pair);
|
||||
}
|
||||
|
||||
void view_colors::init_roles(int color_pair_base)
|
||||
pair<attr_t, attr_t> view_colors::to_attrs(
|
||||
int &pair_base,
|
||||
const lnav_theme <, const style_config &sc,
|
||||
lnav_config_listener::error_reporter &reporter)
|
||||
{
|
||||
rgb_color fg, bg, sbg;
|
||||
string fg1, bg1, sbg1, fg_color, bg_color, sbg_color, errmsg;
|
||||
|
||||
fg1 = sc.sc_color;
|
||||
if (fg1.empty()) {
|
||||
fg1 = lt.lt_style_text.sc_color;
|
||||
}
|
||||
bg1 = sc.sc_background_color;
|
||||
if (bg1.empty()) {
|
||||
bg1 = lt.lt_style_text.sc_background_color;
|
||||
}
|
||||
sbg1 = sc.sc_selected_color;
|
||||
if (sbg1.empty()) {
|
||||
sbg1 = lt.lt_style_text.sc_selected_color;
|
||||
}
|
||||
shlex(fg1).eval(fg_color, lt.lt_vars);
|
||||
shlex(bg1).eval(bg_color, lt.lt_vars);
|
||||
shlex(sbg1).eval(sbg_color, lt.lt_vars);
|
||||
|
||||
if (!rgb_color::from_str(fg_color, fg, errmsg)) {
|
||||
reporter(&sc.sc_color, errmsg);
|
||||
}
|
||||
if (!rgb_color::from_str(bg_color, bg, errmsg)) {
|
||||
reporter(&sc.sc_background_color, errmsg);
|
||||
}
|
||||
if (!rgb_color::from_str(sbg_color, sbg, errmsg)) {
|
||||
reporter(&sc.sc_selected_color, errmsg);
|
||||
}
|
||||
|
||||
attr_t retval1 = this->ensure_color_pair(pair_base, fg, bg);
|
||||
attr_t retval2 = this->ensure_color_pair(pair_base, fg, sbg);
|
||||
|
||||
if (sc.sc_underline) {
|
||||
retval1 |= A_UNDERLINE;
|
||||
retval2 |= A_UNDERLINE;
|
||||
}
|
||||
if (sc.sc_bold) {
|
||||
retval1 |= A_BOLD;
|
||||
retval2 |= A_BOLD;
|
||||
}
|
||||
|
||||
return make_pair(retval1, retval2);
|
||||
}
|
||||
|
||||
void view_colors::init_roles(const lnav_theme <,
|
||||
lnav_config_listener::error_reporter &reporter)
|
||||
{
|
||||
int color_pair_base = VC_ANSI_END;
|
||||
rgb_color fg, bg;
|
||||
string err;
|
||||
|
||||
/* Setup the mappings from roles to actual colors. */
|
||||
this->vc_role_colors[VCR_TEXT] =
|
||||
attr_for_colors(color_pair_base, COLOR_WHITE, COLOR_BLACK);
|
||||
if (lnav_config.lc_ui_dim_text) {
|
||||
this->vc_role_colors[VCR_TEXT] |= A_DIM;
|
||||
if (COLORS == 256) {
|
||||
const style_config &ident_sc = lt.lt_style_identifier;
|
||||
int ident_bg = (lnav_config.lc_ui_default_colors ? -1 : COLOR_BLACK);
|
||||
|
||||
if (!ident_sc.sc_background_color.empty()) {
|
||||
string bg_color, errmsg;
|
||||
rgb_color rgb_bg;
|
||||
|
||||
shlex(ident_sc.sc_background_color).eval(bg_color, lt.lt_vars);
|
||||
if (!rgb_color::from_str(bg_color, rgb_bg, errmsg)) {
|
||||
reporter(&ident_sc.sc_background_color, errmsg);
|
||||
}
|
||||
ident_bg = ACTIVE_PALETTE->match_color(rgb_bg);
|
||||
}
|
||||
for (int z = 0; z < 6; z++) {
|
||||
for (int x = 1; x < 6; x += 2) {
|
||||
for (int y = 1; y < 6; y += 2) {
|
||||
int fg = 16 + x + (y * 6) + (z * 6 * 6);
|
||||
|
||||
init_pair(color_pair_base, fg, ident_bg);
|
||||
color_pair_base += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
color_pair_base = VC_ANSI_END + HI_COLOR_COUNT;
|
||||
}
|
||||
this->vc_role_colors[VCR_SEARCH] = A_REVERSE;
|
||||
this->vc_role_colors[VCR_OK] = attr_for_colors(color_pair_base, COLOR_GREEN, COLOR_BLACK) | A_BOLD;
|
||||
this->vc_role_colors[VCR_ERROR] = attr_for_colors(color_pair_base, COLOR_RED, COLOR_BLACK) | A_BOLD;
|
||||
this->vc_role_colors[VCR_WARNING] = attr_for_colors(color_pair_base, COLOR_YELLOW, COLOR_BLACK) | A_BOLD;
|
||||
this->vc_role_colors[VCR_ALT_ROW] = this->vc_role_colors[VCR_TEXT] | A_BOLD;
|
||||
this->vc_role_colors[VCR_HIDDEN] = attr_for_colors(color_pair_base, COLOR_YELLOW, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_ADJUSTED_TIME] = attr_for_colors(color_pair_base, COLOR_MAGENTA, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_SKEWED_TIME] = attr_for_colors(color_pair_base, COLOR_YELLOW, COLOR_BLACK) | A_UNDERLINE;
|
||||
this->vc_role_colors[VCR_OFFSET_TIME] = attr_for_colors(color_pair_base, COLOR_CYAN, COLOR_BLACK);
|
||||
|
||||
this->vc_role_colors[VCR_STATUS] =
|
||||
attr_for_colors(color_pair_base, COLOR_BLACK, COLOR_WHITE);
|
||||
this->vc_role_colors[VCR_WARN_STATUS] =
|
||||
attr_for_colors(color_pair_base, COLOR_YELLOW, COLOR_WHITE) | A_BOLD;
|
||||
this->vc_role_colors[VCR_ALERT_STATUS] =
|
||||
attr_for_colors(color_pair_base, COLOR_RED, COLOR_WHITE) | A_BOLD;
|
||||
this->vc_role_colors[VCR_ACTIVE_STATUS] =
|
||||
attr_for_colors(color_pair_base, COLOR_GREEN, COLOR_WHITE);
|
||||
/* Setup the mappings from roles to actual colors. */
|
||||
this->vc_role_colors[VCR_TEXT] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_text, reporter);
|
||||
|
||||
{
|
||||
int pnum = PAIR_NUMBER(this->vc_role_colors[VCR_TEXT].first);
|
||||
short text_fg, text_bg;
|
||||
|
||||
pair_content(pnum, &text_fg, &text_bg);
|
||||
for (int ansi_fg = 0; ansi_fg < 8; ansi_fg++) {
|
||||
for (int ansi_bg = 0; ansi_bg < 8; ansi_bg++) {
|
||||
if (ansi_fg == 0 && ansi_bg == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fg_str = lt.lt_vars.find(COLOR_NAMES[ansi_fg]);
|
||||
auto bg_str = lt.lt_vars.find(COLOR_NAMES[ansi_bg]);
|
||||
rgb_color rgb_fg, rgb_bg;
|
||||
string errmsg;
|
||||
|
||||
if (fg_str != lt.lt_vars.end() &&
|
||||
!rgb_color::from_str(fg_str->second, rgb_fg, errmsg)) {
|
||||
reporter(&fg_str->second, errmsg);
|
||||
return;
|
||||
}
|
||||
if (!rgb_color::from_str(bg_str->second, rgb_bg, errmsg)) {
|
||||
reporter(&bg_str->second, errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
short fg = ACTIVE_PALETTE->match_color(rgb_fg);
|
||||
short bg = ACTIVE_PALETTE->match_color(rgb_bg);
|
||||
|
||||
if (rgb_fg.empty()) {
|
||||
fg = ansi_fg;
|
||||
}
|
||||
if (rgb_bg.empty()) {
|
||||
bg = ansi_bg;
|
||||
}
|
||||
|
||||
init_pair(ansi_color_pair_index(ansi_fg, ansi_bg), fg, bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lnav_config.lc_ui_dim_text) {
|
||||
this->vc_role_colors[VCR_TEXT].first |= A_DIM;
|
||||
this->vc_role_colors[VCR_TEXT].second |= A_DIM;
|
||||
}
|
||||
this->vc_role_colors[VCR_SEARCH] = make_pair(A_REVERSE, A_REVERSE);
|
||||
this->vc_role_colors[VCR_OK] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_ok,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_ERROR] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_error,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_WARNING] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_warning,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_ALT_ROW] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_alt_text,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_HIDDEN] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_hidden,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_ADJUSTED_TIME] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_adjusted_time, reporter);
|
||||
this->vc_role_colors[VCR_SKEWED_TIME] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_skewed_time, reporter);
|
||||
this->vc_role_colors[VCR_OFFSET_TIME] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_offset_time, reporter);
|
||||
|
||||
this->vc_role_colors[VCR_STATUS] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_status, reporter);
|
||||
this->vc_role_colors[VCR_WARN_STATUS] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_warn_status, reporter);
|
||||
this->vc_role_colors[VCR_ALERT_STATUS] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_alert_status, reporter);
|
||||
this->vc_role_colors[VCR_ACTIVE_STATUS] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_active_status, reporter);
|
||||
this->vc_role_colors[VCR_ACTIVE_STATUS2] =
|
||||
attr_for_colors(color_pair_base, COLOR_GREEN, COLOR_WHITE) | A_BOLD;
|
||||
this->vc_role_colors[VCR_BOLD_STATUS] =
|
||||
attr_for_colors(color_pair_base, COLOR_BLACK, COLOR_WHITE) | A_BOLD;
|
||||
this->vc_role_colors[VCR_VIEW_STATUS] =
|
||||
attr_for_colors(color_pair_base, COLOR_WHITE, COLOR_BLUE) | A_BOLD;
|
||||
make_pair(this->vc_role_colors[VCR_ACTIVE_STATUS].first | A_BOLD,
|
||||
this->vc_role_colors[VCR_ACTIVE_STATUS].second | A_BOLD);
|
||||
this->vc_role_colors[VCR_STATUS_TITLE] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_status_title, reporter);
|
||||
this->vc_role_colors[VCR_STATUS_SUBTITLE] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_status_subtitle, reporter);
|
||||
|
||||
rgb_color::from_str(string_fragment("White"), fg, err);
|
||||
rgb_color::from_str(string_fragment("Grey37"), bg, err);
|
||||
this->vc_role_colors[VCR_INACTIVE_STATUS] = ensure_color_pair(fg, bg);
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
this->vc_role_colors[VCR_POPUP] =
|
||||
attr_for_colors(color_pair_base, COLOR_WHITE, COLOR_CYAN) | A_BOLD;
|
||||
stitch_sc.sc_color = lt.lt_style_status_subtitle.sc_background_color;
|
||||
stitch_sc.sc_background_color =
|
||||
lt.lt_style_status_title.sc_background_color;
|
||||
this->vc_role_colors[VCR_STATUS_STITCH_TITLE_TO_SUB] =
|
||||
this->to_attrs(color_pair_base, lt, stitch_sc, reporter);
|
||||
}
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
this->vc_role_colors[VCR_KEYWORD] = attr_for_colors(color_pair_base, COLOR_BLUE, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_STRING] = attr_for_colors(color_pair_base, COLOR_GREEN, COLOR_BLACK) | A_BOLD;
|
||||
this->vc_role_colors[VCR_COMMENT] = attr_for_colors(color_pair_base, COLOR_GREEN, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_VARIABLE] = attr_for_colors(color_pair_base, COLOR_CYAN, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_SYMBOL] = attr_for_colors(color_pair_base, COLOR_MAGENTA, COLOR_BLACK) | A_BOLD;
|
||||
this->vc_role_colors[VCR_RE_SPECIAL] = attr_for_colors(color_pair_base, COLOR_CYAN, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_RE_REPEAT] = attr_for_colors(color_pair_base, COLOR_YELLOW, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_FILE] = attr_for_colors(color_pair_base, COLOR_BLUE, COLOR_BLACK);
|
||||
stitch_sc.sc_color = lt.lt_style_status_title.sc_background_color;
|
||||
stitch_sc.sc_background_color =
|
||||
lt.lt_style_status_subtitle.sc_background_color;
|
||||
this->vc_role_colors[VCR_STATUS_STITCH_SUB_TO_TITLE] =
|
||||
this->to_attrs(color_pair_base, lt, stitch_sc, reporter);
|
||||
}
|
||||
|
||||
this->vc_role_colors[VCR_DIFF_DELETE] = attr_for_colors(color_pair_base, COLOR_RED, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_DIFF_ADD] = attr_for_colors(color_pair_base, COLOR_GREEN, COLOR_BLACK);
|
||||
this->vc_role_colors[VCR_DIFF_SECTION] = attr_for_colors(color_pair_base, COLOR_MAGENTA, COLOR_BLACK);
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
this->vc_role_colors[VCR_LOW_THRESHOLD] = attr_for_colors(color_pair_base, COLOR_BLACK, COLOR_GREEN);
|
||||
this->vc_role_colors[VCR_MED_THRESHOLD] = attr_for_colors(color_pair_base, COLOR_BLACK, COLOR_YELLOW);
|
||||
this->vc_role_colors[VCR_HIGH_THRESHOLD] = attr_for_colors(color_pair_base, COLOR_BLACK, COLOR_RED);
|
||||
stitch_sc.sc_color = lt.lt_style_status.sc_background_color;
|
||||
stitch_sc.sc_background_color =
|
||||
lt.lt_style_status_subtitle.sc_background_color;
|
||||
this->vc_role_colors[VCR_STATUS_STITCH_SUB_TO_NORMAL] =
|
||||
this->to_attrs(color_pair_base, lt, stitch_sc, reporter);
|
||||
}
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
this->vc_color_pair_end = color_pair_base + 1;
|
||||
stitch_sc.sc_color = lt.lt_style_status_subtitle.sc_background_color;
|
||||
stitch_sc.sc_background_color =
|
||||
lt.lt_style_status.sc_background_color;
|
||||
this->vc_role_colors[VCR_STATUS_STITCH_NORMAL_TO_SUB] =
|
||||
this->to_attrs(color_pair_base, lt, stitch_sc, reporter);
|
||||
}
|
||||
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
stitch_sc.sc_color = lt.lt_style_status.sc_background_color;
|
||||
stitch_sc.sc_background_color =
|
||||
lt.lt_style_status_title.sc_background_color;
|
||||
this->vc_role_colors[VCR_STATUS_STITCH_TITLE_TO_NORMAL] =
|
||||
this->to_attrs(color_pair_base, lt, stitch_sc, reporter);
|
||||
}
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
stitch_sc.sc_color = lt.lt_style_status_title.sc_background_color;
|
||||
stitch_sc.sc_background_color =
|
||||
lt.lt_style_status.sc_background_color;
|
||||
this->vc_role_colors[VCR_STATUS_STITCH_NORMAL_TO_TITLE] =
|
||||
this->to_attrs(color_pair_base, lt, stitch_sc, reporter);
|
||||
}
|
||||
|
||||
this->vc_role_colors[VCR_INACTIVE_STATUS] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_inactive_status, reporter);
|
||||
|
||||
this->vc_role_colors[VCR_POPUP] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_popup, reporter);
|
||||
this->vc_role_colors[VCR_COLOR_HINT] = make_pair(
|
||||
COLOR_PAIR(color_pair_base), COLOR_PAIR(color_pair_base + 1));
|
||||
color_pair_base += 2;
|
||||
|
||||
this->vc_role_colors[VCR_KEYWORD] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_keyword, reporter);
|
||||
this->vc_role_colors[VCR_STRING] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_string, reporter);
|
||||
this->vc_role_colors[VCR_COMMENT] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_comment, reporter);
|
||||
this->vc_role_colors[VCR_VARIABLE] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_variable, reporter);
|
||||
this->vc_role_colors[VCR_SYMBOL] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_symbol, reporter);
|
||||
this->vc_role_colors[VCR_NUMBER] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_number, reporter);
|
||||
|
||||
this->vc_role_colors[VCR_RE_SPECIAL] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_re_special, reporter);
|
||||
this->vc_role_colors[VCR_RE_REPEAT] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_re_repeat, reporter);
|
||||
this->vc_role_colors[VCR_FILE] = this->to_attrs(color_pair_base,
|
||||
lt, lt.lt_style_file, reporter);
|
||||
|
||||
this->vc_role_colors[VCR_DIFF_DELETE] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_diff_delete, reporter);
|
||||
this->vc_role_colors[VCR_DIFF_ADD] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_diff_add, reporter);
|
||||
this->vc_role_colors[VCR_DIFF_SECTION] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_diff_section, reporter);
|
||||
|
||||
this->vc_role_colors[VCR_LOW_THRESHOLD] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_low_threshold, reporter);
|
||||
this->vc_role_colors[VCR_MED_THRESHOLD] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_med_threshold, reporter);
|
||||
this->vc_role_colors[VCR_HIGH_THRESHOLD] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_high_threshold, reporter);
|
||||
|
||||
for (log_level_t level = static_cast<log_level_t>(LEVEL_UNKNOWN + 1);
|
||||
level < LEVEL__MAX;
|
||||
level = static_cast<log_level_t>(level + 1)) {
|
||||
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(
|
||||
color_pair_base, lt, lt.lt_style_text, reporter);
|
||||
} else {
|
||||
this->vc_level_attrs[level] = this->to_attrs(
|
||||
color_pair_base, lt, level_iter->second, reporter);
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized && this->vc_color_pair_end == 0) {
|
||||
this->vc_color_pair_end = color_pair_base + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int view_colors::ensure_color_pair(const rgb_color &rgb_fg, const rgb_color &rgb_bg)
|
||||
int view_colors::ensure_color_pair(int &pair_base, const rgb_color &rgb_fg, const rgb_color &rgb_bg)
|
||||
{
|
||||
return attr_for_colors(
|
||||
this->vc_color_pair_end,
|
||||
xterm_colors.match_color(rgb_fg),
|
||||
rgb_bg.empty() ? (short) COLOR_BLACK : xterm_colors.match_color(rgb_bg));
|
||||
pair_base,
|
||||
rgb_fg.empty() ? (short) COLOR_WHITE : ACTIVE_PALETTE->match_color(rgb_fg),
|
||||
rgb_bg.empty() ? (short) COLOR_BLACK : ACTIVE_PALETTE->match_color(rgb_bg));
|
||||
}
|
||||
|
||||
attr_t view_colors::attrs_for_ident(const char *str, size_t len) const
|
||||
{
|
||||
unsigned long index = crc32(1, (const Bytef*)str, len);
|
||||
attr_t retval;
|
||||
|
||||
if (COLORS >= 256) {
|
||||
unsigned long offset = index % HI_COLOR_COUNT;
|
||||
retval = COLOR_PAIR(VC_ANSI_END + offset);
|
||||
|
||||
short fg, bg;
|
||||
int pnum = PAIR_NUMBER(retval);
|
||||
pair_content(pnum, &fg, &bg);
|
||||
}
|
||||
else {
|
||||
retval = BASIC_HL_PAIRS[index % BASIC_COLOR_COUNT];
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
lab_color::lab_color(const rgb_color &rgb)
|
||||
|
|
|
@ -64,6 +64,9 @@
|
|||
#include "attr_line.hh"
|
||||
#include "optional.hpp"
|
||||
#include "lnav_util.hh"
|
||||
#include "styling.hh"
|
||||
#include "log_level.hh"
|
||||
#include "lnav_config.hh"
|
||||
|
||||
#define KEY_CTRL_G 7
|
||||
#define KEY_CTRL_L 12
|
||||
|
@ -289,24 +292,6 @@ private:
|
|||
void (*va_invoker)(void *functor, _Sender *sender);
|
||||
};
|
||||
|
||||
struct rgb_color {
|
||||
static bool from_str(const string_fragment &color,
|
||||
rgb_color &rgb_out,
|
||||
std::string &errmsg);
|
||||
|
||||
explicit rgb_color(short r = -1, short g = -1, short b = -1)
|
||||
: rc_r(r), rc_g(g), rc_b(b) {
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return this->rc_r == -1 && this->rc_g == -1 && this->rc_b == -1;
|
||||
}
|
||||
|
||||
short rc_r;
|
||||
short rc_g;
|
||||
short rc_b;
|
||||
};
|
||||
|
||||
struct lab_color {
|
||||
lab_color() : lc_l(0), lc_a(0), lc_b(0) {
|
||||
};
|
||||
|
@ -357,16 +342,24 @@ public:
|
|||
VCR_ALERT_STATUS, /*< Alert status line text. */
|
||||
VCR_ACTIVE_STATUS, /*< */
|
||||
VCR_ACTIVE_STATUS2, /*< */
|
||||
VCR_BOLD_STATUS,
|
||||
VCR_VIEW_STATUS,
|
||||
VCR_STATUS_TITLE,
|
||||
VCR_STATUS_SUBTITLE,
|
||||
VCR_STATUS_STITCH_TITLE_TO_SUB,
|
||||
VCR_STATUS_STITCH_SUB_TO_TITLE,
|
||||
VCR_STATUS_STITCH_SUB_TO_NORMAL,
|
||||
VCR_STATUS_STITCH_NORMAL_TO_SUB,
|
||||
VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
VCR_STATUS_STITCH_NORMAL_TO_TITLE,
|
||||
VCR_INACTIVE_STATUS,
|
||||
VCR_POPUP,
|
||||
VCR_COLOR_HINT,
|
||||
|
||||
VCR_KEYWORD,
|
||||
VCR_STRING,
|
||||
VCR_COMMENT,
|
||||
VCR_VARIABLE,
|
||||
VCR_SYMBOL,
|
||||
VCR_NUMBER,
|
||||
VCR_RE_SPECIAL,
|
||||
VCR_RE_REPEAT,
|
||||
VCR_FILE,
|
||||
|
@ -392,18 +385,23 @@ public:
|
|||
*/
|
||||
static void init(void);
|
||||
|
||||
void init_roles(int color_pair_base);
|
||||
void init_roles(const lnav_theme <, lnav_config_listener::error_reporter &reporter);
|
||||
|
||||
/**
|
||||
* @param role The role to retrieve character attributes for.
|
||||
* @return The attributes to use for the given role.
|
||||
*/
|
||||
attr_t attrs_for_role(role_t role) const
|
||||
attr_t attrs_for_role(role_t role, bool selected = false) const
|
||||
{
|
||||
if (role == VCR_NONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
require(role >= 0);
|
||||
require(role < VCR__MAX);
|
||||
|
||||
return this->vc_role_colors[role];
|
||||
return selected ? this->vc_role_colors[role].second :
|
||||
this->vc_role_colors[role].first;
|
||||
};
|
||||
|
||||
attr_t reverse_attrs_for_role(role_t role) const
|
||||
|
@ -414,26 +412,17 @@ public:
|
|||
return this->vc_role_reverse_colors[role];
|
||||
};
|
||||
|
||||
attr_t attrs_for_ident(const char *str, size_t len) const {
|
||||
unsigned long index = crc32(1, (const Bytef*)str, len);
|
||||
attr_t retval;
|
||||
|
||||
if (COLORS >= 256) {
|
||||
unsigned long offset = index % HI_COLOR_COUNT;
|
||||
retval = COLOR_PAIR(VC_ANSI_END + offset);
|
||||
}
|
||||
else {
|
||||
retval = BASIC_HL_PAIRS[index % BASIC_COLOR_COUNT];
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
attr_t attrs_for_ident(const char *str, size_t len) const;;
|
||||
|
||||
attr_t attrs_for_ident(const std::string &str) const {
|
||||
return this->attrs_for_ident(str.c_str(), str.length());
|
||||
};
|
||||
|
||||
int ensure_color_pair(const rgb_color &fg, const rgb_color &bg);
|
||||
int ensure_color_pair(int &pair_base, const rgb_color &fg, const rgb_color &bg);
|
||||
|
||||
int ensure_color_pair(const rgb_color &fg, const rgb_color &bg) {
|
||||
return this->ensure_color_pair(this->vc_color_pair_end, fg, bg);
|
||||
}
|
||||
|
||||
static inline int ansi_color_pair_index(int fg, int bg)
|
||||
{
|
||||
|
@ -445,20 +434,24 @@ public:
|
|||
return COLOR_PAIR(ansi_color_pair_index(fg, bg));
|
||||
};
|
||||
|
||||
enum {
|
||||
VC_ANSI_START = 0,
|
||||
VC_ANSI_END = VC_ANSI_START + (8 * 8),
|
||||
};
|
||||
static const int VC_ANSI_START = 0;
|
||||
static const int VC_ANSI_END = VC_ANSI_START + (8 * 8);
|
||||
|
||||
std::pair<attr_t, attr_t> to_attrs(int &pair_base,
|
||||
const lnav_theme <, const style_config &sc,
|
||||
lnav_config_listener::error_reporter &reporter);
|
||||
|
||||
std::pair<attr_t, attr_t> vc_level_attrs[LEVEL__MAX];
|
||||
|
||||
static bool initialized;
|
||||
|
||||
private:
|
||||
|
||||
/** Private constructor that initializes the member fields. */
|
||||
view_colors();
|
||||
|
||||
static bool initialized;
|
||||
|
||||
/** Map of role IDs to attribute values. */
|
||||
attr_t vc_role_colors[VCR__MAX];
|
||||
std::pair<attr_t, attr_t> vc_role_colors[VCR__MAX];
|
||||
/** Map of role IDs to reverse-video attribute values. */
|
||||
attr_t vc_role_reverse_colors[VCR__MAX];
|
||||
int vc_color_pair_end;
|
||||
|
@ -554,8 +547,10 @@ public:
|
|||
return this->vc_width;
|
||||
}
|
||||
|
||||
static string_attr_type VC_ROLE;
|
||||
static string_attr_type VC_STYLE;
|
||||
static string_attr_type VC_GRAPHIC;
|
||||
static string_attr_type VC_SELECTED;
|
||||
static string_attr_type VC_FOREGROUND;
|
||||
static string_attr_type VC_BACKGROUND;
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ extern "C" {
|
|||
* The help message text. The value for this comes from the "init.sql" file,
|
||||
* which gets linked into the executable by the Makefile.
|
||||
*/
|
||||
extern const char xterm_palette_json[];
|
||||
extern const unsigned char xterm_palette_json[];
|
||||
|
||||
extern const unsigned char ansi_palette_json[];
|
||||
}
|
||||
#endif
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -71,6 +71,11 @@ yajl_gen_status json_path_handler_base::gen(yajlpp_gen_context &ygc, yajl_gen ha
|
|||
start = lpc + 1;
|
||||
}
|
||||
}
|
||||
if (this->jph_path_provider) {
|
||||
yajl_gen_pstring(handle, &lpath[start], -1);
|
||||
yajl_gen_map_open(handle);
|
||||
ygc.ygc_depth += 1;
|
||||
}
|
||||
|
||||
if (this->jph_obj_provider) {
|
||||
pcre_context_static<30> pc;
|
||||
|
@ -116,13 +121,20 @@ yajl_gen_status json_path_handler_base::gen(yajlpp_gen_context &ygc, yajl_gen ha
|
|||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
void json_path_handler_base::possibilities(
|
||||
std::vector<std::string> &dst, void *root, const string &base) const
|
||||
void json_path_handler_base::walk(
|
||||
const std::function<void(const json_path_handler_base &,
|
||||
const std::string &,
|
||||
void *)> &cb,
|
||||
void *root, const string &base) const
|
||||
{
|
||||
vector<string> local_paths;
|
||||
|
||||
if (this->jph_path_provider) {
|
||||
this->jph_path_provider(root, local_paths);
|
||||
|
||||
for (auto &lpath : local_paths) {
|
||||
cb(*this, lpath, nullptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
local_paths.emplace_back(this->jph_path);
|
||||
|
@ -149,7 +161,8 @@ void json_path_handler_base::possibilities(
|
|||
.with_obj(root)
|
||||
.update_callbacks();
|
||||
if (this->jph_obj_provider) {
|
||||
pcre_input pi(lpath + "/");
|
||||
string full_path = lpath + "/";
|
||||
pcre_input pi(full_path);
|
||||
|
||||
if (!this->jph_regex.match(ypc.ypc_pcre_context, pi)) {
|
||||
ensure(false);
|
||||
|
@ -158,13 +171,18 @@ void json_path_handler_base::possibilities(
|
|||
{{ypc.ypc_pcre_context, pi}, -1}, root);
|
||||
}
|
||||
|
||||
this->jph_children[lpc].possibilities(dst, child_root, full_path);
|
||||
this->jph_children[lpc].walk(cb, child_root, full_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const auto &lpath : local_paths) {
|
||||
dst.push_back(base + lpath);
|
||||
for (auto &lpath : local_paths) {
|
||||
void *field = nullptr;
|
||||
|
||||
if (this->jph_field_getter) {
|
||||
field = this->jph_field_getter(root, lpath);
|
||||
}
|
||||
cb(*this, base + lpath, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -253,6 +271,7 @@ void yajlpp_parse_context::update_callbacks(const json_path_handler_base *orig_h
|
|||
|
||||
if (handlers == NULL) {
|
||||
handlers = this->ypc_handlers;
|
||||
this->ypc_handler_stack.clear();
|
||||
}
|
||||
|
||||
if (!this->ypc_active_paths.empty()) {
|
||||
|
@ -286,11 +305,18 @@ void yajlpp_parse_context::update_callbacks(const json_path_handler_base *orig_h
|
|||
}
|
||||
|
||||
if (jph.jph_children) {
|
||||
if (this->ypc_path[child_start + cap->c_end - 1] != '/') {
|
||||
char last = this->ypc_path[child_start + cap->c_end - 1];
|
||||
|
||||
if (last != '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->update_callbacks(jph.jph_children, child_start + cap->c_end);
|
||||
this->ypc_handler_stack.emplace_back(&jph);
|
||||
|
||||
if (child_start + cap->c_end != (int)this->ypc_path.size() - 1) {
|
||||
this->update_callbacks(jph.jph_children,
|
||||
child_start + cap->c_end);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (child_start + cap->c_end != (int)this->ypc_path.size() - 1) {
|
||||
|
@ -300,18 +326,22 @@ void yajlpp_parse_context::update_callbacks(const json_path_handler_base *orig_h
|
|||
this->ypc_current_handler = &jph;
|
||||
}
|
||||
|
||||
if (jph.jph_callbacks.yajl_null != NULL)
|
||||
if (jph.jph_callbacks.yajl_null != nullptr)
|
||||
this->ypc_callbacks.yajl_null = jph.jph_callbacks.yajl_null;
|
||||
if (jph.jph_callbacks.yajl_boolean != NULL)
|
||||
if (jph.jph_callbacks.yajl_boolean != nullptr)
|
||||
this->ypc_callbacks.yajl_boolean = jph.jph_callbacks.yajl_boolean;
|
||||
if (jph.jph_callbacks.yajl_integer != NULL)
|
||||
if (jph.jph_callbacks.yajl_integer != nullptr)
|
||||
this->ypc_callbacks.yajl_integer = jph.jph_callbacks.yajl_integer;
|
||||
if (jph.jph_callbacks.yajl_double != NULL)
|
||||
if (jph.jph_callbacks.yajl_double != nullptr)
|
||||
this->ypc_callbacks.yajl_double = jph.jph_callbacks.yajl_double;
|
||||
if (jph.jph_callbacks.yajl_string != NULL)
|
||||
if (jph.jph_callbacks.yajl_string != nullptr)
|
||||
this->ypc_callbacks.yajl_string = jph.jph_callbacks.yajl_string;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->ypc_handler_stack.emplace_back(nullptr);
|
||||
}
|
||||
|
||||
int yajlpp_parse_context::map_end(void *ctx)
|
||||
|
@ -478,3 +508,16 @@ void yajlpp_gen_context::gen()
|
|||
jph.gen(*this, this->ygc_handle);
|
||||
}
|
||||
}
|
||||
|
||||
yajlpp_gen_context &yajlpp_gen_context::with_context(yajlpp_parse_context &ypc)
|
||||
{
|
||||
this->ygc_obj_stack = ypc.ypc_obj_stack;
|
||||
this->ygc_base_name = ypc.get_path_fragment(-1);
|
||||
if (ypc.ypc_current_handler == nullptr &&
|
||||
!ypc.ypc_handler_stack.empty() &&
|
||||
ypc.ypc_handler_stack.back() != nullptr) {
|
||||
this->ygc_handlers = static_cast<json_path_handler *>(ypc.ypc_handler_stack.back()->jph_children);
|
||||
this->ygc_depth += 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "optional.hpp"
|
||||
#include "pcrepp.hh"
|
||||
|
@ -135,6 +136,7 @@ struct json_path_handler_base {
|
|||
: jph_path(path),
|
||||
jph_regex(path, PCRE_ANCHORED),
|
||||
jph_gen_callback(NULL),
|
||||
jph_field_getter(nullptr),
|
||||
jph_obj_provider(NULL),
|
||||
jph_path_provider(NULL),
|
||||
jph_synopsis(""),
|
||||
|
@ -163,9 +165,12 @@ struct json_path_handler_base {
|
|||
};
|
||||
|
||||
virtual yajl_gen_status gen(yajlpp_gen_context &ygc, yajl_gen handle) const;
|
||||
virtual void possibilities(std::vector<std::string> &dst,
|
||||
void *root = NULL,
|
||||
const std::string &base = "") const;
|
||||
virtual void walk(
|
||||
const std::function<void(const json_path_handler_base &,
|
||||
const std::string &,
|
||||
void *)> &cb,
|
||||
void *root = nullptr,
|
||||
const std::string &base = "") const;
|
||||
|
||||
const char * jph_path;
|
||||
pcrepp jph_regex;
|
||||
|
@ -173,6 +178,7 @@ struct json_path_handler_base {
|
|||
yajl_gen_status (*jph_gen_callback)(yajlpp_gen_context &, const json_path_handler_base &, yajl_gen);
|
||||
void (*jph_validator)(yajlpp_parse_context &ypc,
|
||||
const json_path_handler_base &jph);
|
||||
void *(*jph_field_getter)(void *root, nonstd::optional<std::string> name);
|
||||
void *(*jph_obj_provider)(const yajlpp_provider_context &pe, void *root);
|
||||
void (*jph_path_provider)(void *root, std::vector<std::string> &paths_out);
|
||||
const char * jph_synopsis;
|
||||
|
@ -181,6 +187,7 @@ struct json_path_handler_base {
|
|||
bool jph_kv_pair;
|
||||
std::shared_ptr<pcrepp> jph_pattern;
|
||||
const char * jph_pattern_re{nullptr};
|
||||
std::function<void(const string_fragment &)> jph_string_validator;
|
||||
size_t jph_min_length;
|
||||
size_t jph_max_length;
|
||||
const enum_value_t *jph_enum_values;
|
||||
|
@ -190,6 +197,19 @@ struct json_path_handler_base {
|
|||
|
||||
struct json_path_handler;
|
||||
|
||||
struct source_location {
|
||||
source_location()
|
||||
: sl_source(intern_string::lookup("unknown")),
|
||||
sl_line_number(-1) {
|
||||
}
|
||||
|
||||
source_location(intern_string_t source, int line)
|
||||
: sl_source(source), sl_line_number(line) {};
|
||||
|
||||
intern_string_t sl_source;
|
||||
int sl_line_number;
|
||||
};
|
||||
|
||||
class yajlpp_parse_context {
|
||||
public:
|
||||
typedef void (*error_reporter_t)(const yajlpp_parse_context &ypc,
|
||||
|
@ -256,6 +276,11 @@ public:
|
|||
this->ypc_path.size() - 2);
|
||||
};
|
||||
|
||||
const intern_string_t get_full_path() const {
|
||||
return intern_string::lookup(&this->ypc_path[0],
|
||||
this->ypc_path.size() - 1);
|
||||
};
|
||||
|
||||
bool is_level(size_t level) const {
|
||||
return this->ypc_path_index_stack.size() == level;
|
||||
};
|
||||
|
@ -426,12 +451,14 @@ public:
|
|||
std::vector<char> ypc_path;
|
||||
std::vector<size_t> ypc_path_index_stack;
|
||||
std::vector<int> ypc_array_index;
|
||||
std::vector<const json_path_handler_base *> ypc_handler_stack;
|
||||
pcre_context_static<30> ypc_pcre_context;
|
||||
bool ypc_ignore_unused{false};
|
||||
const struct json_path_handler_base *ypc_sibling_handlers{nullptr};
|
||||
const struct json_path_handler_base *ypc_current_handler{nullptr};
|
||||
std::set<std::string> ypc_active_paths;
|
||||
error_reporter_t ypc_error_reporter{nullptr};
|
||||
std::map<intern_string_t, source_location> *ypc_locations{nullptr};
|
||||
|
||||
void update_callbacks(const json_path_handler_base *handlers = NULL,
|
||||
int child_start = 0);
|
||||
|
@ -565,11 +592,7 @@ public:
|
|||
return *this;
|
||||
};
|
||||
|
||||
yajlpp_gen_context &with_context(yajlpp_parse_context &ypc) {
|
||||
this->ygc_obj_stack = ypc.ypc_obj_stack;
|
||||
this->ygc_base_name = ypc.get_path_fragment(-1);
|
||||
return *this;
|
||||
}
|
||||
yajlpp_gen_context &with_context(yajlpp_parse_context &ypc);
|
||||
|
||||
void gen();
|
||||
|
||||
|
|
|
@ -153,6 +153,11 @@ struct json_path_handler : public json_path_handler_base {
|
|||
return *this;
|
||||
};
|
||||
|
||||
json_path_handler &with_string_validator(std::function<void(const string_fragment &)> val) {
|
||||
this->jph_string_validator = val;
|
||||
return *this;
|
||||
};
|
||||
|
||||
json_path_handler &with_min_value(long long val) {
|
||||
this->jph_min_value = val;
|
||||
return *this;
|
||||
|
@ -170,10 +175,25 @@ struct json_path_handler : public json_path_handler_base {
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename MEM_T, MEM_T T::*MEM>
|
||||
static void *get_field_lvalue_cb(void *root, nonstd::optional<std::string> name) {
|
||||
auto obj = (T *) root;
|
||||
auto &mem = obj->*MEM;
|
||||
|
||||
return &mem;
|
||||
};
|
||||
|
||||
template<typename T, typename STR_T, STR_T T::*STR>
|
||||
static int string_field_cb(yajlpp_parse_context *ypc, const unsigned char *str, size_t len) {
|
||||
auto handler = ypc->ypc_current_handler;
|
||||
|
||||
if (ypc->ypc_locations) {
|
||||
intern_string_t src = intern_string::lookup(ypc->ypc_source);
|
||||
|
||||
(*ypc->ypc_locations)[ypc->get_full_path()] = {
|
||||
src, ypc->get_line_number() };
|
||||
}
|
||||
|
||||
assign(ypc->get_lvalue(ypc->get_obj_member<T, STR_T, STR>()), string_fragment(str, 0, len));
|
||||
handler->jph_validator(*ypc, *handler);
|
||||
|
||||
|
@ -248,7 +268,8 @@ struct json_path_handler : public json_path_handler_base {
|
|||
auto &field_ptr = ypc.get_rvalue(ypc.get_obj_member<T, STR_T, STR>());
|
||||
|
||||
if (jph.jph_pattern) {
|
||||
pcre_input pi(to_string_fragment(field_ptr));
|
||||
string_fragment sf = to_string_fragment(field_ptr);
|
||||
pcre_input pi(sf);
|
||||
pcre_context_static<30> pc;
|
||||
|
||||
if (!jph.jph_pattern->match(pc, pi)) {
|
||||
|
@ -257,6 +278,15 @@ struct json_path_handler : public json_path_handler_base {
|
|||
jph.jph_pattern_re);
|
||||
}
|
||||
}
|
||||
if (jph.jph_string_validator) {
|
||||
try {
|
||||
jph.jph_string_validator(to_string_fragment(field_ptr));
|
||||
} catch (const std::exception &e) {
|
||||
ypc.report_error(LOG_LEVEL_ERROR,
|
||||
"%s",
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
if (field_ptr.empty() && jph.jph_min_length > 0) {
|
||||
ypc.report_error(LOG_LEVEL_ERROR, "value must not be empty");
|
||||
} else if (field_ptr.size() < jph.jph_min_length) {
|
||||
|
@ -296,11 +326,44 @@ struct json_path_handler : public json_path_handler_base {
|
|||
return gen(obj->*FIELD);
|
||||
};
|
||||
|
||||
static yajl_gen_status map_field_gen(yajlpp_gen_context &ygc,
|
||||
const json_path_handler_base &jph,
|
||||
yajl_gen handle)
|
||||
{
|
||||
const auto def_obj = (std::map<std::string, std::string> *) (
|
||||
ygc.ygc_default_stack.empty() ? nullptr
|
||||
: ygc.ygc_default_stack.top());
|
||||
auto obj = (std::map<std::string, std::string> *) ygc.ygc_obj_stack.top();
|
||||
yajl_gen_status rc;
|
||||
|
||||
for (auto &pair : *obj) {
|
||||
if (def_obj != nullptr) {
|
||||
auto iter = def_obj->find(pair.first);
|
||||
|
||||
if (iter != def_obj->end() && iter->second == pair.second) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = yajl_gen_string(handle, pair.first)) !=
|
||||
yajl_gen_status_ok) {
|
||||
return rc;
|
||||
}
|
||||
if ((rc = yajl_gen_string(handle, pair.second)) !=
|
||||
yajl_gen_status_ok) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return yajl_gen_status_ok;
|
||||
};
|
||||
|
||||
template<typename T, typename STR_T, std::string T::*STR>
|
||||
json_path_handler &for_field() {
|
||||
this->add_cb(string_field_cb<T, STR_T, STR>);
|
||||
this->jph_gen_callback = field_gen<T, STR_T, STR>;
|
||||
this->jph_validator = string_field_validator<T, STR_T, STR>;
|
||||
this->jph_field_getter = get_field_lvalue_cb<T, STR_T, STR>;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
@ -308,6 +371,7 @@ struct json_path_handler : public json_path_handler_base {
|
|||
template<typename T, typename STR_T, std::map<std::string, std::string> T::*STR>
|
||||
json_path_handler &for_field() {
|
||||
this->add_cb(string_field_cb<T, STR_T, STR>);
|
||||
this->jph_gen_callback = map_field_gen;
|
||||
this->jph_validator = string_field_validator<T, STR_T, STR>;
|
||||
|
||||
return *this;
|
||||
|
|
|
@ -220,6 +220,7 @@ dist_noinst_SCRIPTS = \
|
|||
parser_debugger.py \
|
||||
test_cli.sh \
|
||||
test_cmds.sh \
|
||||
test_config.sh \
|
||||
test_curl.sh \
|
||||
test_data_parser.sh \
|
||||
test_format_installer.sh \
|
||||
|
@ -372,6 +373,7 @@ TESTS = \
|
|||
test_format_loader.sh \
|
||||
test_cli.sh \
|
||||
test_cmds.sh \
|
||||
test_config.sh \
|
||||
test_line_buffer2 \
|
||||
test_line_buffer.sh \
|
||||
test_listview.sh \
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"ui": {
|
||||
"theme": "foo"
|
||||
}
|
||||
}
|
|
@ -126,7 +126,7 @@ EOF
|
|||
|
||||
check_output "config clock-format" <<EOF
|
||||
info: changed config option -- /ui/clock-format
|
||||
info: reset option
|
||||
info: reset option -- /ui/clock-format
|
||||
info: /ui/clock-format = "%a %b %d %H:%M:%S %Z"
|
||||
EOF
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":config /ui/theme-defs/default/styles/text/color #f" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "config bad color" <<EOF
|
||||
error:command-option:1:Could not parse color: #f
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":config /ui/theme baddy" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "config bad theme" <<EOF
|
||||
error:command-option:1:unknown theme -- baddy
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-I ${test_dir}/bad-config2 \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
sed -i "" -e "s|/.*/format|format|g" `test_err_filename`
|
||||
|
||||
check_error_output "config bad theme" <<EOF
|
||||
formats/invalid-config/config.json:3:unknown theme -- foo
|
||||
EOF
|
Loading…
Reference in New Issue