forked from aniani/vim
patch 8.1.1341: text properties are lost when joining lines
Problem: Text properties are lost when joining lines. Solution: Move the text properties to the joined line.
This commit is contained in:
52
src/ops.c
52
src/ops.c
@@ -1211,7 +1211,8 @@ do_execreg(
|
||||
int retval = OK;
|
||||
int remap;
|
||||
|
||||
if (regname == '@') /* repeat previous one */
|
||||
// repeat previous one
|
||||
if (regname == '@')
|
||||
{
|
||||
if (execreg_lastc == NUL)
|
||||
{
|
||||
@@ -1220,7 +1221,7 @@ do_execreg(
|
||||
}
|
||||
regname = execreg_lastc;
|
||||
}
|
||||
/* check for valid regname */
|
||||
// check for valid regname
|
||||
if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
|
||||
{
|
||||
emsg_invreg(regname);
|
||||
@@ -1232,11 +1233,13 @@ do_execreg(
|
||||
regname = may_get_selection(regname);
|
||||
#endif
|
||||
|
||||
if (regname == '_') /* black hole: don't stuff anything */
|
||||
// black hole: don't stuff anything
|
||||
if (regname == '_')
|
||||
return OK;
|
||||
|
||||
#ifdef FEAT_CMDHIST
|
||||
if (regname == ':') /* use last command line */
|
||||
// use last command line
|
||||
if (regname == ':')
|
||||
{
|
||||
if (last_cmdline == NULL)
|
||||
{
|
||||
@@ -4438,7 +4441,10 @@ do_join(
|
||||
&& has_format_option(FO_REMOVE_COMS);
|
||||
int prev_was_comment;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
textprop_T **prop_lines = NULL;
|
||||
int *prop_lengths = NULL;
|
||||
#endif
|
||||
|
||||
if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1),
|
||||
(linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
|
||||
@@ -4463,8 +4469,9 @@ do_join(
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't move anything, just compute the final line length
|
||||
* Don't move anything yet, just compute the final line length
|
||||
* and setup the array of space strings lengths
|
||||
* This loops forward over the joined lines.
|
||||
*/
|
||||
for (t = 0; t < count; ++t)
|
||||
{
|
||||
@@ -4556,8 +4563,24 @@ do_join(
|
||||
cend = newp + sumsize;
|
||||
*cend = 0;
|
||||
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
// We need to move properties of the lines that are going to be deleted to
|
||||
// the new long one.
|
||||
if (curbuf->b_has_textprop && !text_prop_frozen)
|
||||
{
|
||||
// Allocate an array to copy the text properties of joined lines into.
|
||||
// And another array to store the number of properties in each line.
|
||||
prop_lines = (textprop_T **)alloc_clear(
|
||||
(int)(count - 1) * sizeof(textprop_T *));
|
||||
prop_lengths = (int *)alloc_clear((int)(count - 1) * sizeof(int));
|
||||
if (prop_lengths == NULL)
|
||||
VIM_CLEAR(prop_lines);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Move affected lines to the new long one.
|
||||
* This loops backwards over the joined lines, including the original line.
|
||||
*
|
||||
* Move marks from each deleted line to the joined line, adjusting the
|
||||
* column. This is not Vi compatible, but Vi deletes the marks, thus that
|
||||
@@ -4583,8 +4606,15 @@ do_join(
|
||||
(long)(cend - newp - spaces_removed), spaces_removed);
|
||||
if (t == 0)
|
||||
break;
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
if (prop_lines != NULL)
|
||||
adjust_props_for_join(curwin->w_cursor.lnum + t,
|
||||
prop_lines + t - 1, prop_lengths + t - 1,
|
||||
(long)(cend - newp - spaces_removed), spaces_removed);
|
||||
#endif
|
||||
|
||||
curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
|
||||
#if defined(FEAT_COMMENTS) || defined(PROTO)
|
||||
#if defined(FEAT_COMMENTS)
|
||||
if (remove_comments)
|
||||
curr += comments[t - 1];
|
||||
#endif
|
||||
@@ -4592,6 +4622,13 @@ do_join(
|
||||
curr = skipwhite(curr);
|
||||
currsize = (int)STRLEN(curr);
|
||||
}
|
||||
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
if (prop_lines != NULL)
|
||||
join_prop_lines(curwin->w_cursor.lnum, newp,
|
||||
prop_lines, prop_lengths, count);
|
||||
else
|
||||
#endif
|
||||
ml_replace(curwin->w_cursor.lnum, newp, FALSE);
|
||||
|
||||
if (setmark)
|
||||
@@ -4605,7 +4642,6 @@ do_join(
|
||||
* the deleted line. */
|
||||
changed_lines(curwin->w_cursor.lnum, currsize,
|
||||
curwin->w_cursor.lnum + 1, 0L);
|
||||
|
||||
/*
|
||||
* Delete following lines. To do this we move the cursor there
|
||||
* briefly, and then move it back. After del_lines() the cursor may
|
||||
|
@@ -15,4 +15,6 @@ void clear_global_prop_types(void);
|
||||
void clear_buf_prop_types(buf_T *buf);
|
||||
void adjust_prop_columns(linenr_T lnum, colnr_T col, int bytes_added);
|
||||
void adjust_props_for_split(linenr_T lnum_props, linenr_T lnum_top, int kept, int deleted);
|
||||
void adjust_props_for_join(linenr_T lnum, textprop_T **prop_line, int *prop_length, long col, int removed);
|
||||
void join_prop_lines(linenr_T lnum, char_u *newp, textprop_T **prop_lines, int *prop_lengths, int count);
|
||||
/* vim: set ft=c : */
|
||||
|
@@ -2,6 +2,7 @@
|
||||
| +0#af5f00255&@1|2| |N+0#0000000#ffff4012|u|m|b|é|r| |1+0#4040ff13&|2|3| +0#0000000&|ä|n|d| |t|h|œ|n| |4+0#4040ff13&|¾|7|.+0#0000000&| +0&#ffffff0@46
|
||||
| +0#af5f00255&@1|3| >-+8#0000000#ffff4012|x+8&#ffffff0|a+8#4040ff13&@1|x+8#0000000&|-@1|x+8#4040ff13&|b@1|x+8#0000000&|-@1|x|c+8#4040ff13&@1|x|-+8#0000000&@1|x+8#4040ff13&|d@1|x|-+8#0000000&@1| @45
|
||||
| +0#af5f00255&@1|4| |/+0#40ff4011&@1| |c|o|m@1|e|n|t| |w+0&#e0e0e08|i|t|h| |e+8&&|r@1|o|r| +0&#ffffff0|i|n| |i|t| +0#0000000&@43
|
||||
| +0#af5f00255&@1|5| |f+0#0000000&|i|r|s|t| |l+0&#ffff4012|i|n|e| @1|s|e|c|o|n|d| +0&#ffffff0|l|i|n|e| @1|t|h|i|r|d| |l|i|n|e| |f|o|u|r|t|h| |l+0&#ffff4012|i|n|e| +0&#ffffff0@23
|
||||
|~+0#4040ff13&| @73
|
||||
|~| @73
|
||||
| +0#0000000&@56|3|,|1| @10|A|l@1|
|
||||
|
@@ -624,6 +624,10 @@ funct Test_textprop_screenshots()
|
||||
\ .. "'Numbér 123 änd thœn 4¾7.',"
|
||||
\ .. "'--aa--bb--cc--dd--',"
|
||||
\ .. "'// comment with error in it',"
|
||||
\ .. "'first line',"
|
||||
\ .. "' second line ',"
|
||||
\ .. "'third line',"
|
||||
\ .. "' fourth line',"
|
||||
\ .. "])",
|
||||
\ "hi NumberProp ctermfg=blue",
|
||||
\ "hi LongProp ctermbg=yellow",
|
||||
@@ -645,6 +649,10 @@ funct Test_textprop_screenshots()
|
||||
\ "call prop_add(3, 15, {'length': 2, 'type': 'both'})",
|
||||
\ "call prop_add(4, 12, {'length': 10, 'type': 'background'})",
|
||||
\ "call prop_add(4, 17, {'length': 5, 'type': 'error'})",
|
||||
\ "call prop_add(5, 7, {'length': 4, 'type': 'long'})",
|
||||
\ "call prop_add(6, 1, {'length': 8, 'type': 'long'})",
|
||||
\ "call prop_add(8, 1, {'length': 1, 'type': 'long'})",
|
||||
\ "call prop_add(8, 11, {'length': 4, 'type': 'long'})",
|
||||
\ "set number cursorline",
|
||||
\ "hi clear SpellBad",
|
||||
\ "set spell",
|
||||
@@ -652,8 +660,11 @@ funct Test_textprop_screenshots()
|
||||
\ "hi Comment ctermfg=green",
|
||||
\ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>",
|
||||
\ "normal 3G0lli\<BS>\<Esc>",
|
||||
\ "normal 6G0i\<BS>\<Esc>",
|
||||
\ "normal 3J",
|
||||
\ "normal 3G",
|
||||
\], 'XtestProp')
|
||||
let buf = RunVimInTerminal('-S XtestProp', {'rows': 7})
|
||||
let buf = RunVimInTerminal('-S XtestProp', {'rows': 8})
|
||||
call VerifyScreenDump(buf, 'Test_textprop_01', {})
|
||||
|
||||
" clean up
|
||||
|
107
src/textprop.c
107
src/textprop.c
@@ -13,8 +13,8 @@
|
||||
* TODO:
|
||||
* - Adjust text property column and length when text is inserted/deleted.
|
||||
* -> a :substitute with a multi-line match
|
||||
* -> join two lines, also with BS in Insert mode
|
||||
* -> search for changed_bytes() from misc1.c
|
||||
* -> search for mark_col_adjust()
|
||||
* - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV?
|
||||
* - 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
|
||||
@@ -1097,4 +1097,109 @@ adjust_props_for_split(
|
||||
ga_clear(&nextprop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Line "lnum" has been joined and will end up at column "col" in the new line.
|
||||
* "removed" bytes have been removed from the start of the line, properties
|
||||
* there are to be discarded.
|
||||
* Move the adjusted text properties to an allocated string, store it in
|
||||
* "prop_line" and adjust the columns.
|
||||
*/
|
||||
void
|
||||
adjust_props_for_join(
|
||||
linenr_T lnum,
|
||||
textprop_T **prop_line,
|
||||
int *prop_length,
|
||||
long col,
|
||||
int removed)
|
||||
{
|
||||
int proplen;
|
||||
char_u *props;
|
||||
int ri;
|
||||
int wi = 0;
|
||||
|
||||
proplen = get_text_props(curbuf, lnum, &props, FALSE);
|
||||
if (proplen > 0)
|
||||
{
|
||||
*prop_line = (textprop_T *)alloc(proplen * (int)sizeof(textprop_T));
|
||||
if (*prop_line != NULL)
|
||||
{
|
||||
for (ri = 0; ri < proplen; ++ri)
|
||||
{
|
||||
textprop_T *cp = *prop_line + wi;
|
||||
|
||||
mch_memmove(cp, props + ri * sizeof(textprop_T),
|
||||
sizeof(textprop_T));
|
||||
if (cp->tp_col + cp->tp_len > removed)
|
||||
{
|
||||
if (cp->tp_col > removed)
|
||||
cp->tp_col += col;
|
||||
else
|
||||
{
|
||||
// property was partly deleted, make it shorter
|
||||
cp->tp_len -= removed - cp->tp_col;
|
||||
cp->tp_col = col;
|
||||
}
|
||||
++wi;
|
||||
}
|
||||
}
|
||||
}
|
||||
*prop_length = wi;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* After joining lines: concatenate the text and the properties of all joined
|
||||
* lines into one line and replace the line.
|
||||
*/
|
||||
void
|
||||
join_prop_lines(
|
||||
linenr_T lnum,
|
||||
char_u *newp,
|
||||
textprop_T **prop_lines,
|
||||
int *prop_lengths,
|
||||
int count)
|
||||
{
|
||||
size_t proplen = 0;
|
||||
size_t oldproplen;
|
||||
char_u *props;
|
||||
int i;
|
||||
int len;
|
||||
char_u *line;
|
||||
size_t l;
|
||||
|
||||
for (i = 0; i < count - 1; ++i)
|
||||
proplen += prop_lengths[i];
|
||||
if (proplen == 0)
|
||||
{
|
||||
ml_replace(lnum, newp, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// get existing properties of the joined line
|
||||
oldproplen = get_text_props(curbuf, lnum, &props, FALSE);
|
||||
|
||||
len = (int)STRLEN(newp) + 1;
|
||||
line = alloc(len + (oldproplen + proplen) * (int)sizeof(textprop_T));
|
||||
if (line == NULL)
|
||||
return;
|
||||
mch_memmove(line, newp, len);
|
||||
l = oldproplen * sizeof(textprop_T);
|
||||
mch_memmove(line + len, props, l);
|
||||
len += l;
|
||||
|
||||
for (i = 0; i < count - 1; ++i)
|
||||
if (prop_lines[i] != NULL)
|
||||
{
|
||||
l = prop_lengths[i] * sizeof(textprop_T);
|
||||
mch_memmove(line + len, prop_lines[i], l);
|
||||
len += l;
|
||||
vim_free(prop_lines[i]);
|
||||
}
|
||||
|
||||
ml_replace_len(lnum, line, len, TRUE, FALSE);
|
||||
vim_free(newp);
|
||||
vim_free(prop_lines);
|
||||
vim_free(prop_lengths);
|
||||
}
|
||||
|
||||
#endif // FEAT_TEXT_PROP
|
||||
|
@@ -767,6 +767,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1341,
|
||||
/**/
|
||||
1340,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user