comparison src/ops.c @ 20583:d067be761cd7 v8.2.0845

patch 8.2.0845: text properties crossing lines not handled correctly Commit: https://github.com/vim/vim/commit/87be9be1db6b6d8fb57ef14e05f23a84e5e8bea0 Author: Bram Moolenaar <Bram@vim.org> Date: Sat May 30 15:32:02 2020 +0200 patch 8.2.0845: text properties crossing lines not handled correctly Problem: Text properties crossing lines not handled correctly. Solution: When joining lines merge text properties if possible. (Axel Forsman, closes #5839, closes #5683)
author Bram Moolenaar <Bram@vim.org>
date Sat, 30 May 2020 15:45:04 +0200
parents 918245588b50
children 9edb439adbea
comparison
equal deleted inserted replaced
20582:49d2f01322db 20583:d067be761cd7
1885 { 1885 {
1886 char_u *curr = NULL; 1886 char_u *curr = NULL;
1887 char_u *curr_start = NULL; 1887 char_u *curr_start = NULL;
1888 char_u *cend; 1888 char_u *cend;
1889 char_u *newp; 1889 char_u *newp;
1890 size_t newp_len;
1890 char_u *spaces; // number of spaces inserted before a line 1891 char_u *spaces; // number of spaces inserted before a line
1891 int endcurr1 = NUL; 1892 int endcurr1 = NUL;
1892 int endcurr2 = NUL; 1893 int endcurr2 = NUL;
1893 int currsize = 0; // size of the current line 1894 int currsize = 0; // size of the current line
1894 int sumsize = 0; // size of the long new line 1895 int sumsize = 0; // size of the long new line
1898 int *comments = NULL; 1899 int *comments = NULL;
1899 int remove_comments = (use_formatoptions == TRUE) 1900 int remove_comments = (use_formatoptions == TRUE)
1900 && has_format_option(FO_REMOVE_COMS); 1901 && has_format_option(FO_REMOVE_COMS);
1901 int prev_was_comment; 1902 int prev_was_comment;
1902 #ifdef FEAT_PROP_POPUP 1903 #ifdef FEAT_PROP_POPUP
1903 textprop_T **prop_lines = NULL; 1904 int propcount = 0; // number of props over all joined lines
1904 int *prop_lengths = NULL; 1905 int props_remaining;
1905 #endif 1906 #endif
1906 1907
1907 if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1), 1908 if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1),
1908 (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL) 1909 (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
1909 return FAIL; 1910 return FAIL;
1930 * This loops forward over the joined lines. 1931 * This loops forward over the joined lines.
1931 */ 1932 */
1932 for (t = 0; t < count; ++t) 1933 for (t = 0; t < count; ++t)
1933 { 1934 {
1934 curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t)); 1935 curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
1936 #ifdef FEAT_PROP_POPUP
1937 propcount += count_props((linenr_T) (curwin->w_cursor.lnum + t), t > 0);
1938 #endif
1935 if (t == 0 && setmark && !cmdmod.lockmarks) 1939 if (t == 0 && setmark && !cmdmod.lockmarks)
1936 { 1940 {
1937 // Set the '[ mark. 1941 // Set the '[ mark.
1938 curwin->w_buffer->b_op_start.lnum = curwin->w_cursor.lnum; 1942 curwin->w_buffer->b_op_start.lnum = curwin->w_cursor.lnum;
1939 curwin->w_buffer->b_op_start.col = (colnr_T)STRLEN(curr); 1943 curwin->w_buffer->b_op_start.col = (colnr_T)STRLEN(curr);
2012 2016
2013 // store the column position before last line 2017 // store the column position before last line
2014 col = sumsize - currsize - spaces[count - 1]; 2018 col = sumsize - currsize - spaces[count - 1];
2015 2019
2016 // allocate the space for the new line 2020 // allocate the space for the new line
2017 newp = alloc(sumsize + 1); 2021 newp_len = sumsize + 1;
2022 #ifdef FEAT_PROP_POPUP
2023 newp_len += propcount * sizeof(textprop_T);
2024 #endif
2025 newp = alloc(newp_len);
2018 if (newp == NULL) 2026 if (newp == NULL)
2019 { 2027 {
2020 ret = FAIL; 2028 ret = FAIL;
2021 goto theend; 2029 goto theend;
2022 } 2030 }
2023 cend = newp + sumsize; 2031 cend = newp + sumsize;
2024 *cend = 0; 2032 *cend = 0;
2025
2026 #ifdef FEAT_PROP_POPUP
2027 // We need to move properties of the lines that are going to be deleted to
2028 // the new long one.
2029 if (curbuf->b_has_textprop && !text_prop_frozen)
2030 {
2031 // Allocate an array to copy the text properties of joined lines into.
2032 // And another array to store the number of properties in each line.
2033 prop_lines = ALLOC_CLEAR_MULT(textprop_T *, count - 1);
2034 prop_lengths = ALLOC_CLEAR_MULT(int, count - 1);
2035 if (prop_lengths == NULL)
2036 VIM_CLEAR(prop_lines);
2037 }
2038 #endif
2039 2033
2040 /* 2034 /*
2041 * Move affected lines to the new long one. 2035 * Move affected lines to the new long one.
2042 * This loops backwards over the joined lines, including the original line. 2036 * This loops backwards over the joined lines, including the original line.
2043 * 2037 *
2044 * Move marks from each deleted line to the joined line, adjusting the 2038 * Move marks from each deleted line to the joined line, adjusting the
2045 * column. This is not Vi compatible, but Vi deletes the marks, thus that 2039 * column. This is not Vi compatible, but Vi deletes the marks, thus that
2046 * should not really be a problem. 2040 * should not really be a problem.
2047 */ 2041 */
2042 #ifdef FEAT_PROP_POPUP
2043 props_remaining = propcount;
2044 #endif
2048 for (t = count - 1; ; --t) 2045 for (t = count - 1; ; --t)
2049 { 2046 {
2050 int spaces_removed; 2047 int spaces_removed;
2051 2048
2052 cend -= currsize; 2049 cend -= currsize;
2053 mch_memmove(cend, curr, (size_t)currsize); 2050 mch_memmove(cend, curr, (size_t)currsize);
2051
2054 if (spaces[t] > 0) 2052 if (spaces[t] > 0)
2055 { 2053 {
2056 cend -= spaces[t]; 2054 cend -= spaces[t];
2057 vim_memset(cend, ' ', (size_t)(spaces[t])); 2055 vim_memset(cend, ' ', (size_t)(spaces[t]));
2058 } 2056 }
2061 // what is added if it is inside these spaces. 2059 // what is added if it is inside these spaces.
2062 spaces_removed = (curr - curr_start) - spaces[t]; 2060 spaces_removed = (curr - curr_start) - spaces[t];
2063 2061
2064 mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t, 2062 mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t,
2065 (long)(cend - newp - spaces_removed), spaces_removed); 2063 (long)(cend - newp - spaces_removed), spaces_removed);
2064 #ifdef FEAT_PROP_POPUP
2065 prepend_joined_props(newp + sumsize + 1, propcount, &props_remaining,
2066 curwin->w_cursor.lnum + t, t == count - 1,
2067 (long)(cend - newp), spaces_removed);
2068 #endif
2069
2066 if (t == 0) 2070 if (t == 0)
2067 break; 2071 break;
2068 #ifdef FEAT_PROP_POPUP
2069 if (prop_lines != NULL)
2070 adjust_props_for_join(curwin->w_cursor.lnum + t,
2071 prop_lines + t - 1, prop_lengths + t - 1,
2072 (long)(cend - newp - spaces_removed), spaces_removed);
2073 #endif
2074
2075 curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1)); 2072 curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
2076 if (remove_comments) 2073 if (remove_comments)
2077 curr += comments[t - 1]; 2074 curr += comments[t - 1];
2078 if (insert_space && t > 1) 2075 if (insert_space && t > 1)
2079 curr = skipwhite(curr); 2076 curr = skipwhite(curr);
2080 currsize = (int)STRLEN(curr); 2077 currsize = (int)STRLEN(curr);
2081 } 2078 }
2082 2079
2083 #ifdef FEAT_PROP_POPUP 2080 ml_replace_len(curwin->w_cursor.lnum, newp, newp_len, TRUE, FALSE);
2084 if (prop_lines != NULL)
2085 join_prop_lines(curwin->w_cursor.lnum, newp,
2086 prop_lines, prop_lengths, count);
2087 else
2088 #endif
2089 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
2090 2081
2091 if (setmark && !cmdmod.lockmarks) 2082 if (setmark && !cmdmod.lockmarks)
2092 { 2083 {
2093 // Set the '] mark. 2084 // Set the '] mark.
2094 curwin->w_buffer->b_op_end.lnum = curwin->w_cursor.lnum; 2085 curwin->w_buffer->b_op_end.lnum = curwin->w_cursor.lnum;