lineedit: fix multi-line PS1 handling: calculate PS1 length from last \n

function                                             old     new   delta
parse_and_put_prompt                                 755     774     +19

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2013-08-19 16:45:04 +02:00
parent 7a18043a96
commit e66a56de23

View File

@ -38,6 +38,14 @@
* and the \] escape to signal the end of such a sequence. Example: * and the \] escape to signal the end of such a sequence. Example:
* *
* PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] ' * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
*
* Unicode in PS1 is not fully supported: prompt length calulation is wrong,
* resulting in line wrap problems with long (multi-line) input.
*
* Multi-line PS1 (e.g. PS1="\n[\w]\n$ ") has problems with history
* browsing: up/down arrows result in scrolling.
* It stems from simplistic "cmdedit_y = cmdedit_prmt_len / cmdedit_termw"
* calculation of how many lines the prompt takes.
*/ */
#include "libbb.h" #include "libbb.h"
#include "unicode.h" #include "unicode.h"
@ -1759,34 +1767,36 @@ static void ask_terminal(void)
#define ask_terminal() ((void)0) #define ask_terminal() ((void)0)
#endif #endif
/* Called just once at read_line_input() init time */
#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
static void parse_and_put_prompt(const char *prmt_ptr) static void parse_and_put_prompt(const char *prmt_ptr)
{ {
const char *p;
cmdedit_prompt = prmt_ptr; cmdedit_prompt = prmt_ptr;
cmdedit_prmt_len = unicode_strlen(prmt_ptr); p = strrchr(prmt_ptr, '\n');
cmdedit_prmt_len = unicode_strlen(p ? p+1 : prmt_ptr);
put_prompt(); put_prompt();
} }
#else #else
static void parse_and_put_prompt(const char *prmt_ptr) static void parse_and_put_prompt(const char *prmt_ptr)
{ {
int prmt_len = 0; int prmt_size = 0;
size_t cur_prmt_len = 0;
char flg_not_length = '[';
char *prmt_mem_ptr = xzalloc(1); char *prmt_mem_ptr = xzalloc(1);
# if ENABLE_USERNAME_OR_HOMEDIR # if ENABLE_USERNAME_OR_HOMEDIR
char *cwd_buf = NULL; char *cwd_buf = NULL;
# endif # endif
char timebuf[sizeof("HH:MM:SS")]; char flg_not_length = '[';
char cbuf[2]; char cbuf[2];
char c;
char *pbuf;
/*cmdedit_prmt_len = 0; - already is */ /*cmdedit_prmt_len = 0; - already is */
cbuf[1] = '\0'; /* never changes */ cbuf[1] = '\0'; /* never changes */
while (*prmt_ptr) { while (*prmt_ptr) {
char timebuf[sizeof("HH:MM:SS")];
char *free_me = NULL; char *free_me = NULL;
char *pbuf;
char c;
pbuf = cbuf; pbuf = cbuf;
c = *prmt_ptr++; c = *prmt_ptr++;
@ -1924,16 +1934,22 @@ static void parse_and_put_prompt(const char *prmt_ptr)
} /* if */ } /* if */
} /* if */ } /* if */
cbuf[0] = c; cbuf[0] = c;
cur_prmt_len = strlen(pbuf); {
prmt_len += cur_prmt_len; int n = strlen(pbuf);
if (flg_not_length != ']') { prmt_size += n;
#if 0 /*ENABLE_UNICODE_SUPPORT - won't work, pbuf is one BYTE string here. FIXME */ if (c == '\n')
cmdedit_prmt_len += unicode_strlen(pbuf); cmdedit_prmt_len = 0;
else if (flg_not_length != ']') {
#if 0 /*ENABLE_UNICODE_SUPPORT*/
/* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */
/* FIXME */
cmdedit_prmt_len += unicode_strlen(pbuf);
#else #else
cmdedit_prmt_len += cur_prmt_len; cmdedit_prmt_len += n;
#endif #endif
}
} }
prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf);
free(free_me); free(free_me);
} /* while */ } /* while */