> Milan, did you read the earlier post? It seems to deal with that. Thank you for the reference, Ian. I made O(n) variant, two patches follows as attachemnts. Bram, are they OK for you, please?
The first one fasten the join operation, the second one removes do_do_join() function as it is no longer needed. They are separate to allow to accept just the first one if API change is not allowed etc. Milan -- Milan Vancura, Prague, Czech Republic, Europe --~--~---------~--~----~------------~-------~--~----~ You received this message from the "vim_dev" maillist. For more information, visit http://www.vim.org/maillist.php -~----------~----~----~----~------~----~------~--~---
>From 584f45b5896a80fb06a0774a491cfe97325aa317 Mon Sep 17 00:00:00 2001 From: mvancura <[email protected]> Date: Tue, 23 Dec 2008 16:57:38 +0100 Subject: [PATCH] New algorithm of joining lines: instead of calling do_join() n-times for n lines, new function do_do_join() do the whole work and accepts number of lines to join directly. That means do_join() function is just a container calling do_do_join() and can be deleted in the future. diff --git a/src/ops.c b/src/ops.c index 557985c..6ab83fc 100644 --- a/src/ops.c +++ b/src/ops.c @@ -4105,135 +4105,118 @@ dis_msg(p, skip_esc) /* * join 'count' lines (minimal 2), including u_save() */ - void + int do_do_join(count, insert_space) long count; int insert_space; { - colnr_T col = MAXCOL; + char_u *curr, *cend; + char_u *newp; + char_u *spaces; /* array of spaces added between lines */ + int endcurr1, endcurr2; + int currsize; /* size of the current line */ + int sumsize=0; /* size of the new (big) line */ + linenr_T t; + colnr_T col = 0; 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; - } + return FAIL; - /* Vi compatible: use the column of the first join */ - if (col != MAXCOL && vim_strchr(p_cpo, CPO_JOINCOL) != NULL) - curwin->w_cursor.col = col; + spaces=lalloc_clear((long_u)count,TRUE); + if(spaces==NUL) + return FAIL; -#if 0 /* - * Need to update the screen if the line where the cursor is became too - * long to fit on the screen. + * Don't move anything, just compute the final line length + * and setup the array of space strings lengths */ - 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. - * - * return FAIL for failure, OK otherwise - */ - int -do_join(insert_space) - int insert_space; -{ - char_u *curr; - char_u *next, *next_start; - char_u *newp; - int endcurr1, endcurr2; - int currsize; /* size of the current line */ - int nextsize; /* size of the next line */ - int spaces; /* number of spaces to insert */ - linenr_T t; - - if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) - return FAIL; /* can't join on last line */ - - curr = ml_get_curline(); - currsize = (int)STRLEN(curr); - endcurr1 = endcurr2 = NUL; - if (insert_space && currsize > 0) + 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) -#endif - ) - { - /* don't add a space if the line is ending in a space */ - if (endcurr1 == ' ') - endcurr1 = endcurr2; + 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 - ++spaces; - /* extra space when 'joinspaces' set and line ends in '.' */ - if ( p_js - && (endcurr1 == '.' - || (vim_strchr(p_cpo, CPO_JOINSP) == NULL - && (endcurr1 == '?' || endcurr1 == '!')))) - ++spaces; +#endif + { + endcurr1 = *(curr + currsize - 1); + if (currsize > 1) + endcurr2 = *(curr + currsize - 2); + } } } - 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]; + + 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. + * Finally move affected lines to the new long one */ - 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 + spaces[t]); + mch_memmove(cend + spaces[t], curr, (size_t)currsize); + if (spaces[t]) + copy_spaces(cend, (size_t)(spaces[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. + */ + 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); + } + mch_memmove(cend, curr, (size_t)currsize); ml_replace(curwin->w_cursor.lnum, newp, FALSE); @@ -4243,34 +4226,55 @@ 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 + * Cursor column setting + * 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; +#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 + + vim_free(spaces); return OK; } +/* + * Join two lines at the cursor position. + * "redraw" is TRUE when the screen should be updated. + * Caller must have setup for undo. + * + * return FAIL for failure, OK otherwise + */ + int +do_join(insert_space) + int insert_space; +{ + return do_do_join(2,insert_space); +} + #ifdef FEAT_COMMENTS /* * Return TRUE if the two comment leaders given are the same. "lnum" is diff --git a/src/proto/ops.pro b/src/proto/ops.pro index 37c3194..1e89509 100644 --- a/src/proto/ops.pro +++ b/src/proto/ops.pro @@ -36,7 +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_do_join __ARGS((long count, int insert_space)); int do_join __ARGS((int insert_space)); void op_format __ARGS((oparg_T *oap, int keep_cursor)); void op_formatexpr __ARGS((oparg_T *oap));
>From c461f7789338ae703b9ced7e5b80299081d90a15 Mon Sep 17 00:00:00 2001 From: mvancura <[email protected]> Date: Tue, 23 Dec 2008 17:15:18 +0100 Subject: [PATCH] The duality do_join() + do_do_join() removed. Only one function do_join accepting number of lines to join is here now. diff --git a/src/edit.c b/src/edit.c index 714d320..3d82eac 100644 --- a/src/edit.c +++ b/src/edit.c @@ -8206,7 +8206,7 @@ ins_del() 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) == FAIL) vim_beep(); else curwin->w_cursor.col = temp; @@ -8386,7 +8386,7 @@ ins_bs(c, mode, inserted_space_p) ptr[len - 1] = NUL; } - (void)do_join(FALSE); + (void)do_join(2,FALSE); if (temp == NUL && gchar_cursor() != NUL) inc_cursor(); } diff --git a/src/ex_docmd.c b/src/ex_docmd.c index b060e63..1fba98e 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -8282,7 +8282,7 @@ ex_join(eap) } ++eap->line2; } - do_do_join(eap->line2 - eap->line1 + 1, !eap->forceit); + do_join(eap->line2 - eap->line1 + 1, !eap->forceit); beginline(BL_WHITE | BL_FIX); ex_may_print(eap); } diff --git a/src/normal.c b/src/normal.c index 0557833..a7124af 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1912,7 +1912,7 @@ do_pending_operator(cap, old_col, gui_yank) beep_flush(); else { - do_do_join(oap->line_count, oap->op_type == OP_JOIN); + do_join(oap->line_count, oap->op_type == OP_JOIN); auto_format(FALSE, TRUE); } break; @@ -9082,7 +9082,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); + do_join(cap->count0, cap->nchar == NUL); } } } diff --git a/src/ops.c b/src/ops.c index 6ab83fc..dc4f81d 100644 --- a/src/ops.c +++ b/src/ops.c @@ -1919,7 +1919,7 @@ op_delete(oap) ); curwin->w_cursor = curpos; /* restore curwin->w_cursor */ - (void)do_join(FALSE); + (void)do_join(2,FALSE); } } @@ -4104,9 +4104,13 @@ dis_msg(p, skip_esc) /* * join 'count' lines (minimal 2), including u_save() + * "redraw" is TRUE when the screen should be updated. + * Caller must have setup for undo. + * + * return FAIL for failure, OK otherwise */ int -do_do_join(count, insert_space) +do_join(count, insert_space) long count; int insert_space; { @@ -4261,20 +4265,6 @@ do_do_join(count, insert_space) return OK; } -/* - * Join two lines at the cursor position. - * "redraw" is TRUE when the screen should be updated. - * Caller must have setup for undo. - * - * return FAIL for failure, OK otherwise - */ - int -do_join(insert_space) - int insert_space; -{ - return do_do_join(2,insert_space); -} - #ifdef FEAT_COMMENTS /* * Return TRUE if the two comment leaders given are the same. "lnum" is @@ -4708,7 +4698,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) == FAIL) { beep_flush(); break; diff --git a/src/proto/ops.pro b/src/proto/ops.pro index 1e89509..fc1d471 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)); -int 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)); 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));
