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

Reply via email to