mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-01 06:48:30 +08:00
Switch highlight_spec_t to a struct
Rather than a janky bitmask, use a real struct with real fields.
This commit is contained in:
parent
d165d1df27
commit
717ac9a8d5
|
@ -275,7 +275,7 @@ static std::string ansi_colorize(const wcstring &text,
|
||||||
assert(colors.size() == text.size());
|
assert(colors.size() == text.size());
|
||||||
outputter_t outp;
|
outputter_t outp;
|
||||||
|
|
||||||
highlight_spec_t last_color = highlight_spec_normal;
|
highlight_spec_t last_color = highlight_role_t::normal;
|
||||||
for (size_t i = 0; i < text.size(); i++) {
|
for (size_t i = 0; i < text.size(); i++) {
|
||||||
highlight_spec_t color = colors.at(i);
|
highlight_spec_t color = colors.at(i);
|
||||||
if (color != last_color) {
|
if (color != last_color) {
|
||||||
|
@ -292,47 +292,47 @@ static std::string ansi_colorize(const wcstring &text,
|
||||||
/// for the various colors.
|
/// for the various colors.
|
||||||
static const wchar_t *html_class_name_for_color(highlight_spec_t spec) {
|
static const wchar_t *html_class_name_for_color(highlight_spec_t spec) {
|
||||||
#define P(x) L"fish_color_" #x
|
#define P(x) L"fish_color_" #x
|
||||||
switch (spec & HIGHLIGHT_SPEC_PRIMARY_MASK) {
|
switch (spec.foreground) {
|
||||||
case highlight_spec_normal: {
|
case highlight_role_t::normal: {
|
||||||
return P(normal);
|
return P(normal);
|
||||||
}
|
}
|
||||||
case highlight_spec_error: {
|
case highlight_role_t::error: {
|
||||||
return P(error);
|
return P(error);
|
||||||
}
|
}
|
||||||
case highlight_spec_command: {
|
case highlight_role_t::command: {
|
||||||
return P(command);
|
return P(command);
|
||||||
}
|
}
|
||||||
case highlight_spec_statement_terminator: {
|
case highlight_role_t::statement_terminator: {
|
||||||
return P(statement_terminator);
|
return P(statement_terminator);
|
||||||
}
|
}
|
||||||
case highlight_spec_param: {
|
case highlight_role_t::param: {
|
||||||
return P(param);
|
return P(param);
|
||||||
}
|
}
|
||||||
case highlight_spec_comment: {
|
case highlight_role_t::comment: {
|
||||||
return P(comment);
|
return P(comment);
|
||||||
}
|
}
|
||||||
case highlight_spec_match: {
|
case highlight_role_t::match: {
|
||||||
return P(match);
|
return P(match);
|
||||||
}
|
}
|
||||||
case highlight_spec_search_match: {
|
case highlight_role_t::search_match: {
|
||||||
return P(search_match);
|
return P(search_match);
|
||||||
}
|
}
|
||||||
case highlight_spec_operator: {
|
case highlight_role_t::operat: {
|
||||||
return P(operator);
|
return P(operator);
|
||||||
}
|
}
|
||||||
case highlight_spec_escape: {
|
case highlight_role_t::escape: {
|
||||||
return P(escape);
|
return P(escape);
|
||||||
}
|
}
|
||||||
case highlight_spec_quote: {
|
case highlight_role_t::quote: {
|
||||||
return P(quote);
|
return P(quote);
|
||||||
}
|
}
|
||||||
case highlight_spec_redirection: {
|
case highlight_role_t::redirection: {
|
||||||
return P(redirection);
|
return P(redirection);
|
||||||
}
|
}
|
||||||
case highlight_spec_autosuggestion: {
|
case highlight_role_t::autosuggestion: {
|
||||||
return P(autosuggestion);
|
return P(autosuggestion);
|
||||||
}
|
}
|
||||||
case highlight_spec_selection: {
|
case highlight_role_t::selection: {
|
||||||
return P(selection);
|
return P(selection);
|
||||||
}
|
}
|
||||||
default: { return P(other); }
|
default: { return P(other); }
|
||||||
|
@ -347,7 +347,7 @@ static std::string html_colorize(const wcstring &text,
|
||||||
|
|
||||||
assert(colors.size() == text.size());
|
assert(colors.size() == text.size());
|
||||||
wcstring html = L"<pre><code>";
|
wcstring html = L"<pre><code>";
|
||||||
highlight_spec_t last_color = highlight_spec_normal;
|
highlight_spec_t last_color = highlight_role_t::normal;
|
||||||
for (size_t i = 0; i < text.size(); i++) {
|
for (size_t i = 0; i < text.size(); i++) {
|
||||||
// Handle colors.
|
// Handle colors.
|
||||||
highlight_spec_t color = colors.at(i);
|
highlight_spec_t color = colors.at(i);
|
||||||
|
|
|
@ -4242,9 +4242,9 @@ static void test_highlighting() {
|
||||||
// Here are the components of our source and the colors we expect those to be.
|
// Here are the components of our source and the colors we expect those to be.
|
||||||
struct highlight_component_t {
|
struct highlight_component_t {
|
||||||
const wchar_t *txt;
|
const wchar_t *txt;
|
||||||
int color;
|
highlight_spec_t color;
|
||||||
bool nospace;
|
bool nospace;
|
||||||
highlight_component_t(const wchar_t *txt, int color, bool nospace = false)
|
highlight_component_t(const wchar_t *txt, highlight_spec_t color, bool nospace = false)
|
||||||
: txt(txt), color(color), nospace(nospace) {}
|
: txt(txt), color(color), nospace(nospace) {}
|
||||||
};
|
};
|
||||||
const bool ns = true;
|
const bool ns = true;
|
||||||
|
@ -4252,182 +4252,184 @@ static void test_highlighting() {
|
||||||
using highlight_component_list_t = std::vector<highlight_component_t>;
|
using highlight_component_list_t = std::vector<highlight_component_t>;
|
||||||
std::vector<highlight_component_list_t> highlight_tests;
|
std::vector<highlight_component_list_t> highlight_tests;
|
||||||
|
|
||||||
highlight_tests.push_back(
|
highlight_spec_t param_valid_path{highlight_role_t::param};
|
||||||
{{L"echo", highlight_spec_command},
|
param_valid_path.valid_path = true;
|
||||||
{L"test/fish_highlight_test/foo", highlight_spec_param | highlight_modifier_valid_path},
|
|
||||||
{L"&", highlight_spec_statement_terminator}});
|
highlight_tests.push_back({{L"echo", highlight_role_t::command},
|
||||||
|
{L"test/fish_highlight_test/foo", param_valid_path},
|
||||||
|
{L"&", highlight_role_t::statement_terminator}});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"command", highlight_spec_command},
|
{L"command", highlight_role_t::command},
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"abc", highlight_spec_param},
|
{L"abc", highlight_role_t::param},
|
||||||
{L"test/fish_highlight_test/foo", highlight_spec_param | highlight_modifier_valid_path},
|
{L"test/fish_highlight_test/foo", param_valid_path},
|
||||||
{L"&", highlight_spec_statement_terminator},
|
{L"&", highlight_role_t::statement_terminator},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"if command ls", highlight_spec_command},
|
{L"if command ls", highlight_role_t::command},
|
||||||
{L"; ", highlight_spec_statement_terminator},
|
{L"; ", highlight_role_t::statement_terminator},
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"abc", highlight_spec_param},
|
{L"abc", highlight_role_t::param},
|
||||||
{L"; ", highlight_spec_statement_terminator},
|
{L"; ", highlight_role_t::statement_terminator},
|
||||||
{L"/bin/definitely_not_a_command", highlight_spec_error},
|
{L"/bin/definitely_not_a_command", highlight_role_t::error},
|
||||||
{L"; ", highlight_spec_statement_terminator},
|
{L"; ", highlight_role_t::statement_terminator},
|
||||||
{L"end", highlight_spec_command},
|
{L"end", highlight_role_t::command},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify that cd shows errors for non-directories.
|
// Verify that cd shows errors for non-directories.
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"cd", highlight_spec_command},
|
{L"cd", highlight_role_t::command},
|
||||||
{L"test/fish_highlight_test", highlight_spec_param | highlight_modifier_valid_path},
|
{L"test/fish_highlight_test", param_valid_path},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"cd", highlight_spec_command},
|
{L"cd", highlight_role_t::command},
|
||||||
{L"test/fish_highlight_test/foo", highlight_spec_error},
|
{L"test/fish_highlight_test/foo", highlight_role_t::error},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"cd", highlight_spec_command},
|
{L"cd", highlight_role_t::command},
|
||||||
{L"--help", highlight_spec_param},
|
{L"--help", highlight_role_t::param},
|
||||||
{L"-h", highlight_spec_param},
|
{L"-h", highlight_role_t::param},
|
||||||
{L"definitely_not_a_directory", highlight_spec_error},
|
{L"definitely_not_a_directory", highlight_role_t::error},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Command substitutions.
|
// Command substitutions.
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"param1", highlight_spec_param},
|
{L"param1", highlight_role_t::param},
|
||||||
{L"(", highlight_spec_operator},
|
{L"(", highlight_role_t::operat},
|
||||||
{L"ls", highlight_spec_command},
|
{L"ls", highlight_role_t::command},
|
||||||
{L"param2", highlight_spec_param},
|
{L"param2", highlight_role_t::param},
|
||||||
{L")", highlight_spec_operator},
|
{L")", highlight_role_t::operat},
|
||||||
{L"|", highlight_spec_statement_terminator},
|
{L"|", highlight_role_t::statement_terminator},
|
||||||
{L"cat", highlight_spec_command},
|
{L"cat", highlight_role_t::command},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redirections substitutions.
|
// Redirections substitutions.
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"param1", highlight_spec_param},
|
{L"param1", highlight_role_t::param},
|
||||||
|
|
||||||
// Input redirection.
|
// Input redirection.
|
||||||
{L"<", highlight_spec_redirection},
|
{L"<", highlight_role_t::redirection},
|
||||||
{L"/bin/echo", highlight_spec_redirection},
|
{L"/bin/echo", highlight_role_t::redirection},
|
||||||
|
|
||||||
// Output redirection to a valid fd.
|
// Output redirection to a valid fd.
|
||||||
{L"1>&2", highlight_spec_redirection},
|
{L"1>&2", highlight_role_t::redirection},
|
||||||
|
|
||||||
// Output redirection to an invalid fd.
|
// Output redirection to an invalid fd.
|
||||||
{L"2>&", highlight_spec_redirection},
|
{L"2>&", highlight_role_t::redirection},
|
||||||
{L"LOL", highlight_spec_error},
|
{L"LOL", highlight_role_t::error},
|
||||||
|
|
||||||
// Just a param, not a redirection.
|
// Just a param, not a redirection.
|
||||||
{L"test/blah", highlight_spec_param},
|
{L"test/blah", highlight_role_t::param},
|
||||||
|
|
||||||
// Input redirection from directory.
|
// Input redirection from directory.
|
||||||
{L"<", highlight_spec_redirection},
|
{L"<", highlight_role_t::redirection},
|
||||||
{L"test/", highlight_spec_error},
|
{L"test/", highlight_role_t::error},
|
||||||
|
|
||||||
// Output redirection to an invalid path.
|
// Output redirection to an invalid path.
|
||||||
{L"3>", highlight_spec_redirection},
|
{L"3>", highlight_role_t::redirection},
|
||||||
{L"/not/a/valid/path/nope", highlight_spec_error},
|
{L"/not/a/valid/path/nope", highlight_role_t::error},
|
||||||
|
|
||||||
// Output redirection to directory.
|
// Output redirection to directory.
|
||||||
{L"3>", highlight_spec_redirection},
|
{L"3>", highlight_role_t::redirection},
|
||||||
{L"test/nope/", highlight_spec_error},
|
{L"test/nope/", highlight_role_t::error},
|
||||||
|
|
||||||
// Redirections to overflow fd.
|
// Redirections to overflow fd.
|
||||||
{L"99999999999999999999>&2", highlight_spec_error},
|
{L"99999999999999999999>&2", highlight_role_t::error},
|
||||||
{L"2>&", highlight_spec_redirection},
|
{L"2>&", highlight_role_t::redirection},
|
||||||
{L"99999999999999999999", highlight_spec_error},
|
{L"99999999999999999999", highlight_role_t::error},
|
||||||
|
|
||||||
// Output redirection containing a command substitution.
|
// Output redirection containing a command substitution.
|
||||||
{L"4>", highlight_spec_redirection},
|
{L"4>", highlight_role_t::redirection},
|
||||||
{L"(", highlight_spec_operator},
|
{L"(", highlight_role_t::operat},
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"test/somewhere", highlight_spec_param},
|
{L"test/somewhere", highlight_role_t::param},
|
||||||
{L")", highlight_spec_operator},
|
{L")", highlight_role_t::operat},
|
||||||
|
|
||||||
// Just another param.
|
// Just another param.
|
||||||
{L"param2", highlight_spec_param},
|
{L"param2", highlight_role_t::param},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"end", highlight_spec_error},
|
{L"end", highlight_role_t::error},
|
||||||
{L";", highlight_spec_statement_terminator},
|
{L";", highlight_role_t::statement_terminator},
|
||||||
{L"if", highlight_spec_command},
|
{L"if", highlight_role_t::command},
|
||||||
{L"end", highlight_spec_error},
|
{L"end", highlight_role_t::error},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"'single_quote", highlight_spec_error},
|
{L"'single_quote", highlight_role_t::error},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"$foo", highlight_spec_operator},
|
{L"$foo", highlight_role_t::operat},
|
||||||
{L"\"", highlight_spec_quote},
|
{L"\"", highlight_role_t::quote},
|
||||||
{L"$bar", highlight_spec_operator},
|
{L"$bar", highlight_role_t::operat},
|
||||||
{L"\"", highlight_spec_quote},
|
{L"\"", highlight_role_t::quote},
|
||||||
{L"$baz[", highlight_spec_operator},
|
{L"$baz[", highlight_role_t::operat},
|
||||||
{L"1 2..3", highlight_spec_param},
|
{L"1 2..3", highlight_role_t::param},
|
||||||
{L"]", highlight_spec_operator},
|
{L"]", highlight_role_t::operat},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"for", highlight_spec_command},
|
{L"for", highlight_role_t::command},
|
||||||
{L"i", highlight_spec_param},
|
{L"i", highlight_role_t::param},
|
||||||
{L"in", highlight_spec_command},
|
{L"in", highlight_role_t::command},
|
||||||
{L"1 2 3", highlight_spec_param},
|
{L"1 2 3", highlight_role_t::param},
|
||||||
{L";", highlight_spec_statement_terminator},
|
{L";", highlight_role_t::statement_terminator},
|
||||||
{L"end", highlight_spec_command},
|
{L"end", highlight_role_t::command},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"$$foo[", highlight_spec_operator},
|
{L"$$foo[", highlight_role_t::operat},
|
||||||
{L"1", highlight_spec_param},
|
{L"1", highlight_role_t::param},
|
||||||
{L"][", highlight_spec_operator},
|
{L"][", highlight_role_t::operat},
|
||||||
{L"2", highlight_spec_param},
|
{L"2", highlight_role_t::param},
|
||||||
{L"]", highlight_spec_operator},
|
{L"]", highlight_role_t::operat},
|
||||||
{L"[3]", highlight_spec_param}, // two dollar signs, so last one is not an expansion
|
{L"[3]", highlight_role_t::param}, // two dollar signs, so last one is not an expansion
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"cat", highlight_spec_command},
|
{L"cat", highlight_role_t::command},
|
||||||
{L"/dev/null", highlight_spec_param},
|
{L"/dev/null", highlight_role_t::param},
|
||||||
{L"|", highlight_spec_statement_terminator},
|
{L"|", highlight_role_t::statement_terminator},
|
||||||
// This is bogus, but we used to use "less" here and that doesn't have to be installed.
|
// This is bogus, but we used to use "less" here and that doesn't have to be installed.
|
||||||
{L"cat", highlight_spec_command},
|
{L"cat", highlight_role_t::command},
|
||||||
{L"2>", highlight_spec_redirection},
|
{L"2>", highlight_role_t::redirection},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"if", highlight_spec_command},
|
{L"if", highlight_role_t::command},
|
||||||
{L"true", highlight_spec_command},
|
{L"true", highlight_role_t::command},
|
||||||
{L"&&", highlight_spec_operator},
|
{L"&&", highlight_role_t::operat},
|
||||||
{L"false", highlight_spec_command},
|
{L"false", highlight_role_t::command},
|
||||||
{L";", highlight_spec_statement_terminator},
|
{L";", highlight_role_t::statement_terminator},
|
||||||
{L"or", highlight_spec_operator},
|
{L"or", highlight_role_t::operat},
|
||||||
{L"false", highlight_spec_command},
|
{L"false", highlight_role_t::command},
|
||||||
{L"||", highlight_spec_operator},
|
{L"||", highlight_role_t::operat},
|
||||||
{L"true", highlight_spec_command},
|
{L"true", highlight_role_t::command},
|
||||||
{L";", highlight_spec_statement_terminator},
|
{L";", highlight_role_t::statement_terminator},
|
||||||
{L"and", highlight_spec_operator},
|
{L"and", highlight_role_t::operat},
|
||||||
{L"not", highlight_spec_operator},
|
{L"not", highlight_role_t::operat},
|
||||||
{L"!", highlight_spec_operator},
|
{L"!", highlight_role_t::operat},
|
||||||
{L"true", highlight_spec_command},
|
{L"true", highlight_role_t::command},
|
||||||
{L";", highlight_spec_statement_terminator},
|
{L";", highlight_role_t::statement_terminator},
|
||||||
{L"end", highlight_spec_command},
|
{L"end", highlight_role_t::command},
|
||||||
});
|
});
|
||||||
|
|
||||||
highlight_tests.push_back({
|
highlight_tests.push_back({
|
||||||
{L"echo", highlight_spec_command},
|
{L"echo", highlight_role_t::command},
|
||||||
{L"%self", highlight_spec_operator},
|
{L"%self", highlight_role_t::operat},
|
||||||
{L"not%self", highlight_spec_param},
|
{L"not%self", highlight_role_t::param},
|
||||||
{L"self%not", highlight_spec_param},
|
{L"self%not", highlight_role_t::param},
|
||||||
});
|
});
|
||||||
|
|
||||||
auto &vars = parser_t::principal_parser().vars();
|
auto &vars = parser_t::principal_parser().vars();
|
||||||
|
@ -4435,21 +4437,21 @@ static void test_highlighting() {
|
||||||
vars.set(L"VARIABLE_IN_COMMAND", ENV_LOCAL, {L"a"});
|
vars.set(L"VARIABLE_IN_COMMAND", ENV_LOCAL, {L"a"});
|
||||||
vars.set(L"VARIABLE_IN_COMMAND2", ENV_LOCAL, {L"at"});
|
vars.set(L"VARIABLE_IN_COMMAND2", ENV_LOCAL, {L"at"});
|
||||||
highlight_tests.push_back(
|
highlight_tests.push_back(
|
||||||
{{L"/bin/ca", highlight_spec_command, ns}, {L"*", highlight_spec_operator, ns}});
|
{{L"/bin/ca", highlight_role_t::command, ns}, {L"*", highlight_role_t::operat, ns}});
|
||||||
|
|
||||||
highlight_tests.push_back({{L"/bin/c", highlight_spec_command, ns},
|
highlight_tests.push_back({{L"/bin/c", highlight_role_t::command, ns},
|
||||||
{L"{$VARIABLE_IN_COMMAND}", highlight_spec_operator, ns},
|
{L"{$VARIABLE_IN_COMMAND}", highlight_role_t::operat, ns},
|
||||||
{L"*", highlight_spec_operator, ns}});
|
{L"*", highlight_role_t::operat, ns}});
|
||||||
|
|
||||||
highlight_tests.push_back({{L"/bin/c", highlight_spec_command, ns},
|
highlight_tests.push_back({{L"/bin/c", highlight_role_t::command, ns},
|
||||||
{L"{$VARIABLE_IN_COMMAND}", highlight_spec_operator, ns},
|
{L"{$VARIABLE_IN_COMMAND}", highlight_role_t::operat, ns},
|
||||||
{L"*", highlight_spec_operator, ns}});
|
{L"*", highlight_role_t::operat, ns}});
|
||||||
|
|
||||||
highlight_tests.push_back({{L"/bin/c", highlight_spec_command, ns},
|
highlight_tests.push_back({{L"/bin/c", highlight_role_t::command, ns},
|
||||||
{L"$VARIABLE_IN_COMMAND2", highlight_spec_operator, ns}});
|
{L"$VARIABLE_IN_COMMAND2", highlight_role_t::operat, ns}});
|
||||||
|
|
||||||
highlight_tests.push_back({{L"$EMPTY_VARIABLE", highlight_spec_error}});
|
highlight_tests.push_back({{L"$EMPTY_VARIABLE", highlight_role_t::error}});
|
||||||
highlight_tests.push_back({{L"\"$EMPTY_VARIABLE\"", highlight_spec_error}});
|
highlight_tests.push_back({{L"\"$EMPTY_VARIABLE\"", highlight_role_t::error}});
|
||||||
|
|
||||||
for (const highlight_component_list_t &components : highlight_tests) {
|
for (const highlight_component_list_t &components : highlight_tests) {
|
||||||
// Generate the text.
|
// Generate the text.
|
||||||
|
@ -4458,7 +4460,7 @@ static void test_highlighting() {
|
||||||
for (const highlight_component_t &comp : components) {
|
for (const highlight_component_t &comp : components) {
|
||||||
if (!text.empty() && !comp.nospace) {
|
if (!text.empty() && !comp.nospace) {
|
||||||
text.push_back(L' ');
|
text.push_back(L' ');
|
||||||
expected_colors.push_back(0);
|
expected_colors.push_back(highlight_spec_t{});
|
||||||
}
|
}
|
||||||
text.append(comp.txt);
|
text.append(comp.txt);
|
||||||
expected_colors.resize(text.size(), comp.color);
|
expected_colors.resize(text.size(), comp.color);
|
||||||
|
|
|
@ -39,71 +39,127 @@ namespace g = grammar;
|
||||||
|
|
||||||
#define CURSOR_POSITION_INVALID ((size_t)(-1))
|
#define CURSOR_POSITION_INVALID ((size_t)(-1))
|
||||||
|
|
||||||
/// Number of elements in the highlight_var array.
|
static const wchar_t *get_highlight_var_name(highlight_role_t role) {
|
||||||
#define VAR_COUNT (sizeof(highlight_var) / sizeof(wchar_t *))
|
switch (role) {
|
||||||
static const wchar_t *const highlight_var[] = {
|
case highlight_role_t::normal:
|
||||||
[highlight_spec_normal] = L"fish_color_normal",
|
return L"fish_color_normal";
|
||||||
[highlight_spec_error] = L"fish_color_error",
|
case highlight_role_t::error:
|
||||||
[highlight_spec_command] = L"fish_color_command",
|
return L"fish_color_error";
|
||||||
[highlight_spec_statement_terminator] = L"fish_color_end",
|
case highlight_role_t::command:
|
||||||
[highlight_spec_param] = L"fish_color_param",
|
return L"fish_color_command";
|
||||||
[highlight_spec_comment] = L"fish_color_comment",
|
case highlight_role_t::statement_terminator:
|
||||||
[highlight_spec_match] = L"fish_color_match",
|
return L"fish_color_end";
|
||||||
[highlight_spec_search_match] = L"fish_color_search_match",
|
case highlight_role_t::param:
|
||||||
[highlight_spec_operator] = L"fish_color_operator",
|
return L"fish_color_param";
|
||||||
[highlight_spec_escape] = L"fish_color_escape",
|
case highlight_role_t::comment:
|
||||||
[highlight_spec_quote] = L"fish_color_quote",
|
return L"fish_color_comment";
|
||||||
[highlight_spec_redirection] = L"fish_color_redirection",
|
case highlight_role_t::match:
|
||||||
[highlight_spec_autosuggestion] = L"fish_color_autosuggestion",
|
return L"fish_color_match";
|
||||||
[highlight_spec_selection] = L"fish_color_selection",
|
case highlight_role_t::search_match:
|
||||||
[highlight_spec_pager_progress] = L"fish_pager_color_progress",
|
return L"fish_color_search_match";
|
||||||
[highlight_spec_pager_background] = L"fish_pager_color_background",
|
case highlight_role_t::operat:
|
||||||
[highlight_spec_pager_prefix] = L"fish_pager_color_prefix",
|
return L"fish_color_operator";
|
||||||
[highlight_spec_pager_completion] = L"fish_pager_color_completion",
|
case highlight_role_t::escape:
|
||||||
[highlight_spec_pager_description] = L"fish_pager_color_description",
|
return L"fish_color_escape";
|
||||||
[highlight_spec_pager_secondary_background] = L"fish_pager_color_secondary_background",
|
case highlight_role_t::quote:
|
||||||
[highlight_spec_pager_secondary_prefix] = L"fish_pager_color_secondary_prefix",
|
return L"fish_color_quote";
|
||||||
[highlight_spec_pager_secondary_completion] = L"fish_pager_color_secondary_completion",
|
case highlight_role_t::redirection:
|
||||||
[highlight_spec_pager_secondary_description] = L"fish_pager_color_secondary_description",
|
return L"fish_color_redirection";
|
||||||
[highlight_spec_pager_selected_background] = L"fish_pager_color_selected_background",
|
case highlight_role_t::autosuggestion:
|
||||||
[highlight_spec_pager_selected_prefix] = L"fish_pager_color_selected_prefix",
|
return L"fish_color_autosuggestion";
|
||||||
[highlight_spec_pager_selected_completion] = L"fish_pager_color_selected_completion",
|
case highlight_role_t::selection:
|
||||||
[highlight_spec_pager_selected_description] = L"fish_pager_color_selected_description",
|
return L"fish_color_selection";
|
||||||
};
|
case highlight_role_t::pager_progress:
|
||||||
static_assert(VAR_COUNT == HIGHLIGHT_SPEC_MAX, "Every color spec has a corresponding env var");
|
return L"fish_pager_color_progress";
|
||||||
|
case highlight_role_t::pager_background:
|
||||||
|
return L"fish_pager_color_background";
|
||||||
|
case highlight_role_t::pager_prefix:
|
||||||
|
return L"fish_pager_color_prefix";
|
||||||
|
case highlight_role_t::pager_completion:
|
||||||
|
return L"fish_pager_color_completion";
|
||||||
|
case highlight_role_t::pager_description:
|
||||||
|
return L"fish_pager_color_description";
|
||||||
|
case highlight_role_t::pager_secondary_background:
|
||||||
|
return L"fish_pager_color_secondary_background";
|
||||||
|
case highlight_role_t::pager_secondary_prefix:
|
||||||
|
return L"fish_pager_color_secondary_prefix";
|
||||||
|
case highlight_role_t::pager_secondary_completion:
|
||||||
|
return L"fish_pager_color_secondary_completion";
|
||||||
|
case highlight_role_t::pager_secondary_description:
|
||||||
|
return L"fish_pager_color_secondary_description";
|
||||||
|
case highlight_role_t::pager_selected_background:
|
||||||
|
return L"fish_pager_color_selected_background";
|
||||||
|
case highlight_role_t::pager_selected_prefix:
|
||||||
|
return L"fish_pager_color_selected_prefix";
|
||||||
|
case highlight_role_t::pager_selected_completion:
|
||||||
|
return L"fish_pager_color_selected_completion";
|
||||||
|
case highlight_role_t::pager_selected_description:
|
||||||
|
return L"fish_pager_color_selected_description";
|
||||||
|
}
|
||||||
|
DIE("invalid highlight role");
|
||||||
|
}
|
||||||
|
|
||||||
// Table used to fetch fallback highlights in case the specified one
|
// Table used to fetch fallback highlights in case the specified one
|
||||||
// wasn't set.
|
// wasn't set.
|
||||||
static const highlight_spec_t fallbacks[] = {
|
static highlight_role_t get_fallback(highlight_role_t role) {
|
||||||
[highlight_spec_normal] = highlight_spec_normal,
|
switch (role) {
|
||||||
[highlight_spec_error] = highlight_spec_normal,
|
case highlight_role_t::normal:
|
||||||
[highlight_spec_command] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_statement_terminator] = highlight_spec_normal,
|
case highlight_role_t::error:
|
||||||
[highlight_spec_param] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_comment] = highlight_spec_normal,
|
case highlight_role_t::command:
|
||||||
[highlight_spec_match] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_search_match] = highlight_spec_normal,
|
case highlight_role_t::statement_terminator:
|
||||||
[highlight_spec_operator] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_escape] = highlight_spec_normal,
|
case highlight_role_t::param:
|
||||||
[highlight_spec_quote] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_redirection] = highlight_spec_normal,
|
case highlight_role_t::comment:
|
||||||
[highlight_spec_autosuggestion] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_selection] = highlight_spec_normal,
|
case highlight_role_t::match:
|
||||||
[highlight_spec_pager_progress] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_pager_background] = highlight_spec_normal,
|
case highlight_role_t::search_match:
|
||||||
[highlight_spec_pager_prefix] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_pager_completion] = highlight_spec_normal,
|
case highlight_role_t::operat:
|
||||||
[highlight_spec_pager_description] = highlight_spec_normal,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_pager_secondary_background] = highlight_spec_pager_background,
|
case highlight_role_t::escape:
|
||||||
[highlight_spec_pager_secondary_prefix] = highlight_spec_pager_prefix,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_pager_secondary_completion] = highlight_spec_pager_completion,
|
case highlight_role_t::quote:
|
||||||
[highlight_spec_pager_secondary_description] = highlight_spec_pager_description,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_pager_selected_background] = highlight_spec_search_match,
|
case highlight_role_t::redirection:
|
||||||
[highlight_spec_pager_selected_prefix] = highlight_spec_pager_prefix,
|
return highlight_role_t::normal;
|
||||||
[highlight_spec_pager_selected_completion] = highlight_spec_pager_completion,
|
case highlight_role_t::autosuggestion:
|
||||||
[highlight_spec_pager_selected_description] = highlight_spec_pager_description,
|
return highlight_role_t::normal;
|
||||||
};
|
case highlight_role_t::selection:
|
||||||
static_assert(sizeof(fallbacks) / sizeof(fallbacks[0]) == HIGHLIGHT_SPEC_MAX, "No missing fallbacks");
|
return highlight_role_t::normal;
|
||||||
|
case highlight_role_t::pager_progress:
|
||||||
|
return highlight_role_t::normal;
|
||||||
|
case highlight_role_t::pager_background:
|
||||||
|
return highlight_role_t::normal;
|
||||||
|
case highlight_role_t::pager_prefix:
|
||||||
|
return highlight_role_t::normal;
|
||||||
|
case highlight_role_t::pager_completion:
|
||||||
|
return highlight_role_t::normal;
|
||||||
|
case highlight_role_t::pager_description:
|
||||||
|
return highlight_role_t::normal;
|
||||||
|
case highlight_role_t::pager_secondary_background:
|
||||||
|
return highlight_role_t::pager_background;
|
||||||
|
case highlight_role_t::pager_secondary_prefix:
|
||||||
|
return highlight_role_t::pager_prefix;
|
||||||
|
case highlight_role_t::pager_secondary_completion:
|
||||||
|
return highlight_role_t::pager_completion;
|
||||||
|
case highlight_role_t::pager_secondary_description:
|
||||||
|
return highlight_role_t::pager_description;
|
||||||
|
case highlight_role_t::pager_selected_background:
|
||||||
|
return highlight_role_t::search_match;
|
||||||
|
case highlight_role_t::pager_selected_prefix:
|
||||||
|
return highlight_role_t::pager_prefix;
|
||||||
|
case highlight_role_t::pager_selected_completion:
|
||||||
|
return highlight_role_t::pager_completion;
|
||||||
|
case highlight_role_t::pager_selected_description:
|
||||||
|
return highlight_role_t::pager_description;
|
||||||
|
}
|
||||||
|
DIE("invalid highlight role");
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine if the filesystem containing the given fd is case insensitive for lookups regardless
|
/// Determine if the filesystem containing the given fd is case insensitive for lookups regardless
|
||||||
/// of whether it preserves the case when saving a pathname.
|
/// of whether it preserves the case when saving a pathname.
|
||||||
|
@ -292,30 +348,19 @@ static bool plain_statement_get_expanded_command(const wcstring &src,
|
||||||
return err == EXPAND_OK || err == EXPAND_WILDCARD_MATCH;
|
return err == EXPAND_OK || err == EXPAND_WILDCARD_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background) {
|
rgb_color_t highlight_get_color(const highlight_spec_t &highlight, bool is_background) {
|
||||||
// TODO: rationalize this principal_vars.
|
// TODO: rationalize this principal_vars.
|
||||||
const auto &vars = env_stack_t::principal();
|
const auto &vars = env_stack_t::principal();
|
||||||
rgb_color_t result = rgb_color_t::normal();
|
rgb_color_t result = rgb_color_t::normal();
|
||||||
|
highlight_role_t role = is_background ? highlight.background : highlight.foreground;
|
||||||
|
|
||||||
bool treat_as_background = is_background;
|
auto var = vars.get(get_highlight_var_name(role));
|
||||||
|
if (!var) var = vars.get(get_highlight_var_name(get_fallback(role)));
|
||||||
// Get the primary variable.
|
if (!var) var = vars.get(get_highlight_var_name(highlight_role_t::normal));
|
||||||
size_t idx = highlight_get_primary(highlight);
|
if (var) result = parse_color(*var, is_background);
|
||||||
if (idx >= VAR_COUNT) {
|
|
||||||
return rgb_color_t::normal();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto var = vars.get(highlight_var[idx]);
|
|
||||||
|
|
||||||
// debug( 1, L"%d -> %d -> %ls", highlight, idx, val );
|
|
||||||
|
|
||||||
if (!var) var = vars.get(highlight_var[fallbacks[idx]]);
|
|
||||||
if (!var) var = vars.get(highlight_var[0]);
|
|
||||||
|
|
||||||
if (var) result = parse_color(*var, treat_as_background);
|
|
||||||
|
|
||||||
// Handle modifiers.
|
// Handle modifiers.
|
||||||
if (highlight & highlight_modifier_valid_path) {
|
if (!is_background && highlight.valid_path) {
|
||||||
auto var2 = vars.get(L"fish_color_valid_path");
|
auto var2 = vars.get(L"fish_color_valid_path");
|
||||||
if (var2) {
|
if (var2) {
|
||||||
rgb_color_t result2 = parse_color(*var2, is_background);
|
rgb_color_t result2 = parse_color(*var2, is_background);
|
||||||
|
@ -331,7 +376,7 @@ rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highlight & highlight_modifier_force_underline) {
|
if (!is_background && highlight.force_underline) {
|
||||||
result.set_underline(true);
|
result.set_underline(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,9 +480,9 @@ static size_t color_variable(const wchar_t *in, size_t in_len,
|
||||||
// Our color depends on the next char.
|
// Our color depends on the next char.
|
||||||
wchar_t next = in[idx + 1];
|
wchar_t next = in[idx + 1];
|
||||||
if (next == L'$' || valid_var_name_char(next)) {
|
if (next == L'$' || valid_var_name_char(next)) {
|
||||||
colors[idx] = highlight_spec_operator;
|
colors[idx] = highlight_role_t::operat;
|
||||||
} else {
|
} else {
|
||||||
colors[idx] = highlight_spec_error;
|
colors[idx] = highlight_role_t::error;
|
||||||
}
|
}
|
||||||
idx++;
|
idx++;
|
||||||
dollar_count++;
|
dollar_count++;
|
||||||
|
@ -445,7 +490,7 @@ static size_t color_variable(const wchar_t *in, size_t in_len,
|
||||||
|
|
||||||
// Handle a sequence of variable characters.
|
// Handle a sequence of variable characters.
|
||||||
while (valid_var_name_char(in[idx])) {
|
while (valid_var_name_char(in[idx])) {
|
||||||
colors[idx++] = highlight_spec_operator;
|
colors[idx++] = highlight_role_t::operat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a slice, up to dollar_count of them. Note that we currently don't do any validation of
|
// Handle a slice, up to dollar_count of them. Note that we currently don't do any validation of
|
||||||
|
@ -456,8 +501,8 @@ static size_t color_variable(const wchar_t *in, size_t in_len,
|
||||||
if (located == 1) {
|
if (located == 1) {
|
||||||
size_t slice_begin_idx = slice_begin - in, slice_end_idx = slice_end - in;
|
size_t slice_begin_idx = slice_begin - in, slice_end_idx = slice_end - in;
|
||||||
assert(slice_end_idx > slice_begin_idx);
|
assert(slice_end_idx > slice_begin_idx);
|
||||||
colors[slice_begin_idx] = highlight_spec_operator;
|
colors[slice_begin_idx] = highlight_role_t::operat;
|
||||||
colors[slice_end_idx] = highlight_spec_operator;
|
colors[slice_end_idx] = highlight_role_t::operat;
|
||||||
idx = slice_end_idx + 1;
|
idx = slice_end_idx + 1;
|
||||||
} else if (located == 0) {
|
} else if (located == 0) {
|
||||||
// not a slice
|
// not a slice
|
||||||
|
@ -468,7 +513,7 @@ static size_t color_variable(const wchar_t *in, size_t in_len,
|
||||||
// double-quoted string that doesn't happen. As such, color the variable + the slice
|
// double-quoted string that doesn't happen. As such, color the variable + the slice
|
||||||
// start red. Coloring any more than that looks bad, unless we're willing to try and
|
// start red. Coloring any more than that looks bad, unless we're willing to try and
|
||||||
// detect where the double-quoted string ends, and I'd rather not do that.
|
// detect where the double-quoted string ends, and I'd rather not do that.
|
||||||
std::fill(colors, colors + idx + 1, (highlight_spec_t)highlight_spec_error);
|
std::fill(colors, colors + idx + 1, highlight_role_t::error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,14 +525,14 @@ static size_t color_variable(const wchar_t *in, size_t in_len,
|
||||||
static void color_string_internal(const wcstring &buffstr, highlight_spec_t base_color,
|
static void color_string_internal(const wcstring &buffstr, highlight_spec_t base_color,
|
||||||
std::vector<highlight_spec_t>::iterator colors) {
|
std::vector<highlight_spec_t>::iterator colors) {
|
||||||
// Clarify what we expect.
|
// Clarify what we expect.
|
||||||
assert((base_color == highlight_spec_param || base_color == highlight_spec_command) &&
|
assert((base_color == highlight_role_t::param || base_color == highlight_role_t::command) &&
|
||||||
"Unexpected base color");
|
"Unexpected base color");
|
||||||
const size_t buff_len = buffstr.size();
|
const size_t buff_len = buffstr.size();
|
||||||
std::fill(colors, colors + buff_len, base_color);
|
std::fill(colors, colors + buff_len, base_color);
|
||||||
|
|
||||||
// Hacky support for %self which must be an unquoted literal argument.
|
// Hacky support for %self which must be an unquoted literal argument.
|
||||||
if (buffstr == PROCESS_EXPAND_SELF_STR) {
|
if (buffstr == PROCESS_EXPAND_SELF_STR) {
|
||||||
std::fill_n(colors, wcslen(PROCESS_EXPAND_SELF_STR), highlight_spec_operator);
|
std::fill_n(colors, wcslen(PROCESS_EXPAND_SELF_STR), highlight_role_t::operat);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +543,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case e_unquoted: {
|
case e_unquoted: {
|
||||||
if (c == L'\\') {
|
if (c == L'\\') {
|
||||||
int fill_color = highlight_spec_escape; // may be set to highlight_error
|
auto fill_color = highlight_role_t::escape; // may be set to highlight_error
|
||||||
const size_t backslash_pos = in_pos;
|
const size_t backslash_pos = in_pos;
|
||||||
size_t fill_end = backslash_pos;
|
size_t fill_end = backslash_pos;
|
||||||
|
|
||||||
|
@ -508,7 +553,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
|
|
||||||
if (escaped_char == L'\0') {
|
if (escaped_char == L'\0') {
|
||||||
fill_end = in_pos;
|
fill_end = in_pos;
|
||||||
fill_color = highlight_spec_error;
|
fill_color = highlight_role_t::error;
|
||||||
} else if (wcschr(L"~%", escaped_char)) {
|
} else if (wcschr(L"~%", escaped_char)) {
|
||||||
if (in_pos == 1) {
|
if (in_pos == 1) {
|
||||||
fill_end = in_pos + 1;
|
fill_end = in_pos + 1;
|
||||||
|
@ -571,7 +616,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
fill_end = in_pos;
|
fill_end = in_pos;
|
||||||
|
|
||||||
// It's an error if we exceeded the max value.
|
// It's an error if we exceeded the max value.
|
||||||
if (res > max_val) fill_color = highlight_spec_error;
|
if (res > max_val) fill_color = highlight_role_t::error;
|
||||||
|
|
||||||
// Subtract one from in_pos, so that the increment in the loop will move to
|
// Subtract one from in_pos, so that the increment in the loop will move to
|
||||||
// the next character.
|
// the next character.
|
||||||
|
@ -584,7 +629,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case L'~': {
|
case L'~': {
|
||||||
if (in_pos == 0) {
|
if (in_pos == 0) {
|
||||||
colors[in_pos] = highlight_spec_operator;
|
colors[in_pos] = highlight_role_t::operat;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -598,39 +643,39 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
}
|
}
|
||||||
case L'?': {
|
case L'?': {
|
||||||
if (!feature_test(features_t::qmark_noglob)) {
|
if (!feature_test(features_t::qmark_noglob)) {
|
||||||
colors[in_pos] = highlight_spec_operator;
|
colors[in_pos] = highlight_role_t::operat;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case L'*':
|
case L'*':
|
||||||
case L'(':
|
case L'(':
|
||||||
case L')': {
|
case L')': {
|
||||||
colors[in_pos] = highlight_spec_operator;
|
colors[in_pos] = highlight_role_t::operat;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case L'{': {
|
case L'{': {
|
||||||
colors[in_pos] = highlight_spec_operator;
|
colors[in_pos] = highlight_role_t::operat;
|
||||||
bracket_count++;
|
bracket_count++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case L'}': {
|
case L'}': {
|
||||||
colors[in_pos] = highlight_spec_operator;
|
colors[in_pos] = highlight_role_t::operat;
|
||||||
bracket_count--;
|
bracket_count--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case L',': {
|
case L',': {
|
||||||
if (bracket_count > 0) {
|
if (bracket_count > 0) {
|
||||||
colors[in_pos] = highlight_spec_operator;
|
colors[in_pos] = highlight_role_t::operat;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case L'\'': {
|
case L'\'': {
|
||||||
colors[in_pos] = highlight_spec_quote;
|
colors[in_pos] = highlight_role_t::quote;
|
||||||
mode = e_single_quoted;
|
mode = e_single_quoted;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case L'\"': {
|
case L'\"': {
|
||||||
colors[in_pos] = highlight_spec_quote;
|
colors[in_pos] = highlight_role_t::quote;
|
||||||
mode = e_double_quoted;
|
mode = e_double_quoted;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -643,14 +688,14 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
}
|
}
|
||||||
// Mode 1 means single quoted string, i.e 'foo'.
|
// Mode 1 means single quoted string, i.e 'foo'.
|
||||||
case e_single_quoted: {
|
case e_single_quoted: {
|
||||||
colors[in_pos] = highlight_spec_quote;
|
colors[in_pos] = highlight_role_t::quote;
|
||||||
if (c == L'\\') {
|
if (c == L'\\') {
|
||||||
// backslash
|
// backslash
|
||||||
if (in_pos + 1 < buff_len) {
|
if (in_pos + 1 < buff_len) {
|
||||||
const wchar_t escaped_char = buffstr.at(in_pos + 1);
|
const wchar_t escaped_char = buffstr.at(in_pos + 1);
|
||||||
if (escaped_char == L'\\' || escaped_char == L'\'') {
|
if (escaped_char == L'\\' || escaped_char == L'\'') {
|
||||||
colors[in_pos] = highlight_spec_escape; // backslash
|
colors[in_pos] = highlight_role_t::escape; // backslash
|
||||||
colors[in_pos + 1] = highlight_spec_escape; // escaped char
|
colors[in_pos + 1] = highlight_role_t::escape; // escaped char
|
||||||
in_pos += 1; // skip over backslash
|
in_pos += 1; // skip over backslash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -664,7 +709,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
// Slices are colored in advance, past `in_pos`, and we don't want to overwrite
|
// Slices are colored in advance, past `in_pos`, and we don't want to overwrite
|
||||||
// that.
|
// that.
|
||||||
if (colors[in_pos] == base_color) {
|
if (colors[in_pos] == base_color) {
|
||||||
colors[in_pos] = highlight_spec_quote;
|
colors[in_pos] = highlight_role_t::quote;
|
||||||
}
|
}
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case L'"': {
|
case L'"': {
|
||||||
|
@ -676,8 +721,8 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
if (in_pos + 1 < buff_len) {
|
if (in_pos + 1 < buff_len) {
|
||||||
const wchar_t escaped_char = buffstr.at(in_pos + 1);
|
const wchar_t escaped_char = buffstr.at(in_pos + 1);
|
||||||
if (wcschr(L"\\\"\n$", escaped_char)) {
|
if (wcschr(L"\\\"\n$", escaped_char)) {
|
||||||
colors[in_pos] = highlight_spec_escape; // backslash
|
colors[in_pos] = highlight_role_t::escape; // backslash
|
||||||
colors[in_pos + 1] = highlight_spec_escape; // escaped char
|
colors[in_pos + 1] = highlight_role_t::escape; // escaped char
|
||||||
in_pos += 1; // skip over backslash
|
in_pos += 1; // skip over backslash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -778,7 +823,7 @@ void highlighter_t::color_command(tnode_t<g::tok_string> node) {
|
||||||
// Get an iterator to the colors associated with the argument.
|
// Get an iterator to the colors associated with the argument.
|
||||||
const size_t arg_start = source_range->start;
|
const size_t arg_start = source_range->start;
|
||||||
const color_array_t::iterator colors = color_array.begin() + arg_start;
|
const color_array_t::iterator colors = color_array.begin() + arg_start;
|
||||||
color_string_internal(cmd_str, highlight_spec_command, colors);
|
color_string_internal(cmd_str, highlight_role_t::command, colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
// node does not necessarily have type symbol_argument here.
|
// node does not necessarily have type symbol_argument here.
|
||||||
|
@ -793,7 +838,7 @@ void highlighter_t::color_argument(tnode_t<g::tok_string> node) {
|
||||||
const color_array_t::iterator arg_colors = color_array.begin() + arg_start;
|
const color_array_t::iterator arg_colors = color_array.begin() + arg_start;
|
||||||
|
|
||||||
// Color this argument without concern for command substitutions.
|
// Color this argument without concern for command substitutions.
|
||||||
color_string_internal(arg_str, highlight_spec_param, arg_colors);
|
color_string_internal(arg_str, highlight_role_t::param, arg_colors);
|
||||||
|
|
||||||
// Now do command substitutions.
|
// Now do command substitutions.
|
||||||
size_t cmdsub_cursor = 0, cmdsub_start = 0, cmdsub_end = 0;
|
size_t cmdsub_cursor = 0, cmdsub_start = 0, cmdsub_end = 0;
|
||||||
|
@ -814,9 +859,9 @@ void highlighter_t::color_argument(tnode_t<g::tok_string> node) {
|
||||||
// Highlight the parens. The open paren must exist; the closed paren may not if it was
|
// Highlight the parens. The open paren must exist; the closed paren may not if it was
|
||||||
// incomplete.
|
// incomplete.
|
||||||
assert(cmdsub_start < arg_str.size());
|
assert(cmdsub_start < arg_str.size());
|
||||||
this->color_array.at(arg_subcmd_start) = highlight_spec_operator;
|
this->color_array.at(arg_subcmd_start) = highlight_role_t::operat;
|
||||||
if (arg_subcmd_end < this->buff.size())
|
if (arg_subcmd_end < this->buff.size())
|
||||||
this->color_array.at(arg_subcmd_end) = highlight_spec_operator;
|
this->color_array.at(arg_subcmd_end) = highlight_role_t::operat;
|
||||||
|
|
||||||
// Compute the cursor's position within the cmdsub. We must be past the open paren (hence >)
|
// Compute the cursor's position within the cmdsub. We must be past the open paren (hence >)
|
||||||
// but can be at the end of the string or closed paren (hence <=).
|
// but can be at the end of the string or closed paren (hence <=).
|
||||||
|
@ -886,7 +931,7 @@ void highlighter_t::color_arguments(const std::vector<tnode_t<g::argument>> &arg
|
||||||
string_prefixes_string(param, L"-h");
|
string_prefixes_string(param, L"-h");
|
||||||
if (!is_help && this->io_ok &&
|
if (!is_help && this->io_ok &&
|
||||||
!is_potential_cd_path(param, working_directory, vars, PATH_EXPAND_TILDE)) {
|
!is_potential_cd_path(param, working_directory, vars, PATH_EXPAND_TILDE)) {
|
||||||
this->color_node(arg, highlight_spec_error);
|
this->color_node(arg, highlight_role_t::error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -905,7 +950,7 @@ void highlighter_t::color_redirection(tnode_t<g::redirection> redirection_node)
|
||||||
redirection_type(redirection_node, this->buff, nullptr, &target);
|
redirection_type(redirection_node, this->buff, nullptr, &target);
|
||||||
|
|
||||||
// We may get a missing redirection type if the redirection is invalid.
|
// We may get a missing redirection type if the redirection is invalid.
|
||||||
auto hl = redirect_type ? highlight_spec_redirection : highlight_spec_error;
|
auto hl = redirect_type ? highlight_role_t::redirection : highlight_role_t::error;
|
||||||
this->color_node(redir_prim, hl);
|
this->color_node(redir_prim, hl);
|
||||||
|
|
||||||
// Check if the argument contains a command substitution. If so, highlight it as a param
|
// Check if the argument contains a command substitution. If so, highlight it as a param
|
||||||
|
@ -999,7 +1044,7 @@ void highlighter_t::color_redirection(tnode_t<g::redirection> redirection_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redir_target) {
|
if (redir_target) {
|
||||||
auto hl = target_is_valid ? highlight_spec_redirection : highlight_spec_error;
|
auto hl = target_is_valid ? highlight_role_t::redirection : highlight_role_t::error;
|
||||||
this->color_node(redir_target, hl);
|
this->color_node(redir_target, hl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1125,7 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
if (length == 0) return color_array;
|
if (length == 0) return color_array;
|
||||||
|
|
||||||
// Start out at zero.
|
// Start out at zero.
|
||||||
std::fill(this->color_array.begin(), this->color_array.end(), 0);
|
std::fill(this->color_array.begin(), this->color_array.end(), highlight_spec_t{});
|
||||||
|
|
||||||
// Walk the node tree.
|
// Walk the node tree.
|
||||||
for (const parse_node_t &node : parse_tree) {
|
for (const parse_node_t &node : parse_tree) {
|
||||||
|
@ -1094,15 +1139,15 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
case symbol_case_item:
|
case symbol_case_item:
|
||||||
case symbol_decorated_statement:
|
case symbol_decorated_statement:
|
||||||
case symbol_if_statement: {
|
case symbol_if_statement: {
|
||||||
this->color_children(node, parse_token_type_string, highlight_spec_command);
|
this->color_children(node, parse_token_type_string, highlight_role_t::command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case symbol_switch_statement: {
|
case symbol_switch_statement: {
|
||||||
tnode_t<g::switch_statement> switchn(&parse_tree, &node);
|
tnode_t<g::switch_statement> switchn(&parse_tree, &node);
|
||||||
auto literal_switch = switchn.child<0>();
|
auto literal_switch = switchn.child<0>();
|
||||||
auto switch_arg = switchn.child<1>();
|
auto switch_arg = switchn.child<1>();
|
||||||
this->color_node(literal_switch, highlight_spec_command);
|
this->color_node(literal_switch, highlight_role_t::command);
|
||||||
this->color_node(switch_arg, highlight_spec_param);
|
this->color_node(switch_arg, highlight_role_t::param);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case symbol_for_header: {
|
case symbol_for_header: {
|
||||||
|
@ -1110,8 +1155,8 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
// Color the 'for' and 'in' as commands.
|
// Color the 'for' and 'in' as commands.
|
||||||
auto literal_for = fhead.child<0>();
|
auto literal_for = fhead.child<0>();
|
||||||
auto literal_in = fhead.child<2>();
|
auto literal_in = fhead.child<2>();
|
||||||
this->color_node(literal_for, highlight_spec_command);
|
this->color_node(literal_for, highlight_role_t::command);
|
||||||
this->color_node(literal_in, highlight_spec_command);
|
this->color_node(literal_in, highlight_role_t::command);
|
||||||
|
|
||||||
// Color the variable name as a parameter.
|
// Color the variable name as a parameter.
|
||||||
this->color_argument(fhead.child<1>());
|
this->color_argument(fhead.child<1>());
|
||||||
|
@ -1120,22 +1165,22 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
|
|
||||||
case parse_token_type_andand:
|
case parse_token_type_andand:
|
||||||
case parse_token_type_oror:
|
case parse_token_type_oror:
|
||||||
this->color_node(node, highlight_spec_operator);
|
this->color_node(node, highlight_role_t::operat);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case symbol_not_statement:
|
case symbol_not_statement:
|
||||||
this->color_children(node, parse_token_type_string, highlight_spec_operator);
|
this->color_children(node, parse_token_type_string, highlight_role_t::operat);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case symbol_job_decorator:
|
case symbol_job_decorator:
|
||||||
this->color_node(node, highlight_spec_operator);
|
this->color_node(node, highlight_role_t::operat);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case parse_token_type_pipe:
|
case parse_token_type_pipe:
|
||||||
case parse_token_type_background:
|
case parse_token_type_background:
|
||||||
case parse_token_type_end:
|
case parse_token_type_end:
|
||||||
case symbol_optional_background: {
|
case symbol_optional_background: {
|
||||||
this->color_node(node, highlight_spec_statement_terminator);
|
this->color_node(node, highlight_role_t::statement_terminator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case symbol_plain_statement: {
|
case symbol_plain_statement: {
|
||||||
|
@ -1166,7 +1211,7 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_valid_cmd) {
|
if (!is_valid_cmd) {
|
||||||
this->color_node(*cmd_node, highlight_spec_error);
|
this->color_node(*cmd_node, highlight_role_t::error);
|
||||||
} else {
|
} else {
|
||||||
this->color_command(cmd_node);
|
this->color_command(cmd_node);
|
||||||
}
|
}
|
||||||
|
@ -1190,16 +1235,16 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case symbol_end_command: {
|
case symbol_end_command: {
|
||||||
this->color_node(node, highlight_spec_command);
|
this->color_node(node, highlight_role_t::command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case parse_special_type_parse_error:
|
case parse_special_type_parse_error:
|
||||||
case parse_special_type_tokenizer_error: {
|
case parse_special_type_tokenizer_error: {
|
||||||
this->color_node(node, highlight_spec_error);
|
this->color_node(node, highlight_role_t::error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case parse_special_type_comment: {
|
case parse_special_type_comment: {
|
||||||
this->color_node(node, highlight_spec_comment);
|
this->color_node(node, highlight_role_t::comment);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: { break; }
|
||||||
|
@ -1225,10 +1270,10 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
node_is_potential_path(buff, node, vars, working_directory)) {
|
node_is_potential_path(buff, node, vars, working_directory)) {
|
||||||
// It is, underline it.
|
// It is, underline it.
|
||||||
for (size_t i = node.source_start; i < node.source_start + node.source_length; i++) {
|
for (size_t i = node.source_start; i < node.source_start + node.source_length; i++) {
|
||||||
// Don't color highlight_spec_error because it looks dorky. For example,
|
// Don't color highlight_role_t::error because it looks dorky. For example,
|
||||||
// trying to cd into a non-directory would show an underline and also red.
|
// trying to cd into a non-directory would show an underline and also red.
|
||||||
if (highlight_get_primary(this->color_array.at(i)) != highlight_spec_error) {
|
if (this->color_array.at(i).foreground != highlight_role_t::error) {
|
||||||
this->color_array.at(i) |= highlight_modifier_valid_path;
|
this->color_array.at(i).valid_path = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1295,10 +1340,8 @@ static void highlight_universal_internal(const wcstring &buffstr,
|
||||||
pos1 = lst.back();
|
pos1 = lst.back();
|
||||||
pos2 = str - buff;
|
pos2 = str - buff;
|
||||||
if (pos1 == pos || pos2 == pos) {
|
if (pos1 == pos || pos2 == pos) {
|
||||||
color.at(pos1) |=
|
color.at(pos1).background = highlight_role_t::match;
|
||||||
highlight_make_background(highlight_spec_match);
|
color.at(pos2).background = highlight_role_t::match;
|
||||||
color.at(pos2) |=
|
|
||||||
highlight_make_background(highlight_spec_match);
|
|
||||||
match_found = true;
|
match_found = true;
|
||||||
}
|
}
|
||||||
prev_q = *str == L'\"' ? L'\'' : L'\"';
|
prev_q = *str == L'\"' ? L'\'' : L'\"';
|
||||||
|
@ -1318,7 +1361,7 @@ static void highlight_universal_internal(const wcstring &buffstr,
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match_found) color.at(pos) = highlight_make_background(highlight_spec_error);
|
if (!match_found) color.at(pos).background = highlight_role_t::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight matching parenthesis.
|
// Highlight matching parenthesis.
|
||||||
|
@ -1335,14 +1378,15 @@ static void highlight_universal_internal(const wcstring &buffstr,
|
||||||
if (test_char == dec_char) level--;
|
if (test_char == dec_char) level--;
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
long pos2 = i;
|
long pos2 = i;
|
||||||
color.at(pos) |= highlight_spec_match << 16;
|
color.at(pos).background = highlight_role_t::match;
|
||||||
color.at(pos2) |= highlight_spec_match << 16;
|
color.at(pos2).background = highlight_role_t::match;
|
||||||
match_found = true;
|
match_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match_found) color[pos] = highlight_make_background(highlight_spec_error);
|
if (!match_found)
|
||||||
|
color.at(pos) = highlight_spec_t::make_background(highlight_role_t::error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1352,6 +1396,6 @@ void highlight_universal(const wcstring &buff, std::vector<highlight_spec_t> &co
|
||||||
UNUSED(error);
|
UNUSED(error);
|
||||||
UNUSED(vars);
|
UNUSED(vars);
|
||||||
assert(buff.size() == color.size());
|
assert(buff.size() == color.size());
|
||||||
std::fill(color.begin(), color.end(), 0);
|
std::fill(color.begin(), color.end(), highlight_spec_t{});
|
||||||
highlight_universal_internal(buff, color, pos);
|
highlight_universal_internal(buff, color, pos);
|
||||||
}
|
}
|
||||||
|
|
112
src/highlight.h
112
src/highlight.h
|
@ -11,66 +11,64 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
|
|
||||||
// Internally, we specify highlight colors using a set of bits. Each highlight_spec is a 32 bit
|
/// Describes the role of a span of text.
|
||||||
// uint. We divide this into low 16 (foreground) and high 16 (background). Each half we further
|
enum class highlight_role_t : uint8_t {
|
||||||
// subdivide into low 8 (primary) and high 8 (modifiers). The primary is not a bitmask; specify
|
normal = 0, // normal text
|
||||||
// exactly one. The modifiers are a bitmask; specify any number.
|
error, // error
|
||||||
enum {
|
command, // command
|
||||||
// The following values are mutually exclusive; specify at most one.
|
statement_terminator, // process separator
|
||||||
highlight_spec_normal = 0, // normal text
|
param, // command parameter (argument)
|
||||||
highlight_spec_error, // error
|
comment, // comment
|
||||||
highlight_spec_command, // command
|
match, // matching parenthesis, etc.
|
||||||
highlight_spec_statement_terminator, // process separator
|
search_match, // search match
|
||||||
highlight_spec_param, // command parameter (argument)
|
operat, // operator
|
||||||
highlight_spec_comment, // comment
|
escape, // escape sequences
|
||||||
highlight_spec_match, // matching parenthesis, etc.
|
quote, // quoted string
|
||||||
highlight_spec_search_match, // search match
|
redirection, // redirection
|
||||||
highlight_spec_operator, // operator
|
autosuggestion, // autosuggestion
|
||||||
highlight_spec_escape, // escape sequences
|
selection,
|
||||||
highlight_spec_quote, // quoted string
|
|
||||||
highlight_spec_redirection, // redirection
|
|
||||||
highlight_spec_autosuggestion, // autosuggestion
|
|
||||||
highlight_spec_selection,
|
|
||||||
|
|
||||||
// Pager support.
|
// Pager support.
|
||||||
// NOTE: pager.cpp relies on these being in this order.
|
// NOTE: pager.cpp relies on these being in this order.
|
||||||
highlight_spec_pager_progress,
|
pager_progress,
|
||||||
highlight_spec_pager_background,
|
pager_background,
|
||||||
highlight_spec_pager_prefix,
|
pager_prefix,
|
||||||
highlight_spec_pager_completion,
|
pager_completion,
|
||||||
highlight_spec_pager_description,
|
pager_description,
|
||||||
highlight_spec_pager_secondary_background,
|
pager_secondary_background,
|
||||||
highlight_spec_pager_secondary_prefix,
|
pager_secondary_prefix,
|
||||||
highlight_spec_pager_secondary_completion,
|
pager_secondary_completion,
|
||||||
highlight_spec_pager_secondary_description,
|
pager_secondary_description,
|
||||||
highlight_spec_pager_selected_background,
|
pager_selected_background,
|
||||||
highlight_spec_pager_selected_prefix,
|
pager_selected_prefix,
|
||||||
highlight_spec_pager_selected_completion,
|
pager_selected_completion,
|
||||||
highlight_spec_pager_selected_description,
|
pager_selected_description,
|
||||||
|
|
||||||
// Used to double check a data structure in highlight.cpp
|
|
||||||
HIGHLIGHT_SPEC_MAX,
|
|
||||||
|
|
||||||
HIGHLIGHT_SPEC_PRIMARY_MASK = 0xFF,
|
|
||||||
|
|
||||||
// The following values are modifiers.
|
|
||||||
highlight_modifier_valid_path = 0x100,
|
|
||||||
highlight_modifier_force_underline = 0x200,
|
|
||||||
/* Very special value */
|
|
||||||
highlight_spec_invalid = 0xFFFF
|
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef uint32_t highlight_spec_t;
|
|
||||||
|
|
||||||
inline highlight_spec_t highlight_get_primary(highlight_spec_t val) {
|
/// Simply value type describing how a character should be highlighted..
|
||||||
return val & HIGHLIGHT_SPEC_PRIMARY_MASK;
|
struct highlight_spec_t {
|
||||||
|
highlight_role_t foreground{highlight_role_t::normal};
|
||||||
|
highlight_role_t background{highlight_role_t::normal};
|
||||||
|
bool valid_path{false};
|
||||||
|
bool force_underline{false};
|
||||||
|
|
||||||
|
highlight_spec_t() = default;
|
||||||
|
|
||||||
|
/* implicit */ highlight_spec_t(highlight_role_t fg,
|
||||||
|
highlight_role_t bg = highlight_role_t::normal)
|
||||||
|
: foreground(fg), background(bg) {}
|
||||||
|
|
||||||
|
bool operator==(const highlight_spec_t &rhs) const {
|
||||||
|
return foreground == rhs.foreground && background == rhs.background &&
|
||||||
|
valid_path == rhs.valid_path && force_underline == rhs.force_underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline highlight_spec_t highlight_make_background(highlight_spec_t val) {
|
bool operator!=(const highlight_spec_t &rhs) const { return !(*this == rhs); }
|
||||||
assert(val >> 16 ==
|
|
||||||
0); // should have nothing in upper bits, otherwise this is already a background
|
static highlight_spec_t make_background(highlight_role_t bg_role) {
|
||||||
return val << 16;
|
return highlight_spec_t{highlight_role_t::normal, bg_role};
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class history_item_t;
|
class history_item_t;
|
||||||
|
|
||||||
|
@ -104,14 +102,8 @@ void highlight_shell_no_io(const wcstring &buffstr, std::vector<highlight_spec_t
|
||||||
void highlight_universal(const wcstring &buffstr, std::vector<highlight_spec_t> &color, size_t pos,
|
void highlight_universal(const wcstring &buffstr, std::vector<highlight_spec_t> &color, size_t pos,
|
||||||
wcstring_list_t *error, const environment_t &vars);
|
wcstring_list_t *error, const environment_t &vars);
|
||||||
|
|
||||||
/// Translate from HIGHLIGHT_* to FISH_COLOR_* according to environment variables. Defaults to
|
/// \return an RGB color for a given highlight spec.
|
||||||
/// FISH_COLOR_NORMAL.
|
rgb_color_t highlight_get_color(const highlight_spec_t &highlight, bool is_background);
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
///
|
|
||||||
/// If the environment variable FISH_FISH_COLOR_ERROR is set to 'red', a call to
|
|
||||||
/// highlight_get_color( highlight_error) will return FISH_COLOR_RED.
|
|
||||||
rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background);
|
|
||||||
|
|
||||||
/// Given a command 'str' from the history, try to determine whether we ought to suggest it by
|
/// Given a command 'str' from the history, try to determine whether we ought to suggest it by
|
||||||
/// specially recognizing the command. Returns true if we validated the command. If so, returns by
|
/// specially recognizing the command. Returns true if we validated the command. If so, returns by
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -137,20 +138,25 @@ line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, s
|
||||||
assert(comp_width <= width);
|
assert(comp_width <= width);
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = selected
|
auto modify_role = [=](highlight_role_t role) -> highlight_role_t {
|
||||||
? (highlight_spec_pager_selected_background - highlight_spec_pager_background)
|
using uint_t = typename std::underlying_type<highlight_role_t>::type;
|
||||||
: (secondary
|
uint_t base = static_cast<uint_t>(role);
|
||||||
? (highlight_spec_pager_secondary_background - highlight_spec_pager_background)
|
if (selected) {
|
||||||
: 0);
|
base += static_cast<uint_t>(highlight_role_t::pager_selected_background) -
|
||||||
highlight_spec_t bg_color = highlight_spec_pager_background + offset;
|
static_cast<uint_t>(highlight_role_t::pager_background);
|
||||||
highlight_spec_t prefix_fg = highlight_spec_pager_prefix + offset;
|
} else if (secondary) {
|
||||||
highlight_spec_t comp_fg = highlight_spec_pager_completion + offset;
|
base += static_cast<uint_t>(highlight_role_t::pager_secondary_background) -
|
||||||
highlight_spec_t desc_fg = highlight_spec_pager_description + offset;
|
static_cast<uint_t>(highlight_role_t::pager_background);
|
||||||
|
}
|
||||||
|
return static_cast<highlight_role_t>(base);
|
||||||
|
};
|
||||||
|
|
||||||
|
highlight_role_t bg_role = modify_role(highlight_role_t::pager_background);
|
||||||
|
highlight_spec_t bg = {highlight_role_t::normal, bg_role};
|
||||||
|
highlight_spec_t prefix_col = {modify_role(highlight_role_t::pager_prefix), bg_role};
|
||||||
|
highlight_spec_t comp_col = {modify_role(highlight_role_t::pager_completion), bg_role};
|
||||||
|
highlight_spec_t desc_col = {modify_role(highlight_role_t::pager_description), bg_role};
|
||||||
|
|
||||||
auto bg = highlight_make_background(bg_color);
|
|
||||||
auto prefix_col = prefix_fg | bg;
|
|
||||||
auto comp_col = comp_fg | bg;
|
|
||||||
auto desc_col = desc_fg | bg;
|
|
||||||
// Print the completion part
|
// Print the completion part
|
||||||
size_t comp_remaining = comp_width;
|
size_t comp_remaining = comp_width;
|
||||||
for (size_t i = 0; i < c->comp.size(); i++) {
|
for (size_t i = 0; i < c->comp.size(); i++) {
|
||||||
|
@ -179,7 +185,7 @@ line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, s
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(desc_remaining >= 2);
|
assert(desc_remaining >= 2);
|
||||||
auto paren_col = highlight_spec_pager_completion | bg;
|
highlight_spec_t paren_col = {highlight_role_t::pager_completion, bg_role};
|
||||||
desc_remaining -= print_max(L"(", paren_col, 1, false, &line_data);
|
desc_remaining -= print_max(L"(", paren_col, 1, false, &line_data);
|
||||||
desc_remaining -= print_max(c->desc, desc_col, desc_remaining - 1, false, &line_data);
|
desc_remaining -= print_max(c->desc, desc_col, desc_remaining - 1, false, &line_data);
|
||||||
desc_remaining -= print_max(L")", paren_col, 1, false, &line_data);
|
desc_remaining -= print_max(L")", paren_col, 1, false, &line_data);
|
||||||
|
@ -226,7 +232,7 @@ void pager_t::completion_print(size_t cols, const size_t *width_by_column, size_
|
||||||
|
|
||||||
// If there's more to come, append two spaces.
|
// If there's more to come, append two spaces.
|
||||||
if (col + 1 < cols) {
|
if (col + 1 < cols) {
|
||||||
line.append(PAGER_SPACER_STRING, 0);
|
line.append(PAGER_SPACER_STRING, highlight_spec_t{});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append this to the real line.
|
// Append this to the real line.
|
||||||
|
@ -503,8 +509,8 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co
|
||||||
|
|
||||||
if (!progress_text.empty()) {
|
if (!progress_text.empty()) {
|
||||||
line_t &line = rendering->screen_data.add_line();
|
line_t &line = rendering->screen_data.add_line();
|
||||||
highlight_spec_t spec = highlight_spec_pager_progress |
|
highlight_spec_t spec = {highlight_role_t::pager_progress,
|
||||||
highlight_make_background(highlight_spec_pager_progress);
|
highlight_role_t::pager_progress};
|
||||||
print_max(progress_text, spec, term_width, true /* has_more */, &line);
|
print_max(progress_text, spec, term_width, true /* has_more */, &line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,11 +527,14 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co
|
||||||
line_t *search_field = &rendering->screen_data.insert_line_at_index(0);
|
line_t *search_field = &rendering->screen_data.insert_line_at_index(0);
|
||||||
|
|
||||||
// We limit the width to term_width - 1.
|
// We limit the width to term_width - 1.
|
||||||
|
highlight_spec_t underline{};
|
||||||
|
underline.force_underline = true;
|
||||||
|
|
||||||
size_t search_field_remaining = term_width - 1;
|
size_t search_field_remaining = term_width - 1;
|
||||||
search_field_remaining -= print_max(SEARCH_FIELD_PROMPT, highlight_spec_normal,
|
search_field_remaining -= print_max(SEARCH_FIELD_PROMPT, highlight_role_t::normal,
|
||||||
search_field_remaining, false, search_field);
|
|
||||||
search_field_remaining -= print_max(search_field_text, highlight_modifier_force_underline,
|
|
||||||
search_field_remaining, false, search_field);
|
search_field_remaining, false, search_field);
|
||||||
|
search_field_remaining -=
|
||||||
|
print_max(search_field_text, underline, search_field_remaining, false, search_field);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -617,10 +617,10 @@ void reader_data_t::repaint() {
|
||||||
if (len < 1) len = 1;
|
if (len < 1) len = 1;
|
||||||
|
|
||||||
std::vector<highlight_spec_t> colors = this->colors;
|
std::vector<highlight_spec_t> colors = this->colors;
|
||||||
colors.resize(len, highlight_spec_autosuggestion);
|
colors.resize(len, highlight_role_t::autosuggestion);
|
||||||
|
|
||||||
if (sel_active) {
|
if (sel_active) {
|
||||||
highlight_spec_t selection_color = highlight_make_background(highlight_spec_selection);
|
highlight_spec_t selection_color = {highlight_role_t::normal, highlight_role_t::selection};
|
||||||
for (size_t i = sel_start_pos; i < std::min(len, sel_stop_pos); i++) {
|
for (size_t i = sel_start_pos; i < std::min(len, sel_stop_pos); i++) {
|
||||||
colors[i] = selection_color;
|
colors[i] = selection_color;
|
||||||
}
|
}
|
||||||
|
@ -1433,7 +1433,7 @@ void reader_data_t::flash() {
|
||||||
struct timespec pollint;
|
struct timespec pollint;
|
||||||
editable_line_t *el = &command_line;
|
editable_line_t *el = &command_line;
|
||||||
for (size_t i = 0; i < el->position; i++) {
|
for (size_t i = 0; i < el->position; i++) {
|
||||||
colors.at(i) = highlight_spec_search_match << 16;
|
colors.at(i) = highlight_spec_t::make_background(highlight_role_t::search_match);
|
||||||
}
|
}
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
|
@ -2025,7 +2025,7 @@ void reader_data_t::highlight_search() {
|
||||||
if (match_pos != wcstring::npos) {
|
if (match_pos != wcstring::npos) {
|
||||||
size_t end = match_pos + needle.size();
|
size_t end = match_pos + needle.size();
|
||||||
for (size_t i = match_pos; i < end; i++) {
|
for (size_t i = match_pos; i < end; i++) {
|
||||||
colors.at(i) |= (highlight_spec_search_match << 16);
|
colors.at(i).background = highlight_role_t::search_match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2059,7 +2059,7 @@ static std::function<highlight_result_t(void)> get_highlight_performer(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
s_thread_generation = generation_count;
|
s_thread_generation = generation_count;
|
||||||
std::vector<highlight_spec_t> colors(text.size(), 0);
|
std::vector<highlight_spec_t> colors(text.size(), highlight_spec_t{});
|
||||||
highlight_func(text, colors, match_highlight_pos, NULL /* error */, vars);
|
highlight_func(text, colors, match_highlight_pos, NULL /* error */, vars);
|
||||||
return {std::move(colors), text};
|
return {std::move(colors), text};
|
||||||
};
|
};
|
||||||
|
|
|
@ -376,7 +376,8 @@ static void s_check_status(screen_t *s) {
|
||||||
|
|
||||||
/// Appends a character to the end of the line that the output cursor is on. This function
|
/// Appends a character to the end of the line that the output cursor is on. This function
|
||||||
/// automatically handles linebreaks and lines longer than the screen width.
|
/// automatically handles linebreaks and lines longer than the screen width.
|
||||||
static void s_desired_append_char(screen_t *s, wchar_t b, int c, int indent, size_t prompt_width) {
|
static void s_desired_append_char(screen_t *s, wchar_t b, highlight_spec_t c, int indent,
|
||||||
|
size_t prompt_width) {
|
||||||
int line_no = s->desired.cursor.y;
|
int line_no = s->desired.cursor.y;
|
||||||
|
|
||||||
if (b == L'\n') {
|
if (b == L'\n') {
|
||||||
|
@ -386,7 +387,7 @@ static void s_desired_append_char(screen_t *s, wchar_t b, int c, int indent, siz
|
||||||
s->desired.cursor.y++;
|
s->desired.cursor.y++;
|
||||||
s->desired.cursor.x = 0;
|
s->desired.cursor.x = 0;
|
||||||
for (size_t i = 0; i < prompt_width + indent * INDENT_STEP; i++) {
|
for (size_t i = 0; i < prompt_width + indent * INDENT_STEP; i++) {
|
||||||
s_desired_append_char(s, L' ', 0, indent, prompt_width);
|
s_desired_append_char(s, L' ', highlight_spec_t{}, indent, prompt_width);
|
||||||
}
|
}
|
||||||
} else if (b == L'\r') {
|
} else if (b == L'\r') {
|
||||||
line_t ¤t = s->desired.line(line_no);
|
line_t ¤t = s->desired.line(line_no);
|
||||||
|
@ -512,10 +513,7 @@ static void s_move(screen_t *s, int new_x, int new_y) {
|
||||||
/// Set the pen color for the terminal.
|
/// Set the pen color for the terminal.
|
||||||
static void s_set_color(screen_t *s, const environment_t &vars, highlight_spec_t c) {
|
static void s_set_color(screen_t *s, const environment_t &vars, highlight_spec_t c) {
|
||||||
UNUSED(s);
|
UNUSED(s);
|
||||||
|
s->outp().set_color(highlight_get_color(c, false), highlight_get_color(c, true));
|
||||||
unsigned int uc = (unsigned int)c;
|
|
||||||
s->outp().set_color(highlight_get_color(uc & 0xfff, false),
|
|
||||||
highlight_get_color((uc >> 16) & 0xffff, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a wide character to a multibyte string and append it to the buffer.
|
/// Convert a wide character to a multibyte string and append it to the buffer.
|
||||||
|
@ -723,7 +721,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
clear_remainder = prev_width > current_width;
|
clear_remainder = prev_width > current_width;
|
||||||
}
|
}
|
||||||
if (clear_remainder && clr_eol) {
|
if (clear_remainder && clr_eol) {
|
||||||
s_set_color(scr, vars, 0xffffffff);
|
s_set_color(scr, vars, highlight_spec_t{});
|
||||||
s_move(scr, current_width, (int)i);
|
s_move(scr, current_width, (int)i);
|
||||||
s_write_mbs(scr, clr_eol);
|
s_write_mbs(scr, clr_eol);
|
||||||
}
|
}
|
||||||
|
@ -731,7 +729,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
// Output any rprompt if this is the first line.
|
// Output any rprompt if this is the first line.
|
||||||
if (i == 0 && right_prompt_width > 0) { //!OCLINT(Use early exit/continue)
|
if (i == 0 && right_prompt_width > 0) { //!OCLINT(Use early exit/continue)
|
||||||
s_move(scr, (int)(screen_width - right_prompt_width), (int)i);
|
s_move(scr, (int)(screen_width - right_prompt_width), (int)i);
|
||||||
s_set_color(scr, vars, 0xffffffff);
|
s_set_color(scr, vars, highlight_spec_t{});
|
||||||
s_write_str(scr, right_prompt.c_str());
|
s_write_str(scr, right_prompt.c_str());
|
||||||
scr->actual.cursor.x += right_prompt_width;
|
scr->actual.cursor.x += right_prompt_width;
|
||||||
|
|
||||||
|
@ -751,7 +749,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
|
|
||||||
// Clear remaining lines (if any) if we haven't cleared the screen.
|
// Clear remaining lines (if any) if we haven't cleared the screen.
|
||||||
if (!has_cleared_screen && scr->desired.line_count() < lines_with_stuff && clr_eol) {
|
if (!has_cleared_screen && scr->desired.line_count() < lines_with_stuff && clr_eol) {
|
||||||
s_set_color(scr, vars, 0xffffffff);
|
s_set_color(scr, vars, highlight_spec_t{});
|
||||||
for (size_t i = scr->desired.line_count(); i < lines_with_stuff; i++) {
|
for (size_t i = scr->desired.line_count(); i < lines_with_stuff; i++) {
|
||||||
s_move(scr, 0, (int)i);
|
s_move(scr, 0, (int)i);
|
||||||
s_write_mbs(scr, clr_eol);
|
s_write_mbs(scr, clr_eol);
|
||||||
|
@ -759,7 +757,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
}
|
}
|
||||||
|
|
||||||
s_move(scr, scr->desired.cursor.x, scr->desired.cursor.y);
|
s_move(scr, scr->desired.cursor.x, scr->desired.cursor.y);
|
||||||
s_set_color(scr, vars, 0xffffffff);
|
s_set_color(scr, vars, highlight_spec_t{});
|
||||||
|
|
||||||
// We have now synced our actual screen against our desired screen. Note that this is a big
|
// We have now synced our actual screen against our desired screen. Note that this is a big
|
||||||
// assignment!
|
// assignment!
|
||||||
|
@ -999,13 +997,13 @@ void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_pro
|
||||||
|
|
||||||
// Append spaces for the left prompt.
|
// Append spaces for the left prompt.
|
||||||
for (size_t i = 0; i < layout.left_prompt_space; i++) {
|
for (size_t i = 0; i < layout.left_prompt_space; i++) {
|
||||||
s_desired_append_char(s, L' ', 0, 0, layout.left_prompt_space);
|
s_desired_append_char(s, L' ', highlight_spec_t{}, 0, layout.left_prompt_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If overflowing, give the prompt its own line to improve the situation.
|
// If overflowing, give the prompt its own line to improve the situation.
|
||||||
size_t first_line_prompt_space = layout.left_prompt_space;
|
size_t first_line_prompt_space = layout.left_prompt_space;
|
||||||
if (layout.prompts_get_own_line) {
|
if (layout.prompts_get_own_line) {
|
||||||
s_desired_append_char(s, L'\n', 0, 0, 0);
|
s_desired_append_char(s, L'\n', highlight_spec_t{}, 0, 0);
|
||||||
first_line_prompt_space = 0;
|
first_line_prompt_space = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user