* and the \] escape to signal the end of such a sequence. Example:
*
* 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 "unicode.h"
#if MAX_HISTORY > 0
-unsigned size_from_HISTFILESIZE(const char *hp)
+unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
{
int size = MAX_HISTORY;
if (hp) {
return 0;
}
+/* Lists command history. Used by shell 'history' builtins */
+void FAST_FUNC show_history(const line_input_t *st)
+{
+ int i;
+
+ if (!st)
+ return;
+ for (i = 0; i < st->cnt_history; i++)
+ printf("%4d %s\n", i, st->history[i]);
+}
+
# if ENABLE_FEATURE_EDITING_SAVEHISTORY
/* We try to ensure that concurrent additions to the history
* do not overwrite each other.
#define ask_terminal() ((void)0)
#endif
+/* Called just once at read_line_input() init time */
#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
static void parse_and_put_prompt(const char *prmt_ptr)
{
+ const char *p;
cmdedit_prompt = prmt_ptr;
- cmdedit_prmt_len = strlen(prmt_ptr);
+ p = strrchr(prmt_ptr, '\n');
+ cmdedit_prmt_len = unicode_strwidth(p ? p+1 : prmt_ptr);
put_prompt();
}
#else
static void parse_and_put_prompt(const char *prmt_ptr)
{
- int prmt_len = 0;
- size_t cur_prmt_len = 0;
- char flg_not_length = '[';
+ int prmt_size = 0;
char *prmt_mem_ptr = xzalloc(1);
# if ENABLE_USERNAME_OR_HOMEDIR
char *cwd_buf = NULL;
# endif
- char timebuf[sizeof("HH:MM:SS")];
+ char flg_not_length = '[';
char cbuf[2];
- char c;
- char *pbuf;
- cmdedit_prmt_len = 0;
+ /*cmdedit_prmt_len = 0; - already is */
cbuf[1] = '\0'; /* never changes */
while (*prmt_ptr) {
+ char timebuf[sizeof("HH:MM:SS")];
char *free_me = NULL;
+ char *pbuf;
+ char c;
pbuf = cbuf;
c = *prmt_ptr++;
}
case '[': case ']':
if (c == flg_not_length) {
- flg_not_length = (flg_not_length == '[' ? ']' : '[');
+ /* Toggle '['/']' hex 5b/5d */
+ flg_not_length ^= 6;
continue;
}
break;
} /* if */
} /* if */
cbuf[0] = c;
- cur_prmt_len = strlen(pbuf);
- prmt_len += cur_prmt_len;
- if (flg_not_length != ']')
- cmdedit_prmt_len += cur_prmt_len;
- prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
+ {
+ int n = strlen(pbuf);
+ prmt_size += n;
+ if (c == '\n')
+ 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_strwidth(pbuf);
+#else
+ cmdedit_prmt_len += n;
+#endif
+ }
+ }
+ prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf);
free(free_me);
} /* while */
S.sent_ESC_br6n = 0;
if (cursor == 0) { /* otherwise it may be bogus */
int col = ((ic >> 32) & 0x7fff) - 1;
- if (col > cmdedit_prmt_len) {
+ /*
+ * Is col > cmdedit_prmt_len?
+ * If yes (terminal says cursor is farther to the right
+ * of where we think it should be),
+ * the prompt wasn't printed starting at col 1,
+ * there was additional text before it.
+ */
+ if ((int)(col - cmdedit_prmt_len) > 0) {
+ /* Fix our understanding of current x position */
cmdedit_x += (col - cmdedit_prmt_len);
while (cmdedit_x >= cmdedit_termw) {
cmdedit_x -= cmdedit_termw;
char read_key_buffer[KEYCODE_BUFFER_SIZE];
const char *matched_history_line;
const char *saved_prompt;
+ unsigned saved_prmt_len;
int32_t ic;
matched_history_line = NULL;
/* Save and replace the prompt */
saved_prompt = cmdedit_prompt;
+ saved_prmt_len = cmdedit_prmt_len;
goto set_prompt;
while (1) {
free((char*)cmdedit_prompt);
set_prompt:
cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf);
- cmdedit_prmt_len = strlen(cmdedit_prompt);
+ cmdedit_prmt_len = unicode_strwidth(cmdedit_prompt);
goto do_redraw;
}
}
free((char*)cmdedit_prompt);
cmdedit_prompt = saved_prompt;
- cmdedit_prmt_len = strlen(cmdedit_prompt);
+ cmdedit_prmt_len = saved_prmt_len;
redraw(cmdedit_y, command_len - cursor);
return ic;
free(command_ps);
#endif
- if (command_len > 0)
+ if (command_len > 0) {
remember_in_history(command);
+ }
if (break_out > 0) {
command[command_len++] = '\n';