summaryrefslogtreecommitdiffstats
path: root/linenoise
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-09-25 06:46:07 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-09-25 06:46:07 -0700
commit9f777d5898216453055a570c06d561e540241261 (patch)
treec71601232614725f33de99744ec5e16d67596e1d /linenoise
parent977d61d2229d3517226edfb3a32b929c6d95d19b (diff)
downloadtxr-9f777d5898216453055a570c06d561e540241261.tar.gz
txr-9f777d5898216453055a570c06d561e540241261.tar.bz2
txr-9f777d5898216453055a570c06d561e540241261.zip
linenoise: fix multi-line issues with long lines
* linenoise/linenoise.c (screen_rows): Restructured. Calculates correct cursor rows (out.rows[1]). It's now possible that the reported cursor row exceeds the number of rows (out.rows[0]), because the cursor is on the last line, which itself doesn't wrap, but the cursor does. (refresh_multiline): Cursor wrapping calculation is simple now: just check that nrow > rows. Coalesced code for dealing with cursor position.
Diffstat (limited to 'linenoise')
-rw-r--r--linenoise/linenoise.c78
1 files changed, 44 insertions, 34 deletions
diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c
index e55fde77..a9981b4f 100644
--- a/linenoise/linenoise.c
+++ b/linenoise/linenoise.c
@@ -869,24 +869,35 @@ struct row_values {
static struct row_values screen_rows(const char *str, size_t pos, int cols)
{
const char *start = str;
- int ch = *str;
+ int col;
struct row_values out = { { 1, 1 } };
- int col = 1;
- if (!ch)
- return out;
+ for (col = 0; ; str++) {
+ int ch = *str;
+ int atpos = (str - start == (ptrdiff_t) pos);
- for (; ; ch = *++str, col++) {
- if (str - start == (ptrdiff_t) pos)
- out.rows[1] = out.rows[0];
- if (ch == 0)
- break;
- if (ch == '\r')
- continue;
- if (ch == '\n' || col == cols) {
+ switch (ch) {
+ case '\n':
col = 0;
out.rows[0]++;
+ /* fallthrough */
+ case '\r': case 0:
+ if (atpos)
+ out.rows[1] = out.rows[0] + (col == cols);
+ break;
+ default:
+ col++;
+ if (col > cols) {
+ col = 1;
+ out.rows[0]++;
+ }
+ if (atpos)
+ out.rows[1] = out.rows[0];
+ break;
}
+
+ if (ch == 0)
+ break;
}
return out;
@@ -909,7 +920,6 @@ static void refresh_multiline(lino_t *l) {
struct row_values r = screen_rows(l->buf, l->pos, l->cols);
int rows = r.rows[0]; /* rows used by current buf. */
int nrow = r.rows[1]; /* cursor row after refresh. */
- int col; /* colum position, zero-based. */
int oldmaxrows = l->maxrows;
int fd = l->ofd, j;
struct abuf ab;
@@ -960,33 +970,33 @@ static void refresh_multiline(lino_t *l) {
ab_append(&ab, l->buf + end, len - end);
}
- /* If we are at the very end of the screen with our prompt, we need to
- * emit a newline and move the cursor to the first column. */
-
- col = col_offset_in_str(l->buf, l->pos);
-
- if (l->pos && l->pos == l->len && col % l->cols == l->cols - 1)
- {
- ab_append(&ab,"\n",1);
- snprintf(seq,64,"\r");
- ab_append(&ab,seq,strlen(seq));
+ /* Cursor has wrapped to new row beyond rows. */
+ if (nrow > rows) {
+ ab_append(&ab, "\r\n", 2);
rows++;
- if (rows > (int)l->maxrows) l->maxrows = rows;
+ if (rows > (int) l->maxrows)
+ l->maxrows = rows;
}
- /* Go up till we reach the expected positon. */
- if (rows - nrow > 0) {
- snprintf(seq,64,"\x1b[%dA", rows - nrow);
+ /* Move cursor to the correct column */
+ {
+ int ccol = col_offset_in_str(l->buf, l->pos) % l->cols;
+
+ /* Go up till we reach the expected positon. */
+ if (rows - nrow > 0) {
+ snprintf(seq,64,"\x1b[%dA", rows - nrow);
+ ab_append(&ab,seq,strlen(seq));
+ }
+
+ /* Set column. */
+ if (ccol)
+ snprintf(seq,64,"\r\x1b[%dC", ccol);
+ else
+ snprintf(seq,64,"\r");
+
ab_append(&ab,seq,strlen(seq));
}
- /* Set column. */
- if (col)
- snprintf(seq,64,"\r\x1b[%dC", col);
- else
- snprintf(seq,64,"\r");
- ab_append(&ab,seq,strlen(seq));
-
/* Remember current cursor row for next time */
l->oldrow = nrow;