summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/todo.txt3
-rw-r--r--src/edit.c6
-rw-r--r--src/ex_docmd.c2
-rw-r--r--src/normal.c4
-rw-r--r--src/ops.c241
-rw-r--r--src/proto/ops.pro3
6 files changed, 126 insertions, 133 deletions
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index b08d40e36..a09a44d66 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1093,9 +1093,6 @@ Vim 7.3:
- Conceal feature: no update when moving to another window. (Dominique Pelle,
2010 Jul 5) Vince will look into it.
Patches to include:
-- Make do_do_join() work faster. Could at least do a binary search way of
- doing this. Hint from Dominique Pelle, Dec 10; Lee Naish, Dec 11.
- Patch from Milan Vancura, 2010 May 16.
- Patch for Lisp support with ECL (Mikael Jansson, 2008 Oct 25)
- Gvimext patch to support wide file names. (Szabolcs Horvat 2008 Sep 10)
- Patch to support netbeans for Mac. (Kazuki Sakamoto, 2009 Jun 25)
diff --git a/src/edit.c b/src/edit.c
index f465f2017..3ee76553c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -8366,9 +8366,7 @@ ins_del()
{
temp = curwin->w_cursor.col;
if (!can_bs(BS_EOL) /* only if "eol" included */
- || u_save((linenr_T)(curwin->w_cursor.lnum - 1),
- (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
- || do_join(FALSE) == FAIL)
+ || do_join(2, FALSE, TRUE) == FAIL)
vim_beep();
else
curwin->w_cursor.col = temp;
@@ -8549,7 +8547,7 @@ ins_bs(c, mode, inserted_space_p)
ptr[len - 1] = NUL;
}
- (void)do_join(FALSE);
+ (void)do_join(2, FALSE, FALSE);
if (temp == NUL && gchar_cursor() != NUL)
inc_cursor();
}
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index d165305e0..1105a8769 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -8394,7 +8394,7 @@ ex_join(eap)
}
++eap->line2;
}
- do_do_join(eap->line2 - eap->line1 + 1, !eap->forceit);
+ (void)do_join(eap->line2 - eap->line1 + 1, !eap->forceit, TRUE);
beginline(BL_WHITE | BL_FIX);
ex_may_print(eap);
}
diff --git a/src/normal.c b/src/normal.c
index efcdb7992..3321b3ff8 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -1908,7 +1908,7 @@ do_pending_operator(cap, old_col, gui_yank)
beep_flush();
else
{
- do_do_join(oap->line_count, oap->op_type == OP_JOIN);
+ (void)do_join(oap->line_count, oap->op_type == OP_JOIN, TRUE);
auto_format(FALSE, TRUE);
}
break;
@@ -9111,7 +9111,7 @@ nv_join(cap)
{
prep_redo(cap->oap->regname, cap->count0,
NUL, cap->cmdchar, NUL, NUL, cap->nchar);
- do_do_join(cap->count0, cap->nchar == NUL);
+ (void)do_join(cap->count0, cap->nchar == NUL, TRUE);
}
}
}
diff --git a/src/ops.c b/src/ops.c
index f8cde3b13..cf83a884a 100644
--- a/src/ops.c
+++ b/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;
+
+ /* 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;
- curr = ml_get_curline();
- currsize = (int)STRLEN(curr);
- endcurr1 = endcurr2 = NUL;
- if (insert_space && currsize > 0)
+ /*
+ * Don't move anything, just compute the final line length
+ * and setup the array of space strings lengths
+ */
+ for (t = 0; t < count; ++t)
{
-#ifdef FEAT_MBYTE
- if (has_mbyte)
+ curr = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
+ if (insert_space && t > 0)
{
- next = curr + currsize;
- mb_ptr_back(curr, next);
- endcurr1 = (*mb_ptr2char)(next);
- if (next > curr)
+ 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
+ )
{
- mb_ptr_back(curr, next);
- endcurr2 = (*mb_ptr2char)(next);
+ /* 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];
}
}
- else
-#endif
+ currsize = (int)STRLEN(curr);
+ sumsize += currsize + spaces[t];
+ endcurr1 = endcurr2 = NUL;
+ if (insert_space && currsize > 0)
{
- 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)
+ 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)
{
- /* 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;
+ ret = FAIL;
+ goto theend;
}
}
- nextsize = (int)STRLEN(next);
- newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
- if (newp == NULL)
- return FAIL;
+ /* store the column position before last line */
+ col = sumsize - currsize - spaces[count - 1];
+
+ /* allocate the space for the new line */
+ newp = alloc_check((unsigned)(sumsize + 1));
+ cend = newp + sumsize;
+ *cend = 0;
/*
- * Insert the next line first, because we already have that pointer.
- * Curr has to be obtained again, because getting next will have
- * invalidated it.
+ * 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.
*/
- mch_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
-
- curr = ml_get_curline();
- mch_memmove(newp, curr, (size_t)currsize);
-
- copy_spaces(newp + currsize, (size_t)spaces);
-
+ 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;
diff --git a/src/proto/ops.pro b/src/proto/ops.pro
index 37c319414..d07c260dc 100644
--- a/src/proto/ops.pro
+++ b/src/proto/ops.pro
@@ -36,8 +36,7 @@ void adjust_cursor_eol __ARGS((void));
int preprocs_left __ARGS((void));
int get_register_name __ARGS((int num));
void ex_display __ARGS((exarg_T *eap));
-void do_do_join __ARGS((long count, int insert_space));
-int do_join __ARGS((int insert_space));
+int do_join __ARGS((long count, int insert_space, int save_undo));
void op_format __ARGS((oparg_T *oap, int keep_cursor));
void op_formatexpr __ARGS((oparg_T *oap));
int fex_format __ARGS((linenr_T lnum, long count, int c));