diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-17 00:45:44 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-17 00:45:44 +0200 |
commit | 248c324f7c6d407467ab3ad9057dfe33fb2723d8 (patch) | |
tree | 2f9831a30685bfdee75872bf58639a527144eec2 | |
parent | d9a3e89f501800c3e7c779b7e9545a5c80134593 (diff) |
lineedit: fix moving backwards across lines with wide chars
function old new delta
input_backward 212 208 -4
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libbb/lineedit.c | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index bc089ab1c..836fc0089 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -413,12 +413,22 @@ static void beep(void) bb_putchar('\007'); } +static void put_prompt(void) +{ + unsigned w; + + out1str(cmdedit_prompt); + fflush_all(); + cursor = 0; + w = cmdedit_termw; /* read volatile var once */ + cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ + cmdedit_x = cmdedit_prmt_len % w; +} + /* Move back one character */ /* (optimized for slow terminals) */ static void input_backward(unsigned num) { - int count_y; - if (num > cursor) num = cursor; if (num == 0) @@ -456,29 +466,44 @@ static void input_backward(unsigned num) } /* Need to go one or more lines up */ -//FIXME: this does not work correctly if prev line has one "unfilled" screen position -//caused by wide unicode char not fitting in that one screen position. - num -= cmdedit_x; - { - unsigned w = cmdedit_termw; /* volatile var */ + if (ENABLE_UNICODE_WIDE_WCHARS) { + /* With wide chars, it is hard to "backtrack" + * and reliably figure out where to put cursor. + * Example (<> is a wide char; # is an ordinary char, _ cursor): + * |prompt: <><> | + * |<><><><><><> | + * |_ | + * and user presses left arrow. num = 1, cmdedit_x = 0, + * We need to go up one line, and then - how do we know that + * we need to go *10* positions to the right? Because + * |prompt: <>#<>| + * |<><><>#<><><>| + * |_ | + * in this situation we need to go *11* positions to the right. + * + * A simpler thing to do is to redraw everything from the start + * up to new cursor position (which is already known): + */ + unsigned sv_cursor; + if (cmdedit_y > 0) /* up to start y */ + printf("\033[%uA", cmdedit_y); + bb_putchar('\r'); + cmdedit_y = 0; + sv_cursor = cursor; + put_prompt(); /* sets cursor to 0 */ + while (cursor < sv_cursor) + put_cur_glyph_and_inc_cursor(); + } else { + int count_y; + unsigned w; + num -= cmdedit_x; + w = cmdedit_termw; /* read volatile var once */ count_y = 1 + (num / w); cmdedit_y -= count_y; cmdedit_x = w * count_y - num; + /* go to 1st column; go up; go to correct column */ + printf("\r" "\033[%uA" "\033[%uC", count_y, cmdedit_x); } - /* go to 1st column; go up; go to correct column */ - printf("\r" "\033[%uA" "\033[%uC", count_y, cmdedit_x); -} - -static void put_prompt(void) -{ - unsigned w; - - out1str(cmdedit_prompt); - fflush_all(); - cursor = 0; - w = cmdedit_termw; /* read volatile var once */ - cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ - cmdedit_x = cmdedit_prmt_len % w; } /* draw prompt, editor line, and clear tail */ |