j += (flags[i] != 0);
assert(j == line->size);
+
+ sfree(flags);
}
/*
hdrpos = b->len;
hdrsize = 0;
add(b, 0);
+ /* And ensure this run doesn't interfere with the next. */
+ prevlen = prevpos = 0;
+ prev2 = FALSE;
continue;
} else {
/*
* Diagnostics: ensure that the compressed data really does
* decompress to the right thing.
+ *
+ * XXX-REMOVE-BEFORE-RELEASE: This is a bit performance-heavy
+ * to be leaving in production code.
*/
#ifndef CHECK_SB_COMPRESSION
{
*/
static void resizeline(Terminal *term, termline *line, int cols)
{
- int i, oldlen;
+ int i, oldcols;
if (line->cols != cols) {
+
+ oldcols = line->cols;
+
/*
* This line is the wrong length, which probably means it
* hasn't been accessed since a resize. Resize it now.
* out in the resize (if we're shrinking the line) and
* return their cc lists to the cc free list.
*/
- for (i = cols; i < line->cols; i++)
+ for (i = cols; i < oldcols; i++)
clear_cc(line, i);
/*
+ * If we're shrinking the line, we now bodily move the
+ * entire cc section from where it started to where it now
+ * needs to be. (We have to do this before the resize, so
+ * that the data we're copying is still there. However, if
+ * we're expanding, we have to wait until _after_ the
+ * resize so that the space we're copying into is there.)
+ */
+ if (cols < oldcols)
+ memmove(line->chars + cols, line->chars + oldcols,
+ (line->size - line->cols) * TSIZE);
+
+ /*
* Now do the actual resize, leaving the _same_ amount of
* cc space as there was to begin with.
*/
- oldlen = line->cols;
- line->size += cols - oldlen;
+ line->size += cols - oldcols;
line->chars = sresize(line->chars, line->size, TTYPE);
line->cols = cols;
/*
- * Bodily move the entire cc section from where it started
- * to where it now needs to be.
+ * If we're expanding the line, _now_ we move the cc
+ * section.
*/
- memmove(line->chars + line->cols, line->chars + oldlen,
- (line->size - line->cols) * TSIZE);
+ if (cols > oldcols)
+ memmove(line->chars + cols, line->chars + oldcols,
+ (line->size - line->cols) * TSIZE);
/*
* Go through what's left of the original line, and adjust
* relative offsets within the cc block.) Also do the same
* to the head of the cc_free list.
*/
- for (i = 0; i < oldlen && i < line->cols; i++)
+ for (i = 0; i < oldcols && i < cols; i++)
if (line->chars[i].cc_next)
- line->chars[i].cc_next += cols - oldlen;
+ line->chars[i].cc_next += cols - oldcols;
if (line->cc_free)
- line->cc_free += cols - oldlen;
+ line->cc_free += cols - oldcols;
/*
* And finally fill in the new space with erase chars. (We
* don't have to worry about cc lists here, because we
* _know_ the erase char doesn't have one.)
*/
- for (i = oldlen; i < cols; i++)
+ for (i = oldcols; i < cols; i++)
line->chars[i] = term->basic_erase_char;
cc_check(line); /* XXX-REMOVE-BEFORE-RELEASE */
if (term->cfg.wordness[i] != cfg->wordness[i])
reset_charclass = 1;
+ /*
+ * If the bidi or shaping settings have changed, flush the bidi
+ * cache completely.
+ */
+ if (term->cfg.arabicshaping != cfg->arabicshaping ||
+ term->cfg.bidi != cfg->bidi) {
+ for (i = 0; i < term->bidi_cache_size; i++) {
+ sfree(term->pre_bidi_cache[i].chars);
+ sfree(term->post_bidi_cache[i].chars);
+ term->pre_bidi_cache[i].width = -1;
+ term->pre_bidi_cache[i].chars = NULL;
+ term->post_bidi_cache[i].width = -1;
+ term->post_bidi_cache[i].chars = NULL;
+ }
+ }
+
term->cfg = *cfg; /* STRUCTURE COPY */
if (reset_wrap)
sfree(term->wcTo);
for (i = 0; i < term->bidi_cache_size; i++) {
- sfree(term->pre_bidi_cache[i]);
- sfree(term->post_bidi_cache[i]);
+ sfree(term->pre_bidi_cache[i].chars);
+ sfree(term->post_bidi_cache[i].chars);
}
sfree(term->pre_bidi_cache);
sfree(term->post_bidi_cache);
addpos234(term->scrollback, compressline(line), sblen);
- line = newline(term, term->cols, TRUE);
+ /* now `line' itself can be reused as the bottom line */
/*
* If the user is currently looking at part of the
term->wrapnext = FALSE;
/* destructive backspace might be disabled */
if (!term->cfg.no_dbackspace) {
+ check_boundary(term, term->curs.x, term->curs.y);
+ check_boundary(term, term->curs.x+1, term->curs.y);
copy_termchar(scrlineptr(term->curs.y),
term->curs.x, &term->erase_char);
}
term->curs.y++;
term->curs.x = 0;
term->wrapnext = FALSE;
+ cline = scrlineptr(term->curs.y);
}
if (term->insert && width > 0)
insch(term, width);
break;
case 0:
- add_cc(cline, term->curs.x - !term->wrapnext, c);
- term->seen_disp_event = 1;
+ if (term->curs.x > 0) {
+ int x = term->curs.x - 1;
+
+ /* If we're in wrapnext state, the character
+ * to combine with is _here_, not to our left. */
+ if (term->wrapnext)
+ x++;
+
+ /*
+ * If the previous character is
+ * UCSWIDE, back up another one.
+ */
+ if (cline->chars[x].chr == UCSWIDE) {
+ assert(x > 0);
+ x--;
+ }
+
+ add_cc(cline, x, c);
+ term->seen_disp_event = 1;
+ }
continue;
default:
continue;
if (line >= term->bidi_cache_size)
return FALSE; /* cache doesn't have this many lines */
- if (!term->pre_bidi_cache[line])
+ if (!term->pre_bidi_cache[line].chars)
return FALSE; /* cache doesn't contain _this_ line */
+ if (term->pre_bidi_cache[line].width != width)
+ return FALSE; /* line is wrong width */
+
for (i = 0; i < width; i++)
- if (!termchars_equal(term->pre_bidi_cache[line] + i, lbefore + i))
+ if (!termchars_equal(term->pre_bidi_cache[line].chars+i, lbefore+i))
return FALSE; /* line doesn't match cache */
return TRUE; /* it didn't match. */
term->bidi_cache_size = line+1;
term->pre_bidi_cache = sresize(term->pre_bidi_cache,
term->bidi_cache_size,
- termchar *);
+ struct bidi_cache_entry);
term->post_bidi_cache = sresize(term->post_bidi_cache,
term->bidi_cache_size,
- termchar *);
+ struct bidi_cache_entry);
while (j < term->bidi_cache_size) {
- term->pre_bidi_cache[j] = term->post_bidi_cache[j] = NULL;
+ term->pre_bidi_cache[j].chars =
+ term->post_bidi_cache[j].chars = NULL;
+ term->pre_bidi_cache[j].width =
+ term->post_bidi_cache[j].width = -1;
j++;
}
}
- sfree(term->pre_bidi_cache[line]);
- sfree(term->post_bidi_cache[line]);
+ sfree(term->pre_bidi_cache[line].chars);
+ sfree(term->post_bidi_cache[line].chars);
- term->pre_bidi_cache[line] = snewn(width, termchar);
- term->post_bidi_cache[line] = snewn(width, termchar);
+ term->pre_bidi_cache[line].width = width;
+ term->pre_bidi_cache[line].chars = snewn(width, termchar);
+ term->post_bidi_cache[line].width = width;
+ term->post_bidi_cache[line].chars = snewn(width, termchar);
- memcpy(term->pre_bidi_cache[line], lbefore, width * TSIZE);
- memcpy(term->post_bidi_cache[line], lafter, width * TSIZE);
+ memcpy(term->pre_bidi_cache[line].chars, lbefore, width * TSIZE);
+ memcpy(term->post_bidi_cache[line].chars, lafter, width * TSIZE);
}
/*
lchars = term->ltemp;
} else {
- lchars = term->post_bidi_cache[i];
+ lchars = term->post_bidi_cache[i].chars;
}
} else
lchars = ldata->chars;
if (bottom >= term->rows) bottom = term->rows-1;
for (i = top; i <= bottom && i < term->rows; i++) {
- if (term->disptext[i]->lattr == LATTR_NORM)
+ if ((term->disptext[i]->lattr & LATTR_MODE) == LATTR_NORM)
for (j = left; j <= right && j < term->cols; j++)
term->disptext[i]->chars[j].attr = ATTR_INVALID;
else
*/
if (!(ldata->lattr & LATTR_WRAPPED)) {
while (IS_SPACE_CHR(ldata->chars[nlpos.x - 1].chr) &&
+ !ldata->chars[nlpos.x - 1].cc_next &&
poslt(top, nlpos))
decpos(nlpos);
if (poslt(nlpos, bottom))
*/
if (!(ldata->lattr & LATTR_WRAPPED)) {
termchar *q = ldata->chars + term->cols;
- while (q > ldata->chars && IS_SPACE_CHR(q[-1].chr))
+ while (q > ldata->chars &&
+ IS_SPACE_CHR(q[-1].chr) && !q[-1].cc_next)
q--;
if (q == ldata->chars + term->cols)
q--;