From 06d109821190e72313783cd1c90f15b5dde18537 Mon Sep 17 00:00:00 2001 From: Timothy Stack Date: Fri, 3 May 2019 13:50:19 -0700 Subject: [PATCH] [config] initial support for themes For #422 Still more to do --- NEWS | 10 + docs/source/conf.py | 2 +- src/CMakeLists.txt | 1 + src/Makefile.am | 28 +- src/ansi-palette.json | 122 + src/command_executor.hh | 2 +- src/default-log-formats.json | 4 +- src/doc_status_source.hh | 5 +- src/filter_status_source.cc | 12 +- src/highlighter.hh | 16 +- src/hotkeys.cc | 1 + src/intern_string.hh | 11 + src/lnav.cc | 7 + src/lnav_commands.cc | 140 +- src/lnav_config.cc | 411 +- src/lnav_config.hh | 15 +- src/log_format_loader.cc | 29 +- src/log_level.cc | 4 +- src/log_level.hh | 5 +- src/log_level_re.cc | 30 +- src/log_level_re.re | 2 +- src/logfile_sub_source.cc | 16 +- src/pcrepp.hh | 4 + src/preview_status_source.hh | 7 +- src/readline_callbacks.cc | 4 + src/readline_curses.cc | 110 +- src/readline_curses.hh | 8 + src/readline_highlighters.cc | 25 +- src/readline_possibilities.cc | 29 +- src/{default-config.json => root-config.json} | 3 +- src/session_data.cc | 1 - src/shlex.hh | 2 +- src/statusview_curses.cc | 7 +- src/statusview_curses.hh | 7 +- src/styling.hh | 103 + src/textfile_highlighters.cc | 14 +- src/themes/default.json | 127 + src/themes/night-owl.json | 143 + src/themes/solarized-dark.json | 152 + src/themes/solarized-light.json | 152 + src/top_status_source.hh | 12 +- src/view_curses.cc | 510 ++- src/view_curses.hh | 85 +- src/xterm-palette.hh | 4 +- src/xterm-palette.json | 3843 ++++++++++++++++- src/yajlpp.cc | 69 +- src/yajlpp.hh | 39 +- src/yajlpp_def.hh | 66 +- test/Makefile.am | 2 + .../formats/invalid-config/config.json | 5 + test/test_cmds.sh | 2 +- test/test_config.sh | 27 + 52 files changed, 6086 insertions(+), 349 deletions(-) create mode 100644 src/ansi-palette.json rename src/{default-config.json => root-config.json} (55%) create mode 100644 src/styling.hh create mode 100644 src/themes/default.json create mode 100644 src/themes/night-owl.json create mode 100644 src/themes/solarized-dark.json create mode 100644 src/themes/solarized-light.json create mode 100644 test/bad-config2/formats/invalid-config/config.json create mode 100755 test/test_config.sh diff --git a/NEWS b/NEWS index b211210d..4cd66af7 100644 --- a/NEWS +++ b/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: diff --git a/docs/source/conf.py b/docs/source/conf.py index de52f11e..d3e0e508 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ab309a5..ed24d3ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 398dfe29..f908d06b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/ansi-palette.json b/src/ansi-palette.json new file mode 100644 index 00000000..f419ba60 --- /dev/null +++ b/src/ansi-palette.json @@ -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" + } +] \ No newline at end of file diff --git a/src/command_executor.hh b/src/command_executor.hh index 96b0e4b9..00616b83 100644 --- a/src/command_executor.hh +++ b/src/command_executor.hh @@ -58,7 +58,7 @@ struct exec_context { ec_pipe_callback(pipe_callback) { this->ec_local_vars.push(std::map()); 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); } diff --git a/src/default-log-formats.json b/src/default-log-formats.json index dd3dfd80..2b07d688 100644 --- a/src/default-log-formats.json +++ b/src/default-log-formats.json @@ -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" } ] }, diff --git a/src/doc_status_source.hh b/src/doc_status_source.hh index 27020367..b3f29eb7 100644 --- a/src/doc_status_source.hh +++ b/src/doc_status_source.hh @@ -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); }; diff --git a/src/filter_status_source.cc b/src/filter_status_source.cc index 323adaeb..5d4126cb 100644 --- a/src/filter_status_source.cc +++ b/src/filter_status_source.cc @@ -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 { diff --git a/src/highlighter.hh b/src/highlighter.hh index 8039d124..de3b533c 100644 --- a/src/highlighter.hh +++ b/src/highlighter.hh @@ -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; diff --git a/src/hotkeys.cc b/src/hotkeys.cc index c894ca8c..507cbbc5 100644 --- a/src/hotkeys.cc +++ b/src/hotkeys.cc @@ -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()); diff --git a/src/intern_string.hh b/src/intern_string.hh index 16653497..73823bac 100644 --- a/src/intern_string.hh +++ b/src/intern_string.hh @@ -37,6 +37,8 @@ #include +#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); diff --git a/src/lnav.cc b/src/lnav.cc index 82fa5f5d..a5f1f383 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -145,6 +145,10 @@ #include "shlex.hh" #include "log_actions.hh" +#ifndef SYSCONFDIR +#define SYSCONFDIR "/usr/etc" +#endif + using namespace std; static multimap 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': diff --git a/src/lnav_commands.cc b/src/lnav_commands.cc index f8a7e552..a407af3b 100644 --- a/src/lnav_commands.cc +++ b/src/lnav_commands.cc @@ -38,6 +38,7 @@ #include #include +#include #include "lnav.hh" #include "lnav_config.hh" @@ -3208,64 +3209,126 @@ static string com_config(exec_context &ec, string cmdline, vector &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 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 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 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 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 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"}) diff --git a/src/lnav_config.cc b/src/lnav_config.cc index b1045ee1..639248f9 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -41,17 +41,20 @@ #include #include +#include #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 lnav_config_locations; + lnav_config_listener *lnav_config_listener::LISTENER_LIST; string dotlnav_path(const char *sub) @@ -283,6 +289,19 @@ struct userdata { vector &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("(?(x[0-9a-f]{2})+)#") .with_synopsis("") @@ -290,7 +309,7 @@ static struct json_path_handler keymap_def_handlers[] = { .with_pattern("[:|;].*") .with_path_provider([](key_map *km, vector &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 &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 &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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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([](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("(?trace|debug5|debug4|debug3|debug2|debug|info|stats|notice|warning|error|critical|fatal)" + "/") + .with_obj_provider([](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([](struct lnav_theme *cfg, vector &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("(?\\w+)") + .with_synopsis("name") + .with_description("A theme variable definition") + .with_path_provider([](struct lnav_theme *lt, vector &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("(?[^/]+)/") + .with_obj_provider([](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 &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("") + .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("") + .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("") + .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("") + .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 &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 &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 &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 &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 &extra_paths, vector &errors) @@ -452,6 +773,7 @@ void load_config(const vector &extra_paths, vector &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 &extra_paths, vector &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 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 &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; } } diff --git a/src/lnav_config.hh b/src/lnav_config.hh index 02ec5f7c..8f59169b 100644 --- a/src/lnav_config.hh +++ b/src/lnav_config.hh @@ -37,10 +37,17 @@ #include #include #include +#include #include +#include "yajlpp.hh" +#include "log_level.hh" +#include "styling.hh" + class lnav_config_listener { public: + using error_reporter = const std::function; + 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 lc_ui_keymaps; std::map lc_ui_key_overrides; std::map lc_global_vars; + std::map lc_ui_theme_defs; }; extern struct _lnav_config lnav_config; +extern struct _lnav_config rollback_lnav_config; +extern std::map lnav_config_locations; extern struct json_path_handler lnav_config_handlers[]; @@ -111,7 +122,7 @@ void load_config(const std::vector &extra_paths, void reset_config(const std::string &path); -void reload_config(); +void reload_config(std::vector &errors); std::string save_config(); diff --git a/src/log_format_loader.cc b/src/log_format_loader.cc index 7c131df3..35cefc35 100644 --- a/src/log_format_loader.cc +++ b/src/log_format_loader.cc @@ -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 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 handle(yajl_free); @@ -807,6 +804,12 @@ static void load_from_path(const string &path, std::vector &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 format_list; @@ -815,9 +818,9 @@ static void load_from_path(const string &path, std::vector &errors) log_warning("Empty format file: %s", filename.c_str()); } else { - for (vector::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 &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::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()) { diff --git a/src/log_level.cc b/src/log_level.cc index e6d9c18a..1f391db5 100644 --- a/src/log_level.cc +++ b/src/log_level.cc @@ -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': diff --git a/src/log_level.hh b/src/log_level.hh index 2baa4937..4bb5543d 100644 --- a/src/log_level.hh +++ b/src/log_level.hh @@ -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]; diff --git a/src/log_level_re.cc b/src/log_level_re.cc index 8ce88c74..339c8594 100644 --- a/src/log_level_re.cc +++ b/src/log_level_re.cc @@ -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" diff --git a/src/log_level_re.re b/src/log_level_re.re index 5b453447..313ae52e 100644 --- a/src/log_level_re.re +++ b/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); } diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index 4ee47a58..1ce0a0a1 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -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))); diff --git a/src/pcrepp.hh b/src/pcrepp.hh index 4c951c96..d2857aaf 100644 --- a/src/pcrepp.hh +++ b/src/pcrepp.hh @@ -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 diff --git a/src/preview_status_source.hh b/src/preview_status_source.hh index 0a38550b..b2c17d83 100644 --- a/src/preview_status_source.hh +++ b/src/preview_status_source.hh @@ -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; }; diff --git a/src/readline_callbacks.cc b/src/readline_callbacks.cc index 7ff93276..c3b178d2 100644 --- a/src/readline_callbacks.cc +++ b/src/readline_callbacks.cc @@ -507,6 +507,10 @@ void rl_abort(void *dummy, readline_curses *rc) tc->get_highlights().erase("$preview"); tc->get_highlights().erase("$bodypreview"); + vector errors; + lnav_config = rollback_lnav_config; + reload_config(errors); + lnav_data.ld_bottom_source.grep_error(""); switch (lnav_data.ld_mode) { case LNM_SEARCH: diff --git a/src/readline_curses.cc b/src/readline_curses.cc index 81c17959..17d85947 100644 --- a/src/readline_curses.cc +++ b/src/readline_curses.cc @@ -56,6 +56,7 @@ #include #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 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 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 &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 &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 &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 && diff --git a/src/readline_curses.hh b/src/readline_curses.hh index 79004b3e..566c19d7 100644 --- a/src/readline_curses.hh +++ b/src/readline_curses.hh @@ -209,6 +209,8 @@ public: }; static int command_complete(int, int); + + std::map 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 &prefix, + const std::string &value); + + void clear_prefixes(int context); + void add_possibility(int context, const std::string &type, const std::string &value); diff --git a/src/readline_highlighters.cc b/src/readline_highlighters.cc index da4f4dc8..f27162ae 100644 --- a/src/readline_highlighters.cc +++ b/src/readline_highlighters.cc @@ -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; diff --git a/src/readline_possibilities.cc b/src/readline_possibilities.cc index 6d77dfb1..9f613c1f 100644 --- a/src/readline_possibilities.cc +++ b/src/readline_possibilities.cc @@ -281,14 +281,35 @@ void add_mark_possibilities() void add_config_possibilities() { readline_curses *rc = lnav_data.ld_rl_view; - vector config_options; + set 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{"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() diff --git a/src/default-config.json b/src/root-config.json similarity index 55% rename from src/default-config.json rename to src/root-config.json index 9ca052a1..06c24ce2 100644 --- a/src/default-config.json +++ b/src/root-config.json @@ -1,6 +1,7 @@ { "ui" : { "clock-format": "%a %b %d %H:%M:%S %Z", - "keymap": "default" + "keymap": "default", + "theme": "default" } } diff --git a/src/session_data.cc b/src/session_data.cc index b07e964d..aa72287f 100644 --- a/src/session_data.cc +++ b/src/session_data.cc @@ -1280,7 +1280,6 @@ void save_session() continue; } - filter_stack::iterator filter_iter; filter_stack &fs = tss->get_filters(); view_map.gen("commands"); diff --git a/src/shlex.hh b/src/shlex.hh index 0435e927..01acd235 100644 --- a/src/shlex.hh +++ b/src/shlex.hh @@ -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); diff --git a/src/statusview_curses.cc b/src/statusview_curses.cc index 4aae6512..c460d50b 100644 --- a/src/statusview_curses.cc +++ b/src/statusview_curses.cc @@ -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; } } } diff --git a/src/statusview_curses.hh b/src/statusview_curses.hh index b2c465a6..b5886413 100644 --- a/src/statusview_curses.hh +++ b/src/statusview_curses.hh @@ -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; }; diff --git a/src/styling.hh b/src/styling.hh new file mode 100644 index 00000000..00531bd5 --- /dev/null +++ b/src/styling.hh @@ -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 +#include + +#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 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 lt_level_styles; +}; + +#endif diff --git a/src/textfile_highlighters.cc b/src/textfile_highlighters.cc index 24d8d675..cda0e352 100644 --- a/src/textfile_highlighters.cc +++ b/src/textfile_highlighters.cc @@ -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*[!=+\\-*/|&^]?=|" "(?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) { diff --git a/src/view_curses.cc b/src/view_curses.cc index 64f9ce44..99f2ee33 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -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([](const auto &pc, xterm_color *xc) { return &xc->xc_color; }) - .with_children(xterm_color_rgb_handler), + .with_obj_provider([](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>( - [](const yajlpp_provider_context &ypc, vector *palette) { + .with_obj_provider>( + [](const yajlpp_provider_context &ypc, vector *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 xc_palette; -} xterm_colors; + vector 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 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(LEVEL_UNKNOWN + 1); + level < LEVEL__MAX; + level = static_cast(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) diff --git a/src/view_curses.hh b/src/view_curses.hh index d01574e3..4ed096af 100644 --- a/src/view_curses.hh +++ b/src/view_curses.hh @@ -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 to_attrs(int &pair_base, + const lnav_theme <, const style_config &sc, + lnav_config_listener::error_reporter &reporter); + + std::pair 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 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; diff --git a/src/xterm-palette.hh b/src/xterm-palette.hh index 2d4fc14c..58b6ef11 100644 --- a/src/xterm-palette.hh +++ b/src/xterm-palette.hh @@ -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 diff --git a/src/xterm-palette.json b/src/xterm-palette.json index 6df76121..4c64d999 100644 --- a/src/xterm-palette.json +++ b/src/xterm-palette.json @@ -1 +1,3842 @@ -[{"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"},{"colorId":8,"hexString":"#808080","rgb":{"r":128,"g":128,"b":128},"hsl":{"h":0,"s":0,"l":50},"name":"Grey"},{"colorId":9,"hexString":"#ff0000","rgb":{"r":255,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":50},"name":"Red"},{"colorId":10,"hexString":"#00ff00","rgb":{"r":0,"g":255,"b":0},"hsl":{"h":120,"s":100,"l":50},"name":"Lime"},{"colorId":11,"hexString":"#ffff00","rgb":{"r":255,"g":255,"b":0},"hsl":{"h":60,"s":100,"l":50},"name":"Yellow"},{"colorId":12,"hexString":"#0000ff","rgb":{"r":0,"g":0,"b":255},"hsl":{"h":240,"s":100,"l":50},"name":"Blue"},{"colorId":13,"hexString":"#ff00ff","rgb":{"r":255,"g":0,"b":255},"hsl":{"h":300,"s":100,"l":50},"name":"Fuchsia"},{"colorId":14,"hexString":"#00ffff","rgb":{"r":0,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":50},"name":"Aqua"},{"colorId":15,"hexString":"#ffffff","rgb":{"r":255,"g":255,"b":255},"hsl":{"h":0,"s":0,"l":100},"name":"White"},{"colorId":16,"hexString":"#000000","rgb":{"r":0,"g":0,"b":0},"hsl":{"h":0,"s":0,"l":0},"name":"Grey0"},{"colorId":17,"hexString":"#00005f","rgb":{"r":0,"g":0,"b":95},"hsl":{"h":240,"s":100,"l":18},"name":"NavyBlue"},{"colorId":18,"hexString":"#000087","rgb":{"r":0,"g":0,"b":135},"hsl":{"h":240,"s":100,"l":26},"name":"DarkBlue"},{"colorId":19,"hexString":"#0000af","rgb":{"r":0,"g":0,"b":175},"hsl":{"h":240,"s":100,"l":34},"name":"Blue3"},{"colorId":20,"hexString":"#0000d7","rgb":{"r":0,"g":0,"b":215},"hsl":{"h":240,"s":100,"l":42},"name":"Blue3"},{"colorId":21,"hexString":"#0000ff","rgb":{"r":0,"g":0,"b":255},"hsl":{"h":240,"s":100,"l":50},"name":"Blue1"},{"colorId":22,"hexString":"#005f00","rgb":{"r":0,"g":95,"b":0},"hsl":{"h":120,"s":100,"l":18},"name":"DarkGreen"},{"colorId":23,"hexString":"#005f5f","rgb":{"r":0,"g":95,"b":95},"hsl":{"h":180,"s":100,"l":18},"name":"DeepSkyBlue4"},{"colorId":24,"hexString":"#005f87","rgb":{"r":0,"g":95,"b":135},"hsl":{"h":197.777777777778,"s":100,"l":26},"name":"DeepSkyBlue4"},{"colorId":25,"hexString":"#005faf","rgb":{"r":0,"g":95,"b":175},"hsl":{"h":207.428571428571,"s":100,"l":34},"name":"DeepSkyBlue4"},{"colorId":26,"hexString":"#005fd7","rgb":{"r":0,"g":95,"b":215},"hsl":{"h":213.488372093023,"s":100,"l":42},"name":"DodgerBlue3"},{"colorId":27,"hexString":"#005fff","rgb":{"r":0,"g":95,"b":255},"hsl":{"h":217.647058823529,"s":100,"l":50},"name":"DodgerBlue2"},{"colorId":28,"hexString":"#008700","rgb":{"r":0,"g":135,"b":0},"hsl":{"h":120,"s":100,"l":26},"name":"Green4"},{"colorId":29,"hexString":"#00875f","rgb":{"r":0,"g":135,"b":95},"hsl":{"h":162.222222222222,"s":100,"l":26},"name":"SpringGreen4"},{"colorId":30,"hexString":"#008787","rgb":{"r":0,"g":135,"b":135},"hsl":{"h":180,"s":100,"l":26},"name":"Turquoise4"},{"colorId":31,"hexString":"#0087af","rgb":{"r":0,"g":135,"b":175},"hsl":{"h":193.714285714286,"s":100,"l":34},"name":"DeepSkyBlue3"},{"colorId":32,"hexString":"#0087d7","rgb":{"r":0,"g":135,"b":215},"hsl":{"h":202.325581395349,"s":100,"l":42},"name":"DeepSkyBlue3"},{"colorId":33,"hexString":"#0087ff","rgb":{"r":0,"g":135,"b":255},"hsl":{"h":208.235294117647,"s":100,"l":50},"name":"DodgerBlue1"},{"colorId":34,"hexString":"#00af00","rgb":{"r":0,"g":175,"b":0},"hsl":{"h":120,"s":100,"l":34},"name":"Green3"},{"colorId":35,"hexString":"#00af5f","rgb":{"r":0,"g":175,"b":95},"hsl":{"h":152.571428571429,"s":100,"l":34},"name":"SpringGreen3"},{"colorId":36,"hexString":"#00af87","rgb":{"r":0,"g":175,"b":135},"hsl":{"h":166.285714285714,"s":100,"l":34},"name":"DarkCyan"},{"colorId":37,"hexString":"#00afaf","rgb":{"r":0,"g":175,"b":175},"hsl":{"h":180,"s":100,"l":34},"name":"LightSeaGreen"},{"colorId":38,"hexString":"#00afd7","rgb":{"r":0,"g":175,"b":215},"hsl":{"h":191.162790697674,"s":100,"l":42},"name":"DeepSkyBlue2"},{"colorId":39,"hexString":"#00afff","rgb":{"r":0,"g":175,"b":255},"hsl":{"h":198.823529411765,"s":100,"l":50},"name":"DeepSkyBlue1"},{"colorId":40,"hexString":"#00d700","rgb":{"r":0,"g":215,"b":0},"hsl":{"h":120,"s":100,"l":42},"name":"Green3"},{"colorId":41,"hexString":"#00d75f","rgb":{"r":0,"g":215,"b":95},"hsl":{"h":146.511627906977,"s":100,"l":42},"name":"SpringGreen3"},{"colorId":42,"hexString":"#00d787","rgb":{"r":0,"g":215,"b":135},"hsl":{"h":157.674418604651,"s":100,"l":42},"name":"SpringGreen2"},{"colorId":43,"hexString":"#00d7af","rgb":{"r":0,"g":215,"b":175},"hsl":{"h":168.837209302326,"s":100,"l":42},"name":"Cyan3"},{"colorId":44,"hexString":"#00d7d7","rgb":{"r":0,"g":215,"b":215},"hsl":{"h":180,"s":100,"l":42},"name":"DarkTurquoise"},{"colorId":45,"hexString":"#00d7ff","rgb":{"r":0,"g":215,"b":255},"hsl":{"h":189.411764705882,"s":100,"l":50},"name":"Turquoise2"},{"colorId":46,"hexString":"#00ff00","rgb":{"r":0,"g":255,"b":0},"hsl":{"h":120,"s":100,"l":50},"name":"Green1"},{"colorId":47,"hexString":"#00ff5f","rgb":{"r":0,"g":255,"b":95},"hsl":{"h":142.352941176471,"s":100,"l":50},"name":"SpringGreen2"},{"colorId":48,"hexString":"#00ff87","rgb":{"r":0,"g":255,"b":135},"hsl":{"h":151.764705882353,"s":100,"l":50},"name":"SpringGreen1"},{"colorId":49,"hexString":"#00ffaf","rgb":{"r":0,"g":255,"b":175},"hsl":{"h":161.176470588235,"s":100,"l":50},"name":"MediumSpringGreen"},{"colorId":50,"hexString":"#00ffd7","rgb":{"r":0,"g":255,"b":215},"hsl":{"h":170.588235294118,"s":100,"l":50},"name":"Cyan2"},{"colorId":51,"hexString":"#00ffff","rgb":{"r":0,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":50},"name":"Cyan1"},{"colorId":52,"hexString":"#5f0000","rgb":{"r":95,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":18},"name":"DarkRed"},{"colorId":53,"hexString":"#5f005f","rgb":{"r":95,"g":0,"b":95},"hsl":{"h":300,"s":100,"l":18},"name":"DeepPink4"},{"colorId":54,"hexString":"#5f0087","rgb":{"r":95,"g":0,"b":135},"hsl":{"h":282.222222222222,"s":100,"l":26},"name":"Purple4"},{"colorId":55,"hexString":"#5f00af","rgb":{"r":95,"g":0,"b":175},"hsl":{"h":272.571428571429,"s":100,"l":34},"name":"Purple4"},{"colorId":56,"hexString":"#5f00d7","rgb":{"r":95,"g":0,"b":215},"hsl":{"h":266.511627906977,"s":100,"l":42},"name":"Purple3"},{"colorId":57,"hexString":"#5f00ff","rgb":{"r":95,"g":0,"b":255},"hsl":{"h":262.352941176471,"s":100,"l":50},"name":"BlueViolet"},{"colorId":58,"hexString":"#5f5f00","rgb":{"r":95,"g":95,"b":0},"hsl":{"h":60,"s":100,"l":18},"name":"Orange4"},{"colorId":59,"hexString":"#5f5f5f","rgb":{"r":95,"g":95,"b":95},"hsl":{"h":0,"s":0,"l":37},"name":"Grey37"},{"colorId":60,"hexString":"#5f5f87","rgb":{"r":95,"g":95,"b":135},"hsl":{"h":240,"s":17,"l":45},"name":"MediumPurple4"},{"colorId":61,"hexString":"#5f5faf","rgb":{"r":95,"g":95,"b":175},"hsl":{"h":240,"s":33,"l":52},"name":"SlateBlue3"},{"colorId":62,"hexString":"#5f5fd7","rgb":{"r":95,"g":95,"b":215},"hsl":{"h":240,"s":60,"l":60},"name":"SlateBlue3"},{"colorId":63,"hexString":"#5f5fff","rgb":{"r":95,"g":95,"b":255},"hsl":{"h":240,"s":100,"l":68},"name":"RoyalBlue1"},{"colorId":64,"hexString":"#5f8700","rgb":{"r":95,"g":135,"b":0},"hsl":{"h":77.7777777777778,"s":100,"l":26},"name":"Chartreuse4"},{"colorId":65,"hexString":"#5f875f","rgb":{"r":95,"g":135,"b":95},"hsl":{"h":120,"s":17,"l":45},"name":"DarkSeaGreen4"},{"colorId":66,"hexString":"#5f8787","rgb":{"r":95,"g":135,"b":135},"hsl":{"h":180,"s":17,"l":45},"name":"PaleTurquoise4"},{"colorId":67,"hexString":"#5f87af","rgb":{"r":95,"g":135,"b":175},"hsl":{"h":210,"s":33,"l":52},"name":"SteelBlue"},{"colorId":68,"hexString":"#5f87d7","rgb":{"r":95,"g":135,"b":215},"hsl":{"h":220,"s":60,"l":60},"name":"SteelBlue3"},{"colorId":69,"hexString":"#5f87ff","rgb":{"r":95,"g":135,"b":255},"hsl":{"h":225,"s":100,"l":68},"name":"CornflowerBlue"},{"colorId":70,"hexString":"#5faf00","rgb":{"r":95,"g":175,"b":0},"hsl":{"h":87.4285714285714,"s":100,"l":34},"name":"Chartreuse3"},{"colorId":71,"hexString":"#5faf5f","rgb":{"r":95,"g":175,"b":95},"hsl":{"h":120,"s":33,"l":52},"name":"DarkSeaGreen4"},{"colorId":72,"hexString":"#5faf87","rgb":{"r":95,"g":175,"b":135},"hsl":{"h":150,"s":33,"l":52},"name":"CadetBlue"},{"colorId":73,"hexString":"#5fafaf","rgb":{"r":95,"g":175,"b":175},"hsl":{"h":180,"s":33,"l":52},"name":"CadetBlue"},{"colorId":74,"hexString":"#5fafd7","rgb":{"r":95,"g":175,"b":215},"hsl":{"h":200,"s":60,"l":60},"name":"SkyBlue3"},{"colorId":75,"hexString":"#5fafff","rgb":{"r":95,"g":175,"b":255},"hsl":{"h":210,"s":100,"l":68},"name":"SteelBlue1"},{"colorId":76,"hexString":"#5fd700","rgb":{"r":95,"g":215,"b":0},"hsl":{"h":93.4883720930233,"s":100,"l":42},"name":"Chartreuse3"},{"colorId":77,"hexString":"#5fd75f","rgb":{"r":95,"g":215,"b":95},"hsl":{"h":120,"s":60,"l":60},"name":"PaleGreen3"},{"colorId":78,"hexString":"#5fd787","rgb":{"r":95,"g":215,"b":135},"hsl":{"h":140,"s":60,"l":60},"name":"SeaGreen3"},{"colorId":79,"hexString":"#5fd7af","rgb":{"r":95,"g":215,"b":175},"hsl":{"h":160,"s":60,"l":60},"name":"Aquamarine3"},{"colorId":80,"hexString":"#5fd7d7","rgb":{"r":95,"g":215,"b":215},"hsl":{"h":180,"s":60,"l":60},"name":"MediumTurquoise"},{"colorId":81,"hexString":"#5fd7ff","rgb":{"r":95,"g":215,"b":255},"hsl":{"h":195,"s":100,"l":68},"name":"SteelBlue1"},{"colorId":82,"hexString":"#5fff00","rgb":{"r":95,"g":255,"b":0},"hsl":{"h":97.6470588235294,"s":100,"l":50},"name":"Chartreuse2"},{"colorId":83,"hexString":"#5fff5f","rgb":{"r":95,"g":255,"b":95},"hsl":{"h":120,"s":100,"l":68},"name":"SeaGreen2"},{"colorId":84,"hexString":"#5fff87","rgb":{"r":95,"g":255,"b":135},"hsl":{"h":135,"s":100,"l":68},"name":"SeaGreen1"},{"colorId":85,"hexString":"#5fffaf","rgb":{"r":95,"g":255,"b":175},"hsl":{"h":150,"s":100,"l":68},"name":"SeaGreen1"},{"colorId":86,"hexString":"#5fffd7","rgb":{"r":95,"g":255,"b":215},"hsl":{"h":165,"s":100,"l":68},"name":"Aquamarine1"},{"colorId":87,"hexString":"#5fffff","rgb":{"r":95,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":68},"name":"DarkSlateGray2"},{"colorId":88,"hexString":"#870000","rgb":{"r":135,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":26},"name":"DarkRed"},{"colorId":89,"hexString":"#87005f","rgb":{"r":135,"g":0,"b":95},"hsl":{"h":317.777777777778,"s":100,"l":26},"name":"DeepPink4"},{"colorId":90,"hexString":"#870087","rgb":{"r":135,"g":0,"b":135},"hsl":{"h":300,"s":100,"l":26},"name":"DarkMagenta"},{"colorId":91,"hexString":"#8700af","rgb":{"r":135,"g":0,"b":175},"hsl":{"h":286.285714285714,"s":100,"l":34},"name":"DarkMagenta"},{"colorId":92,"hexString":"#8700d7","rgb":{"r":135,"g":0,"b":215},"hsl":{"h":277.674418604651,"s":100,"l":42},"name":"DarkViolet"},{"colorId":93,"hexString":"#8700ff","rgb":{"r":135,"g":0,"b":255},"hsl":{"h":271.764705882353,"s":100,"l":50},"name":"Purple"},{"colorId":94,"hexString":"#875f00","rgb":{"r":135,"g":95,"b":0},"hsl":{"h":42.2222222222222,"s":100,"l":26},"name":"Orange4"},{"colorId":95,"hexString":"#875f5f","rgb":{"r":135,"g":95,"b":95},"hsl":{"h":0,"s":17,"l":45},"name":"LightPink4"},{"colorId":96,"hexString":"#875f87","rgb":{"r":135,"g":95,"b":135},"hsl":{"h":300,"s":17,"l":45},"name":"Plum4"},{"colorId":97,"hexString":"#875faf","rgb":{"r":135,"g":95,"b":175},"hsl":{"h":270,"s":33,"l":52},"name":"MediumPurple3"},{"colorId":98,"hexString":"#875fd7","rgb":{"r":135,"g":95,"b":215},"hsl":{"h":260,"s":60,"l":60},"name":"MediumPurple3"},{"colorId":99,"hexString":"#875fff","rgb":{"r":135,"g":95,"b":255},"hsl":{"h":255,"s":100,"l":68},"name":"SlateBlue1"},{"colorId":100,"hexString":"#878700","rgb":{"r":135,"g":135,"b":0},"hsl":{"h":60,"s":100,"l":26},"name":"Yellow4"},{"colorId":101,"hexString":"#87875f","rgb":{"r":135,"g":135,"b":95},"hsl":{"h":60,"s":17,"l":45},"name":"Wheat4"},{"colorId":102,"hexString":"#878787","rgb":{"r":135,"g":135,"b":135},"hsl":{"h":0,"s":0,"l":52},"name":"Grey53"},{"colorId":103,"hexString":"#8787af","rgb":{"r":135,"g":135,"b":175},"hsl":{"h":240,"s":20,"l":60},"name":"LightSlateGrey"},{"colorId":104,"hexString":"#8787d7","rgb":{"r":135,"g":135,"b":215},"hsl":{"h":240,"s":50,"l":68},"name":"MediumPurple"},{"colorId":105,"hexString":"#8787ff","rgb":{"r":135,"g":135,"b":255},"hsl":{"h":240,"s":100,"l":76},"name":"LightSlateBlue"},{"colorId":106,"hexString":"#87af00","rgb":{"r":135,"g":175,"b":0},"hsl":{"h":73.7142857142857,"s":100,"l":34},"name":"Yellow4"},{"colorId":107,"hexString":"#87af5f","rgb":{"r":135,"g":175,"b":95},"hsl":{"h":90,"s":33,"l":52},"name":"DarkOliveGreen3"},{"colorId":108,"hexString":"#87af87","rgb":{"r":135,"g":175,"b":135},"hsl":{"h":120,"s":20,"l":60},"name":"DarkSeaGreen"},{"colorId":109,"hexString":"#87afaf","rgb":{"r":135,"g":175,"b":175},"hsl":{"h":180,"s":20,"l":60},"name":"LightSkyBlue3"},{"colorId":110,"hexString":"#87afd7","rgb":{"r":135,"g":175,"b":215},"hsl":{"h":210,"s":50,"l":68},"name":"LightSkyBlue3"},{"colorId":111,"hexString":"#87afff","rgb":{"r":135,"g":175,"b":255},"hsl":{"h":220,"s":100,"l":76},"name":"SkyBlue2"},{"colorId":112,"hexString":"#87d700","rgb":{"r":135,"g":215,"b":0},"hsl":{"h":82.3255813953488,"s":100,"l":42},"name":"Chartreuse2"},{"colorId":113,"hexString":"#87d75f","rgb":{"r":135,"g":215,"b":95},"hsl":{"h":100,"s":60,"l":60},"name":"DarkOliveGreen3"},{"colorId":114,"hexString":"#87d787","rgb":{"r":135,"g":215,"b":135},"hsl":{"h":120,"s":50,"l":68},"name":"PaleGreen3"},{"colorId":115,"hexString":"#87d7af","rgb":{"r":135,"g":215,"b":175},"hsl":{"h":150,"s":50,"l":68},"name":"DarkSeaGreen3"},{"colorId":116,"hexString":"#87d7d7","rgb":{"r":135,"g":215,"b":215},"hsl":{"h":180,"s":50,"l":68},"name":"DarkSlateGray3"},{"colorId":117,"hexString":"#87d7ff","rgb":{"r":135,"g":215,"b":255},"hsl":{"h":200,"s":100,"l":76},"name":"SkyBlue1"},{"colorId":118,"hexString":"#87ff00","rgb":{"r":135,"g":255,"b":0},"hsl":{"h":88.2352941176471,"s":100,"l":50},"name":"Chartreuse1"},{"colorId":119,"hexString":"#87ff5f","rgb":{"r":135,"g":255,"b":95},"hsl":{"h":105,"s":100,"l":68},"name":"LightGreen"},{"colorId":120,"hexString":"#87ff87","rgb":{"r":135,"g":255,"b":135},"hsl":{"h":120,"s":100,"l":76},"name":"LightGreen"},{"colorId":121,"hexString":"#87ffaf","rgb":{"r":135,"g":255,"b":175},"hsl":{"h":140,"s":100,"l":76},"name":"PaleGreen1"},{"colorId":122,"hexString":"#87ffd7","rgb":{"r":135,"g":255,"b":215},"hsl":{"h":160,"s":100,"l":76},"name":"Aquamarine1"},{"colorId":123,"hexString":"#87ffff","rgb":{"r":135,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":76},"name":"DarkSlateGray1"},{"colorId":124,"hexString":"#af0000","rgb":{"r":175,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":34},"name":"Red3"},{"colorId":125,"hexString":"#af005f","rgb":{"r":175,"g":0,"b":95},"hsl":{"h":327.428571428571,"s":100,"l":34},"name":"DeepPink4"},{"colorId":126,"hexString":"#af0087","rgb":{"r":175,"g":0,"b":135},"hsl":{"h":313.714285714286,"s":100,"l":34},"name":"MediumVioletRed"},{"colorId":127,"hexString":"#af00af","rgb":{"r":175,"g":0,"b":175},"hsl":{"h":300,"s":100,"l":34},"name":"Magenta3"},{"colorId":128,"hexString":"#af00d7","rgb":{"r":175,"g":0,"b":215},"hsl":{"h":288.837209302326,"s":100,"l":42},"name":"DarkViolet"},{"colorId":129,"hexString":"#af00ff","rgb":{"r":175,"g":0,"b":255},"hsl":{"h":281.176470588235,"s":100,"l":50},"name":"Purple"},{"colorId":130,"hexString":"#af5f00","rgb":{"r":175,"g":95,"b":0},"hsl":{"h":32.5714285714286,"s":100,"l":34},"name":"DarkOrange3"},{"colorId":131,"hexString":"#af5f5f","rgb":{"r":175,"g":95,"b":95},"hsl":{"h":0,"s":33,"l":52},"name":"IndianRed"},{"colorId":132,"hexString":"#af5f87","rgb":{"r":175,"g":95,"b":135},"hsl":{"h":330,"s":33,"l":52},"name":"HotPink3"},{"colorId":133,"hexString":"#af5faf","rgb":{"r":175,"g":95,"b":175},"hsl":{"h":300,"s":33,"l":52},"name":"MediumOrchid3"},{"colorId":134,"hexString":"#af5fd7","rgb":{"r":175,"g":95,"b":215},"hsl":{"h":280,"s":60,"l":60},"name":"MediumOrchid"},{"colorId":135,"hexString":"#af5fff","rgb":{"r":175,"g":95,"b":255},"hsl":{"h":270,"s":100,"l":68},"name":"MediumPurple2"},{"colorId":136,"hexString":"#af8700","rgb":{"r":175,"g":135,"b":0},"hsl":{"h":46.2857142857143,"s":100,"l":34},"name":"DarkGoldenrod"},{"colorId":137,"hexString":"#af875f","rgb":{"r":175,"g":135,"b":95},"hsl":{"h":30,"s":33,"l":52},"name":"LightSalmon3"},{"colorId":138,"hexString":"#af8787","rgb":{"r":175,"g":135,"b":135},"hsl":{"h":0,"s":20,"l":60},"name":"RosyBrown"},{"colorId":139,"hexString":"#af87af","rgb":{"r":175,"g":135,"b":175},"hsl":{"h":300,"s":20,"l":60},"name":"Grey63"},{"colorId":140,"hexString":"#af87d7","rgb":{"r":175,"g":135,"b":215},"hsl":{"h":270,"s":50,"l":68},"name":"MediumPurple2"},{"colorId":141,"hexString":"#af87ff","rgb":{"r":175,"g":135,"b":255},"hsl":{"h":260,"s":100,"l":76},"name":"MediumPurple1"},{"colorId":142,"hexString":"#afaf00","rgb":{"r":175,"g":175,"b":0},"hsl":{"h":60,"s":100,"l":34},"name":"Gold3"},{"colorId":143,"hexString":"#afaf5f","rgb":{"r":175,"g":175,"b":95},"hsl":{"h":60,"s":33,"l":52},"name":"DarkKhaki"},{"colorId":144,"hexString":"#afaf87","rgb":{"r":175,"g":175,"b":135},"hsl":{"h":60,"s":20,"l":60},"name":"NavajoWhite3"},{"colorId":145,"hexString":"#afafaf","rgb":{"r":175,"g":175,"b":175},"hsl":{"h":0,"s":0,"l":68},"name":"Grey69"},{"colorId":146,"hexString":"#afafd7","rgb":{"r":175,"g":175,"b":215},"hsl":{"h":240,"s":33,"l":76},"name":"LightSteelBlue3"},{"colorId":147,"hexString":"#afafff","rgb":{"r":175,"g":175,"b":255},"hsl":{"h":240,"s":100,"l":84},"name":"LightSteelBlue"},{"colorId":148,"hexString":"#afd700","rgb":{"r":175,"g":215,"b":0},"hsl":{"h":71.1627906976744,"s":100,"l":42},"name":"Yellow3"},{"colorId":149,"hexString":"#afd75f","rgb":{"r":175,"g":215,"b":95},"hsl":{"h":80,"s":60,"l":60},"name":"DarkOliveGreen3"},{"colorId":150,"hexString":"#afd787","rgb":{"r":175,"g":215,"b":135},"hsl":{"h":90,"s":50,"l":68},"name":"DarkSeaGreen3"},{"colorId":151,"hexString":"#afd7af","rgb":{"r":175,"g":215,"b":175},"hsl":{"h":120,"s":33,"l":76},"name":"DarkSeaGreen2"},{"colorId":152,"hexString":"#afd7d7","rgb":{"r":175,"g":215,"b":215},"hsl":{"h":180,"s":33,"l":76},"name":"LightCyan3"},{"colorId":153,"hexString":"#afd7ff","rgb":{"r":175,"g":215,"b":255},"hsl":{"h":210,"s":100,"l":84},"name":"LightSkyBlue1"},{"colorId":154,"hexString":"#afff00","rgb":{"r":175,"g":255,"b":0},"hsl":{"h":78.8235294117647,"s":100,"l":50},"name":"GreenYellow"},{"colorId":155,"hexString":"#afff5f","rgb":{"r":175,"g":255,"b":95},"hsl":{"h":90,"s":100,"l":68},"name":"DarkOliveGreen2"},{"colorId":156,"hexString":"#afff87","rgb":{"r":175,"g":255,"b":135},"hsl":{"h":100,"s":100,"l":76},"name":"PaleGreen1"},{"colorId":157,"hexString":"#afffaf","rgb":{"r":175,"g":255,"b":175},"hsl":{"h":120,"s":100,"l":84},"name":"DarkSeaGreen2"},{"colorId":158,"hexString":"#afffd7","rgb":{"r":175,"g":255,"b":215},"hsl":{"h":150,"s":100,"l":84},"name":"DarkSeaGreen1"},{"colorId":159,"hexString":"#afffff","rgb":{"r":175,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":84},"name":"PaleTurquoise1"},{"colorId":160,"hexString":"#d70000","rgb":{"r":215,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":42},"name":"Red3"},{"colorId":161,"hexString":"#d7005f","rgb":{"r":215,"g":0,"b":95},"hsl":{"h":333.488372093023,"s":100,"l":42},"name":"DeepPink3"},{"colorId":162,"hexString":"#d70087","rgb":{"r":215,"g":0,"b":135},"hsl":{"h":322.325581395349,"s":100,"l":42},"name":"DeepPink3"},{"colorId":163,"hexString":"#d700af","rgb":{"r":215,"g":0,"b":175},"hsl":{"h":311.162790697674,"s":100,"l":42},"name":"Magenta3"},{"colorId":164,"hexString":"#d700d7","rgb":{"r":215,"g":0,"b":215},"hsl":{"h":300,"s":100,"l":42},"name":"Magenta3"},{"colorId":165,"hexString":"#d700ff","rgb":{"r":215,"g":0,"b":255},"hsl":{"h":290.588235294118,"s":100,"l":50},"name":"Magenta2"},{"colorId":166,"hexString":"#d75f00","rgb":{"r":215,"g":95,"b":0},"hsl":{"h":26.5116279069767,"s":100,"l":42},"name":"DarkOrange3"},{"colorId":167,"hexString":"#d75f5f","rgb":{"r":215,"g":95,"b":95},"hsl":{"h":0,"s":60,"l":60},"name":"IndianRed"},{"colorId":168,"hexString":"#d75f87","rgb":{"r":215,"g":95,"b":135},"hsl":{"h":340,"s":60,"l":60},"name":"HotPink3"},{"colorId":169,"hexString":"#d75faf","rgb":{"r":215,"g":95,"b":175},"hsl":{"h":320,"s":60,"l":60},"name":"HotPink2"},{"colorId":170,"hexString":"#d75fd7","rgb":{"r":215,"g":95,"b":215},"hsl":{"h":300,"s":60,"l":60},"name":"Orchid"},{"colorId":171,"hexString":"#d75fff","rgb":{"r":215,"g":95,"b":255},"hsl":{"h":285,"s":100,"l":68},"name":"MediumOrchid1"},{"colorId":172,"hexString":"#d78700","rgb":{"r":215,"g":135,"b":0},"hsl":{"h":37.6744186046512,"s":100,"l":42},"name":"Orange3"},{"colorId":173,"hexString":"#d7875f","rgb":{"r":215,"g":135,"b":95},"hsl":{"h":20,"s":60,"l":60},"name":"LightSalmon3"},{"colorId":174,"hexString":"#d78787","rgb":{"r":215,"g":135,"b":135},"hsl":{"h":0,"s":50,"l":68},"name":"LightPink3"},{"colorId":175,"hexString":"#d787af","rgb":{"r":215,"g":135,"b":175},"hsl":{"h":330,"s":50,"l":68},"name":"Pink3"},{"colorId":176,"hexString":"#d787d7","rgb":{"r":215,"g":135,"b":215},"hsl":{"h":300,"s":50,"l":68},"name":"Plum3"},{"colorId":177,"hexString":"#d787ff","rgb":{"r":215,"g":135,"b":255},"hsl":{"h":280,"s":100,"l":76},"name":"Violet"},{"colorId":178,"hexString":"#d7af00","rgb":{"r":215,"g":175,"b":0},"hsl":{"h":48.8372093023256,"s":100,"l":42},"name":"Gold3"},{"colorId":179,"hexString":"#d7af5f","rgb":{"r":215,"g":175,"b":95},"hsl":{"h":40,"s":60,"l":60},"name":"LightGoldenrod3"},{"colorId":180,"hexString":"#d7af87","rgb":{"r":215,"g":175,"b":135},"hsl":{"h":30,"s":50,"l":68},"name":"Tan"},{"colorId":181,"hexString":"#d7afaf","rgb":{"r":215,"g":175,"b":175},"hsl":{"h":0,"s":33,"l":76},"name":"MistyRose3"},{"colorId":182,"hexString":"#d7afd7","rgb":{"r":215,"g":175,"b":215},"hsl":{"h":300,"s":33,"l":76},"name":"Thistle3"},{"colorId":183,"hexString":"#d7afff","rgb":{"r":215,"g":175,"b":255},"hsl":{"h":270,"s":100,"l":84},"name":"Plum2"},{"colorId":184,"hexString":"#d7d700","rgb":{"r":215,"g":215,"b":0},"hsl":{"h":60,"s":100,"l":42},"name":"Yellow3"},{"colorId":185,"hexString":"#d7d75f","rgb":{"r":215,"g":215,"b":95},"hsl":{"h":60,"s":60,"l":60},"name":"Khaki3"},{"colorId":186,"hexString":"#d7d787","rgb":{"r":215,"g":215,"b":135},"hsl":{"h":60,"s":50,"l":68},"name":"LightGoldenrod2"},{"colorId":187,"hexString":"#d7d7af","rgb":{"r":215,"g":215,"b":175},"hsl":{"h":60,"s":33,"l":76},"name":"LightYellow3"},{"colorId":188,"hexString":"#d7d7d7","rgb":{"r":215,"g":215,"b":215},"hsl":{"h":0,"s":0,"l":84},"name":"Grey84"},{"colorId":189,"hexString":"#d7d7ff","rgb":{"r":215,"g":215,"b":255},"hsl":{"h":240,"s":100,"l":92},"name":"LightSteelBlue1"},{"colorId":190,"hexString":"#d7ff00","rgb":{"r":215,"g":255,"b":0},"hsl":{"h":69.4117647058823,"s":100,"l":50},"name":"Yellow2"},{"colorId":191,"hexString":"#d7ff5f","rgb":{"r":215,"g":255,"b":95},"hsl":{"h":75,"s":100,"l":68},"name":"DarkOliveGreen1"},{"colorId":192,"hexString":"#d7ff87","rgb":{"r":215,"g":255,"b":135},"hsl":{"h":80,"s":100,"l":76},"name":"DarkOliveGreen1"},{"colorId":193,"hexString":"#d7ffaf","rgb":{"r":215,"g":255,"b":175},"hsl":{"h":90,"s":100,"l":84},"name":"DarkSeaGreen1"},{"colorId":194,"hexString":"#d7ffd7","rgb":{"r":215,"g":255,"b":215},"hsl":{"h":120,"s":100,"l":92},"name":"Honeydew2"},{"colorId":195,"hexString":"#d7ffff","rgb":{"r":215,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":92},"name":"LightCyan1"},{"colorId":196,"hexString":"#ff0000","rgb":{"r":255,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":50},"name":"Red1"},{"colorId":197,"hexString":"#ff005f","rgb":{"r":255,"g":0,"b":95},"hsl":{"h":337.647058823529,"s":100,"l":50},"name":"DeepPink2"},{"colorId":198,"hexString":"#ff0087","rgb":{"r":255,"g":0,"b":135},"hsl":{"h":328.235294117647,"s":100,"l":50},"name":"DeepPink1"},{"colorId":199,"hexString":"#ff00af","rgb":{"r":255,"g":0,"b":175},"hsl":{"h":318.823529411765,"s":100,"l":50},"name":"DeepPink1"},{"colorId":200,"hexString":"#ff00d7","rgb":{"r":255,"g":0,"b":215},"hsl":{"h":309.411764705882,"s":100,"l":50},"name":"Magenta2"},{"colorId":201,"hexString":"#ff00ff","rgb":{"r":255,"g":0,"b":255},"hsl":{"h":300,"s":100,"l":50},"name":"Magenta1"},{"colorId":202,"hexString":"#ff5f00","rgb":{"r":255,"g":95,"b":0},"hsl":{"h":22.3529411764706,"s":100,"l":50},"name":"OrangeRed1"},{"colorId":203,"hexString":"#ff5f5f","rgb":{"r":255,"g":95,"b":95},"hsl":{"h":0,"s":100,"l":68},"name":"IndianRed1"},{"colorId":204,"hexString":"#ff5f87","rgb":{"r":255,"g":95,"b":135},"hsl":{"h":345,"s":100,"l":68},"name":"IndianRed1"},{"colorId":205,"hexString":"#ff5faf","rgb":{"r":255,"g":95,"b":175},"hsl":{"h":330,"s":100,"l":68},"name":"HotPink"},{"colorId":206,"hexString":"#ff5fd7","rgb":{"r":255,"g":95,"b":215},"hsl":{"h":315,"s":100,"l":68},"name":"HotPink"},{"colorId":207,"hexString":"#ff5fff","rgb":{"r":255,"g":95,"b":255},"hsl":{"h":300,"s":100,"l":68},"name":"MediumOrchid1"},{"colorId":208,"hexString":"#ff8700","rgb":{"r":255,"g":135,"b":0},"hsl":{"h":31.7647058823529,"s":100,"l":50},"name":"DarkOrange"},{"colorId":209,"hexString":"#ff875f","rgb":{"r":255,"g":135,"b":95},"hsl":{"h":15,"s":100,"l":68},"name":"Salmon1"},{"colorId":210,"hexString":"#ff8787","rgb":{"r":255,"g":135,"b":135},"hsl":{"h":0,"s":100,"l":76},"name":"LightCoral"},{"colorId":211,"hexString":"#ff87af","rgb":{"r":255,"g":135,"b":175},"hsl":{"h":340,"s":100,"l":76},"name":"PaleVioletRed1"},{"colorId":212,"hexString":"#ff87d7","rgb":{"r":255,"g":135,"b":215},"hsl":{"h":320,"s":100,"l":76},"name":"Orchid2"},{"colorId":213,"hexString":"#ff87ff","rgb":{"r":255,"g":135,"b":255},"hsl":{"h":300,"s":100,"l":76},"name":"Orchid1"},{"colorId":214,"hexString":"#ffaf00","rgb":{"r":255,"g":175,"b":0},"hsl":{"h":41.1764705882353,"s":100,"l":50},"name":"Orange1"},{"colorId":215,"hexString":"#ffaf5f","rgb":{"r":255,"g":175,"b":95},"hsl":{"h":30,"s":100,"l":68},"name":"SandyBrown"},{"colorId":216,"hexString":"#ffaf87","rgb":{"r":255,"g":175,"b":135},"hsl":{"h":20,"s":100,"l":76},"name":"LightSalmon1"},{"colorId":217,"hexString":"#ffafaf","rgb":{"r":255,"g":175,"b":175},"hsl":{"h":0,"s":100,"l":84},"name":"LightPink1"},{"colorId":218,"hexString":"#ffafd7","rgb":{"r":255,"g":175,"b":215},"hsl":{"h":330,"s":100,"l":84},"name":"Pink1"},{"colorId":219,"hexString":"#ffafff","rgb":{"r":255,"g":175,"b":255},"hsl":{"h":300,"s":100,"l":84},"name":"Plum1"},{"colorId":220,"hexString":"#ffd700","rgb":{"r":255,"g":215,"b":0},"hsl":{"h":50.5882352941176,"s":100,"l":50},"name":"Gold1"},{"colorId":221,"hexString":"#ffd75f","rgb":{"r":255,"g":215,"b":95},"hsl":{"h":45,"s":100,"l":68},"name":"LightGoldenrod2"},{"colorId":222,"hexString":"#ffd787","rgb":{"r":255,"g":215,"b":135},"hsl":{"h":40,"s":100,"l":76},"name":"LightGoldenrod2"},{"colorId":223,"hexString":"#ffd7af","rgb":{"r":255,"g":215,"b":175},"hsl":{"h":30,"s":100,"l":84},"name":"NavajoWhite1"},{"colorId":224,"hexString":"#ffd7d7","rgb":{"r":255,"g":215,"b":215},"hsl":{"h":0,"s":100,"l":92},"name":"MistyRose1"},{"colorId":225,"hexString":"#ffd7ff","rgb":{"r":255,"g":215,"b":255},"hsl":{"h":300,"s":100,"l":92},"name":"Thistle1"},{"colorId":226,"hexString":"#ffff00","rgb":{"r":255,"g":255,"b":0},"hsl":{"h":60,"s":100,"l":50},"name":"Yellow1"},{"colorId":227,"hexString":"#ffff5f","rgb":{"r":255,"g":255,"b":95},"hsl":{"h":60,"s":100,"l":68},"name":"LightGoldenrod1"},{"colorId":228,"hexString":"#ffff87","rgb":{"r":255,"g":255,"b":135},"hsl":{"h":60,"s":100,"l":76},"name":"Khaki1"},{"colorId":229,"hexString":"#ffffaf","rgb":{"r":255,"g":255,"b":175},"hsl":{"h":60,"s":100,"l":84},"name":"Wheat1"},{"colorId":230,"hexString":"#ffffd7","rgb":{"r":255,"g":255,"b":215},"hsl":{"h":60,"s":100,"l":92},"name":"Cornsilk1"},{"colorId":231,"hexString":"#ffffff","rgb":{"r":255,"g":255,"b":255},"hsl":{"h":0,"s":0,"l":100},"name":"Grey100"},{"colorId":232,"hexString":"#080808","rgb":{"r":8,"g":8,"b":8},"hsl":{"h":0,"s":0,"l":3},"name":"Grey3"},{"colorId":233,"hexString":"#121212","rgb":{"r":18,"g":18,"b":18},"hsl":{"h":0,"s":0,"l":7},"name":"Grey7"},{"colorId":234,"hexString":"#1c1c1c","rgb":{"r":28,"g":28,"b":28},"hsl":{"h":0,"s":0,"l":10},"name":"Grey11"},{"colorId":235,"hexString":"#262626","rgb":{"r":38,"g":38,"b":38},"hsl":{"h":0,"s":0,"l":14},"name":"Grey15"},{"colorId":236,"hexString":"#303030","rgb":{"r":48,"g":48,"b":48},"hsl":{"h":0,"s":0,"l":18},"name":"Grey19"},{"colorId":237,"hexString":"#3a3a3a","rgb":{"r":58,"g":58,"b":58},"hsl":{"h":0,"s":0,"l":22},"name":"Grey23"},{"colorId":238,"hexString":"#444444","rgb":{"r":68,"g":68,"b":68},"hsl":{"h":0,"s":0,"l":26},"name":"Grey27"},{"colorId":239,"hexString":"#4e4e4e","rgb":{"r":78,"g":78,"b":78},"hsl":{"h":0,"s":0,"l":30},"name":"Grey30"},{"colorId":240,"hexString":"#585858","rgb":{"r":88,"g":88,"b":88},"hsl":{"h":0,"s":0,"l":34},"name":"Grey35"},{"colorId":241,"hexString":"#626262","rgb":{"r":98,"g":98,"b":98},"hsl":{"h":0,"s":0,"l":37},"name":"Grey39"},{"colorId":242,"hexString":"#6c6c6c","rgb":{"r":108,"g":108,"b":108},"hsl":{"h":0,"s":0,"l":40},"name":"Grey42"},{"colorId":243,"hexString":"#767676","rgb":{"r":118,"g":118,"b":118},"hsl":{"h":0,"s":0,"l":46},"name":"Grey46"},{"colorId":244,"hexString":"#808080","rgb":{"r":128,"g":128,"b":128},"hsl":{"h":0,"s":0,"l":50},"name":"Grey50"},{"colorId":245,"hexString":"#8a8a8a","rgb":{"r":138,"g":138,"b":138},"hsl":{"h":0,"s":0,"l":54},"name":"Grey54"},{"colorId":246,"hexString":"#949494","rgb":{"r":148,"g":148,"b":148},"hsl":{"h":0,"s":0,"l":58},"name":"Grey58"},{"colorId":247,"hexString":"#9e9e9e","rgb":{"r":158,"g":158,"b":158},"hsl":{"h":0,"s":0,"l":61},"name":"Grey62"},{"colorId":248,"hexString":"#a8a8a8","rgb":{"r":168,"g":168,"b":168},"hsl":{"h":0,"s":0,"l":65},"name":"Grey66"},{"colorId":249,"hexString":"#b2b2b2","rgb":{"r":178,"g":178,"b":178},"hsl":{"h":0,"s":0,"l":69},"name":"Grey70"},{"colorId":250,"hexString":"#bcbcbc","rgb":{"r":188,"g":188,"b":188},"hsl":{"h":0,"s":0,"l":73},"name":"Grey74"},{"colorId":251,"hexString":"#c6c6c6","rgb":{"r":198,"g":198,"b":198},"hsl":{"h":0,"s":0,"l":77},"name":"Grey78"},{"colorId":252,"hexString":"#d0d0d0","rgb":{"r":208,"g":208,"b":208},"hsl":{"h":0,"s":0,"l":81},"name":"Grey82"},{"colorId":253,"hexString":"#dadada","rgb":{"r":218,"g":218,"b":218},"hsl":{"h":0,"s":0,"l":85},"name":"Grey85"},{"colorId":254,"hexString":"#e4e4e4","rgb":{"r":228,"g":228,"b":228},"hsl":{"h":0,"s":0,"l":89},"name":"Grey89"},{"colorId":255,"hexString":"#eeeeee","rgb":{"r":238,"g":238,"b":238},"hsl":{"h":0,"s":0,"l":93},"name":"Grey93"}] \ No newline at end of file +[ + { + "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" + }, + { + "colorId": 8, + "hexString": "#808080", + "rgb": { + "r": 128, + "g": 128, + "b": 128 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 50 + }, + "name": "Grey" + }, + { + "colorId": 9, + "hexString": "#ff0000", + "rgb": { + "r": 255, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 50 + }, + "name": "Red" + }, + { + "colorId": 10, + "hexString": "#00ff00", + "rgb": { + "r": 0, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 50 + }, + "name": "Lime" + }, + { + "colorId": 11, + "hexString": "#ffff00", + "rgb": { + "r": 255, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 50 + }, + "name": "Yellow" + }, + { + "colorId": 12, + "hexString": "#0000ff", + "rgb": { + "r": 0, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 50 + }, + "name": "Blue" + }, + { + "colorId": 13, + "hexString": "#ff00ff", + "rgb": { + "r": 255, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 50 + }, + "name": "Fuchsia" + }, + { + "colorId": 14, + "hexString": "#00ffff", + "rgb": { + "r": 0, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 50 + }, + "name": "Aqua" + }, + { + "colorId": 15, + "hexString": "#ffffff", + "rgb": { + "r": 255, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 100 + }, + "name": "White" + }, + { + "colorId": 16, + "hexString": "#000000", + "rgb": { + "r": 0, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 0 + }, + "name": "Grey0" + }, + { + "colorId": 17, + "hexString": "#00005f", + "rgb": { + "r": 0, + "g": 0, + "b": 95 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 18 + }, + "name": "NavyBlue" + }, + { + "colorId": 18, + "hexString": "#000087", + "rgb": { + "r": 0, + "g": 0, + "b": 135 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 26 + }, + "name": "DarkBlue" + }, + { + "colorId": 19, + "hexString": "#0000af", + "rgb": { + "r": 0, + "g": 0, + "b": 175 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 34 + }, + "name": "Blue3" + }, + { + "colorId": 20, + "hexString": "#0000d7", + "rgb": { + "r": 0, + "g": 0, + "b": 215 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 42 + }, + "name": "Blue3" + }, + { + "colorId": 21, + "hexString": "#0000ff", + "rgb": { + "r": 0, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 50 + }, + "name": "Blue1" + }, + { + "colorId": 22, + "hexString": "#005f00", + "rgb": { + "r": 0, + "g": 95, + "b": 0 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 18 + }, + "name": "DarkGreen" + }, + { + "colorId": 23, + "hexString": "#005f5f", + "rgb": { + "r": 0, + "g": 95, + "b": 95 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 18 + }, + "name": "DeepSkyBlue4" + }, + { + "colorId": 24, + "hexString": "#005f87", + "rgb": { + "r": 0, + "g": 95, + "b": 135 + }, + "hsl": { + "h": 197.777777777778, + "s": 100, + "l": 26 + }, + "name": "DeepSkyBlue4" + }, + { + "colorId": 25, + "hexString": "#005faf", + "rgb": { + "r": 0, + "g": 95, + "b": 175 + }, + "hsl": { + "h": 207.428571428571, + "s": 100, + "l": 34 + }, + "name": "DeepSkyBlue4" + }, + { + "colorId": 26, + "hexString": "#005fd7", + "rgb": { + "r": 0, + "g": 95, + "b": 215 + }, + "hsl": { + "h": 213.488372093023, + "s": 100, + "l": 42 + }, + "name": "DodgerBlue3" + }, + { + "colorId": 27, + "hexString": "#005fff", + "rgb": { + "r": 0, + "g": 95, + "b": 255 + }, + "hsl": { + "h": 217.647058823529, + "s": 100, + "l": 50 + }, + "name": "DodgerBlue2" + }, + { + "colorId": 28, + "hexString": "#008700", + "rgb": { + "r": 0, + "g": 135, + "b": 0 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 26 + }, + "name": "Green4" + }, + { + "colorId": 29, + "hexString": "#00875f", + "rgb": { + "r": 0, + "g": 135, + "b": 95 + }, + "hsl": { + "h": 162.222222222222, + "s": 100, + "l": 26 + }, + "name": "SpringGreen4" + }, + { + "colorId": 30, + "hexString": "#008787", + "rgb": { + "r": 0, + "g": 135, + "b": 135 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 26 + }, + "name": "Turquoise4" + }, + { + "colorId": 31, + "hexString": "#0087af", + "rgb": { + "r": 0, + "g": 135, + "b": 175 + }, + "hsl": { + "h": 193.714285714286, + "s": 100, + "l": 34 + }, + "name": "DeepSkyBlue3" + }, + { + "colorId": 32, + "hexString": "#0087d7", + "rgb": { + "r": 0, + "g": 135, + "b": 215 + }, + "hsl": { + "h": 202.325581395349, + "s": 100, + "l": 42 + }, + "name": "DeepSkyBlue3" + }, + { + "colorId": 33, + "hexString": "#0087ff", + "rgb": { + "r": 0, + "g": 135, + "b": 255 + }, + "hsl": { + "h": 208.235294117647, + "s": 100, + "l": 50 + }, + "name": "DodgerBlue1" + }, + { + "colorId": 34, + "hexString": "#00af00", + "rgb": { + "r": 0, + "g": 175, + "b": 0 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 34 + }, + "name": "Green3" + }, + { + "colorId": 35, + "hexString": "#00af5f", + "rgb": { + "r": 0, + "g": 175, + "b": 95 + }, + "hsl": { + "h": 152.571428571429, + "s": 100, + "l": 34 + }, + "name": "SpringGreen3" + }, + { + "colorId": 36, + "hexString": "#00af87", + "rgb": { + "r": 0, + "g": 175, + "b": 135 + }, + "hsl": { + "h": 166.285714285714, + "s": 100, + "l": 34 + }, + "name": "DarkCyan" + }, + { + "colorId": 37, + "hexString": "#00afaf", + "rgb": { + "r": 0, + "g": 175, + "b": 175 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 34 + }, + "name": "LightSeaGreen" + }, + { + "colorId": 38, + "hexString": "#00afd7", + "rgb": { + "r": 0, + "g": 175, + "b": 215 + }, + "hsl": { + "h": 191.162790697674, + "s": 100, + "l": 42 + }, + "name": "DeepSkyBlue2" + }, + { + "colorId": 39, + "hexString": "#00afff", + "rgb": { + "r": 0, + "g": 175, + "b": 255 + }, + "hsl": { + "h": 198.823529411765, + "s": 100, + "l": 50 + }, + "name": "DeepSkyBlue1" + }, + { + "colorId": 40, + "hexString": "#00d700", + "rgb": { + "r": 0, + "g": 215, + "b": 0 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 42 + }, + "name": "Green3" + }, + { + "colorId": 41, + "hexString": "#00d75f", + "rgb": { + "r": 0, + "g": 215, + "b": 95 + }, + "hsl": { + "h": 146.511627906977, + "s": 100, + "l": 42 + }, + "name": "SpringGreen3" + }, + { + "colorId": 42, + "hexString": "#00d787", + "rgb": { + "r": 0, + "g": 215, + "b": 135 + }, + "hsl": { + "h": 157.674418604651, + "s": 100, + "l": 42 + }, + "name": "SpringGreen2" + }, + { + "colorId": 43, + "hexString": "#00d7af", + "rgb": { + "r": 0, + "g": 215, + "b": 175 + }, + "hsl": { + "h": 168.837209302326, + "s": 100, + "l": 42 + }, + "name": "Cyan3" + }, + { + "colorId": 44, + "hexString": "#00d7d7", + "rgb": { + "r": 0, + "g": 215, + "b": 215 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 42 + }, + "name": "DarkTurquoise" + }, + { + "colorId": 45, + "hexString": "#00d7ff", + "rgb": { + "r": 0, + "g": 215, + "b": 255 + }, + "hsl": { + "h": 189.411764705882, + "s": 100, + "l": 50 + }, + "name": "Turquoise2" + }, + { + "colorId": 46, + "hexString": "#00ff00", + "rgb": { + "r": 0, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 50 + }, + "name": "Green1" + }, + { + "colorId": 47, + "hexString": "#00ff5f", + "rgb": { + "r": 0, + "g": 255, + "b": 95 + }, + "hsl": { + "h": 142.352941176471, + "s": 100, + "l": 50 + }, + "name": "SpringGreen2" + }, + { + "colorId": 48, + "hexString": "#00ff87", + "rgb": { + "r": 0, + "g": 255, + "b": 135 + }, + "hsl": { + "h": 151.764705882353, + "s": 100, + "l": 50 + }, + "name": "SpringGreen1" + }, + { + "colorId": 49, + "hexString": "#00ffaf", + "rgb": { + "r": 0, + "g": 255, + "b": 175 + }, + "hsl": { + "h": 161.176470588235, + "s": 100, + "l": 50 + }, + "name": "MediumSpringGreen" + }, + { + "colorId": 50, + "hexString": "#00ffd7", + "rgb": { + "r": 0, + "g": 255, + "b": 215 + }, + "hsl": { + "h": 170.588235294118, + "s": 100, + "l": 50 + }, + "name": "Cyan2" + }, + { + "colorId": 51, + "hexString": "#00ffff", + "rgb": { + "r": 0, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 50 + }, + "name": "Cyan1" + }, + { + "colorId": 52, + "hexString": "#5f0000", + "rgb": { + "r": 95, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 18 + }, + "name": "DarkRed" + }, + { + "colorId": 53, + "hexString": "#5f005f", + "rgb": { + "r": 95, + "g": 0, + "b": 95 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 18 + }, + "name": "DeepPink4" + }, + { + "colorId": 54, + "hexString": "#5f0087", + "rgb": { + "r": 95, + "g": 0, + "b": 135 + }, + "hsl": { + "h": 282.222222222222, + "s": 100, + "l": 26 + }, + "name": "Purple4" + }, + { + "colorId": 55, + "hexString": "#5f00af", + "rgb": { + "r": 95, + "g": 0, + "b": 175 + }, + "hsl": { + "h": 272.571428571429, + "s": 100, + "l": 34 + }, + "name": "Purple4" + }, + { + "colorId": 56, + "hexString": "#5f00d7", + "rgb": { + "r": 95, + "g": 0, + "b": 215 + }, + "hsl": { + "h": 266.511627906977, + "s": 100, + "l": 42 + }, + "name": "Purple3" + }, + { + "colorId": 57, + "hexString": "#5f00ff", + "rgb": { + "r": 95, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 262.352941176471, + "s": 100, + "l": 50 + }, + "name": "BlueViolet" + }, + { + "colorId": 58, + "hexString": "#5f5f00", + "rgb": { + "r": 95, + "g": 95, + "b": 0 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 18 + }, + "name": "Orange4" + }, + { + "colorId": 59, + "hexString": "#5f5f5f", + "rgb": { + "r": 95, + "g": 95, + "b": 95 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 37 + }, + "name": "Grey37" + }, + { + "colorId": 60, + "hexString": "#5f5f87", + "rgb": { + "r": 95, + "g": 95, + "b": 135 + }, + "hsl": { + "h": 240, + "s": 17, + "l": 45 + }, + "name": "MediumPurple4" + }, + { + "colorId": 61, + "hexString": "#5f5faf", + "rgb": { + "r": 95, + "g": 95, + "b": 175 + }, + "hsl": { + "h": 240, + "s": 33, + "l": 52 + }, + "name": "SlateBlue3" + }, + { + "colorId": 62, + "hexString": "#5f5fd7", + "rgb": { + "r": 95, + "g": 95, + "b": 215 + }, + "hsl": { + "h": 240, + "s": 60, + "l": 60 + }, + "name": "SlateBlue3" + }, + { + "colorId": 63, + "hexString": "#5f5fff", + "rgb": { + "r": 95, + "g": 95, + "b": 255 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 68 + }, + "name": "RoyalBlue1" + }, + { + "colorId": 64, + "hexString": "#5f8700", + "rgb": { + "r": 95, + "g": 135, + "b": 0 + }, + "hsl": { + "h": 77.7777777777778, + "s": 100, + "l": 26 + }, + "name": "Chartreuse4" + }, + { + "colorId": 65, + "hexString": "#5f875f", + "rgb": { + "r": 95, + "g": 135, + "b": 95 + }, + "hsl": { + "h": 120, + "s": 17, + "l": 45 + }, + "name": "DarkSeaGreen4" + }, + { + "colorId": 66, + "hexString": "#5f8787", + "rgb": { + "r": 95, + "g": 135, + "b": 135 + }, + "hsl": { + "h": 180, + "s": 17, + "l": 45 + }, + "name": "PaleTurquoise4" + }, + { + "colorId": 67, + "hexString": "#5f87af", + "rgb": { + "r": 95, + "g": 135, + "b": 175 + }, + "hsl": { + "h": 210, + "s": 33, + "l": 52 + }, + "name": "SteelBlue" + }, + { + "colorId": 68, + "hexString": "#5f87d7", + "rgb": { + "r": 95, + "g": 135, + "b": 215 + }, + "hsl": { + "h": 220, + "s": 60, + "l": 60 + }, + "name": "SteelBlue3" + }, + { + "colorId": 69, + "hexString": "#5f87ff", + "rgb": { + "r": 95, + "g": 135, + "b": 255 + }, + "hsl": { + "h": 225, + "s": 100, + "l": 68 + }, + "name": "CornflowerBlue" + }, + { + "colorId": 70, + "hexString": "#5faf00", + "rgb": { + "r": 95, + "g": 175, + "b": 0 + }, + "hsl": { + "h": 87.4285714285714, + "s": 100, + "l": 34 + }, + "name": "Chartreuse3" + }, + { + "colorId": 71, + "hexString": "#5faf5f", + "rgb": { + "r": 95, + "g": 175, + "b": 95 + }, + "hsl": { + "h": 120, + "s": 33, + "l": 52 + }, + "name": "DarkSeaGreen4" + }, + { + "colorId": 72, + "hexString": "#5faf87", + "rgb": { + "r": 95, + "g": 175, + "b": 135 + }, + "hsl": { + "h": 150, + "s": 33, + "l": 52 + }, + "name": "CadetBlue" + }, + { + "colorId": 73, + "hexString": "#5fafaf", + "rgb": { + "r": 95, + "g": 175, + "b": 175 + }, + "hsl": { + "h": 180, + "s": 33, + "l": 52 + }, + "name": "CadetBlue" + }, + { + "colorId": 74, + "hexString": "#5fafd7", + "rgb": { + "r": 95, + "g": 175, + "b": 215 + }, + "hsl": { + "h": 200, + "s": 60, + "l": 60 + }, + "name": "SkyBlue3" + }, + { + "colorId": 75, + "hexString": "#5fafff", + "rgb": { + "r": 95, + "g": 175, + "b": 255 + }, + "hsl": { + "h": 210, + "s": 100, + "l": 68 + }, + "name": "SteelBlue1" + }, + { + "colorId": 76, + "hexString": "#5fd700", + "rgb": { + "r": 95, + "g": 215, + "b": 0 + }, + "hsl": { + "h": 93.4883720930233, + "s": 100, + "l": 42 + }, + "name": "Chartreuse3" + }, + { + "colorId": 77, + "hexString": "#5fd75f", + "rgb": { + "r": 95, + "g": 215, + "b": 95 + }, + "hsl": { + "h": 120, + "s": 60, + "l": 60 + }, + "name": "PaleGreen3" + }, + { + "colorId": 78, + "hexString": "#5fd787", + "rgb": { + "r": 95, + "g": 215, + "b": 135 + }, + "hsl": { + "h": 140, + "s": 60, + "l": 60 + }, + "name": "SeaGreen3" + }, + { + "colorId": 79, + "hexString": "#5fd7af", + "rgb": { + "r": 95, + "g": 215, + "b": 175 + }, + "hsl": { + "h": 160, + "s": 60, + "l": 60 + }, + "name": "Aquamarine3" + }, + { + "colorId": 80, + "hexString": "#5fd7d7", + "rgb": { + "r": 95, + "g": 215, + "b": 215 + }, + "hsl": { + "h": 180, + "s": 60, + "l": 60 + }, + "name": "MediumTurquoise" + }, + { + "colorId": 81, + "hexString": "#5fd7ff", + "rgb": { + "r": 95, + "g": 215, + "b": 255 + }, + "hsl": { + "h": 195, + "s": 100, + "l": 68 + }, + "name": "SteelBlue1" + }, + { + "colorId": 82, + "hexString": "#5fff00", + "rgb": { + "r": 95, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 97.6470588235294, + "s": 100, + "l": 50 + }, + "name": "Chartreuse2" + }, + { + "colorId": 83, + "hexString": "#5fff5f", + "rgb": { + "r": 95, + "g": 255, + "b": 95 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 68 + }, + "name": "SeaGreen2" + }, + { + "colorId": 84, + "hexString": "#5fff87", + "rgb": { + "r": 95, + "g": 255, + "b": 135 + }, + "hsl": { + "h": 135, + "s": 100, + "l": 68 + }, + "name": "SeaGreen1" + }, + { + "colorId": 85, + "hexString": "#5fffaf", + "rgb": { + "r": 95, + "g": 255, + "b": 175 + }, + "hsl": { + "h": 150, + "s": 100, + "l": 68 + }, + "name": "SeaGreen1" + }, + { + "colorId": 86, + "hexString": "#5fffd7", + "rgb": { + "r": 95, + "g": 255, + "b": 215 + }, + "hsl": { + "h": 165, + "s": 100, + "l": 68 + }, + "name": "Aquamarine1" + }, + { + "colorId": 87, + "hexString": "#5fffff", + "rgb": { + "r": 95, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 68 + }, + "name": "DarkSlateGray2" + }, + { + "colorId": 88, + "hexString": "#870000", + "rgb": { + "r": 135, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 26 + }, + "name": "DarkRed" + }, + { + "colorId": 89, + "hexString": "#87005f", + "rgb": { + "r": 135, + "g": 0, + "b": 95 + }, + "hsl": { + "h": 317.777777777778, + "s": 100, + "l": 26 + }, + "name": "DeepPink4" + }, + { + "colorId": 90, + "hexString": "#870087", + "rgb": { + "r": 135, + "g": 0, + "b": 135 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 26 + }, + "name": "DarkMagenta" + }, + { + "colorId": 91, + "hexString": "#8700af", + "rgb": { + "r": 135, + "g": 0, + "b": 175 + }, + "hsl": { + "h": 286.285714285714, + "s": 100, + "l": 34 + }, + "name": "DarkMagenta" + }, + { + "colorId": 92, + "hexString": "#8700d7", + "rgb": { + "r": 135, + "g": 0, + "b": 215 + }, + "hsl": { + "h": 277.674418604651, + "s": 100, + "l": 42 + }, + "name": "DarkViolet" + }, + { + "colorId": 93, + "hexString": "#8700ff", + "rgb": { + "r": 135, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 271.764705882353, + "s": 100, + "l": 50 + }, + "name": "Purple" + }, + { + "colorId": 94, + "hexString": "#875f00", + "rgb": { + "r": 135, + "g": 95, + "b": 0 + }, + "hsl": { + "h": 42.2222222222222, + "s": 100, + "l": 26 + }, + "name": "Orange4" + }, + { + "colorId": 95, + "hexString": "#875f5f", + "rgb": { + "r": 135, + "g": 95, + "b": 95 + }, + "hsl": { + "h": 0, + "s": 17, + "l": 45 + }, + "name": "LightPink4" + }, + { + "colorId": 96, + "hexString": "#875f87", + "rgb": { + "r": 135, + "g": 95, + "b": 135 + }, + "hsl": { + "h": 300, + "s": 17, + "l": 45 + }, + "name": "Plum4" + }, + { + "colorId": 97, + "hexString": "#875faf", + "rgb": { + "r": 135, + "g": 95, + "b": 175 + }, + "hsl": { + "h": 270, + "s": 33, + "l": 52 + }, + "name": "MediumPurple3" + }, + { + "colorId": 98, + "hexString": "#875fd7", + "rgb": { + "r": 135, + "g": 95, + "b": 215 + }, + "hsl": { + "h": 260, + "s": 60, + "l": 60 + }, + "name": "MediumPurple3" + }, + { + "colorId": 99, + "hexString": "#875fff", + "rgb": { + "r": 135, + "g": 95, + "b": 255 + }, + "hsl": { + "h": 255, + "s": 100, + "l": 68 + }, + "name": "SlateBlue1" + }, + { + "colorId": 100, + "hexString": "#878700", + "rgb": { + "r": 135, + "g": 135, + "b": 0 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 26 + }, + "name": "Yellow4" + }, + { + "colorId": 101, + "hexString": "#87875f", + "rgb": { + "r": 135, + "g": 135, + "b": 95 + }, + "hsl": { + "h": 60, + "s": 17, + "l": 45 + }, + "name": "Wheat4" + }, + { + "colorId": 102, + "hexString": "#878787", + "rgb": { + "r": 135, + "g": 135, + "b": 135 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 52 + }, + "name": "Grey53" + }, + { + "colorId": 103, + "hexString": "#8787af", + "rgb": { + "r": 135, + "g": 135, + "b": 175 + }, + "hsl": { + "h": 240, + "s": 20, + "l": 60 + }, + "name": "LightSlateGrey" + }, + { + "colorId": 104, + "hexString": "#8787d7", + "rgb": { + "r": 135, + "g": 135, + "b": 215 + }, + "hsl": { + "h": 240, + "s": 50, + "l": 68 + }, + "name": "MediumPurple" + }, + { + "colorId": 105, + "hexString": "#8787ff", + "rgb": { + "r": 135, + "g": 135, + "b": 255 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 76 + }, + "name": "LightSlateBlue" + }, + { + "colorId": 106, + "hexString": "#87af00", + "rgb": { + "r": 135, + "g": 175, + "b": 0 + }, + "hsl": { + "h": 73.7142857142857, + "s": 100, + "l": 34 + }, + "name": "Yellow4" + }, + { + "colorId": 107, + "hexString": "#87af5f", + "rgb": { + "r": 135, + "g": 175, + "b": 95 + }, + "hsl": { + "h": 90, + "s": 33, + "l": 52 + }, + "name": "DarkOliveGreen3" + }, + { + "colorId": 108, + "hexString": "#87af87", + "rgb": { + "r": 135, + "g": 175, + "b": 135 + }, + "hsl": { + "h": 120, + "s": 20, + "l": 60 + }, + "name": "DarkSeaGreen" + }, + { + "colorId": 109, + "hexString": "#87afaf", + "rgb": { + "r": 135, + "g": 175, + "b": 175 + }, + "hsl": { + "h": 180, + "s": 20, + "l": 60 + }, + "name": "LightSkyBlue3" + }, + { + "colorId": 110, + "hexString": "#87afd7", + "rgb": { + "r": 135, + "g": 175, + "b": 215 + }, + "hsl": { + "h": 210, + "s": 50, + "l": 68 + }, + "name": "LightSkyBlue3" + }, + { + "colorId": 111, + "hexString": "#87afff", + "rgb": { + "r": 135, + "g": 175, + "b": 255 + }, + "hsl": { + "h": 220, + "s": 100, + "l": 76 + }, + "name": "SkyBlue2" + }, + { + "colorId": 112, + "hexString": "#87d700", + "rgb": { + "r": 135, + "g": 215, + "b": 0 + }, + "hsl": { + "h": 82.3255813953488, + "s": 100, + "l": 42 + }, + "name": "Chartreuse2" + }, + { + "colorId": 113, + "hexString": "#87d75f", + "rgb": { + "r": 135, + "g": 215, + "b": 95 + }, + "hsl": { + "h": 100, + "s": 60, + "l": 60 + }, + "name": "DarkOliveGreen3" + }, + { + "colorId": 114, + "hexString": "#87d787", + "rgb": { + "r": 135, + "g": 215, + "b": 135 + }, + "hsl": { + "h": 120, + "s": 50, + "l": 68 + }, + "name": "PaleGreen3" + }, + { + "colorId": 115, + "hexString": "#87d7af", + "rgb": { + "r": 135, + "g": 215, + "b": 175 + }, + "hsl": { + "h": 150, + "s": 50, + "l": 68 + }, + "name": "DarkSeaGreen3" + }, + { + "colorId": 116, + "hexString": "#87d7d7", + "rgb": { + "r": 135, + "g": 215, + "b": 215 + }, + "hsl": { + "h": 180, + "s": 50, + "l": 68 + }, + "name": "DarkSlateGray3" + }, + { + "colorId": 117, + "hexString": "#87d7ff", + "rgb": { + "r": 135, + "g": 215, + "b": 255 + }, + "hsl": { + "h": 200, + "s": 100, + "l": 76 + }, + "name": "SkyBlue1" + }, + { + "colorId": 118, + "hexString": "#87ff00", + "rgb": { + "r": 135, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 88.2352941176471, + "s": 100, + "l": 50 + }, + "name": "Chartreuse1" + }, + { + "colorId": 119, + "hexString": "#87ff5f", + "rgb": { + "r": 135, + "g": 255, + "b": 95 + }, + "hsl": { + "h": 105, + "s": 100, + "l": 68 + }, + "name": "LightGreen" + }, + { + "colorId": 120, + "hexString": "#87ff87", + "rgb": { + "r": 135, + "g": 255, + "b": 135 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 76 + }, + "name": "LightGreen" + }, + { + "colorId": 121, + "hexString": "#87ffaf", + "rgb": { + "r": 135, + "g": 255, + "b": 175 + }, + "hsl": { + "h": 140, + "s": 100, + "l": 76 + }, + "name": "PaleGreen1" + }, + { + "colorId": 122, + "hexString": "#87ffd7", + "rgb": { + "r": 135, + "g": 255, + "b": 215 + }, + "hsl": { + "h": 160, + "s": 100, + "l": 76 + }, + "name": "Aquamarine1" + }, + { + "colorId": 123, + "hexString": "#87ffff", + "rgb": { + "r": 135, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 76 + }, + "name": "DarkSlateGray1" + }, + { + "colorId": 124, + "hexString": "#af0000", + "rgb": { + "r": 175, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 34 + }, + "name": "Red3" + }, + { + "colorId": 125, + "hexString": "#af005f", + "rgb": { + "r": 175, + "g": 0, + "b": 95 + }, + "hsl": { + "h": 327.428571428571, + "s": 100, + "l": 34 + }, + "name": "DeepPink4" + }, + { + "colorId": 126, + "hexString": "#af0087", + "rgb": { + "r": 175, + "g": 0, + "b": 135 + }, + "hsl": { + "h": 313.714285714286, + "s": 100, + "l": 34 + }, + "name": "MediumVioletRed" + }, + { + "colorId": 127, + "hexString": "#af00af", + "rgb": { + "r": 175, + "g": 0, + "b": 175 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 34 + }, + "name": "Magenta3" + }, + { + "colorId": 128, + "hexString": "#af00d7", + "rgb": { + "r": 175, + "g": 0, + "b": 215 + }, + "hsl": { + "h": 288.837209302326, + "s": 100, + "l": 42 + }, + "name": "DarkViolet" + }, + { + "colorId": 129, + "hexString": "#af00ff", + "rgb": { + "r": 175, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 281.176470588235, + "s": 100, + "l": 50 + }, + "name": "Purple" + }, + { + "colorId": 130, + "hexString": "#af5f00", + "rgb": { + "r": 175, + "g": 95, + "b": 0 + }, + "hsl": { + "h": 32.5714285714286, + "s": 100, + "l": 34 + }, + "name": "DarkOrange3" + }, + { + "colorId": 131, + "hexString": "#af5f5f", + "rgb": { + "r": 175, + "g": 95, + "b": 95 + }, + "hsl": { + "h": 0, + "s": 33, + "l": 52 + }, + "name": "IndianRed" + }, + { + "colorId": 132, + "hexString": "#af5f87", + "rgb": { + "r": 175, + "g": 95, + "b": 135 + }, + "hsl": { + "h": 330, + "s": 33, + "l": 52 + }, + "name": "HotPink3" + }, + { + "colorId": 133, + "hexString": "#af5faf", + "rgb": { + "r": 175, + "g": 95, + "b": 175 + }, + "hsl": { + "h": 300, + "s": 33, + "l": 52 + }, + "name": "MediumOrchid3" + }, + { + "colorId": 134, + "hexString": "#af5fd7", + "rgb": { + "r": 175, + "g": 95, + "b": 215 + }, + "hsl": { + "h": 280, + "s": 60, + "l": 60 + }, + "name": "MediumOrchid" + }, + { + "colorId": 135, + "hexString": "#af5fff", + "rgb": { + "r": 175, + "g": 95, + "b": 255 + }, + "hsl": { + "h": 270, + "s": 100, + "l": 68 + }, + "name": "MediumPurple2" + }, + { + "colorId": 136, + "hexString": "#af8700", + "rgb": { + "r": 175, + "g": 135, + "b": 0 + }, + "hsl": { + "h": 46.2857142857143, + "s": 100, + "l": 34 + }, + "name": "DarkGoldenrod" + }, + { + "colorId": 137, + "hexString": "#af875f", + "rgb": { + "r": 175, + "g": 135, + "b": 95 + }, + "hsl": { + "h": 30, + "s": 33, + "l": 52 + }, + "name": "LightSalmon3" + }, + { + "colorId": 138, + "hexString": "#af8787", + "rgb": { + "r": 175, + "g": 135, + "b": 135 + }, + "hsl": { + "h": 0, + "s": 20, + "l": 60 + }, + "name": "RosyBrown" + }, + { + "colorId": 139, + "hexString": "#af87af", + "rgb": { + "r": 175, + "g": 135, + "b": 175 + }, + "hsl": { + "h": 300, + "s": 20, + "l": 60 + }, + "name": "Grey63" + }, + { + "colorId": 140, + "hexString": "#af87d7", + "rgb": { + "r": 175, + "g": 135, + "b": 215 + }, + "hsl": { + "h": 270, + "s": 50, + "l": 68 + }, + "name": "MediumPurple2" + }, + { + "colorId": 141, + "hexString": "#af87ff", + "rgb": { + "r": 175, + "g": 135, + "b": 255 + }, + "hsl": { + "h": 260, + "s": 100, + "l": 76 + }, + "name": "MediumPurple1" + }, + { + "colorId": 142, + "hexString": "#afaf00", + "rgb": { + "r": 175, + "g": 175, + "b": 0 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 34 + }, + "name": "Gold3" + }, + { + "colorId": 143, + "hexString": "#afaf5f", + "rgb": { + "r": 175, + "g": 175, + "b": 95 + }, + "hsl": { + "h": 60, + "s": 33, + "l": 52 + }, + "name": "DarkKhaki" + }, + { + "colorId": 144, + "hexString": "#afaf87", + "rgb": { + "r": 175, + "g": 175, + "b": 135 + }, + "hsl": { + "h": 60, + "s": 20, + "l": 60 + }, + "name": "NavajoWhite3" + }, + { + "colorId": 145, + "hexString": "#afafaf", + "rgb": { + "r": 175, + "g": 175, + "b": 175 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 68 + }, + "name": "Grey69" + }, + { + "colorId": 146, + "hexString": "#afafd7", + "rgb": { + "r": 175, + "g": 175, + "b": 215 + }, + "hsl": { + "h": 240, + "s": 33, + "l": 76 + }, + "name": "LightSteelBlue3" + }, + { + "colorId": 147, + "hexString": "#afafff", + "rgb": { + "r": 175, + "g": 175, + "b": 255 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 84 + }, + "name": "LightSteelBlue" + }, + { + "colorId": 148, + "hexString": "#afd700", + "rgb": { + "r": 175, + "g": 215, + "b": 0 + }, + "hsl": { + "h": 71.1627906976744, + "s": 100, + "l": 42 + }, + "name": "Yellow3" + }, + { + "colorId": 149, + "hexString": "#afd75f", + "rgb": { + "r": 175, + "g": 215, + "b": 95 + }, + "hsl": { + "h": 80, + "s": 60, + "l": 60 + }, + "name": "DarkOliveGreen3" + }, + { + "colorId": 150, + "hexString": "#afd787", + "rgb": { + "r": 175, + "g": 215, + "b": 135 + }, + "hsl": { + "h": 90, + "s": 50, + "l": 68 + }, + "name": "DarkSeaGreen3" + }, + { + "colorId": 151, + "hexString": "#afd7af", + "rgb": { + "r": 175, + "g": 215, + "b": 175 + }, + "hsl": { + "h": 120, + "s": 33, + "l": 76 + }, + "name": "DarkSeaGreen2" + }, + { + "colorId": 152, + "hexString": "#afd7d7", + "rgb": { + "r": 175, + "g": 215, + "b": 215 + }, + "hsl": { + "h": 180, + "s": 33, + "l": 76 + }, + "name": "LightCyan3" + }, + { + "colorId": 153, + "hexString": "#afd7ff", + "rgb": { + "r": 175, + "g": 215, + "b": 255 + }, + "hsl": { + "h": 210, + "s": 100, + "l": 84 + }, + "name": "LightSkyBlue1" + }, + { + "colorId": 154, + "hexString": "#afff00", + "rgb": { + "r": 175, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 78.8235294117647, + "s": 100, + "l": 50 + }, + "name": "GreenYellow" + }, + { + "colorId": 155, + "hexString": "#afff5f", + "rgb": { + "r": 175, + "g": 255, + "b": 95 + }, + "hsl": { + "h": 90, + "s": 100, + "l": 68 + }, + "name": "DarkOliveGreen2" + }, + { + "colorId": 156, + "hexString": "#afff87", + "rgb": { + "r": 175, + "g": 255, + "b": 135 + }, + "hsl": { + "h": 100, + "s": 100, + "l": 76 + }, + "name": "PaleGreen1" + }, + { + "colorId": 157, + "hexString": "#afffaf", + "rgb": { + "r": 175, + "g": 255, + "b": 175 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 84 + }, + "name": "DarkSeaGreen2" + }, + { + "colorId": 158, + "hexString": "#afffd7", + "rgb": { + "r": 175, + "g": 255, + "b": 215 + }, + "hsl": { + "h": 150, + "s": 100, + "l": 84 + }, + "name": "DarkSeaGreen1" + }, + { + "colorId": 159, + "hexString": "#afffff", + "rgb": { + "r": 175, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 84 + }, + "name": "PaleTurquoise1" + }, + { + "colorId": 160, + "hexString": "#d70000", + "rgb": { + "r": 215, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 42 + }, + "name": "Red3" + }, + { + "colorId": 161, + "hexString": "#d7005f", + "rgb": { + "r": 215, + "g": 0, + "b": 95 + }, + "hsl": { + "h": 333.488372093023, + "s": 100, + "l": 42 + }, + "name": "DeepPink3" + }, + { + "colorId": 162, + "hexString": "#d70087", + "rgb": { + "r": 215, + "g": 0, + "b": 135 + }, + "hsl": { + "h": 322.325581395349, + "s": 100, + "l": 42 + }, + "name": "DeepPink3" + }, + { + "colorId": 163, + "hexString": "#d700af", + "rgb": { + "r": 215, + "g": 0, + "b": 175 + }, + "hsl": { + "h": 311.162790697674, + "s": 100, + "l": 42 + }, + "name": "Magenta3" + }, + { + "colorId": 164, + "hexString": "#d700d7", + "rgb": { + "r": 215, + "g": 0, + "b": 215 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 42 + }, + "name": "Magenta3" + }, + { + "colorId": 165, + "hexString": "#d700ff", + "rgb": { + "r": 215, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 290.588235294118, + "s": 100, + "l": 50 + }, + "name": "Magenta2" + }, + { + "colorId": 166, + "hexString": "#d75f00", + "rgb": { + "r": 215, + "g": 95, + "b": 0 + }, + "hsl": { + "h": 26.5116279069767, + "s": 100, + "l": 42 + }, + "name": "DarkOrange3" + }, + { + "colorId": 167, + "hexString": "#d75f5f", + "rgb": { + "r": 215, + "g": 95, + "b": 95 + }, + "hsl": { + "h": 0, + "s": 60, + "l": 60 + }, + "name": "IndianRed" + }, + { + "colorId": 168, + "hexString": "#d75f87", + "rgb": { + "r": 215, + "g": 95, + "b": 135 + }, + "hsl": { + "h": 340, + "s": 60, + "l": 60 + }, + "name": "HotPink3" + }, + { + "colorId": 169, + "hexString": "#d75faf", + "rgb": { + "r": 215, + "g": 95, + "b": 175 + }, + "hsl": { + "h": 320, + "s": 60, + "l": 60 + }, + "name": "HotPink2" + }, + { + "colorId": 170, + "hexString": "#d75fd7", + "rgb": { + "r": 215, + "g": 95, + "b": 215 + }, + "hsl": { + "h": 300, + "s": 60, + "l": 60 + }, + "name": "Orchid" + }, + { + "colorId": 171, + "hexString": "#d75fff", + "rgb": { + "r": 215, + "g": 95, + "b": 255 + }, + "hsl": { + "h": 285, + "s": 100, + "l": 68 + }, + "name": "MediumOrchid1" + }, + { + "colorId": 172, + "hexString": "#d78700", + "rgb": { + "r": 215, + "g": 135, + "b": 0 + }, + "hsl": { + "h": 37.6744186046512, + "s": 100, + "l": 42 + }, + "name": "Orange3" + }, + { + "colorId": 173, + "hexString": "#d7875f", + "rgb": { + "r": 215, + "g": 135, + "b": 95 + }, + "hsl": { + "h": 20, + "s": 60, + "l": 60 + }, + "name": "LightSalmon3" + }, + { + "colorId": 174, + "hexString": "#d78787", + "rgb": { + "r": 215, + "g": 135, + "b": 135 + }, + "hsl": { + "h": 0, + "s": 50, + "l": 68 + }, + "name": "LightPink3" + }, + { + "colorId": 175, + "hexString": "#d787af", + "rgb": { + "r": 215, + "g": 135, + "b": 175 + }, + "hsl": { + "h": 330, + "s": 50, + "l": 68 + }, + "name": "Pink3" + }, + { + "colorId": 176, + "hexString": "#d787d7", + "rgb": { + "r": 215, + "g": 135, + "b": 215 + }, + "hsl": { + "h": 300, + "s": 50, + "l": 68 + }, + "name": "Plum3" + }, + { + "colorId": 177, + "hexString": "#d787ff", + "rgb": { + "r": 215, + "g": 135, + "b": 255 + }, + "hsl": { + "h": 280, + "s": 100, + "l": 76 + }, + "name": "Violet" + }, + { + "colorId": 178, + "hexString": "#d7af00", + "rgb": { + "r": 215, + "g": 175, + "b": 0 + }, + "hsl": { + "h": 48.8372093023256, + "s": 100, + "l": 42 + }, + "name": "Gold3" + }, + { + "colorId": 179, + "hexString": "#d7af5f", + "rgb": { + "r": 215, + "g": 175, + "b": 95 + }, + "hsl": { + "h": 40, + "s": 60, + "l": 60 + }, + "name": "LightGoldenrod3" + }, + { + "colorId": 180, + "hexString": "#d7af87", + "rgb": { + "r": 215, + "g": 175, + "b": 135 + }, + "hsl": { + "h": 30, + "s": 50, + "l": 68 + }, + "name": "Tan" + }, + { + "colorId": 181, + "hexString": "#d7afaf", + "rgb": { + "r": 215, + "g": 175, + "b": 175 + }, + "hsl": { + "h": 0, + "s": 33, + "l": 76 + }, + "name": "MistyRose3" + }, + { + "colorId": 182, + "hexString": "#d7afd7", + "rgb": { + "r": 215, + "g": 175, + "b": 215 + }, + "hsl": { + "h": 300, + "s": 33, + "l": 76 + }, + "name": "Thistle3" + }, + { + "colorId": 183, + "hexString": "#d7afff", + "rgb": { + "r": 215, + "g": 175, + "b": 255 + }, + "hsl": { + "h": 270, + "s": 100, + "l": 84 + }, + "name": "Plum2" + }, + { + "colorId": 184, + "hexString": "#d7d700", + "rgb": { + "r": 215, + "g": 215, + "b": 0 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 42 + }, + "name": "Yellow3" + }, + { + "colorId": 185, + "hexString": "#d7d75f", + "rgb": { + "r": 215, + "g": 215, + "b": 95 + }, + "hsl": { + "h": 60, + "s": 60, + "l": 60 + }, + "name": "Khaki3" + }, + { + "colorId": 186, + "hexString": "#d7d787", + "rgb": { + "r": 215, + "g": 215, + "b": 135 + }, + "hsl": { + "h": 60, + "s": 50, + "l": 68 + }, + "name": "LightGoldenrod2" + }, + { + "colorId": 187, + "hexString": "#d7d7af", + "rgb": { + "r": 215, + "g": 215, + "b": 175 + }, + "hsl": { + "h": 60, + "s": 33, + "l": 76 + }, + "name": "LightYellow3" + }, + { + "colorId": 188, + "hexString": "#d7d7d7", + "rgb": { + "r": 215, + "g": 215, + "b": 215 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 84 + }, + "name": "Grey84" + }, + { + "colorId": 189, + "hexString": "#d7d7ff", + "rgb": { + "r": 215, + "g": 215, + "b": 255 + }, + "hsl": { + "h": 240, + "s": 100, + "l": 92 + }, + "name": "LightSteelBlue1" + }, + { + "colorId": 190, + "hexString": "#d7ff00", + "rgb": { + "r": 215, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 69.4117647058823, + "s": 100, + "l": 50 + }, + "name": "Yellow2" + }, + { + "colorId": 191, + "hexString": "#d7ff5f", + "rgb": { + "r": 215, + "g": 255, + "b": 95 + }, + "hsl": { + "h": 75, + "s": 100, + "l": 68 + }, + "name": "DarkOliveGreen1" + }, + { + "colorId": 192, + "hexString": "#d7ff87", + "rgb": { + "r": 215, + "g": 255, + "b": 135 + }, + "hsl": { + "h": 80, + "s": 100, + "l": 76 + }, + "name": "DarkOliveGreen1" + }, + { + "colorId": 193, + "hexString": "#d7ffaf", + "rgb": { + "r": 215, + "g": 255, + "b": 175 + }, + "hsl": { + "h": 90, + "s": 100, + "l": 84 + }, + "name": "DarkSeaGreen1" + }, + { + "colorId": 194, + "hexString": "#d7ffd7", + "rgb": { + "r": 215, + "g": 255, + "b": 215 + }, + "hsl": { + "h": 120, + "s": 100, + "l": 92 + }, + "name": "Honeydew2" + }, + { + "colorId": 195, + "hexString": "#d7ffff", + "rgb": { + "r": 215, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 180, + "s": 100, + "l": 92 + }, + "name": "LightCyan1" + }, + { + "colorId": 196, + "hexString": "#ff0000", + "rgb": { + "r": 255, + "g": 0, + "b": 0 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 50 + }, + "name": "Red1" + }, + { + "colorId": 197, + "hexString": "#ff005f", + "rgb": { + "r": 255, + "g": 0, + "b": 95 + }, + "hsl": { + "h": 337.647058823529, + "s": 100, + "l": 50 + }, + "name": "DeepPink2" + }, + { + "colorId": 198, + "hexString": "#ff0087", + "rgb": { + "r": 255, + "g": 0, + "b": 135 + }, + "hsl": { + "h": 328.235294117647, + "s": 100, + "l": 50 + }, + "name": "DeepPink1" + }, + { + "colorId": 199, + "hexString": "#ff00af", + "rgb": { + "r": 255, + "g": 0, + "b": 175 + }, + "hsl": { + "h": 318.823529411765, + "s": 100, + "l": 50 + }, + "name": "DeepPink1" + }, + { + "colorId": 200, + "hexString": "#ff00d7", + "rgb": { + "r": 255, + "g": 0, + "b": 215 + }, + "hsl": { + "h": 309.411764705882, + "s": 100, + "l": 50 + }, + "name": "Magenta2" + }, + { + "colorId": 201, + "hexString": "#ff00ff", + "rgb": { + "r": 255, + "g": 0, + "b": 255 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 50 + }, + "name": "Magenta1" + }, + { + "colorId": 202, + "hexString": "#ff5f00", + "rgb": { + "r": 255, + "g": 95, + "b": 0 + }, + "hsl": { + "h": 22.3529411764706, + "s": 100, + "l": 50 + }, + "name": "OrangeRed1" + }, + { + "colorId": 203, + "hexString": "#ff5f5f", + "rgb": { + "r": 255, + "g": 95, + "b": 95 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 68 + }, + "name": "IndianRed1" + }, + { + "colorId": 204, + "hexString": "#ff5f87", + "rgb": { + "r": 255, + "g": 95, + "b": 135 + }, + "hsl": { + "h": 345, + "s": 100, + "l": 68 + }, + "name": "IndianRed1" + }, + { + "colorId": 205, + "hexString": "#ff5faf", + "rgb": { + "r": 255, + "g": 95, + "b": 175 + }, + "hsl": { + "h": 330, + "s": 100, + "l": 68 + }, + "name": "HotPink" + }, + { + "colorId": 206, + "hexString": "#ff5fd7", + "rgb": { + "r": 255, + "g": 95, + "b": 215 + }, + "hsl": { + "h": 315, + "s": 100, + "l": 68 + }, + "name": "HotPink" + }, + { + "colorId": 207, + "hexString": "#ff5fff", + "rgb": { + "r": 255, + "g": 95, + "b": 255 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 68 + }, + "name": "MediumOrchid1" + }, + { + "colorId": 208, + "hexString": "#ff8700", + "rgb": { + "r": 255, + "g": 135, + "b": 0 + }, + "hsl": { + "h": 31.7647058823529, + "s": 100, + "l": 50 + }, + "name": "DarkOrange" + }, + { + "colorId": 209, + "hexString": "#ff875f", + "rgb": { + "r": 255, + "g": 135, + "b": 95 + }, + "hsl": { + "h": 15, + "s": 100, + "l": 68 + }, + "name": "Salmon1" + }, + { + "colorId": 210, + "hexString": "#ff8787", + "rgb": { + "r": 255, + "g": 135, + "b": 135 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 76 + }, + "name": "LightCoral" + }, + { + "colorId": 211, + "hexString": "#ff87af", + "rgb": { + "r": 255, + "g": 135, + "b": 175 + }, + "hsl": { + "h": 340, + "s": 100, + "l": 76 + }, + "name": "PaleVioletRed1" + }, + { + "colorId": 212, + "hexString": "#ff87d7", + "rgb": { + "r": 255, + "g": 135, + "b": 215 + }, + "hsl": { + "h": 320, + "s": 100, + "l": 76 + }, + "name": "Orchid2" + }, + { + "colorId": 213, + "hexString": "#ff87ff", + "rgb": { + "r": 255, + "g": 135, + "b": 255 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 76 + }, + "name": "Orchid1" + }, + { + "colorId": 214, + "hexString": "#ffaf00", + "rgb": { + "r": 255, + "g": 175, + "b": 0 + }, + "hsl": { + "h": 41.1764705882353, + "s": 100, + "l": 50 + }, + "name": "Orange1" + }, + { + "colorId": 215, + "hexString": "#ffaf5f", + "rgb": { + "r": 255, + "g": 175, + "b": 95 + }, + "hsl": { + "h": 30, + "s": 100, + "l": 68 + }, + "name": "SandyBrown" + }, + { + "colorId": 216, + "hexString": "#ffaf87", + "rgb": { + "r": 255, + "g": 175, + "b": 135 + }, + "hsl": { + "h": 20, + "s": 100, + "l": 76 + }, + "name": "LightSalmon1" + }, + { + "colorId": 217, + "hexString": "#ffafaf", + "rgb": { + "r": 255, + "g": 175, + "b": 175 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 84 + }, + "name": "LightPink1" + }, + { + "colorId": 218, + "hexString": "#ffafd7", + "rgb": { + "r": 255, + "g": 175, + "b": 215 + }, + "hsl": { + "h": 330, + "s": 100, + "l": 84 + }, + "name": "Pink1" + }, + { + "colorId": 219, + "hexString": "#ffafff", + "rgb": { + "r": 255, + "g": 175, + "b": 255 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 84 + }, + "name": "Plum1" + }, + { + "colorId": 220, + "hexString": "#ffd700", + "rgb": { + "r": 255, + "g": 215, + "b": 0 + }, + "hsl": { + "h": 50.5882352941176, + "s": 100, + "l": 50 + }, + "name": "Gold1" + }, + { + "colorId": 221, + "hexString": "#ffd75f", + "rgb": { + "r": 255, + "g": 215, + "b": 95 + }, + "hsl": { + "h": 45, + "s": 100, + "l": 68 + }, + "name": "LightGoldenrod2" + }, + { + "colorId": 222, + "hexString": "#ffd787", + "rgb": { + "r": 255, + "g": 215, + "b": 135 + }, + "hsl": { + "h": 40, + "s": 100, + "l": 76 + }, + "name": "LightGoldenrod2" + }, + { + "colorId": 223, + "hexString": "#ffd7af", + "rgb": { + "r": 255, + "g": 215, + "b": 175 + }, + "hsl": { + "h": 30, + "s": 100, + "l": 84 + }, + "name": "NavajoWhite1" + }, + { + "colorId": 224, + "hexString": "#ffd7d7", + "rgb": { + "r": 255, + "g": 215, + "b": 215 + }, + "hsl": { + "h": 0, + "s": 100, + "l": 92 + }, + "name": "MistyRose1" + }, + { + "colorId": 225, + "hexString": "#ffd7ff", + "rgb": { + "r": 255, + "g": 215, + "b": 255 + }, + "hsl": { + "h": 300, + "s": 100, + "l": 92 + }, + "name": "Thistle1" + }, + { + "colorId": 226, + "hexString": "#ffff00", + "rgb": { + "r": 255, + "g": 255, + "b": 0 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 50 + }, + "name": "Yellow1" + }, + { + "colorId": 227, + "hexString": "#ffff5f", + "rgb": { + "r": 255, + "g": 255, + "b": 95 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 68 + }, + "name": "LightGoldenrod1" + }, + { + "colorId": 228, + "hexString": "#ffff87", + "rgb": { + "r": 255, + "g": 255, + "b": 135 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 76 + }, + "name": "Khaki1" + }, + { + "colorId": 229, + "hexString": "#ffffaf", + "rgb": { + "r": 255, + "g": 255, + "b": 175 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 84 + }, + "name": "Wheat1" + }, + { + "colorId": 230, + "hexString": "#ffffd7", + "rgb": { + "r": 255, + "g": 255, + "b": 215 + }, + "hsl": { + "h": 60, + "s": 100, + "l": 92 + }, + "name": "Cornsilk1" + }, + { + "colorId": 231, + "hexString": "#ffffff", + "rgb": { + "r": 255, + "g": 255, + "b": 255 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 100 + }, + "name": "Grey100" + }, + { + "colorId": 232, + "hexString": "#080808", + "rgb": { + "r": 8, + "g": 8, + "b": 8 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 3 + }, + "name": "Grey3" + }, + { + "colorId": 233, + "hexString": "#121212", + "rgb": { + "r": 18, + "g": 18, + "b": 18 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 7 + }, + "name": "Grey7" + }, + { + "colorId": 234, + "hexString": "#1c1c1c", + "rgb": { + "r": 28, + "g": 28, + "b": 28 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 10 + }, + "name": "Grey11" + }, + { + "colorId": 235, + "hexString": "#262626", + "rgb": { + "r": 38, + "g": 38, + "b": 38 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 14 + }, + "name": "Grey15" + }, + { + "colorId": 236, + "hexString": "#303030", + "rgb": { + "r": 48, + "g": 48, + "b": 48 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 18 + }, + "name": "Grey19" + }, + { + "colorId": 237, + "hexString": "#3a3a3a", + "rgb": { + "r": 58, + "g": 58, + "b": 58 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 22 + }, + "name": "Grey23" + }, + { + "colorId": 238, + "hexString": "#444444", + "rgb": { + "r": 68, + "g": 68, + "b": 68 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 26 + }, + "name": "Grey27" + }, + { + "colorId": 239, + "hexString": "#4e4e4e", + "rgb": { + "r": 78, + "g": 78, + "b": 78 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 30 + }, + "name": "Grey30" + }, + { + "colorId": 240, + "hexString": "#585858", + "rgb": { + "r": 88, + "g": 88, + "b": 88 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 34 + }, + "name": "Grey35" + }, + { + "colorId": 241, + "hexString": "#626262", + "rgb": { + "r": 98, + "g": 98, + "b": 98 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 37 + }, + "name": "Grey39" + }, + { + "colorId": 242, + "hexString": "#6c6c6c", + "rgb": { + "r": 108, + "g": 108, + "b": 108 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 40 + }, + "name": "Grey42" + }, + { + "colorId": 243, + "hexString": "#767676", + "rgb": { + "r": 118, + "g": 118, + "b": 118 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 46 + }, + "name": "Grey46" + }, + { + "colorId": 244, + "hexString": "#808080", + "rgb": { + "r": 128, + "g": 128, + "b": 128 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 50 + }, + "name": "Grey50" + }, + { + "colorId": 245, + "hexString": "#8a8a8a", + "rgb": { + "r": 138, + "g": 138, + "b": 138 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 54 + }, + "name": "Grey54" + }, + { + "colorId": 246, + "hexString": "#949494", + "rgb": { + "r": 148, + "g": 148, + "b": 148 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 58 + }, + "name": "Grey58" + }, + { + "colorId": 247, + "hexString": "#9e9e9e", + "rgb": { + "r": 158, + "g": 158, + "b": 158 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 61 + }, + "name": "Grey62" + }, + { + "colorId": 248, + "hexString": "#a8a8a8", + "rgb": { + "r": 168, + "g": 168, + "b": 168 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 65 + }, + "name": "Grey66" + }, + { + "colorId": 249, + "hexString": "#b2b2b2", + "rgb": { + "r": 178, + "g": 178, + "b": 178 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 69 + }, + "name": "Grey70" + }, + { + "colorId": 250, + "hexString": "#bcbcbc", + "rgb": { + "r": 188, + "g": 188, + "b": 188 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 73 + }, + "name": "Grey74" + }, + { + "colorId": 251, + "hexString": "#c6c6c6", + "rgb": { + "r": 198, + "g": 198, + "b": 198 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 77 + }, + "name": "Grey78" + }, + { + "colorId": 252, + "hexString": "#d0d0d0", + "rgb": { + "r": 208, + "g": 208, + "b": 208 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 81 + }, + "name": "Grey82" + }, + { + "colorId": 253, + "hexString": "#dadada", + "rgb": { + "r": 218, + "g": 218, + "b": 218 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 85 + }, + "name": "Grey85" + }, + { + "colorId": 254, + "hexString": "#e4e4e4", + "rgb": { + "r": 228, + "g": 228, + "b": 228 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 89 + }, + "name": "Grey89" + }, + { + "colorId": 255, + "hexString": "#eeeeee", + "rgb": { + "r": 238, + "g": 238, + "b": 238 + }, + "hsl": { + "h": 0, + "s": 0, + "l": 93 + }, + "name": "Grey93" + } +] \ No newline at end of file diff --git a/src/yajlpp.cc b/src/yajlpp.cc index 82450d1f..5b7b48aa 100644 --- a/src/yajlpp.cc +++ b/src/yajlpp.cc @@ -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 &dst, void *root, const string &base) const +void json_path_handler_base::walk( + const std::function &cb, + void *root, const string &base) const { vector 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(ypc.ypc_handler_stack.back()->jph_children); + this->ygc_depth += 1; + } + return *this; +} diff --git a/src/yajlpp.hh b/src/yajlpp.hh index e37c7119..292eb264 100644 --- a/src/yajlpp.hh +++ b/src/yajlpp.hh @@ -44,6 +44,7 @@ #include #include #include +#include #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 &dst, - void *root = NULL, - const std::string &base = "") const; + virtual void walk( + const std::function &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 name); void *(*jph_obj_provider)(const yajlpp_provider_context &pe, void *root); void (*jph_path_provider)(void *root, std::vector &paths_out); const char * jph_synopsis; @@ -181,6 +187,7 @@ struct json_path_handler_base { bool jph_kv_pair; std::shared_ptr jph_pattern; const char * jph_pattern_re{nullptr}; + std::function 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 ypc_path; std::vector ypc_path_index_stack; std::vector ypc_array_index; + std::vector 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 ypc_active_paths; error_reporter_t ypc_error_reporter{nullptr}; + std::map *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(); diff --git a/src/yajlpp_def.hh b/src/yajlpp_def.hh index 5bdb6ef6..deb00947 100644 --- a/src/yajlpp_def.hh +++ b/src/yajlpp_def.hh @@ -153,6 +153,11 @@ struct json_path_handler : public json_path_handler_base { return *this; }; + json_path_handler &with_string_validator(std::function 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 + static void *get_field_lvalue_cb(void *root, nonstd::optional name) { + auto obj = (T *) root; + auto &mem = obj->*MEM; + + return &mem; + }; + template 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()), 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()); 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 *) ( + ygc.ygc_default_stack.empty() ? nullptr + : ygc.ygc_default_stack.top()); + auto obj = (std::map *) 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 json_path_handler &for_field() { this->add_cb(string_field_cb); this->jph_gen_callback = field_gen; this->jph_validator = string_field_validator; + this->jph_field_getter = get_field_lvalue_cb; return *this; }; @@ -308,6 +371,7 @@ struct json_path_handler : public json_path_handler_base { template T::*STR> json_path_handler &for_field() { this->add_cb(string_field_cb); + this->jph_gen_callback = map_field_gen; this->jph_validator = string_field_validator; return *this; diff --git a/test/Makefile.am b/test/Makefile.am index f5302a35..eea64437 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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 \ diff --git a/test/bad-config2/formats/invalid-config/config.json b/test/bad-config2/formats/invalid-config/config.json new file mode 100644 index 00000000..ba5cf2fb --- /dev/null +++ b/test/bad-config2/formats/invalid-config/config.json @@ -0,0 +1,5 @@ +{ + "ui": { + "theme": "foo" + } +} \ No newline at end of file diff --git a/test/test_cmds.sh b/test/test_cmds.sh index 7849afb1..0998aaa6 100644 --- a/test/test_cmds.sh +++ b/test/test_cmds.sh @@ -126,7 +126,7 @@ EOF check_output "config clock-format" <