summaryrefslogtreecommitdiffstats
path: root/fish
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-10-29 12:49:21 +0000
committerRichard W.M. Jones <rjones@redhat.com>2012-10-29 12:49:21 +0000
commitbad5c7d5a50e7f340d3a5daff59d7f3c18c0ab8f (patch)
tree9fecd1c7daf53c89ab9532308a39cc8b4abbb568 /fish
parent9de4dfddc7acf0d6c9d3a32f5d923ffa650cbce1 (diff)
downloadlibguestfs-bad5c7d5a50e7f340d3a5daff59d7f3c18c0ab8f.tar.gz
libguestfs-bad5c7d5a50e7f340d3a5daff59d7f3c18c0ab8f.tar.xz
libguestfs-bad5c7d5a50e7f340d3a5daff59d7f3c18c0ab8f.zip
fish: Add GUESTFISH_PS1 environment variable to control prompt.
Diffstat (limited to 'fish')
-rw-r--r--fish/fish.c143
-rw-r--r--fish/guestfish.pod69
2 files changed, 203 insertions, 9 deletions
diff --git a/fish/fish.c b/fish/fish.c
index c46cd116..332ef1ac 100644
--- a/fish/fish.c
+++ b/fish/fish.c
@@ -69,6 +69,7 @@ static void error_cb (guestfs_h *g, void *data, const char *msg);
static void initialize_readline (void);
static void cleanup_readline (void);
#ifdef HAVE_LIBREADLINE
+static char *decode_ps1 (const char *);
static void add_history_line (const char *);
#endif
@@ -614,12 +615,14 @@ shell_script (void)
#define FISH "><fs> "
+static char *ps1 = NULL;
static char *line_read = NULL;
static char *
rl_gets (int prompt)
{
#ifdef HAVE_LIBREADLINE
+ char *p = NULL;
if (prompt) {
if (line_read) {
@@ -627,7 +630,9 @@ rl_gets (int prompt)
line_read = NULL;
}
- line_read = readline (prompt ? FISH : "");
+ p = prompt && ps1 ? decode_ps1 (ps1) : NULL;
+ line_read = readline (prompt ? (ps1 ? p : FISH) : "");
+ free (p);
if (line_read && *line_read)
add_history_line (line_read);
@@ -1431,14 +1436,7 @@ static void
initialize_readline (void)
{
#ifdef HAVE_LIBREADLINE
- const char *home;
-
- home = getenv ("HOME");
- if (home) {
- snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
- using_history ();
- (void) read_history (histfile);
- }
+ const char *str;
rl_readline_name = "guestfish";
rl_attempted_completion_function = do_completion;
@@ -1449,6 +1447,25 @@ initialize_readline (void)
* they wish.
*/
(void) rl_variable_bind ("completion-ignore-case", "on");
+
+ /* Set up the history file. */
+ str = getenv ("HOME");
+ if (str) {
+ snprintf (histfile, sizeof histfile, "%s/.guestfish", str);
+ using_history ();
+ (void) read_history (histfile);
+ }
+
+ /* Set up the prompt. */
+ str = getenv ("GUESTFISH_PS1");
+ if (str) {
+ free (ps1);
+ ps1 = strdup (str);
+ if (!ps1) {
+ perror ("strdup");
+ exit (EXIT_FAILURE);
+ }
+ }
#endif
}
@@ -1483,6 +1500,114 @@ add_history_line (const char *line)
add_history (line);
nr_history_lines++;
}
+
+static int decode_ps1_octal (const char *s, size_t *i);
+static int decode_ps1_hex (const char *s, size_t *i);
+
+/* Decode 'str' into the final printable prompt string. */
+static char *
+decode_ps1 (const char *str)
+{
+ char *ret;
+ size_t len = strlen (str);
+ size_t i, j;
+
+ /* Result string is always smaller than the input string. This will
+ * change if we add new features like date/time substitution in
+ * future.
+ */
+ ret = malloc (len + 1);
+ if (!ret) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = j = 0; i < len; ++i) {
+ if (str[i] == '\\') { /* Start of an escape sequence. */
+ if (i < len-1)
+ i++;
+ switch (str[i]) {
+ case '\\':
+ ret[j++] = '\\';
+ break;
+ case '[':
+ ret[j++] = RL_PROMPT_START_IGNORE;
+ break;
+ case ']':
+ ret[j++] = RL_PROMPT_END_IGNORE;
+ break;
+ case 'a':
+ ret[j++] = '\a';
+ break;
+ case 'e':
+ ret[j++] = '\033';
+ break;
+ case 'n':
+ ret[j++] = '\n';
+ break;
+ case 'r':
+ ret[j++] = '\r';
+ break;
+ case '0'...'7':
+ ret[j++] = decode_ps1_octal (str, &i);
+ i--;
+ break;
+ case 'x':
+ i++;
+ ret[j++] = decode_ps1_hex (str, &i);
+ i--;
+ break;
+ default:
+ ret[j++] = '?';
+ }
+ }
+ else
+ ret[j++] = str[i];
+ }
+
+ ret[j] = '\0';
+ return ret; /* caller frees */
+}
+
+static int
+decode_ps1_octal (const char *s, size_t *i)
+{
+ size_t lim = 3;
+ int ret = 0;
+
+ while (lim > 0 && s[*i] >= '0' && s[*i] <= '7') {
+ ret *= 8;
+ ret += s[*i] - '0';
+ (*i)++;
+ lim--;
+ }
+
+ return ret;
+}
+
+static int
+decode_ps1_hex (const char *s, size_t *i)
+{
+ size_t lim = 2;
+ int ret = 0;
+
+ while (lim > 0 && c_isxdigit (s[*i])) {
+ ret *= 16;
+ if (s[*i] >= '0' && s[*i] <= '9')
+ ret += s[*i] - '0';
+ else if (s[*i] >= 'a' && s[*i] <= 'f')
+ ret += s[*i] - 'a' + 10;
+ else if (s[*i] >= 'A' && s[*i] <= 'F')
+ ret += s[*i] - 'A' + 10;
+ (*i)++;
+ lim--;
+ }
+
+ if (lim == 2) /* \x not followed by any hex digits */
+ return '?';
+
+ return ret;
+}
#endif
int
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index 4a665e0f..94b3df48 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -1103,6 +1103,71 @@ interactively. You can enable them even for non-interactive modes
using I<--progress-bars>, and you can disable them completely using
I<--no-progress-bars>.
+=head1 PROMPT
+
+You can change or add colours to the default prompt
+(C<E<gt>E<lt>fsE<gt>>) by setting the C<GUESTFISH_PS1> environment
+variable. A simple change can be made simply by setting this to an
+alternate string:
+
+ $ GUESTFISH_PS1='(type a command) '
+ $ export GUESTFISH_PS1
+ $ guestfish
+ [...]
+ (type a command) ls
+
+You can also use special escape sequences, as described in the table
+below:
+
+=over 4
+
+=item \\
+
+A literal backslash character.
+
+=item \[
+
+=item \]
+
+Place non-printing characters (eg. terminal control codes for colours)
+between C<\[...\]>. What this does it to tell the L<readline(3)>
+library that it should treat this subsequence as zero-width, so that
+command-line redisplay, editing etc works.
+
+=item \a
+
+A bell character.
+
+=item \e
+
+An ASCII ESC (escape) character.
+
+=item \n
+
+A newline.
+
+=item \r
+
+A carriage return.
+
+=item \NNN
+
+The ASCII character whose code is the octal value NNN.
+
+=item \xNN
+
+The ASCII character whose code is the hex value NN.
+
+=back
+
+=head2 EXAMPLES OF PROMPTS
+
+Note these these require a terminal that supports ANSI escape codes.
+
+ GUESTFISH_PS1='\[\e[1;30m\]><fs>\[\e[0;30m\] '
+
+A bold black version of the ordinary prompt.
+
=head1 GUESTFISH COMMANDS
The commands in this section are guestfish convenience commands, in
@@ -1162,6 +1227,10 @@ Used with the I<--remote> option to specify the remote guestfish
process to control. See section
L</REMOTE CONTROL GUESTFISH OVER A SOCKET>.
+=item GUESTFISH_PS1
+
+Set the command prompt. See L</PROMPT>.
+
=item HEXEDITOR
The L</hexedit> command uses C<$HEXEDITOR> as the external hex