[themes] move highlights to theme definitions

Fixes #783
This commit is contained in:
Timothy Stack 2020-10-28 21:19:57 -07:00
parent 3b0168025d
commit a63cf003a0
17 changed files with 251 additions and 46 deletions

View File

@ -426,6 +426,7 @@ void filter_sub_source::rl_abort(readline_curses *rc)
top_view->get_highlights().erase({highlight_source_t::PREVIEW, "preview"});
top_view->reload_data();
fs.delete_filter("");
this->tss_view->reload_data();
this->fss_editor.set_visible(false);
this->fss_editing = false;
this->tss_view->set_needs_update();

View File

@ -16,6 +16,7 @@ highlighter::highlighter(const highlighter &other)
this->h_text_format = other.h_text_format;
this->h_format_name = other.h_format_name;
this->h_nestable = other.h_nestable;
this->h_semantic = other.h_semantic;
}
highlighter &highlighter::operator=(const highlighter &other)
@ -37,6 +38,7 @@ highlighter &highlighter::operator=(const highlighter &other)
this->h_attrs = other.h_attrs;
this->h_text_format = other.h_text_format;
this->h_nestable = other.h_nestable;
this->h_semantic = other.h_semantic;
return *this;
}
@ -49,7 +51,7 @@ void highlighter::study()
if (!this->h_code_extra && errptr) {
log_error("pcre_study error: %s", errptr);
}
if (this->h_code_extra != NULL) {
if (this->h_code_extra != nullptr) {
pcre_extra *extra = this->h_code_extra;
extra->flags |= (PCRE_EXTRA_MATCH_LIMIT |
@ -104,6 +106,10 @@ void highlighter::annotate(attr_line_t &al, int start) const
if (this->h_attrs != -1) {
attrs = this->h_attrs;
}
if (this->h_semantic) {
attrs |= vc.attrs_for_ident(&line_start[lr.lr_start],
lr.length());
}
if (!this->h_fg.empty()) {
sa.emplace_back(lr,
&view_curses::VC_FOREGROUND,

View File

@ -40,12 +40,10 @@
struct highlighter {
highlighter()
: h_code(nullptr),
h_code_extra(nullptr),
h_attrs(-1),
h_text_format(text_format_t::TF_UNKNOWN) { };
h_code_extra(nullptr) { };
explicit highlighter(pcre *code)
: h_code(code), h_attrs(-1), h_text_format(text_format_t::TF_UNKNOWN)
: h_code(code)
{
pcre_refcount(this->h_code, 1);
this->study();
@ -107,6 +105,11 @@ struct highlighter {
return *this;
}
highlighter &with_semantic(bool val) {
this->h_semantic = val;
return *this;
}
int get_attrs() const
{
ensure(this->h_attrs != -1);
@ -122,10 +125,11 @@ struct highlighter {
rgb_color h_bg;
pcre *h_code;
pcre_extra *h_code_extra;
int h_attrs;
text_format_t h_text_format;
int h_attrs{-1};
text_format_t h_text_format{text_format_t::TF_UNKNOWN};
intern_string_t h_format_name;
bool h_nestable{true};
bool h_semantic{false};
};
#endif

View File

@ -150,6 +150,11 @@
"title": "/ui/theme-defs/<theme_name>/syntax-styles/comment",
"$ref": "#/definitions/style"
},
"doc-directive": {
"description": "Styling for documentation directives in source files",
"title": "/ui/theme-defs/<theme_name>/syntax-styles/doc-directive",
"$ref": "#/definitions/style"
},
"variable": {
"description": "Styling for variables in text",
"title": "/ui/theme-defs/<theme_name>/syntax-styles/variable",
@ -252,6 +257,31 @@
}
},
"additionalProperties": false
},
"highlights": {
"description": "Styles for text highlights.",
"title": "/ui/theme-defs/<theme_name>/highlights",
"type": "object",
"patternProperties": {
"(\\w+)": {
"title": "/ui/theme-defs/<theme_name>/highlights/<highlight_name>",
"type": "object",
"properties": {
"pattern": {
"title": "/ui/theme-defs/<theme_name>/highlights/<highlight_name>/pattern",
"description": "The regular expression to highlight",
"type": "string"
},
"style": {
"description": "The styling for the text that matches the associated pattern",
"title": "/ui/theme-defs/<theme_name>/highlights/<highlight_name>/style",
"$ref": "#/definitions/style"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -318,6 +348,11 @@
"type": "object",
"$$target": "#/definitions/style",
"properties": {
"semantic": {
"title": "/semantic",
"description": "Pick a color based on the text being highlighted",
"type": "boolean"
},
"color": {
"title": "/color",
"description": "The foreground color value for this style. The value can be the name of an xterm color, the hexadecimal value, or a theme variable reference.",

View File

@ -449,6 +449,10 @@ static struct json_path_container global_var_handlers = {
static struct json_path_container style_config_handlers =
json_path_container{
json_path_handler("semantic")
.with_description(
"Pick a color based on the text being highlighted")
.FOR_FIELD(style_config, sc_semantic),
json_path_handler("color")
.with_synopsis("#hex|color_name")
.with_description(
@ -571,6 +575,12 @@ static struct json_path_container theme_syntax_styles_handlers = {
return &root->lt_style_comment;
})
.with_children(style_config_handlers),
json_path_handler("doc-directive")
.with_description("Styling for documentation directives in source files")
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
return &root->lt_style_doc_directive;
})
.with_children(style_config_handlers),
json_path_handler("variable")
.with_description("Styling for variables in text")
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
@ -689,6 +699,36 @@ static struct json_path_container theme_log_level_styles_handlers = {
.with_children(style_config_handlers)
};
static struct json_path_container highlighter_handlers = {
json_path_handler("pattern")
.with_synopsis("regular expression")
.with_description("The regular expression to highlight")
.FOR_FIELD(highlighter_config, hc_regex),
json_path_handler("style")
.with_description("The styling for the text that matches the associated pattern")
.with_obj_provider<style_config, highlighter_config>([](const yajlpp_provider_context &ypc, highlighter_config *root) {
return &root->hc_style;
})
.with_children(style_config_handlers),
};
static struct json_path_container theme_highlights_handlers = {
json_path_handler(pcrepp("(?<highlight_name>\\w+)"))
.with_obj_provider<highlighter_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
highlighter_config &hc = root->lt_highlights[
ypc.ypc_extractor.get_substr_i("highlight_name").get()];
return &hc;
})
.with_path_provider<lnav_theme>([](struct lnav_theme *cfg, vector<string> &paths_out) {
for (const auto& pair : cfg->lt_highlights) {
paths_out.emplace_back(pair.first);
}
})
.with_children(highlighter_handlers)
};
static struct json_path_container theme_vars_handlers = {
json_path_handler(pcrepp("(?<var_name>\\w+)"))
.with_synopsis("name")
@ -720,7 +760,11 @@ static struct json_path_container theme_def_handlers = {
json_path_handler("log-level-styles")
.with_description("Styles for each log message level.")
.with_children(theme_log_level_styles_handlers)
.with_children(theme_log_level_styles_handlers),
json_path_handler("highlights")
.with_description("Styles for text highlights.")
.with_children(theme_highlights_handlers),
};
static struct json_path_container theme_defs_handlers = {

View File

@ -116,12 +116,18 @@ struct term_color_palette {
};
struct style_config {
bool sc_semantic{false};
std::string sc_color;
std::string sc_background_color;
bool sc_underline{false};
bool sc_bold{false};
};
struct highlighter_config {
std::string hc_regex;
style_config hc_style;
};
struct lnav_theme {
std::map<std::string, std::string> lt_vars;
style_config lt_style_identifier;
@ -141,6 +147,7 @@ struct lnav_theme {
style_config lt_style_keyword;
style_config lt_style_string;
style_config lt_style_comment;
style_config lt_style_doc_directive;
style_config lt_style_variable;
style_config lt_style_symbol;
style_config lt_style_number;
@ -159,6 +166,7 @@ struct lnav_theme {
style_config lt_style_inactive_status;
style_config lt_style_file;
std::map<log_level_t, style_config> lt_level_styles;
std::map<std::string, highlighter_config> lt_highlights;
};
extern term_color_palette xterm_colors;

View File

@ -55,11 +55,6 @@ static pcre *xpcre_compile(const char *pattern, int options = 0)
return retval;
}
static highlighter static_highlighter(const string &regex) {
return highlighter(xpcre_compile(regex.c_str()))
.with_attrs(view_colors::singleton().attrs_for_ident(regex));
}
void setup_highlights(textview_curses::highlight_map_t &hm)
{
hm[{highlight_source_t::INTERNAL, "python"}] = highlighter(xpcre_compile(
@ -399,7 +394,6 @@ void setup_highlights(textview_curses::highlight_map_t &hm)
"(?:java|a|o|so|c|cc|cpp|cxx|h|hh|hpp|hxx|py|pyc|rb):"
"\\d+"))
.with_role(view_colors::VCR_FILE);
hm[{highlight_source_t::INTERNAL, "xml"}] = static_highlighter("<(/?[^ >=]+)[^>]*>");
hm[{highlight_source_t::INTERNAL, "1.stringd"}] = highlighter(xpcre_compile(
"\"(?:\\\\.|[^\"])*\""))
.with_role(view_colors::VCR_STRING);
@ -418,12 +412,12 @@ void setup_highlights(textview_curses::highlight_map_t &hm)
hm[{highlight_source_t::INTERNAL, "diffs"}] = highlighter(xpcre_compile(
"^\\@@ .*"))
.with_role(view_colors::VCR_DIFF_SECTION);
hm[{highlight_source_t::INTERNAL, "ip"}] = static_highlighter("\\d+\\.\\d+\\.\\d+\\.\\d+");
hm[{highlight_source_t::INTERNAL, "0.comment"}] = highlighter(xpcre_compile(
"(?<=[\\s;])//.*|/\\*.*\\*/|\\(\\*.*\\*\\)|^#.*|\\s+#.*|dnl.*"))
.with_role(view_colors::VCR_COMMENT);
hm[{highlight_source_t::INTERNAL, "javadoc"}] = static_highlighter(
"@(?:author|deprecated|exception|file|param|return|see|since|throws|todo|version)");
hm[{highlight_source_t::INTERNAL, "javadoc"}] = highlighter(xpcre_compile(
"@(?:author|deprecated|exception|file|param|return|see|since|throws|todo|version)"))
.with_role(view_colors::VCR_DOC_DIRECTIVE);
hm[{highlight_source_t::INTERNAL, "var"}] = highlighter(xpcre_compile(
"(?:"
"(?:var\\s+)?([\\-\\w]+)\\s*[!=+\\-*/|&^]?=|"

View File

@ -34,6 +34,8 @@
#include <pcrecpp.h>
#include "shlex.hh"
#include "fmt/format.h"
#include "pcrepp/pcrepp.hh"
#include "lnav_util.hh"
#include "data_parser.hh"
@ -120,8 +122,8 @@ string_attr_type textview_curses::SA_FORMAT("format");
string_attr_type textview_curses::SA_REMOVED("removed");
textview_curses::textview_curses()
: tc_sub_source(NULL),
tc_delegate(NULL),
: tc_sub_source(nullptr),
tc_delegate(nullptr),
tc_selection_start(-1),
tc_selection_last(-1),
tc_selection_cleared(false),
@ -130,10 +132,83 @@ textview_curses::textview_curses()
this->set_data_source(this);
}
textview_curses::~textview_curses()
{ }
void textview_curses::reload_config(error_reporter &reporter)
{
static auto DEFAULT_THEME_NAME = string("default");
void textview_curses::reload_data(void)
for (auto iter = this->tc_highlights.begin();
iter != this->tc_highlights.end();) {
if (iter->first.first != highlight_source_t::THEME) {
++iter;
continue;
}
iter = this->tc_highlights.erase(iter);
}
for (const auto& theme_name : {DEFAULT_THEME_NAME, lnav_config.lc_ui_theme}) {
auto theme_iter = lnav_config.lc_ui_theme_defs.find(theme_name);
if (theme_iter == lnav_config.lc_ui_theme_defs.end()) {
continue;
}
for (const auto &hl_pair : theme_iter->second.lt_highlights) {
if (hl_pair.second.hc_regex.empty()) {
continue;
}
const char *errptr;
pcre *code;
int eoff;
if ((code = pcre_compile(hl_pair.second.hc_regex.c_str(),
0,
&errptr,
&eoff,
nullptr)) == nullptr) {
reporter(&hl_pair.second.hc_regex,
fmt::format("invalid highlight regex: {} at {}",
errptr, eoff));
continue;
}
const auto &sc = hl_pair.second.hc_style;
string fg1, bg1, fg_color, bg_color, errmsg;
rgb_color fg, bg;
int attrs = 0;
fg1 = sc.sc_color;
bg1 = sc.sc_background_color;
shlex(fg1).eval(fg_color, theme_iter->second.lt_vars);
shlex(bg1).eval(bg_color, theme_iter->second.lt_vars);
if (!rgb_color::from_str(fg_color, fg, errmsg)) {
reporter(&sc.sc_color, errmsg);
continue;
}
if (!rgb_color::from_str(bg_color, bg, errmsg)) {
reporter(&sc.sc_background_color, errmsg);
continue;
}
if (sc.sc_bold) {
attrs |= A_BOLD;
}
if (sc.sc_underline) {
attrs |= A_UNDERLINE;
}
this->tc_highlights[{highlight_source_t::THEME, hl_pair.first}] =
highlighter(code)
.with_pattern(hl_pair.second.hc_regex)
.with_attrs(attrs != 0 ? attrs : -1)
.with_color(fg, bg)
.with_semantic(sc.sc_semantic);
}
}
}
void textview_curses::reload_data()
{
if (this->tc_sub_source != nullptr) {
this->tc_sub_source->text_update_marks(this->tc_bookmarks);
@ -343,7 +418,8 @@ void textview_curses::textview_value_for_row(vis_line_t row,
for (auto &tc_highlight : this->tc_highlights) {
bool internal_hl =
tc_highlight.first.first == highlight_source_t::INTERNAL;
tc_highlight.first.first == highlight_source_t::INTERNAL ||
tc_highlight.first.first == highlight_source_t::THEME;
if (tc_highlight.second.h_text_format != text_format_t::TF_UNKNOWN &&
source_format != tc_highlight.second.h_text_format) {

View File

@ -568,6 +568,7 @@ public:
enum class highlight_source_t {
INTERNAL,
THEME,
PREVIEW,
CONFIGURATION,
INTERACTIVE,
@ -581,7 +582,8 @@ class textview_curses
: public listview_curses,
public list_data_source,
public grep_proc_source<vis_line_t>,
public grep_proc_sink<vis_line_t> {
public grep_proc_sink<vis_line_t>,
public lnav_config_listener {
public:
typedef view_action<textview_curses> action;
@ -597,7 +599,9 @@ public:
static string_attr_type SA_REMOVED;
textview_curses();
virtual ~textview_curses();
virtual ~textview_curses() = default;
void reload_config(error_reporter &reporter);
void set_paused(bool paused) {
this->tc_paused = paused;

View File

@ -56,6 +56,9 @@
"comment": {
"color": "Green"
},
"doc-directive": {
"color": "Teal"
},
"variable": {
"color": "Teal"
},
@ -125,6 +128,20 @@
"fatal": {
"color": "Red"
}
},
"highlights": {
"ipv4": {
"pattern": "\\b(?<!\\d\\.)\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b(?!\\.\\d)",
"style": {
"semantic": true
}
},
"xml": {
"pattern": "</?([^ >=]+)[^>]*>",
"style": {
"semantic": true
}
}
}
}
}

View File

@ -67,6 +67,9 @@
"comment": {
"color": "$cyan"
},
"doc-directive": {
"color": "$green"
},
"number": {
"color": "$red"
},

View File

@ -72,6 +72,9 @@
"comment": {
"color": "#727072"
},
"doc-directive": {
"color": "#a9dc76"
},
"variable": {
"color": "#a9dc76"
},

View File

@ -65,6 +65,9 @@
"comment": {
"color": "#676e95"
},
"doc-directive": {
"color": "#addb67"
},
"variable": {
"color": "#addb67"
},

View File

@ -76,6 +76,9 @@
"comment": {
"color": "$base01"
},
"doc-directive": {
"color": "$cyan"
},
"variable": {
"color": "$blue"
},

View File

@ -76,6 +76,9 @@
"comment": {
"color": "$base1"
},
"doc-directive": {
"color": "$blue"
},
"variable": {
"color": "$blue"
},

View File

@ -918,6 +918,8 @@ void view_colors::init_roles(const lnav_theme &lt,
lt, lt.lt_style_string, lt.lt_style_text, reporter);
this->vc_role_colors[VCR_COMMENT] = this->to_attrs(color_pair_base,
lt, lt.lt_style_comment, lt.lt_style_text, reporter);
this->vc_role_colors[VCR_DOC_DIRECTIVE] = this->to_attrs(color_pair_base,
lt, lt.lt_style_doc_directive, lt.lt_style_text, reporter);
this->vc_role_colors[VCR_VARIABLE] = this->to_attrs(color_pair_base,
lt, lt.lt_style_variable, lt.lt_style_text, reporter);
this->vc_role_colors[VCR_SYMBOL] = this->to_attrs(color_pair_base,

View File

@ -172,37 +172,37 @@ private:
* Class that encapsulates a method to execute and the object on which to
* execute it.
*
* @param _Sender The type of object that will be triggering an action.
* @param Sender The type of object that will be triggering an action.
*/
template<class _Sender>
template<class Sender>
class view_action {
public:
/**
*
* @param _Receiver The type of object that will be triggered by an action.
* @param Receiver The type of object that will be triggered by an action.
*/
template<class _Receiver>
template<class Receiver>
class mem_functor_t {
public:
mem_functor_t(_Receiver &receiver,
void(_Receiver::*selector)(_Sender *))
mem_functor_t(Receiver &receiver,
void(Receiver::*selector)(Sender *))
: mf_receiver(receiver),
mf_selector(selector) { };
void operator()(_Sender *sender) const
void operator()(Sender *sender) const
{
(this->mf_receiver.*mf_selector)(sender);
};
static void invoke(mem_functor_t *self, _Sender *sender)
static void invoke(mem_functor_t *self, Sender *sender)
{
(*self)(sender);
};
private:
_Receiver & mf_receiver;
void (_Receiver::*mf_selector)(_Sender *);
Receiver & mf_receiver;
void (Receiver::*mf_selector)(Sender *);
};
class broadcaster
@ -213,7 +213,7 @@ public:
: b_functor(*this, &broadcaster::invoke) { };
virtual ~broadcaster() = default;
void invoke(_Sender *sender)
void invoke(Sender *sender)
{
typename std::vector<view_action>::iterator iter;
@ -238,15 +238,15 @@ private:
* parameters, the first being the value of the receiver pointer and the
* second being the sender pointer as passed to invoke().
*/
view_action(void(*invoker)(void *, _Sender *) = nullptr)
view_action(void(*invoker)(void *, Sender *) = nullptr)
: va_functor(nullptr),
va_invoker(invoker) { };
template<class _Receiver>
view_action(mem_functor_t<_Receiver> *mf)
template<class Receiver>
view_action(mem_functor_t<Receiver> *mf)
: va_functor(mf),
va_invoker((void(*) (void *, _Sender *))
mem_functor_t<_Receiver>::invoke) { };
va_invoker((void(*) (void *, Sender *))
mem_functor_t<Receiver>::invoke) { };
/**
* Performs a shallow copy of another view_action.
@ -258,8 +258,6 @@ private:
: va_functor(va.va_functor),
va_invoker(va.va_invoker) { };
~view_action() { };
/**
* @param rhs The view_action to shallow copy.
* @return *this
@ -277,7 +275,7 @@ private:
*
* @param sender Pointer to the object that called this method.
*/
void invoke(_Sender *sender)
void invoke(Sender *sender)
{
if (this->va_invoker != NULL) {
this->va_invoker(this->va_functor, sender);
@ -289,7 +287,7 @@ private:
/** The object to pass as the first argument to the selector function.*/
void *va_functor;
/** The function to call when this action is invoke()'d. */
void (*va_invoker)(void *functor, _Sender *sender);
void (*va_invoker)(void *functor, Sender *sender);
};
/**
@ -339,6 +337,7 @@ public:
VCR_KEYWORD,
VCR_STRING,
VCR_COMMENT,
VCR_DOC_DIRECTIVE,
VCR_VARIABLE,
VCR_SYMBOL,
VCR_NUMBER,
@ -365,7 +364,7 @@ public:
* called before this method, but the returned attributes cannot be used
* with curses code until this method is called.
*/
static void init(void);
static void init();
void init_roles(const lnav_theme &lt, lnav_config_listener::error_reporter &reporter);