mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 9.0.0145: substitute that joins lines drops text properties
Problem: Substitute that joins lines drops text properties. Solution: Move text properties of the last line to the new line.
This commit is contained in:
@@ -3709,6 +3709,9 @@ ex_substitute(exarg_T *eap)
|
|||||||
int save_ma = 0;
|
int save_ma = 0;
|
||||||
int save_sandbox = 0;
|
int save_sandbox = 0;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_PROP_POPUP
|
||||||
|
textprop_T *text_props = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
cmd = eap->arg;
|
cmd = eap->arg;
|
||||||
if (!global_busy)
|
if (!global_busy)
|
||||||
@@ -4049,6 +4052,7 @@ ex_substitute(exarg_T *eap)
|
|||||||
#ifdef FEAT_PROP_POPUP
|
#ifdef FEAT_PROP_POPUP
|
||||||
int apc_flags = APC_SAVE_FOR_UNDO | APC_SUBSTITUTE;
|
int apc_flags = APC_SAVE_FOR_UNDO | APC_SUBSTITUTE;
|
||||||
colnr_T total_added = 0;
|
colnr_T total_added = 0;
|
||||||
|
int text_prop_count = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4501,8 +4505,59 @@ ex_substitute(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p1 = ml_get(sub_firstlnum + nmatch - 1);
|
linenr_T lastlnum = sub_firstlnum + nmatch - 1;
|
||||||
|
#ifdef FEAT_PROP_POPUP
|
||||||
|
if (curbuf->b_has_textprop)
|
||||||
|
{
|
||||||
|
char_u *prop_start;
|
||||||
|
|
||||||
|
// Props in the first line may be shortened or deleted
|
||||||
|
if (adjust_prop_columns(lnum,
|
||||||
|
total_added + regmatch.startpos[0].col,
|
||||||
|
-MAXCOL, apc_flags))
|
||||||
|
apc_flags &= ~APC_SAVE_FOR_UNDO;
|
||||||
|
total_added -= (colnr_T)STRLEN(
|
||||||
|
sub_firstline + regmatch.startpos[0].col);
|
||||||
|
|
||||||
|
// Props in the last line may be moved or deleted
|
||||||
|
if (adjust_prop_columns(lastlnum,
|
||||||
|
0, -regmatch.endpos[0].col, apc_flags))
|
||||||
|
// When text properties are changed, need to save
|
||||||
|
// for undo first, unless done already.
|
||||||
|
apc_flags &= ~APC_SAVE_FOR_UNDO;
|
||||||
|
|
||||||
|
// Copy the text props of the last line, they will be
|
||||||
|
// later appended to the changed line.
|
||||||
|
text_prop_count = get_text_props(curbuf, lastlnum,
|
||||||
|
&prop_start, FALSE);
|
||||||
|
if (text_prop_count > 0)
|
||||||
|
{
|
||||||
|
// TODO: what when we already did this?
|
||||||
|
vim_free(text_props);
|
||||||
|
text_props = ALLOC_MULT(textprop_T,
|
||||||
|
text_prop_count);
|
||||||
|
if (text_props != NULL)
|
||||||
|
{
|
||||||
|
int pi;
|
||||||
|
|
||||||
|
mch_memmove(text_props, prop_start,
|
||||||
|
text_prop_count * sizeof(textprop_T));
|
||||||
|
// After joining the text prop columns will
|
||||||
|
// increase.
|
||||||
|
for (pi = 0; pi < text_prop_count; ++pi)
|
||||||
|
text_props[pi].tp_col +=
|
||||||
|
regmatch.startpos[0].col + sublen - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
p1 = ml_get(lastlnum);
|
||||||
nmatch_tl += nmatch - 1;
|
nmatch_tl += nmatch - 1;
|
||||||
|
#ifdef FEAT_PROP_POPUP
|
||||||
|
if (curbuf->b_has_textprop)
|
||||||
|
total_added += (colnr_T)STRLEN(
|
||||||
|
p1 + regmatch.endpos[0].col);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
copy_len = regmatch.startpos[0].col - copycol;
|
copy_len = regmatch.startpos[0].col - copycol;
|
||||||
needed_len = copy_len + ((unsigned)STRLEN(p1)
|
needed_len = copy_len + ((unsigned)STRLEN(p1)
|
||||||
@@ -4708,7 +4763,10 @@ skip:
|
|||||||
if (u_savesub(lnum) != OK)
|
if (u_savesub(lnum) != OK)
|
||||||
break;
|
break;
|
||||||
ml_replace(lnum, new_start, TRUE);
|
ml_replace(lnum, new_start, TRUE);
|
||||||
|
#ifdef FEAT_PROP_POPUP
|
||||||
|
if (text_props != NULL)
|
||||||
|
add_text_props(lnum, text_props, text_prop_count);
|
||||||
|
#endif
|
||||||
if (nmatch_tl > 0)
|
if (nmatch_tl > 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -4793,6 +4851,10 @@ skip:
|
|||||||
outofmem:
|
outofmem:
|
||||||
vim_free(sub_firstline); // may have to free allocated copy of the line
|
vim_free(sub_firstline); // may have to free allocated copy of the line
|
||||||
|
|
||||||
|
#ifdef FEAT_PROP_POPUP
|
||||||
|
vim_free(text_props);
|
||||||
|
#endif
|
||||||
|
|
||||||
// ":s/pat//n" doesn't move the cursor
|
// ":s/pat//n" doesn't move the cursor
|
||||||
if (subflags.do_count)
|
if (subflags.do_count)
|
||||||
curwin->w_cursor = old_cursor;
|
curwin->w_cursor = old_cursor;
|
||||||
|
@@ -6,6 +6,7 @@ int prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict, buf_T
|
|||||||
int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
|
int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
|
||||||
int count_props(linenr_T lnum, int only_starting, int last_line);
|
int count_props(linenr_T lnum, int only_starting, int last_line);
|
||||||
int find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop, linenr_T *found_lnum);
|
int find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop, linenr_T *found_lnum);
|
||||||
|
void add_text_props(linenr_T lnum, textprop_T *text_props, int text_prop_count);
|
||||||
proptype_T *text_prop_type_by_id(buf_T *buf, int id);
|
proptype_T *text_prop_type_by_id(buf_T *buf, int id);
|
||||||
void f_prop_clear(typval_T *argvars, typval_T *rettv);
|
void f_prop_clear(typval_T *argvars, typval_T *rettv);
|
||||||
void f_prop_find(typval_T *argvars, typval_T *rettv);
|
void f_prop_find(typval_T *argvars, typval_T *rettv);
|
||||||
|
@@ -1363,15 +1363,18 @@ func Test_proptype_substitute2()
|
|||||||
\ #{type_bufnr: 0, id: 0, col: 50, end: 1, type: 'number', length: 4, start: 1}]
|
\ #{type_bufnr: 0, id: 0, col: 50, end: 1, type: 'number', length: 4, start: 1}]
|
||||||
|
|
||||||
" TODO
|
" TODO
|
||||||
return
|
if 0
|
||||||
" Add some text in between
|
" Add some text in between
|
||||||
%s/\s\+/ /g
|
%s/\s\+/ /g
|
||||||
call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3))
|
call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3))
|
||||||
|
|
||||||
" remove some text
|
" remove some text
|
||||||
:1s/[a-z]\{3\}//g
|
:1s/[a-z]\{3\}//g
|
||||||
let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}]
|
let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}]
|
||||||
call assert_equal(expected, prop_list(1))
|
call assert_equal(expected, prop_list(1))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call prop_type_delete('number')
|
||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
@@ -1388,6 +1391,36 @@ func Test_proptype_substitute3()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_proptype_substitute_join()
|
||||||
|
new
|
||||||
|
call setline(1, [
|
||||||
|
\ 'This is some end',
|
||||||
|
\ 'start is highlighted end',
|
||||||
|
\ 'some is highlighted',
|
||||||
|
\ 'start is also highlighted'])
|
||||||
|
|
||||||
|
call prop_type_add('number', {'highlight': 'ErrorMsg'})
|
||||||
|
|
||||||
|
call prop_add(1, 6, {'length': 2, 'type': 'number'})
|
||||||
|
call prop_add(2, 7, {'length': 2, 'type': 'number'})
|
||||||
|
call prop_add(3, 6, {'length': 2, 'type': 'number'})
|
||||||
|
call prop_add(4, 7, {'length': 2, 'type': 'number'})
|
||||||
|
" The highlighted "is" in line 1, 2 and 4 is kept and ajudsted.
|
||||||
|
" The highlighted "is" in line 3 is deleted.
|
||||||
|
let expected = [
|
||||||
|
\ #{type_bufnr: 0, id: 0, col: 6, end: 1, type: 'number', length: 2, start: 1},
|
||||||
|
\ #{type_bufnr: 0, id: 0, col: 21, end: 1, type: 'number', length: 2, start: 1},
|
||||||
|
\ #{type_bufnr: 0, id: 0, col: 43, end: 1, type: 'number', length: 2, start: 1}]
|
||||||
|
|
||||||
|
s/end\nstart/joined/
|
||||||
|
s/end\n.*\nstart/joined/
|
||||||
|
call assert_equal('This is some joined is highlighted joined is also highlighted', getline(1))
|
||||||
|
call assert_equal(expected, prop_list(1))
|
||||||
|
|
||||||
|
call prop_type_delete('number')
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func SaveOptions()
|
func SaveOptions()
|
||||||
let d = #{tabstop: &tabstop,
|
let d = #{tabstop: &tabstop,
|
||||||
\ softtabstop: &softtabstop,
|
\ softtabstop: &softtabstop,
|
||||||
|
@@ -12,7 +12,6 @@
|
|||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - Adjust text property column and length when text is inserted/deleted.
|
* - Adjust text property column and length when text is inserted/deleted.
|
||||||
* -> a :substitute with a multi-line match
|
|
||||||
* -> search for changed_bytes() from misc1.c
|
* -> search for changed_bytes() from misc1.c
|
||||||
* -> search for mark_col_adjust()
|
* -> search for mark_col_adjust()
|
||||||
* - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV?
|
* - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV?
|
||||||
@@ -683,6 +682,29 @@ set_text_props(linenr_T lnum, char_u *props, int len)
|
|||||||
curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
|
curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add "text_props" with "text_prop_count" text propertis to line "lnum".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
add_text_props(linenr_T lnum, textprop_T *text_props, int text_prop_count)
|
||||||
|
{
|
||||||
|
char_u *text;
|
||||||
|
char_u *newtext;
|
||||||
|
int proplen = text_prop_count * (int)sizeof(textprop_T);
|
||||||
|
|
||||||
|
text = ml_get(lnum);
|
||||||
|
newtext = alloc(curbuf->b_ml.ml_line_len + proplen);
|
||||||
|
if (newtext == NULL)
|
||||||
|
return;
|
||||||
|
mch_memmove(newtext, text, curbuf->b_ml.ml_line_len);
|
||||||
|
mch_memmove(newtext + curbuf->b_ml.ml_line_len, text_props, proplen);
|
||||||
|
if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED))
|
||||||
|
vim_free(curbuf->b_ml.ml_line_ptr);
|
||||||
|
curbuf->b_ml.ml_line_ptr = newtext;
|
||||||
|
curbuf->b_ml.ml_line_len += proplen;
|
||||||
|
curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
static proptype_T *
|
static proptype_T *
|
||||||
find_type_by_id(hashtab_T *ht, int id)
|
find_type_by_id(hashtab_T *ht, int id)
|
||||||
{
|
{
|
||||||
|
@@ -735,6 +735,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
145,
|
||||||
/**/
|
/**/
|
||||||
144,
|
144,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user