diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2025-07-03 08:55:35 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-03 08:55:35 -0400 |
commit | f1fa639bdfb6e8da91b57f892acf26d438d30fd3 (patch) | |
tree | 5f16fa741463837e53316d0db6f8776152637dfc | |
parent | 42235435aab09bc48765707b6706eaa1ecf1a0a7 (diff) | |
parent | b4a8afc2cfdbd91dedf2f387427c0984cad6d54a (diff) | |
download | bfs-f1fa639bdfb6e8da91b57f892acf26d438d30fd3.tar.xz |
Merge pull request #157 from vinxcls/freebsd-coloring
Support for FreeBSD-style ls Coloring
-rw-r--r-- | src/color.c | 81 | ||||
-rw-r--r-- | tests/bfs/color_bsd.out | 27 | ||||
-rw-r--r-- | tests/bfs/color_bsd.sh | 1 | ||||
-rw-r--r-- | tests/bfs/color_bsd_fail.sh | 2 | ||||
-rw-r--r-- | tests/util.sh | 1 |
5 files changed, 107 insertions, 5 deletions
diff --git a/src/color.c b/src/color.c index a026831..f77877d 100644 --- a/src/color.c +++ b/src/color.c @@ -607,6 +607,67 @@ fail: return ret; } +/** Parse the FreeBSD $LSCOLORS format. */ +static int parse_bsd_ls_colors(struct colors *colors, const char *lscolors) { + static const char *keys[] = { + "di", "ln", "so", "pi", "ex", "bd", "cd", "su", "sg", "tw", "ow" + }; + + static const char *fg_codes[256] = { + ['a'] = "30", ['b'] = "31", ['c'] = "32", ['d'] = "33", + ['e'] = "34", ['f'] = "35", ['g'] = "36", ['h'] = "37", ['x'] = "39", + ['A'] = "1;30", ['B'] = "1;31", ['C'] = "1;32", ['D'] = "1;33", + ['E'] = "1;34", ['F'] = "1;35", ['G'] = "1;36", ['H'] = "1;37", ['X'] = "1" + }; + + static const char *bg_codes[256] = { + ['a'] = "40", ['b'] = "41", ['c'] = "42", ['d'] = "43", + ['e'] = "44", ['f'] = "45", ['g'] = "46", ['h'] = "47", ['x'] = "49", + ['A'] = "4;100", ['B'] = "4;101", ['C'] = "4;102", ['D'] = "4;103", + ['E'] = "4;104", ['F'] = "4;105", ['G'] = "4;106", ['H'] = "4;107", ['X'] = "4;49" + }; + + // Please refer to https://man.freebsd.org/cgi/man.cgi?ls(1)#ENVIRONMENT + char complete_colors[] = "exfxcxdxbxegedabagacad"; + + size_t max = strlen(complete_colors); + size_t len = strnlen(lscolors, max + 1); + if (len == 0 || len % 2 != 0 || len > max) { + errno = EINVAL; + return -1; + } + memcpy(complete_colors, lscolors, len); + + for (size_t i = 0; i < countof(keys); ++i) { + uint8_t fg = complete_colors[i * 2]; + uint8_t bg = complete_colors[(i * 2) + 1]; + + const char *fg_code = fg_codes[fg]; + const char *bg_code = bg_codes[bg]; + + if (!fg_code || !bg_code) { + continue; + } + + dchar *esc = dstrprintf("%s;%s", fg_code, bg_code); + if (!esc) { + return -1; + } + + int ret = set_esc(colors, keys[i], esc); + dstrfree(esc); + if (ret != 0) { + return -1; + } + } + + return 0; +} + +static bool str_isset(const char *str) { + return str && *str; +} + struct colors *parse_colors(void) { struct colors *colors = ALLOC(struct colors); if (!colors) { @@ -676,12 +737,22 @@ struct colors *parse_colors(void) { goto fail; } - if (parse_gnu_ls_colors(colors, getenv("LS_COLORS")) != 0) { - goto fail; - } - if (parse_gnu_ls_colors(colors, getenv("BFS_COLORS")) != 0) { - goto fail; + const char *gnu_colors = getenv("LS_COLORS"); + const char *bfs_colors = getenv("BFS_COLORS"); + const char *bsd_colors = getenv("LSCOLORS"); + if (str_isset(gnu_colors) || str_isset(bfs_colors)) { + if (parse_gnu_ls_colors(colors, gnu_colors) != 0) { + goto fail; + } + if (parse_gnu_ls_colors(colors, bfs_colors) != 0) { + goto fail; + } + } else if (str_isset(bsd_colors)) { + if (parse_bsd_ls_colors(colors, bsd_colors) != 0) { + goto fail; + } } + if (build_iext_trie(colors) != 0) { goto fail; } diff --git a/tests/bfs/color_bsd.out b/tests/bfs/color_bsd.out new file mode 100644 index 0000000..f7c577c --- /dev/null +++ b/tests/bfs/color_bsd.out @@ -0,0 +1,27 @@ +[34;4;101m$'rainbow/\e[1m'[0m +[34;4;101m$'rainbow/\e[1m/'[0m$'\e[0m' +[34;4;101mrainbow[0m +[34;4;101mrainbow/[0m[30;41msugid[0m +[34;4;101mrainbow/[0m[30;41msuid[0m +[34;4;101mrainbow/[0m[30;42msticky_ow[0m +[34;4;101mrainbow/[0m[30;43mow[0m +[34;4;101mrainbow/[0m[30;46msgid[0m +[34;4;101mrainbow/[0m[31;49mexec.sh[0m +[34;4;101mrainbow/[0m[32;49msocket[0m +[34;4;101mrainbow/[0m[33;49mpipe[0m +[34;4;101mrainbow/[0m[35;49mbroken[0m +[34;4;101mrainbow/[0m[35;49mchardev_link[0m +[34;4;101mrainbow/[0m[35;49mlink.txt[0m +[34;4;101mrainbow/[0m[37;44msticky[0m +[34;4;101mrainbow/[0mfile.dat +[34;4;101mrainbow/[0mfile.txt +[34;4;101mrainbow/[0mlower.gz +[34;4;101mrainbow/[0mlower.tar +[34;4;101mrainbow/[0mlower.tar.gz +[34;4;101mrainbow/[0mlu.tar.GZ +[34;4;101mrainbow/[0mmh1 +[34;4;101mrainbow/[0mmh2 +[34;4;101mrainbow/[0mul.TAR.gz +[34;4;101mrainbow/[0mupper.GZ +[34;4;101mrainbow/[0mupper.TAR +[34;4;101mrainbow/[0mupper.TAR.GZ diff --git a/tests/bfs/color_bsd.sh b/tests/bfs/color_bsd.sh new file mode 100644 index 0000000..f8a777f --- /dev/null +++ b/tests/bfs/color_bsd.sh @@ -0,0 +1 @@ +LSCOLORS="eB" bfs_diff rainbow -color diff --git a/tests/bfs/color_bsd_fail.sh b/tests/bfs/color_bsd_fail.sh new file mode 100644 index 0000000..94e1209 --- /dev/null +++ b/tests/bfs/color_bsd_fail.sh @@ -0,0 +1,2 @@ +# LSCOLORS can be at most 22 characters long (11 color pairs); this one has 24. +! LSCOLORS="exfxcxdxbxegedabagacadeB" invoke_bfs rainbow -color diff --git a/tests/util.sh b/tests/util.sh index 1718a1a..c998927 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -34,6 +34,7 @@ stdenv() { export LS_COLORS="" unset BFS_COLORS + unset LSCOLORS if [ "$UNAME" = Darwin ]; then # ASan on macOS likes to report |