To: vim_dev@googlegroups.com Subject: Patch 8.1.0655 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0655 Problem: When appending a line text property flags are not added. Solution: Add text properties to a newly added line. Files: src/memline.c, src/testdir/test_textprop.vim, src/textprop.c *** ../vim-8.1.0654/src/memline.c 2018-12-28 21:59:24.508993022 +0100 --- src/memline.c 2018-12-28 22:55:57.259280353 +0100 *************** *** 2568,2573 **** --- 2568,2633 ---- return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY); } + #ifdef FEAT_TEXT_PROP + static void + add_text_props_for_append( + buf_T *buf, + linenr_T lnum, + char_u **line, + int *len, + char_u **tofree) + { + int round; + int new_prop_count = 0; + int count; + int n; + char_u *props; + int new_len; + char_u *new_line; + textprop_T prop; + + // Make two rounds: + // 1. calculate the extra space needed + // 2. allocate the space and fill it + for (round = 1; round <= 2; ++round) + { + if (round == 2) + { + if (new_prop_count == 0) + return; // nothing to do + new_len = *len + new_prop_count * sizeof(textprop_T); + new_line = alloc((unsigned)new_len); + if (new_line == NULL) + return; + mch_memmove(new_line, *line, *len); + new_prop_count = 0; + } + + // Get the line above to find any props that continue in the next + // line. + count = get_text_props(buf, lnum, &props, FALSE); + for (n = 0; n < count; ++n) + { + mch_memmove(&prop, props + n * sizeof(textprop_T), sizeof(textprop_T)); + if (prop.tp_flags & TP_FLAG_CONT_NEXT) + { + if (round == 2) + { + prop.tp_flags |= TP_FLAG_CONT_PREV; + prop.tp_col = 1; + prop.tp_len = *len; + mch_memmove(new_line + *len + new_prop_count * sizeof(textprop_T), &prop, sizeof(textprop_T)); + } + ++new_prop_count; + } + } + } + *line = new_line; + *tofree = new_line; + *len = new_len; + } + #endif + /* * Append a line after lnum (may be 0 to insert a line in front of the file). * "line" does not need to be allocated, but can't be another line in a *************** *** 2622,2633 **** ml_append_int( buf_T *buf, linenr_T lnum, // append after this line (can be 0) ! char_u *line, // text of the new line colnr_T len_arg, // length of line, including NUL, or 0 int newfile, // flag, see above int mark) // mark the new line { ! colnr_T len = len_arg; // length of line, including NUL, or 0 int i; int line_count; // number of indexes in current block int offset; --- 2682,2694 ---- ml_append_int( buf_T *buf, linenr_T lnum, // append after this line (can be 0) ! char_u *line_arg, // text of the new line colnr_T len_arg, // length of line, including NUL, or 0 int newfile, // flag, see above int mark) // mark the new line { ! char_u *line = line_arg; ! colnr_T len = len_arg; int i; int line_count; // number of indexes in current block int offset; *************** *** 2641,2656 **** DATA_BL *dp; PTR_BL *pp; infoptr_T *ip; - /* lnum out of range */ if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL) ! return FAIL; if (lowest_marked && lowest_marked > lnum) lowest_marked = lnum + 1; if (len == 0) len = (colnr_T)STRLEN(line) + 1; // space needed for the text space_needed = len + INDEX_SIZE; // space needed for text + index mfp = buf->b_ml.ml_mfp; --- 2702,2727 ---- DATA_BL *dp; PTR_BL *pp; infoptr_T *ip; + #ifdef FEAT_TEXT_PROP + char_u *tofree = NULL; + #endif + int ret = FAIL; if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL) ! return FAIL; // lnum out of range if (lowest_marked && lowest_marked > lnum) lowest_marked = lnum + 1; if (len == 0) len = (colnr_T)STRLEN(line) + 1; // space needed for the text + + #ifdef FEAT_TEXT_PROP + if (curbuf->b_has_textprop && lnum > 0) + // Add text properties that continue from the previous line. + add_text_props_for_append(buf, lnum, &line, &len, &tofree); + #endif + space_needed = len + INDEX_SIZE; // space needed for text + index mfp = buf->b_ml.ml_mfp; *************** *** 2663,2669 **** */ if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum, ML_INSERT)) == NULL) ! return FAIL; buf->b_ml.ml_flags &= ~ML_EMPTY; --- 2734,2740 ---- */ if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum, ML_INSERT)) == NULL) ! goto theend; buf->b_ml.ml_flags &= ~ML_EMPTY; *************** *** 2694,2700 **** --(buf->b_ml.ml_locked_lineadd); --(buf->b_ml.ml_locked_high); if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL) ! return FAIL; db_idx = -1; /* careful, it is negative! */ /* get line count before the insertion */ --- 2765,2771 ---- --(buf->b_ml.ml_locked_lineadd); --(buf->b_ml.ml_locked_high); if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL) ! goto theend; db_idx = -1; /* careful, it is negative! */ /* get line count before the insertion */ *************** *** 2708,2716 **** if ((int)dp->db_free >= space_needed) /* enough room in data block */ { ! /* ! * Insert new line in existing data block, or in data block allocated above. ! */ dp->db_txt_start -= len; dp->db_free -= space_needed; ++(dp->db_line_count); --- 2779,2788 ---- if ((int)dp->db_free >= space_needed) /* enough room in data block */ { ! /* ! * Insert the new line in an existing data block, or in the data block ! * allocated above. ! */ dp->db_txt_start -= len; dp->db_free -= space_needed; ++(dp->db_line_count); *************** *** 2756,2770 **** } else /* not enough space in data block */ { - /* - * If there is not enough room we have to create a new data block and copy some - * lines into it. - * Then we have to insert an entry in the pointer block. - * If this pointer block also is full, we go up another block, and so on, up - * to the root if necessary. - * The line counts in the pointer blocks have already been adjusted by - * ml_find_line(). - */ long line_count_left, line_count_right; int page_count_left, page_count_right; bhdr_T *hp_left; --- 2828,2833 ---- *************** *** 2783,2788 **** --- 2846,2859 ---- PTR_BL *pp_new; /* + * There is not enough room, we have to create a new data block and + * copy some lines into it. + * Then we have to insert an entry in the pointer block. + * If this pointer block also is full, we go up another block, and so + * on, up to the root if necessary. + * The line counts in the pointer blocks have already been adjusted by + * ml_find_line(). + * * We are going to allocate a new data block. Depending on the * situation it will be put to the left or right of the existing * block. If possible we put the new line in the left block and move *************** *** 2826,2832 **** /* correct line counts in pointer blocks */ --(buf->b_ml.ml_locked_lineadd); --(buf->b_ml.ml_locked_high); ! return FAIL; } if (db_idx < 0) /* left block is new */ { --- 2897,2903 ---- /* correct line counts in pointer blocks */ --(buf->b_ml.ml_locked_lineadd); --(buf->b_ml.ml_locked_high); ! goto theend; } if (db_idx < 0) /* left block is new */ { *************** *** 2951,2963 **** ip = &(buf->b_ml.ml_stack[stack_idx]); pb_idx = ip->ip_index; if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) ! return FAIL; pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */ if (pp->pb_id != PTR_ID) { IEMSG(_("E317: pointer block id wrong 3")); mf_put(mfp, hp, FALSE, FALSE); ! return FAIL; } /* * TODO: If the pointer block is full and we are adding at the end --- 3022,3034 ---- ip = &(buf->b_ml.ml_stack[stack_idx]); pb_idx = ip->ip_index; if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) ! goto theend; pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */ if (pp->pb_id != PTR_ID) { IEMSG(_("E317: pointer block id wrong 3")); mf_put(mfp, hp, FALSE, FALSE); ! goto theend; } /* * TODO: If the pointer block is full and we are adding at the end *************** *** 3014,3020 **** { hp_new = ml_new_ptr(mfp); if (hp_new == NULL) /* TODO: try to fix tree */ ! return FAIL; pp_new = (PTR_BL *)(hp_new->bh_data); if (hp->bh_bnum != 1) --- 3085,3091 ---- { hp_new = ml_new_ptr(mfp); if (hp_new == NULL) /* TODO: try to fix tree */ ! goto theend; pp_new = (PTR_BL *)(hp_new->bh_data); if (hp->bh_bnum != 1) *************** *** 3119,3126 **** if (buf->b_write_to_channel) channel_write_new_lines(buf); #endif ! return OK; } /* --- 3190,3202 ---- if (buf->b_write_to_channel) channel_write_new_lines(buf); #endif + ret = OK; ! theend: ! #ifdef FEAT_TEXT_PROP ! vim_free(tofree); ! #endif ! return ret; } /* *** ../vim-8.1.0654/src/testdir/test_textprop.vim 2018-12-28 21:59:24.512992993 +0100 --- src/testdir/test_textprop.vim 2018-12-28 23:18:00.504921000 +0100 *************** *** 257,262 **** --- 257,272 ---- call assert_equal([expect_short], prop_list(4)) bwipe! + " Test appending a line below the text prop start. + call Setup_three_line_prop() + let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} + call assert_equal([expect2], prop_list(2)) + call append(2, "new line") + call assert_equal([expect2], prop_list(2)) + let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} + call assert_equal([expect3], prop_list(3)) + bwipe! + call prop_type_delete('comment') endfunc *** ../vim-8.1.0654/src/textprop.c 2018-12-25 23:15:41.795966567 +0100 --- src/textprop.c 2018-12-28 23:19:17.068318767 +0100 *************** *** 17,30 **** * Text properties have a type, which can be used to specify highlighting. * * TODO: ! * - mismatch in column 1 being the first column ! * - Let props overrule syntax HL. ! * - When deleting a line where a prop ended, adjust flag of previous line. ! * - When deleting a line where a prop started, adjust flag of next line. ! * - When inserting a line add props that continue from previous line. ! * - Adjust property column and length when text is inserted/deleted ! * - Add an arrray for global_proptypes, to quickly lookup a proptype by ID ! * - Add an arrray for b_proptypes, to quickly lookup a proptype by ID * - Also test line2byte() with many lines, so that ml_updatechunk() is taken * into account. * - add mechanism to keep track of changed lines. --- 17,28 ---- * Text properties have a type, which can be used to specify highlighting. * * TODO: ! * - Perhaps we only need TP_FLAG_CONT_NEXT ? ! * - Adjust text property column and length when text is inserted/deleted ! * - Add an arrray for global_proptypes, to quickly lookup a prop type by ID ! * - Add an arrray for b_proptypes, to quickly lookup a prop type by ID ! * - Checking the text length to detect text properties is slow. Use a flag in ! * the index, like DB_MARKED? * - Also test line2byte() with many lines, so that ml_updatechunk() is taken * into account. * - add mechanism to keep track of changed lines. *** ../vim-8.1.0654/src/version.c 2018-12-28 21:59:24.512992993 +0100 --- src/version.c 2018-12-28 22:58:21.238154315 +0100 *************** *** 801,802 **** --- 801,804 ---- { /* Add new patch number below this line */ + /**/ + 655, /**/ -- hundred-and-one symptoms of being an internet addict: 71. You wonder how people walk /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///