fish: Add GUESTFISH_PS1 environment variable to control prompt.

This commit is contained in:
Richard W.M. Jones
2012-10-29 12:49:21 +00:00
parent 9de4dfddc7
commit bad5c7d5a5
2 changed files with 203 additions and 9 deletions

View File

@@ -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

View File

@@ -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