From 0a4c72e78b929237711717508746390e666f3811 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 12 Feb 2012 18:05:59 -0800 Subject: [PATCH] Added color.h, color.cpp. Got term256 colors working. --- FishsFish.xcodeproj/project.pbxproj | 4 + Makefile.in | 45 ++-- color.cpp | 254 ++++++++++++++++++ color.h | 120 +++++++++ fish_tests.cpp | 19 +- highlight.cpp | 2 +- highlight.h | 1 + output.cpp | 67 +++-- output.h | 1 + screen.h | 154 ----------- .../functions/__fish_config_interactive.fish | 1 + 11 files changed, 471 insertions(+), 197 deletions(-) create mode 100644 color.cpp create mode 100644 color.h diff --git a/FishsFish.xcodeproj/project.pbxproj b/FishsFish.xcodeproj/project.pbxproj index d6a14d51d..ccfcdb3ed 100644 --- a/FishsFish.xcodeproj/project.pbxproj +++ b/FishsFish.xcodeproj/project.pbxproj @@ -105,6 +105,8 @@ D0A0856513B3ACEE0099B651 /* xdgmimeint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xdgmimeint.cpp; sourceTree = ""; }; D0A0856613B3ACEE0099B651 /* xdgmimemagic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xdgmimemagic.cpp; sourceTree = ""; }; D0A0856713B3ACEE0099B651 /* xdgmimeparent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xdgmimeparent.cpp; sourceTree = ""; }; + D0B6B0FE14E88BA400AD6C10 /* color.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = color.cpp; sourceTree = ""; }; + D0B6B0FF14E88BA400AD6C10 /* color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = color.h; sourceTree = ""; }; D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = autoload.cpp; sourceTree = ""; }; D0C6FCCB14CFA4B7004CE8AD /* autoload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autoload.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -122,6 +124,8 @@ D0A0853313B3ACEE0099B651 /* builtin_set.cpp */, D0A0853413B3ACEE0099B651 /* builtin_ulimit.cpp */, D0A0853513B3ACEE0099B651 /* builtin.cpp */, + D0B6B0FF14E88BA400AD6C10 /* color.h */, + D0B6B0FE14E88BA400AD6C10 /* color.cpp */, D0A0850413B3ACEE0099B651 /* common.h */, D0A0853613B3ACEE0099B651 /* common.cpp */, D0A0850513B3ACEE0099B651 /* complete.h */, diff --git a/Makefile.in b/Makefile.in index 73c5d8d5f..4f5aaa278 100644 --- a/Makefile.in +++ b/Makefile.in @@ -96,7 +96,7 @@ FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \ tokenizer.o wildcard.o wgetopt.o wutil.o input.o output.o intern.o \ env_universal.o env_universal_common.o input_common.o event.o \ signal.o io.o parse_util.o common.o screen.o path.o autoload.o \ - parser_keywords.o iothread.o builtin_scripts.o + parser_keywords.o iothread.o builtin_scripts.o color.o FISH_INDENT_OBJS := fish_indent.o print_help.o common.o \ parser_keywords.o wutil.o tokenizer.o @@ -115,7 +115,7 @@ BUILTIN_FILES := builtin_set.cpp builtin_commandline.cpp \ FISH_PAGER_OBJS := fish_pager.o output.o wutil.o \ input_common.o env_universal.o env_universal_common.o common.o \ - print_help.o iothread.o + print_help.o iothread.o color.o # @@ -922,8 +922,8 @@ autoload.o: builtin_scripts.h exec.h proc.h io.h builtin.o: config.h signal.h fallback.h util.h wutil.h builtin.h io.h builtin.o: common.h function.h event.h complete.h proc.h parser.h reader.h builtin.o: env.h wgetopt.h sanity.h tokenizer.h wildcard.h input_common.h -builtin.o: input.h intern.h exec.h highlight.h parse_util.h autoload.h lru.h -builtin.o: parser_keywords.h expand.h path.h builtin_set.cpp +builtin.o: input.h intern.h exec.h highlight.h screen.h color.h parse_util.h +builtin.o: autoload.h lru.h parser_keywords.h expand.h path.h builtin_set.cpp builtin.o: builtin_commandline.cpp builtin_complete.cpp builtin_ulimit.cpp builtin.o: builtin_jobs.cpp builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h builtin.h @@ -941,6 +941,7 @@ builtin_set.o: common.h env.h expand.h wgetopt.h proc.h parser.h event.h builtin_set.o: function.h builtin_ulimit.o: config.h fallback.h signal.h util.h builtin.h io.h common.h builtin_ulimit.o: wgetopt.h +color.o: color.h config.h common.h util.h common.o: config.h fallback.h signal.h util.h wutil.h common.h expand.h common.o: proc.h io.h wildcard.h parser.h event.h function.h complete.h common.o: util.cpp fallback.cpp @@ -968,16 +969,16 @@ expand.o: tokenizer.h complete.h parse_util.h autoload.h lru.h fallback.o: config.h fallback.h signal.h util.h fish.o: config.h signal.h fallback.h util.h common.h reader.h io.h builtin.h fish.o: function.h event.h complete.h wutil.h env.h sanity.h proc.h parser.h -fish.o: expand.h intern.h exec.h output.h history.h path.h +fish.o: expand.h intern.h exec.h output.h screen.h color.h history.h path.h fish_indent.o: config.h fallback.h signal.h util.h common.h wutil.h fish_indent.o: tokenizer.h print_help.h parser_keywords.h fish_pager.o: config.h signal.h fallback.h util.h wutil.h common.h complete.h -fish_pager.o: output.h input_common.h env_universal.h env_universal_common.h -fish_pager.o: print_help.h +fish_pager.o: output.h screen.h color.h input_common.h env_universal.h +fish_pager.o: env_universal_common.h print_help.h fish_tests.o: config.h signal.h fallback.h util.h common.h proc.h io.h fish_tests.o: reader.h builtin.h function.h event.h autoload.h lru.h fish_tests.o: complete.h wutil.h env.h expand.h parser.h tokenizer.h output.h -fish_tests.o: exec.h path.h history.h +fish_tests.o: screen.h color.h exec.h path.h history.h fishd.o: config.h signal.h fallback.h util.h common.h wutil.h fishd.o: env_universal_common.h path.h print_help.h function.o: config.h signal.h wutil.h fallback.h util.h function.h common.h @@ -985,14 +986,15 @@ function.o: event.h proc.h io.h parser.h intern.h reader.h parse_util.h function.o: autoload.h lru.h parser_keywords.h env.h expand.h function.o: builtin_scripts.h highlight.o: config.h signal.h fallback.h util.h wutil.h highlight.h env.h -highlight.o: common.h tokenizer.h proc.h io.h parser.h event.h function.h -highlight.o: parse_util.h autoload.h lru.h parser_keywords.h builtin.h -highlight.o: expand.h sanity.h complete.h output.h wildcard.h path.h +highlight.o: common.h screen.h color.h tokenizer.h proc.h io.h parser.h +highlight.o: event.h function.h parse_util.h autoload.h lru.h +highlight.o: parser_keywords.h builtin.h expand.h sanity.h complete.h +highlight.o: output.h wildcard.h path.h history.o: config.h fallback.h signal.h util.h sanity.h wutil.h history.h history.o: common.h intern.h path.h autoload.h lru.h -input.o: config.h signal.h fallback.h util.h wutil.h reader.h io.h proc.h -input.o: common.h sanity.h input_common.h input.h parser.h event.h function.h -input.o: env.h expand.h output.h intern.h +input.o: config.h signal.h fallback.h util.h wutil.h reader.h io.h common.h +input.o: proc.h sanity.h input_common.h input.h parser.h event.h function.h +input.o: env.h expand.h output.h screen.h color.h intern.h input_common.o: config.h fallback.h signal.h util.h common.h wutil.h input_common.o: input_common.h env_universal.h env_universal_common.h input_common.o: iothread.h @@ -1004,7 +1006,7 @@ kill.o: config.h signal.h fallback.h util.h wutil.h kill.h proc.h io.h kill.o: common.h sanity.h env.h exec.h path.h mimedb.o: config.h xdgmime.h fallback.h signal.h util.h print_help.h output.o: config.h signal.h fallback.h util.h wutil.h expand.h common.h -output.o: output.h highlight.h env.h +output.o: output.h screen.h color.h highlight.h env.h parse_util.o: config.h fallback.h signal.h util.h wutil.h common.h parse_util.o: tokenizer.h parse_util.h autoload.h lru.h expand.h intern.h parse_util.o: exec.h proc.h io.h env.h wildcard.h @@ -1019,16 +1021,17 @@ path.o: config.h fallback.h signal.h util.h common.h env.h wutil.h path.h path.o: expand.h print_help.o: print_help.h proc.o: config.h signal.h fallback.h util.h wutil.h proc.h io.h common.h -proc.o: reader.h sanity.h env.h parser.h event.h function.h output.h +proc.o: reader.h sanity.h env.h parser.h event.h function.h output.h screen.h +proc.o: color.h reader.o: config.h signal.h fallback.h util.h wutil.h highlight.h env.h -reader.o: common.h reader.h io.h proc.h parser.h event.h function.h -reader.o: complete.h history.h sanity.h exec.h expand.h tokenizer.h kill.h -reader.o: input_common.h input.h output.h screen.h iothread.h intern.h -reader.o: parse_util.h autoload.h lru.h +reader.o: common.h screen.h color.h reader.h io.h proc.h parser.h event.h +reader.o: function.h complete.h history.h sanity.h exec.h expand.h +reader.o: tokenizer.h kill.h input_common.h input.h output.h iothread.h +reader.o: intern.h parse_util.h autoload.h lru.h sanity.o: config.h signal.h fallback.h util.h common.h sanity.h proc.h io.h sanity.o: history.h reader.h kill.h wutil.h screen.o: config.h fallback.h signal.h common.h util.h wutil.h output.h -screen.o: highlight.h env.h screen.h +screen.o: screen.h color.h highlight.h env.h set_color.o: config.h fallback.h signal.h print_help.h signal.o: config.h signal.h common.h util.h fallback.h wutil.h event.h signal.o: reader.h io.h proc.h diff --git a/color.cpp b/color.cpp new file mode 100644 index 000000000..2a2db5df6 --- /dev/null +++ b/color.cpp @@ -0,0 +1,254 @@ +/** \file color.cpp Color class implementation +*/ + +#include "color.h" + + +bool rgb_color_t::try_parse_special(const wcstring &special) { + bzero(&data, sizeof data); + const wchar_t *name = special.c_str(); + if (! wcscasecmp(name, L"normal")) { + this->type = type_normal; + } else if (! wcscasecmp(name, L"reset")) { + this->type = type_reset; + } else if (! wcscasecmp(name, L"ignore")) { + this->type = type_ignore; + } else { + this->type = type_none; + } + return this->type != type_none; +} + +static int parse_hex_digit(wchar_t x) { + switch (x) { + case L'0': return 0x0; + case L'1': return 0x1; + case L'2': return 0x2; + case L'3': return 0x3; + case L'4': return 0x4; + case L'5': return 0x5; + case L'6': return 0x6; + case L'7': return 0x7; + case L'8': return 0x8; + case L'9': return 0x9; + case L'a':case L'A': return 0xA; + case L'b':case L'B': return 0xB; + case L'c':case L'C': return 0xC; + case L'd':case L'D': return 0xD; + case L'e':case L'E': return 0xE; + case L'f':case L'F': return 0xF; + default: return -1; + } +} + +static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *colors, size_t color_count) { + long r = rgb[0], g = rgb[1], b = rgb[2]; + unsigned long best_distance = (unsigned long)(-1); + unsigned char best_index = (unsigned char)(-1); + for (unsigned char idx = 0; idx < color_count; idx++) { + uint32_t color = colors[idx]; + long test_r = (color >> 16) & 0xFF, test_g = (color >> 8) & 0xFF, test_b = (color >> 0) & 0xFF; + unsigned long distance = 0; + distance += (r - test_r) * (r - test_r); + distance += (g - test_g) * (g - test_g); + distance += (b - test_b) * (b - test_b); + if (distance <= best_distance) { + best_index = idx; + best_distance = distance; + } + } + return best_index; + +} + +bool rgb_color_t::try_parse_rgb(const wcstring &name) { + bzero(&data, sizeof data); + /* We support the following style of rgb formats (case insensitive): + #FA3 + #F3A035 + FA3 + F3A035 + */ + + size_t digit_idx = 0, len = name.size(); + + /* Skip any leading # */ + if (len > 0 && name.at(0) == L'#') + digit_idx++; + + bool success = false; + size_t i; + if (len - digit_idx == 3) { + // type FA3 + for (i=0; i < 3; i++) { + int val = parse_hex_digit(name.at(digit_idx++)); + if (val < 0) break; + data.rgb[i] = val*16+val; + } + success = (i == 3); + } else if (len - digit_idx == 6) { + // type F3A035 + for (i=0; i < 3; i++) { + int hi = parse_hex_digit(name.at(digit_idx++)); + int lo = parse_hex_digit(name.at(digit_idx++)); + if (lo < 0 || hi < 0) break; + data.rgb[i] = hi*16+lo; + } + success = (i == 3); + } + if (success) { + this->type = type_rgb; + } + return success; +} + +struct named_color_t { + const wchar_t * name; + unsigned char idx; + unsigned char rgb[3]; +}; + +static const named_color_t named_colors[11] = { + {L"black", 0, {0, 0, 0}}, + {L"red", 1, {0xFF, 0, 0}}, + {L"green", 2, {0, 0xFF, 0}}, + {L"brown", 3, {0x72, 0x50, 0}}, + {L"yellow", 3, {0xFF, 0xFF, 0}}, + {L"blue", 4, {0, 0, 0xFF}}, + {L"magenta", 5, {0xFF, 0, 0xFF}}, + {L"purple", 5, {0xFF, 0, 0xFF}}, + {L"cyan", 6, {0, 0xFF, 0xFF}}, + {L"white", 7, {0xFF, 0xFF, 0xFF}}, + {L"normal", 8, {0xFF, 0xFF, 0XFF}} +}; + +bool rgb_color_t::try_parse_named(const wcstring &str) { + bzero(&data, sizeof data); + size_t max = sizeof named_colors / sizeof *named_colors; + for (size_t idx=0; idx < max; idx++) { + if (0 == wcscasecmp(str.c_str(), named_colors[idx].name)) { + data.name_idx = named_colors[idx].idx; + this->type = type_named; + return true; + } + } + return false; +} + +rgb_color_t::rgb_color_t(unsigned char t, unsigned char i) : type(t), data(), flags() { + data.name_idx = i; +} + +rgb_color_t rgb_color_t::normal() { return rgb_color_t(type_normal); } +rgb_color_t rgb_color_t::reset() { return rgb_color_t(type_reset); } +rgb_color_t rgb_color_t::ignore() { return rgb_color_t(type_ignore); } +rgb_color_t rgb_color_t::none() { return rgb_color_t(type_none); } +rgb_color_t rgb_color_t::white() { return rgb_color_t(type_named, 7); } +rgb_color_t rgb_color_t::black() { return rgb_color_t(type_named, 0); } + +static unsigned char term8_color_for_rgb(const unsigned char rgb[3]) { + const uint32_t kColors[] = { + 0x000000, //Black + 0xFF0000, //Red + 0x00FF00, //Green + 0x725000, //Brown + 0xFFFF00, //Yellow + 0x0000FF, //Blue + 0xFF00FF, //Magenta + 0xFF00FF, //Purple + 0x00FFFF, //Cyan + 0xFFFFFF, //White + }; + return convert_color(rgb, kColors, sizeof kColors / sizeof *kColors); +} + +static unsigned char term256_color_for_rgb(const unsigned char rgb[3]) { + const uint32_t kColors[240] = { + 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, + 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af, + 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, + 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, + 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, + 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, + 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f, + 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, + 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, + 0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, + 0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af, + 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, + 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, + 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, + 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, + 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, + 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af, + 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, + 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, + 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, + 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, + 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f, + 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, + 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, + 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, + 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af, + 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff, + 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, + 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, + 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee + }; + return 16 + convert_color(rgb, kColors, sizeof kColors / sizeof *kColors); +} + +unsigned char rgb_color_t::to_term256_index() const { + assert(type == type_rgb); + return term256_color_for_rgb(data.rgb); +} + +unsigned char rgb_color_t::to_name_index() const { + if (type == type_named) { + return data.name_idx; + } else if (type == type_rgb) { + return term8_color_for_rgb(data.rgb); + } else { + throw "Bad type for to_name_index"; + } +} + +rgb_color_t::rgb_color_t(const wcstring &str) { + bool success = false; + if (! success) success = try_parse_special(str); + if (! success) success = try_parse_named(str); + if (! success) success = try_parse_rgb(str); + if (! success) { + bzero(this->data.rgb, sizeof this->data.rgb); + this->type = type_none; + } + if (! success) success = try_parse_special(str); + if (this->try_parse_special(str)) { + /* Nothing */ + } else if (this->try_parse_named(str)) { + + } else if (this->try_parse_rgb(str)) { + this->type = type_rgb; + } else { + bzero(this->data.rgb, sizeof this->data.rgb); + this->type = type_none; + } +} + +wcstring rgb_color_t::description() const { + switch (type) { + case type_none: + return L"none"; + case type_named: + return format_string(L"named(%d)", (int)data.name_idx); + case type_rgb: + return format_string(L"rgb(0x%02x%02x%02x)", data.rgb[0], data.rgb[1], data.rgb[2]); + case type_reset: + return L"reset"; + case type_ignore: + return L"ignore"; + default: + abort(); + return L""; + } +} \ No newline at end of file diff --git a/color.h b/color.h new file mode 100644 index 000000000..f0e17990b --- /dev/null +++ b/color.h @@ -0,0 +1,120 @@ +/** \file color.h Color class. + */ +#ifndef FISH_COLOR_H +#define FISH_COLOR_H + +#include +#include +#include "config.h" +#include "common.h" + + +/* A type that represents a color */ +class rgb_color_t { + enum { + type_none, + type_named, + type_rgb, + type_normal, + type_reset, + type_ignore + }; + unsigned char type; + union { + unsigned char name_idx; //0-10 + unsigned char rgb[3]; + } data; + unsigned flags; + + /** Try parsing a special color name like "normal" */ + bool try_parse_special(const wcstring &str); + + /** Try parsing an rgb color like "#F0A030" */ + bool try_parse_rgb(const wcstring &str); + + /** Try parsing an explicit color name like "magenta" */ + bool try_parse_named(const wcstring &str); + + /** Private constructor */ + explicit rgb_color_t(unsigned char t, unsigned char i=0); + + public: + + /** Default constructor of type none */ + explicit rgb_color_t() : type(type_none), data(), flags() {} + + /** Parse a color from a string */ + explicit rgb_color_t(const wcstring &str); + + /** Returns white */ + static rgb_color_t white(); + + /** Returns black */ + static rgb_color_t black(); + + /** Returns the reset special color */ + static rgb_color_t reset(); + + /** Returns the normal special color */ + static rgb_color_t normal(); + + /** Returns the ignore special color */ + static rgb_color_t ignore(); + + /** Returns the none special color */ + static rgb_color_t none(); + + /** Returns whether the color is the ignore special color */ + bool is_ignore(void) const { return type == type_ignore; } + + /** Returns whether the color is the normal special color */ + bool is_normal(void) const { return type == type_normal; } + + /** Returns whether the color is the reset special color */ + bool is_reset(void) const { return type == type_reset; } + + /** Returns whether the color is the none special color */ + bool is_none(void) const { return type == type_none; } + + /** Returns whether the color is a named color (like "magenta") */ + bool is_named(void) const { return type == type_named; } + + /** Returns whether the color is specified via RGB components */ + bool is_rgb(void) const { return type == type_rgb; } + + /** Returns whether the color is special, that is, not rgb or named */ + bool is_special(void) const { return type != type_named && type != type_rgb; } + + /** Returns a description of the color */ + wcstring description() const; + + /** Returns the name index for the given color. Requires that the color be named or RGB. */ + unsigned char to_name_index() const; + + /** Returns the term256 index for the given color. Requires that the color be named or RGB. */ + unsigned char to_term256_index() const; + + /** Returns whether the color is bold */ + bool is_bold() const { return flags & 1; } + + /** Set whether the color is bold */ + void set_bold(bool x) { if (x) flags |= 1; else flags &= ~1; } + + /** Returns whether the color is underlined */ + bool is_underline() const { return flags & 2; } + + /** Set whether the color is underlined */ + void set_underline(bool x) { if (x) flags |= 2; else flags &= ~2; } + + /** Compare two colors for equality */ + bool operator==(const rgb_color_t &other) const { + return type == other.type && ! memcmp(&data, &other.data, sizeof data); + } + + /** Compare two colors for inequality */ + bool operator!=(const rgb_color_t &other) const { + return !(*this == other); + } +}; + +#endif diff --git a/fish_tests.cpp b/fish_tests.cpp index 06f5e6e40..f206cd838 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -670,12 +670,28 @@ static void test_path() wcstring path = L"//foo//////bar/"; wcstring canon = path; path_make_canonical(canon); - if( canon != L"/foo/bar" ) ) + if( canon != L"/foo/bar" ) { err( L"Bug in canonical PATH code" ); } } +/** Testing colors */ +static void test_colors() +{ + say(L"Testing colors"); + assert(rgb_color_t(L"#FF00A0").is_rgb()); + assert(rgb_color_t(L"FF00A0").is_rgb()); + assert(rgb_color_t(L"#F30").is_rgb()); + assert(rgb_color_t(L"F30").is_rgb()); + assert(rgb_color_t(L"f30").is_rgb()); + assert(rgb_color_t(L"#FF30a5").is_rgb()); + assert(rgb_color_t(L"3f30").is_none()); + assert(rgb_color_t(L"##f30").is_none()); + assert(rgb_color_t(L"magenta").is_named()); + assert(rgb_color_t(L"MaGeNTa").is_named()); + assert(rgb_color_t(L"mooganta").is_none()); +} /** @@ -808,6 +824,7 @@ int main( int argc, char **argv ) test_lru(); test_expand(); test_path(); + test_colors(); test_history(); say( L"Encountered %d errors in low-level tests", err_count ); diff --git a/highlight.cpp b/highlight.cpp index 6c4f38bee..490b201e2 100644 --- a/highlight.cpp +++ b/highlight.cpp @@ -201,7 +201,7 @@ rgb_color_t highlight_get_rgb_color( int highlight, bool is_background ) const wcstring val2 = val2_wstr.missing() ? L"" : val2_wstr.c_str(); rgb_color_t result2 = parse_color( val2, is_background ); - if( result == rgb_color_t::normal() ) + if( result.is_normal() ) result = result2; else { diff --git a/highlight.h b/highlight.h index 73500d446..6f77ea5bd 100644 --- a/highlight.h +++ b/highlight.h @@ -10,6 +10,7 @@ #include "env.h" #include "util.h" #include "screen.h" +#include "color.h" /** Internal value representing highlighting of normal text diff --git a/output.cpp b/output.cpp index fce1105d8..12ecd6634 100644 --- a/output.cpp +++ b/output.cpp @@ -55,6 +55,7 @@ #include "common.h" #include "output.h" #include "highlight.h" +#include "env.h" /** Number of color names in the col array @@ -126,8 +127,30 @@ int (*output_get_writer())(char) return out; } +bool allow_term256(void) +{ + //consider using t_Co + ASSERT_IS_MAIN_THREAD(); + const wchar_t *t = output_get_term(); + return t && wcsstr(t, L"256color"); +} + +static unsigned char index_for_color(rgb_color_t c) { + if (c.is_named() || ! allow_term256()) { + return c.to_name_index(); + } else { + return c.to_term256_index(); + } +} + void set_color(rgb_color_t c, rgb_color_t c2) { + +#if 0 + wcstring tmp = c.description(); + wcstring tmp2 = c2.description(); + printf("set_color %ls : %ls\n", tmp.c_str(), tmp2.c_str()); +#endif ASSERT_IS_MAIN_THREAD(); const rgb_color_t normal = rgb_color_t::normal(); @@ -198,9 +221,9 @@ void set_color(rgb_color_t c, rgb_color_t c2) was_underline=0; } - if( last_color2 != rgb_color_t::normal() && - last_color2 != rgb_color_t::reset() && - last_color2 != rgb_color_t::ignore() ) + if( ! last_color2.is_normal() && + ! last_color2.is_reset() && + ! last_color2.is_ignore() ) { /* Background was set @@ -208,15 +231,14 @@ void set_color(rgb_color_t c, rgb_color_t c2) last_bg_set=1; } - if( c2 != rgb_color_t::normal() && - c2 != rgb_color_t::ignore() ) + if( ! c2.is_normal() && + ! c2.is_ignore()) { /* Background is set */ bg_set=1; - // PCA color fix - //c = (c2==FISH_COLOR_WHITE)?FISH_COLOR_BLACK:FISH_COLOR_WHITE; + c = (c2==rgb_color_t::white())?rgb_color_t::black():rgb_color_t::white(); } if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0)) @@ -253,7 +275,7 @@ void set_color(rgb_color_t c, rgb_color_t c2) if( last_color != c ) { - if( c==rgb_color_t::normal() ) + if( c.is_normal() ) { if( fg ) { @@ -265,11 +287,11 @@ void set_color(rgb_color_t c, rgb_color_t c2) was_bold=0; was_underline=0; } - else if( c.is_named() ) + else if( ! c.is_special() ) { if( fg ) { - writembs( tparm( fg, c.name_index() ) ); + writembs( tparm(fg, index_for_color(c)) ); } } } @@ -278,7 +300,7 @@ void set_color(rgb_color_t c, rgb_color_t c2) if( last_color2 != c2 ) { - if( c2 == rgb_color_t::normal() ) + if( c2.is_normal() ) { if( bg ) { @@ -286,12 +308,9 @@ void set_color(rgb_color_t c, rgb_color_t c2) } writembs( exit_attribute_mode ); - if( ( last_color != rgb_color_t::normal() ) && fg ) + if( ! last_color.is_normal() && fg ) { - if( fg ) - { - writembs( tparm( fg, last_color.name_index() ) ); - } + writembs( tparm( fg, index_for_color(last_color) )); } @@ -299,11 +318,11 @@ void set_color(rgb_color_t c, rgb_color_t c2) was_underline=0; last_color2 = c2; } - else if ( c2.is_named() && c2 != normal) + else if ( ! c2.is_special() ) { if( bg ) { - writembs( tparm( bg, c2.name_index() ) ); + writembs( tparm( bg, index_for_color(c2) )); } last_color2 = c2; } @@ -794,7 +813,6 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) { if (string_prefixes_string(prefix, next)) { color_name = wcstring(next, prefix.size()); } - } else { if (next == L"--bold" || next == L"-o") is_bold = true; @@ -805,9 +823,18 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) { } if (! color_name.empty()) { - rgb_color_t::parse(color_name, result); + result = rgb_color_t(color_name); + if (result.is_none()) { + result = rgb_color_t::normal(); + } } } +#if 0 + wcstring desc = result.description(); + printf("Parsed %ls from %ls (%s)\n", desc.c_str(), val.c_str(), is_background ? "background" : "foreground"); +#endif + if (result.is_none()) + result = rgb_color_t::normal(); return result; } diff --git a/output.h b/output.h index d1a1ad898..c277b322c 100644 --- a/output.h +++ b/output.h @@ -10,6 +10,7 @@ #include #include "screen.h" +#include "color.h" /** Constants for various colors as used by the set_color function. diff --git a/screen.h b/screen.h index aa88be118..0fe08eec3 100644 --- a/screen.h +++ b/screen.h @@ -14,160 +14,6 @@ #include -/* A type that represents a color */ -class rgb_color_t { - enum { - type_none, - type_named, - type_rgb, - type_reset, - type_ignore - }; - unsigned char type; - union { - unsigned char name_idx; //0-10 - unsigned char rgb[3]; - } data; - unsigned flags; - - /* Try parsing an explicit color name like "magenta" */ - bool try_parse_named(const wcstring &str) { - bzero(&data, sizeof data); - const struct {const wchar_t * name; unsigned char idx;} names[] = { - {L"black", 0}, - {L"red", 1}, - {L"green", 2}, - {L"brown", 3}, - {L"yellow", 3}, - {L"blue", 4}, - {L"magenta", 5}, - {L"purple", 5}, - {L"cyan", 6}, - {L"white", 7}, - {L"normal", 8} - }; - size_t max = sizeof names / sizeof *names; - for (size_t idx=0; idx < max; idx++) { - if (0 == wcscasecmp(str.c_str(), names[idx].name)) { - data.name_idx = names[idx].idx; - return true; - } - } - return false; - } - - static int parse_hex_digit(wchar_t x) { - switch (x) { - case L'0': return 0x0; - case L'1': return 0x1; - case L'2': return 0x2; - case L'3': return 0x3; - case L'4': return 0x4; - case L'5': return 0x5; - case L'6': return 0x6; - case L'7': return 0x7; - case L'8': return 0x8; - case L'9': return 0x9; - case L'a':case L'A': return 0xA; - case L'b':case L'B': return 0xB; - case L'c':case L'C': return 0xC; - case L'd':case L'D': return 0xD; - case L'e':case L'E': return 0xE; - case L'f':case L'F': return 0xF; - default: return -1; - } - } - - bool try_parse_rgb(const wcstring &name) { - bzero(&data, sizeof data); - /* We support the following style of rgb formats (case insensitive): - #FA3 - #F3A035 - */ - size_t i; - if (name.size() == 4 && name.at(0) == L'#') { - // type #FA3 - for (i=0; i < 3; i++) { - int val = parse_hex_digit(name.at(i)); - if (val < 0) break; - data.rgb[i] = val*16+val; - } - return i == 3; - } else if (name.size() == 7 && name.at(0) == L'#') { - // type #F3A035 - for (i=0; i < 6;) { - int hi = parse_hex_digit(name.at(i++)); - int lo = parse_hex_digit(name.at(i++)); - if (lo < 0 || hi < 0) break; - data.rgb[i] = hi*16+lo; - } - return i == 6; - } else { - return false; - } - } - - static rgb_color_t named_color(unsigned char which) - { - rgb_color_t result(type_named); - result.data.name_idx = which; - return result; - } - - public: - - explicit rgb_color_t(unsigned char t = type_none) : type(t), data(), flags() {} - - static rgb_color_t normal() { return named_color(8); } - static rgb_color_t white() { return named_color(7); } - static rgb_color_t black() { return named_color(0); } - static rgb_color_t reset() { return rgb_color_t(type_reset); } - static rgb_color_t ignore() { return rgb_color_t(type_ignore); } - - rgb_color_t(unsigned char r, unsigned char g, unsigned char b) - { - type = type_rgb; - data.rgb[0] = r; - data.rgb[1] = g; - data.rgb[2] = b; - } - - static bool parse(const wcstring &str, rgb_color_t &color) { - if (color.try_parse_named(str)) { - color.type = type_named; - } else if (color.try_parse_rgb(str)) { - color.type = type_rgb; - } else { - bzero(color.data.rgb, sizeof color.data.rgb); - color.type = type_none; - } - return color.type != type_none; - } - - unsigned char name_index() const { - assert(type == type_named); - return data.name_idx; - } - - bool is_bold() const { return flags & 1; } - void set_bold(bool x) { if (x) flags |= 1; else flags &= ~1; } - bool is_underline() const { return flags & 2; } - void set_underline(bool x) { if (x) flags |= 2; else flags &= ~2; } - - bool is_reset(void) const { return type == type_reset; } - bool is_ignore(void) const { return type == type_ignore; } - bool is_named(void) const { return type == type_named; } - - bool operator==(const rgb_color_t &other) const { - return type == other.type && ! memcmp(&data, &other.data, sizeof data); - } - - bool operator!=(const rgb_color_t &other) const { - return !(*this == other); - } - -}; - struct line_entry_t { wchar_t text; diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish index 3c243ee51..c60fa6065 100644 --- a/share/functions/__fish_config_interactive.fish +++ b/share/functions/__fish_config_interactive.fish @@ -104,6 +104,7 @@ function __fish_config_interactive -d "Initializations that should be performed set_default fish_color_escape cyan set_default fish_color_operator cyan set_default fish_color_quote brown + set_default fish_color_autosuggestion 555 set_default fish_color_valid_path --underline set_default fish_color_cwd green