Mercurial > vim
changeset 15349:6abee072b93c v8.1.0682
patch 8.1.0682: text properties not adjusted when backspacing replaced text
commit https://github.com/vim/vim/commit/196d157f12cf0476d97f78834155fc67d6b161de
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Jan 2 23:47:18 2019 +0100
patch 8.1.0682: text properties not adjusted when backspacing replaced text
Problem: Text properties are not adjusted when backspacing replaced text.
Solution: Keep text properties on text restored in replace mode.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 03 Jan 2019 00:00:54 +0100 |
parents | 24c31bd03f3a |
children | 09c9a8384440 |
files | src/edit.c src/globals.h src/testdir/test_textprop.vim src/textprop.c src/version.c |
diffstat | 5 files changed, 98 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/src/edit.c +++ b/src/edit.c @@ -7962,6 +7962,17 @@ replace_do_bs(int limit_col) cc = replace_pop(); if (cc > 0) { +#ifdef FEAT_TEXT_PROP + size_t len_before; + + if (curbuf->b_has_textprop) + { + // Do not adjust text properties for individual delete and insert + // operations, do it afterwards on the resulting text. + len_before = STRLEN(ml_get_curline()); + ++text_prop_frozen; + } +#endif if (State & VREPLACE_FLAG) { /* Get the number of screen cells used by the character we are @@ -8012,8 +8023,19 @@ replace_do_bs(int limit_col) curwin->w_cursor.col -= ins_len; } - /* mark the buffer as changed and prepare for displaying */ + // mark the buffer as changed and prepare for displaying changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); + +#ifdef FEAT_TEXT_PROP + if (curbuf->b_has_textprop) + { + size_t len_now = STRLEN(ml_get_curline()); + + --text_prop_frozen; + adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col, + (int)(len_now - len_before)); + } +#endif } else if (cc == 0) (void)del_char_after_col(limit_col);
--- a/src/globals.h +++ b/src/globals.h @@ -1658,6 +1658,10 @@ EXTERN int *eval_lavars_used INIT(= NULL EXTERN int ctrl_break_was_pressed INIT(= FALSE); #endif +#ifdef FEAT_TEXT_PROP +EXTERN int text_prop_frozen INIT(= 0); +#endif + /* * Optional Farsi support. Include it here, so EXTERN and INIT are defined. */
--- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -145,6 +145,19 @@ func Test_prop_remove() bwipe! endfunc +func SetupOneLine() + call setline(1, 'xonex xtwoxx') + call AddPropTypes() + call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'}) + call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'}) + let expected = [ + \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, + \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, + \] + call assert_equal(expected, prop_list(1)) + return expected +endfunc + func Test_prop_add_remove_buf() new let bufnr = bufnr('') @@ -180,15 +193,7 @@ endfunc func Test_prop_backspace() new set bs=2 - call setline(1, 'xonex xtwoxx') - call AddPropTypes() - call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'}) - call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'}) - let expected = [ - \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, - \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, - \] - call assert_equal(expected, prop_list(1)) + let expected = SetupOneLine() " 'xonex xtwoxx' exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>" call assert_equal('one xtwoxx', getline(1)) @@ -201,6 +206,32 @@ func Test_prop_backspace() set bs& endfunc +func Test_prop_replace() + new + set bs=2 + let expected = SetupOneLine() " 'xonex xtwoxx' + + exe "normal 0Ryyy\<Esc>" + call assert_equal('yyyex xtwoxx', getline(1)) + call assert_equal(expected, prop_list(1)) + + exe "normal ftRyy\<BS>" + call assert_equal('yyyex xywoxx', getline(1)) + call assert_equal(expected, prop_list(1)) + + exe "normal 0fwRyy\<BS>" + call assert_equal('yyyex xyyoxx', getline(1)) + call assert_equal(expected, prop_list(1)) + + exe "normal 0foRyy\<BS>\<BS>" + call assert_equal('yyyex xyyoxx', getline(1)) + call assert_equal(expected, prop_list(1)) + + call DeletePropTypes() + bwipe! + set bs& +endfunc + func Test_prop_clear() new call AddPropTypes()
--- a/src/textprop.c +++ b/src/textprop.c @@ -920,41 +920,59 @@ clear_buf_prop_types(buf_T *buf) * Called is expected to check b_has_textprop and "bytes_added" being non-zero. */ void -adjust_prop_columns(linenr_T lnum, colnr_T col, int bytes_added) +adjust_prop_columns( + linenr_T lnum, + colnr_T col, + int bytes_added) { int proplen; char_u *props; textprop_T tmp_prop; proptype_T *pt; int dirty = FALSE; - int i; + int ri, wi; + size_t textlen; + + if (text_prop_frozen > 0) + return; proplen = get_text_props(curbuf, lnum, &props, TRUE); if (proplen == 0) return; + textlen = curbuf->b_ml.ml_line_len - proplen * sizeof(textprop_T); - for (i = 0; i < proplen; ++i) + wi = 0; // write index + for (ri = 0; ri < proplen; ++ri) { - mch_memmove(&tmp_prop, props + i * sizeof(textprop_T), + mch_memmove(&tmp_prop, props + ri * sizeof(textprop_T), sizeof(textprop_T)); pt = text_prop_type_by_id(curbuf, tmp_prop.tp_type); - if (tmp_prop.tp_col >= col + (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL) ? 2 : 1)) + if (bytes_added > 0 + ? (tmp_prop.tp_col >= col + (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL) ? 2 : 1)) + : (tmp_prop.tp_col > col + 1)) { tmp_prop.tp_col += bytes_added; dirty = TRUE; } - else if (tmp_prop.tp_col + tmp_prop.tp_len > col + (pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL) ? 0 : 1)) + else if (tmp_prop.tp_len > 0 + && tmp_prop.tp_col + tmp_prop.tp_len > col + + ((pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL)) + ? 0 : 1)) { tmp_prop.tp_len += bytes_added; dirty = TRUE; + if (tmp_prop.tp_len <= 0) + continue; // drop this text property } - if (dirty) - { - curbuf->b_ml.ml_flags |= ML_LINE_DIRTY; - mch_memmove(props + i * sizeof(textprop_T), &tmp_prop, + mch_memmove(props + wi * sizeof(textprop_T), &tmp_prop, sizeof(textprop_T)); - } + ++wi; + } + if (dirty) + { + curbuf->b_ml.ml_flags |= ML_LINE_DIRTY; + curbuf->b_ml.ml_line_len = textlen + wi * sizeof(textprop_T); } }