Hi, I finished 6 patches which add color to filename completions in readline.
You'll find them here (651569 to 9cb76f) http://gitorious.org/drzraf/bash/commits/enhanced-completion and also attached. Most of code, more or less modified, comes from the LS_COLORS (parser / indicator selection) which can be found in coreutils/src/ls.c. I wish these patch will be reviewed (and appreciated). Raph PS: these patches apply to readline, but the bash mailing-list probably hosts more testers, please excuse me for crossposting.
>From 651569ec2fba50adf5457a854dcfa660e1c62d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Tue, 31 May 2011 00:46:04 +0200 Subject: [PATCH 1/6] Colored completion, readline.h (1/6) Adds the basic data structures needed by readline to support the colored output of filename completions. --- lib/readline/readline.h | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 49b40d3..dc8b29a 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -72,6 +72,32 @@ typedef struct _funmap { extern FUNMAP **funmap; + +/* Null is a valid character in a color indicator (think about Epson + printers, for example) so we have to use a length/buffer string + type. */ +struct bin_str { + size_t len; + const char *string; +}; + +/* file type indicators (dir, sock, fifo, ...) + Default value is initialized in parse-colors.c. + It is then modified from the values of $LS_COLORS. */ +extern struct bin_str color_indicator[]; + +/* The LS_COLORS variable is in a termcap-like format. */ +typedef struct _color_ext_type { + struct bin_str ext; /* The extension we're looking for */ + struct bin_str seq; /* The sequence to output when we do */ + struct _color_ext_type *next; /* Next in list */ +} COLOR_EXT_TYPE; + +/* file extensions indicators (.txt, .log, .jpg, ...) + Values are taken from $LS_COLORS in rl_parse_colors().*/ +extern COLOR_EXT_TYPE *_rl_color_ext_list; + + /* **************************************************************** */ /* */ /* Functions available to bind to key sequences */ @@ -893,6 +919,12 @@ struct readline_state { extern int rl_save_state PARAMS((struct readline_state *)); extern int rl_restore_state PARAMS((struct readline_state *)); +/* This is the function which parses the environment variable LS_COLORS + to fill _rl_color_ext_list. + This is not necessary in order to support basic colorization (file type). + But this is needed to add specific colors according to file extension. */ +extern void rl_parse_colors PARAMS((void)); + #ifdef __cplusplus } #endif -- 1.7.3.4
>From 8093e98ae8c1fa81ec6037b488ec96eedfd04d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Tue, 31 May 2011 00:47:33 +0200 Subject: [PATCH 2/6] Colored completion, core functions (2/6) Adds the functions to handle colors: - to parse the LS_COLORS value (termcap format) - to choose a color according to a file type or a file extension This is a modified/downstripped version of the colorization code originally found in coreutils-8.7 (src/ls.c) --- lib/readline/colors.c | 211 ++++++++++++++++++++++ lib/readline/colors.h | 79 +++++++++ lib/readline/parse-colors.c | 408 +++++++++++++++++++++++++++++++++++++++++++ lib/readline/parse-colors.h | 45 +++++ 4 files changed, 743 insertions(+), 0 deletions(-) create mode 100644 lib/readline/colors.c create mode 100644 lib/readline/colors.h create mode 100644 lib/readline/parse-colors.c create mode 100644 lib/readline/parse-colors.h diff --git a/lib/readline/colors.c b/lib/readline/colors.c new file mode 100644 index 0000000..b2629c1 --- /dev/null +++ b/lib/readline/colors.c @@ -0,0 +1,211 @@ +/* `dir', `vdir' and `ls' directory listing programs for GNU. + Copyright (C) 1985, 1988, 1990-1991, 1995-2010 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +/* Color support by Peter Anvin <peter.an...@linux.org> and Dennis + Flaherty <denn...@denix.elk.miles.com> based on original patches by + Greg Lee <l...@uhunix.uhcc.hawaii.edu>. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include "rlconf.h" + +#include <stdio.h> + +#include "posixstat.h" // stat related macros (S_ISREG, ...) +#include <fcntl.h> // S_ISUID + +// strlen() +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +// abort() +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "readline.h" +#include "colors.h" + +/* Output a color indicator (which may contain nulls). */ +void put_indicator (const struct bin_str *ind) { + fwrite (ind->string, ind->len, 1, rl_outstream); +} + + +bool is_colored (enum indicator_no colored_filetype) +{ + size_t len = color_indicator[colored_filetype].len; + char const *s = color_indicator[colored_filetype].string; + return ! (len == 0 + || (len == 1 && strncmp (s, "0", 1) == 0) + || (len == 2 && strncmp (s, "00", 2) == 0)); +} + +void +restore_default_color (void) +{ + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_RIGHT]); +} + +void +set_normal_color (void) +{ + if (is_colored (C_NORM)) + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_NORM]); + put_indicator (&color_indicator[C_RIGHT]); + } +} + +/* Returns whether any color sequence was printed. */ +bool print_color_indicator (char *f) +{ + enum indicator_no colored_filetype; + COLOR_EXT_TYPE *ext; /* Color extension */ + size_t len; /* Length of name */ + + const char* name; + struct stat astat; + mode_t mode; + int linkok; + name = f; + + int stat_ok = stat(f, &astat); + if( stat_ok == 0 ) { + mode = astat.st_mode; + linkok = 1; //f->linkok; + } + else + linkok = -1; + + /* Is this a nonexistent file? If so, linkok == -1. */ + + if (linkok == -1 && color_indicator[C_MISSING].string != NULL) + colored_filetype = C_MISSING; + else if(stat_ok != 0) + { + static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS; + colored_filetype = filetype_indicator[normal]; //f->filetype]; + } + else + { + if (S_ISREG (mode)) + { + colored_filetype = C_FILE; + + if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) + colored_filetype = C_SETUID; + else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) + colored_filetype = C_SETGID; + else if (is_colored (C_CAP) && 0) //f->has_capability) + colored_filetype = C_CAP; + else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) + colored_filetype = C_EXEC; + else if ((1 < astat.st_nlink) && is_colored (C_MULTIHARDLINK)) + colored_filetype = C_MULTIHARDLINK; + } + else if (S_ISDIR (mode)) + { + colored_filetype = C_DIR; + + if ((mode & S_ISVTX) && (mode & S_IWOTH) + && is_colored (C_STICKY_OTHER_WRITABLE)) + colored_filetype = C_STICKY_OTHER_WRITABLE; + else if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) + colored_filetype = C_OTHER_WRITABLE; + else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) + colored_filetype = C_STICKY; + } + else if (S_ISLNK (mode)) + colored_filetype = ((linkok == 0 + && (!strncmp (color_indicator[C_LINK].string, "target", 6) + || color_indicator[C_ORPHAN].string)) + ? C_ORPHAN : C_LINK); + else if (S_ISFIFO (mode)) + colored_filetype = C_FIFO; + else if (S_ISSOCK (mode)) + colored_filetype = C_SOCK; + else if (S_ISBLK (mode)) + colored_filetype = C_BLK; + else if (S_ISCHR (mode)) + colored_filetype = C_CHR; + else + { + /* Classify a file of some other type as C_ORPHAN. */ + colored_filetype = C_ORPHAN; + } + } + + /* Check the file's suffix only if still classified as C_FILE. */ + ext = NULL; + if (colored_filetype == C_FILE) + { + /* Test if NAME has a recognized suffix. */ + len = strlen (name); + name += len; /* Pointer to final \0. */ + for (ext = _rl_color_ext_list; ext != NULL; ext = ext->next) + { + if (ext->ext.len <= len + && strncmp (name - ext->ext.len, ext->ext.string, + ext->ext.len) == 0) + break; + } + } + + { + const struct bin_str *const s + = ext ? &(ext->seq) : &color_indicator[colored_filetype]; + if (s->string != NULL) + { + /* Need to reset so not dealing with attribute combinations */ + if (is_colored (C_NORM)) + restore_default_color (); + put_indicator (&color_indicator[C_LEFT]); + put_indicator (s); + put_indicator (&color_indicator[C_RIGHT]); + return 0; + } + else + return 1; + } +} + +void +prep_non_filename_text (void) +{ + if (color_indicator[C_END].string != NULL) + put_indicator (&color_indicator[C_END]); + else + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_RESET]); + put_indicator (&color_indicator[C_RIGHT]); + } +} diff --git a/lib/readline/colors.h b/lib/readline/colors.h new file mode 100644 index 0000000..4681f88 --- /dev/null +++ b/lib/readline/colors.h @@ -0,0 +1,79 @@ +/* `dir', `vdir' and `ls' directory listing programs for GNU. + Copyright (C) 1985, 1988, 1990-1991, 1995-2010 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +/* Color support by Peter Anvin <peter.an...@linux.org> and Dennis + Flaherty <denn...@denix.elk.miles.com> based on original patches by + Greg Lee <l...@uhunix.uhcc.hawaii.edu>. */ + +#ifndef _COLORS_H_ +#define _COLORS_H_ + +#include <stdio.h> // size_t +#include <stdbool.h> // bool + +#include "readline.h" // bin_str + +#define FILETYPE_INDICATORS \ + { \ + C_ORPHAN, C_FIFO, C_CHR, C_DIR, C_BLK, C_FILE, \ + C_LINK, C_SOCK, C_FILE, C_DIR \ + } + +/* Whether we used any colors in the output so far. If so, we will + need to restore the default color later. If not, we will need to + call prep_non_filename_text before using color for the first time. */ + +enum indicator_no + { + C_LEFT, C_RIGHT, C_END, C_RESET, C_NORM, C_FILE, C_DIR, C_LINK, + C_FIFO, C_SOCK, + C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR, C_SETUID, C_SETGID, + C_STICKY, C_OTHER_WRITABLE, C_STICKY_OTHER_WRITABLE, C_CAP, C_MULTIHARDLINK, + C_CLR_TO_EOL + }; + + +#if !S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +enum filetype + { + unknown, + fifo, + chardev, + directory, + blockdev, + normal, + symbolic_link, + sock, + whiteout, + arg_directory + }; + +void put_indicator (const struct bin_str *ind); +bool is_colored (enum indicator_no type); +void restore_default_color (void); +void set_normal_color (void); +bool print_color_indicator (char *f); +void prep_non_filename_text (void); + +FILE *rl_outstream; + +#endif /* !_COLORS_H_ */ diff --git a/lib/readline/parse-colors.c b/lib/readline/parse-colors.c new file mode 100644 index 0000000..ccbe4fd --- /dev/null +++ b/lib/readline/parse-colors.c @@ -0,0 +1,408 @@ +/* `dir', `vdir' and `ls' directory listing programs for GNU. + Copyright (C) 1985, 1988, 1990-1991, 1995-2010 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +/* Color support by Peter Anvin <peter.an...@linux.org> and Dennis + Flaherty <denn...@denix.elk.miles.com> based on original patches by + Greg Lee <l...@uhunix.uhcc.hawaii.edu>. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> + +// strdup() / strcpy() +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +// abort() +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdbool.h> // bool + +#include "rldefs.h" // STREQ +#include "readline.h" +#include "rlprivate.h" +#include "xmalloc.h" + +#include "parse-colors.h" + +struct bin_str color_indicator[] = + { + { LEN_STR_PAIR ("\033[") }, // lc: Left of color sequence + { LEN_STR_PAIR ("m") }, // rc: Right of color sequence + { 0, NULL }, // ec: End color (replaces lc+no+rc) + { LEN_STR_PAIR ("0") }, // rs: Reset to ordinary colors + { 0, NULL }, // no: Normal + { 0, NULL }, // fi: File: default + { LEN_STR_PAIR ("01;34") }, // di: Directory: bright blue + { LEN_STR_PAIR ("01;36") }, // ln: Symlink: bright cyan + { LEN_STR_PAIR ("33") }, // pi: Pipe: yellow/brown + { LEN_STR_PAIR ("01;35") }, // so: Socket: bright magenta + { LEN_STR_PAIR ("01;33") }, // bd: Block device: bright yellow + { LEN_STR_PAIR ("01;33") }, // cd: Char device: bright yellow + { 0, NULL }, // mi: Missing file: undefined + { 0, NULL }, // or: Orphaned symlink: undefined + { LEN_STR_PAIR ("01;32") }, // ex: Executable: bright green + { LEN_STR_PAIR ("01;35") }, // do: Door: bright magenta + { LEN_STR_PAIR ("37;41") }, // su: setuid: white on red + { LEN_STR_PAIR ("30;43") }, // sg: setgid: black on yellow + { LEN_STR_PAIR ("37;44") }, // st: sticky: black on blue + { LEN_STR_PAIR ("34;42") }, // ow: other-writable: blue on green + { LEN_STR_PAIR ("30;42") }, // tw: ow w/ sticky: black on green + { LEN_STR_PAIR ("30;41") }, // ca: black on red + { 0, NULL }, // mh: disabled by default + { LEN_STR_PAIR ("\033[K") }, // cl: clear to end of line + }; + +/* Parse a string as part of the LS_COLORS variable; this may involve + decoding all kinds of escape characters. If equals_end is set an + unescaped equal sign ends the string, otherwise only a : or \0 + does. Set *OUTPUT_COUNT to the number of bytes output. Return + true if successful. + + The resulting string is *not* null-terminated, but may contain + embedded nulls. + + Note that both dest and src are char **; on return they point to + the first free byte after the array and the character that ended + the input string, respectively. */ + +bool get_funky_string (char **dest, const char **src, bool equals_end, size_t *output_count) { + char num; /* For numerical codes */ + size_t count; /* Something to count with */ + enum { + ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR + } state; + const char *p; + char *q; + + p = *src; /* We don't want to double-indirect */ + q = *dest; /* the whole darn time. */ + + count = 0; /* No characters counted in yet. */ + num = 0; + + state = ST_GND; /* Start in ground state. */ + while (state < ST_END) + { + switch (state) + { + case ST_GND: /* Ground state (no escapes) */ + switch (*p) + { + case ':': + case '\0': + state = ST_END; /* End of string */ + break; + case '\\': + state = ST_BACKSLASH; /* Backslash scape sequence */ + ++p; + break; + case '^': + state = ST_CARET; /* Caret escape */ + ++p; + break; + case '=': + if (equals_end) + { + state = ST_END; /* End */ + break; + } + /* else fall through */ + default: + *(q++) = *(p++); + ++count; + break; + } + break; + + case ST_BACKSLASH: /* Backslash escaped character */ + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state = ST_OCTAL; /* Octal sequence */ + num = *p - '0'; + break; + case 'x': + case 'X': + state = ST_HEX; /* Hex sequence */ + num = 0; + break; + case 'a': /* Bell */ + num = '\a'; + break; + case 'b': /* Backspace */ + num = '\b'; + break; + case 'e': /* Escape */ + num = 27; + break; + case 'f': /* Form feed */ + num = '\f'; + break; + case 'n': /* Newline */ + num = '\n'; + break; + case 'r': /* Carriage return */ + num = '\r'; + break; + case 't': /* Tab */ + num = '\t'; + break; + case 'v': /* Vtab */ + num = '\v'; + break; + case '?': /* Delete */ + num = 127; + break; + case '_': /* Space */ + num = ' '; + break; + case '\0': /* End of string */ + state = ST_ERROR; /* Error! */ + break; + default: /* Escaped character like \ ^ : = */ + num = *p; + break; + } + if (state == ST_BACKSLASH) + { + *(q++) = num; + ++count; + state = ST_GND; + } + ++p; + break; + + case ST_OCTAL: /* Octal sequence */ + if (*p < '0' || *p > '7') + { + *(q++) = num; + ++count; + state = ST_GND; + } + else + num = (num << 3) + (*(p++) - '0'); + break; + + case ST_HEX: /* Hex sequence */ + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + num = (num << 4) + (*(p++) - '0'); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + num = (num << 4) + (*(p++) - 'a') + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + num = (num << 4) + (*(p++) - 'A') + 10; + break; + default: + *(q++) = num; + ++count; + state = ST_GND; + break; + } + break; + + case ST_CARET: /* Caret escape */ + state = ST_GND; /* Should be the next state... */ + if (*p >= '@' && *p <= '~') + { + *(q++) = *(p++) & 037; + ++count; + } + else if (*p == '?') + { + *(q++) = 127; + ++count; + } + else + state = ST_ERROR; + break; + + default: + /* should we ? */ + abort (); + } + } + + *dest = q; + *src = p; + *output_count = count; + + return state != ST_ERROR; +} + +void rl_parse_colors() { + const char *p; /* Pointer to character being parsed */ + char *buf; /* color_buf buffer pointer */ + int state; /* State of parser */ + int ind_no; /* Indicator number */ + char label[3]; /* Indicator label */ + COLOR_EXT_TYPE *ext; /* Extension we are working on */ + + if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') { + _rl_color_ext_list = NULL; + return; + } + + ext = NULL; + strcpy (label, "??"); + + /* This is an overly conservative estimate, but any possible + LS_COLORS string will *not* generate a color_buf longer than + itself, so it is a safe way of allocating a buffer in + advance. */ + buf = color_buf = strdup (p); + + state = 1; + while (state > 0) + { + switch (state) + { + case 1: /* First label character */ + switch (*p) + { + case ':': + ++p; + break; + + case '*': + /* Allocate new extension block and add to head of + linked list (this way a later definition will + override an earlier one, which can be useful for + having terminal-specific defs override global). */ + + ext = (COLOR_EXT_TYPE *)xmalloc (sizeof *ext); + ext->next = _rl_color_ext_list; + _rl_color_ext_list = ext; + + ++p; + ext->ext.string = buf; + + state = (get_funky_string (&buf, &p, true, &ext->ext.len) + ? 4 : -1); + break; + + case '\0': + state = 0; /* Done! */ + break; + + default: /* Assume it is file type label */ + label[0] = *(p++); + state = 2; + break; + } + break; + + case 2: /* Second label character */ + if (*p) + { + label[1] = *(p++); + state = 3; + } + else + state = -1; /* Error */ + break; + + case 3: /* Equal sign after indicator label */ + state = -1; /* Assume failure... */ + if (*(p++) == '=')/* It *should* be... */ + { + for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) + { + if (STREQ (label, indicator_name[ind_no])) + { + color_indicator[ind_no].string = buf; + state = (get_funky_string (&buf, &p, false, + &color_indicator[ind_no].len) + ? 1 : -1); + break; + } + } + if (state == -1) + fprintf (stderr, "bash: LS_COLORS: unrecognized prefix: %s\n", label); + } + break; + + case 4: /* Equal sign after *.ext */ + if (*(p++) == '=') + { + ext->seq.string = buf; + state = (get_funky_string (&buf, &p, false, &ext->seq.len) + ? 1 : -1); + } + else + state = -1; + break; + } + } + + if (state < 0) + { + COLOR_EXT_TYPE *e; + COLOR_EXT_TYPE *e2; + + fprintf(stderr, "bash: unparsable value for LS_COLORS environment variable\n"); + free (color_buf); + for (e = _rl_color_ext_list; e != NULL; /* empty */) + { + e2 = e; + e = e->next; + free (e2); + } + } +} diff --git a/lib/readline/parse-colors.h b/lib/readline/parse-colors.h new file mode 100644 index 0000000..d6f7226 --- /dev/null +++ b/lib/readline/parse-colors.h @@ -0,0 +1,45 @@ +/* `dir', `vdir' and `ls' directory listing programs for GNU. + Copyright (C) 1985, 1988, 1990-1991, 1995-2010 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +/* Color support by Peter Anvin <peter.an...@linux.org> and Dennis + Flaherty <denn...@denix.elk.miles.com> based on original patches by + Greg Lee <l...@uhunix.uhcc.hawaii.edu>. */ + +#ifndef _PARSE_COLORS_H_ +#define _PARSE_COLORS_H_ + +#include <stdbool.h> // bool +#include "readline.h" + +#define LEN_STR_PAIR(s) sizeof (s) - 1, s + +bool get_funky_string (char **dest, const char **src, bool equals_end, size_t *output_count); +void rl_parse_colors (void); + +static const char *const indicator_name[]= + { + "lc", "rc", "ec", "rs", "no", "fi", "di", "ln", "pi", "so", + "bd", "cd", "mi", "or", "ex", "do", "su", "sg", "st", + "ow", "tw", "ca", "mh", "cl", NULL + }; + +/* Buffer for color sequences */ +static char *color_buf; + +#endif /* !_PARSE_COLORS_H_ */ -- 1.7.3.4
>From 60e2a71733fb62086dc7d5d8354bc065058e8686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Tue, 31 May 2011 00:55:28 +0200 Subject: [PATCH 3/6] Colored completion, readline configuration (3/6) - #define COLORED_STATS - add "rl_colored_stats" which controls the colorization activation The feature depends on the readline configuration variable "colored-stats". --- lib/readline/bind.c | 3 +++ lib/readline/rlconf.h | 4 ++++ lib/readline/rlprivate.h | 4 ++++ 3 files changed, 11 insertions(+), 0 deletions(-) diff --git a/lib/readline/bind.c b/lib/readline/bind.c index 59e7964..f6d2ac9 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -1451,6 +1451,9 @@ static const struct { #if defined (VISIBLE_STATS) { "visible-stats", &rl_visible_stats, 0 }, #endif /* VISIBLE_STATS */ +#if defined (COLORED_STATS) + { "colored-stats", &rl_colored_stats, 0 }, +#endif /* !COLORED_STATS */ { (char *)NULL, (int *)NULL, 0 } }; diff --git a/lib/readline/rlconf.h b/lib/readline/rlconf.h index 39f94db..b93a6d7 100644 --- a/lib/readline/rlconf.h +++ b/lib/readline/rlconf.h @@ -28,6 +28,10 @@ /* Define this to get an indication of file type when listing completions. */ #define VISIBLE_STATS +/* Define this to get filenames colorized according to their type when + listing completions. */ +#define COLORED_STATS + /* This definition is needed by readline.c, rltty.c, and signals.c. */ /* If on, then readline handles signals in a way that doesn't screw. */ #define HANDLE_SIGNALS diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 384ff67..46834f9 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -174,6 +174,10 @@ extern int rl_complete_with_tilde_expansion; extern int rl_visible_stats; #endif /* VISIBLE_STATS */ +#if defined (COLORED_STATS) +extern int rl_colored_stats; +#endif /* !COLORED_STATS */ + /* readline.c */ extern int rl_line_buffer_len; extern int rl_arg_sign; -- 1.7.3.4
>From 85552f85c84f3a911d77edc43f7f89a3cf0d7372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Tue, 31 May 2011 01:06:05 +0200 Subject: [PATCH 4/6] Colored completion, print_filename() process (4/6) Handle the insertion of colored indicators before the filename output during the complete.c:print_filename() process. It is compatible with the "mark-directories" and "visible-stats" options. --- lib/readline/complete.c | 74 +++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 66 insertions(+), 8 deletions(-) diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 0526768..1f6ca81 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -100,6 +100,14 @@ rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)N # endif static int stat_char PARAMS((char *)); #endif +#if defined (COLORED_STATS) +# if !defined (X_OK) +# define X_OK 1 +# endif +#include "colors.h" +static int colored_stat_start PARAMS((char *)); +static void colored_stat_end PARAMS((void)); +#endif static int path_isdir PARAMS((const char *)); @@ -189,6 +197,13 @@ int _rl_completion_columns = -1; int rl_visible_stats = 0; #endif /* VISIBLE_STATS */ +#if defined (COLORED_STATS) +/* Non-zero means colorize filename displayed + during listing completion if rl_filename_completion_desired which helps + to indicate the type of file being listed. */ +int rl_colored_stats = 0; +#endif /* !COLORED_STATS */ + /* If non-zero, when completing in the middle of a word, don't insert characters from the match that match characters following point in the word. This means, for instance, completing when the cursor is @@ -607,6 +622,21 @@ stat_char (filename) } #endif /* VISIBLE_STATS */ +#if defined (COLORED_STATS) +static int colored_stat_start (filename) + char *filename; +{ + set_normal_color(); + return print_color_indicator(filename); +} + +static void colored_stat_end (void) +{ + prep_non_filename_text (); + put_indicator (&color_indicator[C_CLR_TO_EOL]); +} +#endif + /* Return the portion of PATHNAME that should be output when listing possible completions. If we are hacking filename completion, we are only interested in the basename, the portion following the @@ -803,13 +833,22 @@ print_filename (to_print, full_pathname, prefix_bytes) char *s, c, *new_full_pathname, *dn; extension_char = 0; - printed_len = fnprint (to_print, prefix_bytes); + /* Postpones printing the filename if we need + to prefix the output with a color indicator. */ +#if defined (COLORED_STATS) + if (! rl_colored_stats) +#endif + printed_len = fnprint (to_print, prefix_bytes); + + if (rl_filename_completion_desired && ( #if defined (VISIBLE_STATS) - if (rl_filename_completion_desired && (rl_visible_stats || _rl_complete_mark_directories)) -#else - if (rl_filename_completion_desired && _rl_complete_mark_directories) + rl_visible_stats || #endif +#if defined (COLORED_STATS) + rl_colored_stats || +#endif + _rl_complete_mark_directories)) { /* If to_print != full_pathname, to_print is the basename of the path passed. In this case, we try to expand the directory @@ -855,9 +894,21 @@ print_filename (to_print, full_pathname, prefix_bytes) extension_char = stat_char (new_full_pathname); else #endif - if (path_isdir (new_full_pathname)) - extension_char = '/'; - + if (_rl_complete_mark_directories && path_isdir (new_full_pathname)) + extension_char = '/'; +#if defined(COLORED_STATS) + if(rl_colored_stats) { + colored_stat_start(new_full_pathname); + printed_len = fnprint (to_print, prefix_bytes); + /* + We can try to raise(SIGKILL) here to test whether or not + there are risks to mess-up with the initial terminal color. + But even ls /usr/bin/<TAB><TAB> with "page-completions" "off" + seems safe. + */ + colored_stat_end (); + } +#endif xfree (new_full_pathname); to_print[-1] = c; } @@ -869,8 +920,15 @@ print_filename (to_print, full_pathname, prefix_bytes) extension_char = stat_char (s); else #endif - if (path_isdir (s)) + if (_rl_complete_mark_directories && path_isdir (s)) extension_char = '/'; +#if defined(COLORED_STATS) + if(rl_colored_stats) { + colored_stat_start(s); + printed_len = fnprint (to_print, prefix_bytes); + colored_stat_end (); + } +#endif } xfree (s); -- 1.7.3.4
>From 733093f4808a9a2623e55b65615276e5cca1de90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Tue, 31 May 2011 01:10:04 +0200 Subject: [PATCH 5/6] Colored completion, LS_COLORS handling (5/6) Runs rl_parse_colors() at readline initialization. It builds the _rl_color_ext_list structure which allows colors to not only depends on file type (dir, sock, fifo, ...) but also on filename extensions, according to $LS_COLORS. See DIR_COLORS(5) for more information. --- lib/readline/readline.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/lib/readline/readline.c b/lib/readline/readline.c index f2e4d93..afd76f0 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -279,6 +279,11 @@ int _rl_revert_all_at_newline = 0; characters corresponding to keyboard-generated signals. */ int _rl_echo_control_chars = 1; +/* The content of $LS_COLORS as parsed by rl_parse_colors() */ +#if defined (COLORED_STATS) +COLOR_EXT_TYPE *_rl_color_ext_list = NULL; +#endif + /* **************************************************************** */ /* */ /* Top Level Functions */ @@ -1099,6 +1104,14 @@ readline_initialize_everything () been set yet, then do so now. */ if (rl_completer_word_break_characters == (char *)NULL) rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; + +#ifdef COLORED_STATS + /* This adds colors from $LS_COLORS to filename completion. + This function depends on rl_colored_stats == 1 + (this initialization is done by rl_read_init_file() above). */ + if(rl_colored_stats) + rl_parse_colors (); +#endif } /* If this system allows us to look at the values of the regular -- 1.7.3.4
>From 9cb76fbde354c02a47df9e82c3854eace9fe889e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Tue, 31 May 2011 01:14:27 +0200 Subject: [PATCH 6/6] Colored completion, Makefile.in (6/6) $ echo set colored-stats on >> ~/.inputrc $ [C-x C-r] $ ls /tmp/<TAB><TAB> ... [ don't forget your sunglasses ] --- lib/readline/Makefile.in | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/readline/Makefile.in b/lib/readline/Makefile.in index 4387a54..ff9b113 100644 --- a/lib/readline/Makefile.in +++ b/lib/readline/Makefile.in @@ -83,13 +83,13 @@ CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \ $(srcdir)/histfile.c $(srcdir)/nls.c $(srcdir)/search.c \ $(srcdir)/shell.c $(srcdir)/tilde.c $(srcdir)/savestring.c \ $(srcdir)/text.c $(srcdir)/misc.c $(srcdir)/compat.c \ - $(srcdir)/mbutil.c $(srcdir)/xfree.c + $(srcdir)/mbutil.c $(srcdir)/xfree.c $(srcdir)/colors.c $(srcdir)/parse-colors.c # The header files for this library. HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \ posixstat.h posixdir.h posixjmp.h tilde.h rlconf.h rltty.h \ ansi_stdlib.h rlstdc.h tcap.h xmalloc.h rlprivate.h rlshell.h \ - rltypedefs.h rlmbutil.h + rltypedefs.h rlmbutil.h colors.h parse-colors.h HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o \ mbutil.o @@ -97,7 +97,8 @@ TILDEOBJ = tilde.o OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \ rltty.o complete.o bind.o isearch.o display.o signals.o \ util.o kill.o undo.o macro.o input.o callback.o terminal.o \ - text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o xfree.o compat.o + text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o xfree.o compat.o \ + colors.o parse-colors.o # The texinfo files which document this library. DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo @@ -173,9 +174,11 @@ callback.o: rlconf.h ansi_stdlib.h callback.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h callback.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h compat.o: rlstdc.h +colors.o: rlconf.h ${BUILD_DIR}/config.h posixstat.h ansi_stdlib.h +colors.o: readline.h colors.h complete.o: ansi_stdlib.h posixdir.h posixstat.h complete.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -complete.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +complete.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h colors.h display.o: ansi_stdlib.h posixstat.h display.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h display.o: tcap.h @@ -226,6 +229,8 @@ nls.o: history.h rlstdc.h parens.o: rlconf.h parens.o: ${BUILD_DIR}/config.h parens.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +parse-colors.o: rldefs.h ${BUILD_DIR}/config.h ansi_stdlib.h +parse-colors.o: rlprivate.h xmalloc.h readline.h parse-colors.h readline.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h readline.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h readline.o: history.h rlstdc.h -- 1.7.3.4