forked from aniani/vim
Make joining a range of lines much faster. (Milan Vancura)
This commit is contained in:
257
src/ops.c
257
src/ops.c
@@ -1949,7 +1949,7 @@ op_delete(oap)
|
||||
);
|
||||
curwin->w_cursor = curpos; /* restore curwin->w_cursor */
|
||||
|
||||
(void)do_join(FALSE);
|
||||
(void)do_join(2, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4140,138 +4140,137 @@ dis_msg(p, skip_esc)
|
||||
}
|
||||
|
||||
/*
|
||||
* join 'count' lines (minimal 2), including u_save()
|
||||
*/
|
||||
void
|
||||
do_do_join(count, insert_space)
|
||||
long count;
|
||||
int insert_space;
|
||||
{
|
||||
colnr_T col = MAXCOL;
|
||||
|
||||
if (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
|
||||
(linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
|
||||
return;
|
||||
|
||||
while (--count > 0)
|
||||
{
|
||||
line_breakcheck();
|
||||
if (got_int || do_join(insert_space) == FAIL)
|
||||
{
|
||||
beep_flush();
|
||||
break;
|
||||
}
|
||||
if (col == MAXCOL && vim_strchr(p_cpo, CPO_JOINCOL) != NULL)
|
||||
col = curwin->w_cursor.col;
|
||||
}
|
||||
|
||||
/* Vi compatible: use the column of the first join */
|
||||
if (col != MAXCOL && vim_strchr(p_cpo, CPO_JOINCOL) != NULL)
|
||||
curwin->w_cursor.col = col;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Need to update the screen if the line where the cursor is became too
|
||||
* long to fit on the screen.
|
||||
*/
|
||||
update_topline_redraw();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Join two lines at the cursor position.
|
||||
* "redraw" is TRUE when the screen should be updated.
|
||||
* Caller must have setup for undo.
|
||||
* Join 'count' lines (minimal 2) at cursor position.
|
||||
* When "save_undo" is TRUE save lines for undo first.
|
||||
*
|
||||
* return FAIL for failure, OK otherwise
|
||||
*/
|
||||
int
|
||||
do_join(insert_space)
|
||||
int insert_space;
|
||||
do_join(count, insert_space, save_undo)
|
||||
long count;
|
||||
int insert_space;
|
||||
int save_undo;
|
||||
{
|
||||
char_u *curr;
|
||||
char_u *next, *next_start;
|
||||
char_u *curr = NULL;
|
||||
char_u *cend;
|
||||
char_u *newp;
|
||||
char_u *spaces; /* number of spaces inserte before a line */
|
||||
int endcurr1, endcurr2;
|
||||
int currsize; /* size of the current line */
|
||||
int nextsize; /* size of the next line */
|
||||
int spaces; /* number of spaces to insert */
|
||||
int currsize = 0; /* size of the current line */
|
||||
int sumsize = 0; /* size of the long new line */
|
||||
linenr_T t;
|
||||
colnr_T col = 0;
|
||||
int ret = OK;
|
||||
|
||||
if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
|
||||
return FAIL; /* can't join on last line */
|
||||
if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1),
|
||||
(linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
curr = ml_get_curline();
|
||||
currsize = (int)STRLEN(curr);
|
||||
endcurr1 = endcurr2 = NUL;
|
||||
if (insert_space && currsize > 0)
|
||||
{
|
||||
#ifdef FEAT_MBYTE
|
||||
if (has_mbyte)
|
||||
{
|
||||
next = curr + currsize;
|
||||
mb_ptr_back(curr, next);
|
||||
endcurr1 = (*mb_ptr2char)(next);
|
||||
if (next > curr)
|
||||
{
|
||||
mb_ptr_back(curr, next);
|
||||
endcurr2 = (*mb_ptr2char)(next);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
endcurr1 = *(curr + currsize - 1);
|
||||
if (currsize > 1)
|
||||
endcurr2 = *(curr + currsize - 2);
|
||||
}
|
||||
}
|
||||
|
||||
next = next_start = ml_get((linenr_T)(curwin->w_cursor.lnum + 1));
|
||||
spaces = 0;
|
||||
if (insert_space)
|
||||
{
|
||||
next = skipwhite(next);
|
||||
if (*next != ')' && currsize != 0 && endcurr1 != TAB
|
||||
#ifdef FEAT_MBYTE
|
||||
&& (!has_format_option(FO_MBYTE_JOIN)
|
||||
|| (mb_ptr2char(next) < 0x100 && endcurr1 < 0x100))
|
||||
&& (!has_format_option(FO_MBYTE_JOIN2)
|
||||
|| mb_ptr2char(next) < 0x100 || endcurr1 < 0x100)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* don't add a space if the line is ending in a space */
|
||||
if (endcurr1 == ' ')
|
||||
endcurr1 = endcurr2;
|
||||
else
|
||||
++spaces;
|
||||
/* extra space when 'joinspaces' set and line ends in '.' */
|
||||
if ( p_js
|
||||
&& (endcurr1 == '.'
|
||||
|| (vim_strchr(p_cpo, CPO_JOINSP) == NULL
|
||||
&& (endcurr1 == '?' || endcurr1 == '!'))))
|
||||
++spaces;
|
||||
}
|
||||
}
|
||||
nextsize = (int)STRLEN(next);
|
||||
|
||||
newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
|
||||
if (newp == NULL)
|
||||
/* Allocate an array to store the number of spaces inserted before each
|
||||
* line. We will use it to pre-compute the length of the new line and the
|
||||
* proper placement of each original line in the new one. */
|
||||
spaces = lalloc_clear((long_u)count, TRUE);
|
||||
if (spaces == NULL)
|
||||
return FAIL;
|
||||
|
||||
/*
|
||||
* Insert the next line first, because we already have that pointer.
|
||||
* Curr has to be obtained again, because getting next will have
|
||||
* invalidated it.
|
||||
* Don't move anything, just compute the final line length
|
||||
* and setup the array of space strings lengths
|
||||
*/
|
||||
mch_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
|
||||
for (t = 0; t < count; ++t)
|
||||
{
|
||||
curr = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
|
||||
if (insert_space && t > 0)
|
||||
{
|
||||
curr = skipwhite(curr);
|
||||
if (*curr != ')' && currsize != 0 && endcurr1 != TAB
|
||||
#ifdef FEAT_MBYTE
|
||||
&& (!has_format_option(FO_MBYTE_JOIN)
|
||||
|| (mb_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
|
||||
&& (!has_format_option(FO_MBYTE_JOIN2)
|
||||
|| mb_ptr2char(curr) < 0x100 || endcurr1 < 0x100)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* don't add a space if the line is ending in a space */
|
||||
if (endcurr1 == ' ')
|
||||
endcurr1 = endcurr2;
|
||||
else
|
||||
++spaces[t];
|
||||
/* extra space when 'joinspaces' set and line ends in '.' */
|
||||
if ( p_js
|
||||
&& (endcurr1 == '.'
|
||||
|| (vim_strchr(p_cpo, CPO_JOINSP) == NULL
|
||||
&& (endcurr1 == '?' || endcurr1 == '!'))))
|
||||
++spaces[t];
|
||||
}
|
||||
}
|
||||
currsize = (int)STRLEN(curr);
|
||||
sumsize += currsize + spaces[t];
|
||||
endcurr1 = endcurr2 = NUL;
|
||||
if (insert_space && currsize > 0)
|
||||
{
|
||||
#ifdef FEAT_MBYTE
|
||||
if (has_mbyte)
|
||||
{
|
||||
cend = curr + currsize;
|
||||
mb_ptr_back(curr, cend);
|
||||
endcurr1 = (*mb_ptr2char)(cend);
|
||||
if (cend > curr)
|
||||
{
|
||||
mb_ptr_back(curr, cend);
|
||||
endcurr2 = (*mb_ptr2char)(cend);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
endcurr1 = *(curr + currsize - 1);
|
||||
if (currsize > 1)
|
||||
endcurr2 = *(curr + currsize - 2);
|
||||
}
|
||||
}
|
||||
line_breakcheck();
|
||||
if (got_int)
|
||||
{
|
||||
ret = FAIL;
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
|
||||
curr = ml_get_curline();
|
||||
mch_memmove(newp, curr, (size_t)currsize);
|
||||
/* store the column position before last line */
|
||||
col = sumsize - currsize - spaces[count - 1];
|
||||
|
||||
copy_spaces(newp + currsize, (size_t)spaces);
|
||||
/* allocate the space for the new line */
|
||||
newp = alloc_check((unsigned)(sumsize + 1));
|
||||
cend = newp + sumsize;
|
||||
*cend = 0;
|
||||
|
||||
/*
|
||||
* Move affected lines to the new long one.
|
||||
*
|
||||
* 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
|
||||
* should not really be a problem.
|
||||
*/
|
||||
for (t = count - 1; ; --t)
|
||||
{
|
||||
cend -= currsize;
|
||||
mch_memmove(cend, curr, (size_t)currsize);
|
||||
if (spaces[t] > 0)
|
||||
{
|
||||
cend -= spaces[t];
|
||||
copy_spaces(cend, (size_t)(spaces[t]));
|
||||
}
|
||||
mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t,
|
||||
(long)(cend - newp + spaces[t]));
|
||||
if (t == 0)
|
||||
break;
|
||||
curr = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
|
||||
if (insert_space && t > 1)
|
||||
curr = skipwhite(curr);
|
||||
currsize = (int)STRLEN(curr);
|
||||
}
|
||||
ml_replace(curwin->w_cursor.lnum, newp, FALSE);
|
||||
|
||||
/* Only report the change in the first line here, del_lines() will report
|
||||
@@ -4280,32 +4279,32 @@ do_join(insert_space)
|
||||
curwin->w_cursor.lnum + 1, 0L);
|
||||
|
||||
/*
|
||||
* Delete the following line. To do this we move the cursor there
|
||||
* Delete following lines. To do this we move the cursor there
|
||||
* briefly, and then move it back. After del_lines() the cursor may
|
||||
* have moved up (last line deleted), so the current lnum is kept in t.
|
||||
*
|
||||
* Move marks from the deleted line to the joined line, adjusting the
|
||||
* column. This is not Vi compatible, but Vi deletes the marks, thus that
|
||||
* should not really be a problem.
|
||||
*/
|
||||
t = curwin->w_cursor.lnum;
|
||||
mark_col_adjust(t + 1, (colnr_T)0, (linenr_T)-1,
|
||||
(long)(currsize + spaces - (next - next_start)));
|
||||
++curwin->w_cursor.lnum;
|
||||
del_lines(1L, FALSE);
|
||||
del_lines(count - 1, FALSE);
|
||||
curwin->w_cursor.lnum = t;
|
||||
|
||||
/*
|
||||
* go to first character of the joined line
|
||||
* Set the cursor column:
|
||||
* Vi compatible: use the column of the first join
|
||||
* vim: use the column of the last join
|
||||
*/
|
||||
curwin->w_cursor.col = currsize;
|
||||
curwin->w_cursor.col =
|
||||
(vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col);
|
||||
check_cursor_col();
|
||||
|
||||
#ifdef FEAT_VIRTUALEDIT
|
||||
curwin->w_cursor.coladd = 0;
|
||||
#endif
|
||||
curwin->w_set_curswant = TRUE;
|
||||
|
||||
return OK;
|
||||
theend:
|
||||
vim_free(spaces);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef FEAT_COMMENTS
|
||||
@@ -4718,7 +4717,7 @@ format_lines(line_count, avoid_fex)
|
||||
curwin->w_cursor.lnum++;
|
||||
curwin->w_cursor.col = 0;
|
||||
if (line_count < 0 && u_save_cursor() == FAIL)
|
||||
break;
|
||||
break;
|
||||
#ifdef FEAT_COMMENTS
|
||||
(void)del_bytes((long)next_leader_len, FALSE, FALSE);
|
||||
if (next_leader_len > 0)
|
||||
@@ -4726,7 +4725,7 @@ format_lines(line_count, avoid_fex)
|
||||
(long)-next_leader_len);
|
||||
#endif
|
||||
curwin->w_cursor.lnum--;
|
||||
if (do_join(TRUE) == FAIL)
|
||||
if (do_join(2, TRUE, FALSE) == FAIL)
|
||||
{
|
||||
beep_flush();
|
||||
break;
|
||||
|
Reference in New Issue
Block a user