Hi Ingo!
On Di, 26 Mai 2015, Ingo Karkat wrote:
> On 24-May-2015 13:15, Christian Brabandt wrote:
> > On Mo, 18 Mai 2015, Ingo Karkat wrote:
> >
> >> Hello Vim developers,
> >>
> >> appending to the end of a visual blockwise selection can be done with
> >> the A command. I just noticed that this doesn't work reliably any more
> >> when
> >> - lines are wrapped and the cursor is in a following screen line AND
> >> - :set linebreak
> >> This happens with "real" blocks as well as a corner case single-line
> >> blockwise selection.
> >> To reproduce:
> >>
> >> vim -N -u NONE
> >> :set linebreak
> >> :normal! 40afoo bar
> >> :normal! BB^VeAX
> >> Appending should be after the selected word ("barfooX"), but it occurs
> >> at the beginning instead ("Xbarfoo").
> >>
> >> I've bisected this down to the following patch:
> >>
> >> ,----[ bad change ]----
> >> | 7.4.576 redrawing problem with 'relativenumber' and 'linebreak'
> >> `----
> >>
> >> Attached is a test that verifies the correct behavior.
> >>
> >> I can reproduce this on Vim version 7.4.716 on Windows/x64 as well as on
> >> latest Vim 7.4.729 on Linux/x64.
> >>
> >
> > I can reproduce it. Thanks for the feedback. Looks like one needs to
> > recalculate the virtual column numbers after resetting the linebreak
> > option. This also happens for the OP_REPLACE part. Here is a patch,
> > including your testcase.
>
> Thank you Christian! Unfortunately, there's still an off-by-one error
> with :set selection=exclusive; the cursor is positioned one character
> left of the selection's end (resulting in "barfoXo" in the test).
>
> I hope that is easy to fix; it might also be worthwhile to test that
> variation, too.
Updated patch and test attached.
Best,
Christian
--
Mit Adleraugen sehen wir die Fehler anderer, mit Maulwurfaugen unsere
eigenen.
-- Franz von Sales
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/src/normal.c b/src/normal.c
--- a/src/normal.c
+++ b/src/normal.c
@@ -174,6 +174,7 @@ static void nv_drop __ARGS((cmdarg_T *ca
#ifdef FEAT_AUTOCMD
static void nv_cursorhold __ARGS((cmdarg_T *cap));
#endif
+static void get_op_vcol __ARGS((oparg_T *oap, colnr_T col, int adjust_sel));
static char *e_noident = N_("E349: No identifier under cursor");
@@ -1629,61 +1630,7 @@ do_pending_operator(cap, old_col, gui_ya
if (VIsual_active || redo_VIsual_busy)
{
- if (VIsual_mode == Ctrl_V) /* block mode */
- {
- colnr_T start, end;
-
- oap->block_mode = TRUE;
-
- getvvcol(curwin, &(oap->start),
- &oap->start_vcol, NULL, &oap->end_vcol);
- if (!redo_VIsual_busy)
- {
- getvvcol(curwin, &(oap->end), &start, NULL, &end);
-
- if (start < oap->start_vcol)
- oap->start_vcol = start;
- if (end > oap->end_vcol)
- {
- if (*p_sel == 'e' && start >= 1
- && start - 1 >= oap->end_vcol)
- oap->end_vcol = start - 1;
- else
- oap->end_vcol = end;
- }
- }
-
- /* if '$' was used, get oap->end_vcol from longest line */
- if (curwin->w_curswant == MAXCOL)
- {
- curwin->w_cursor.col = MAXCOL;
- oap->end_vcol = 0;
- for (curwin->w_cursor.lnum = oap->start.lnum;
- curwin->w_cursor.lnum <= oap->end.lnum;
- ++curwin->w_cursor.lnum)
- {
- getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
- if (end > oap->end_vcol)
- oap->end_vcol = end;
- }
- }
- else if (redo_VIsual_busy)
- oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
- /*
- * Correct oap->end.col and oap->start.col to be the
- * upper-left and lower-right corner of the block area.
- *
- * (Actually, this does convert column positions into character
- * positions)
- */
- curwin->w_cursor.lnum = oap->end.lnum;
- coladvance(oap->end_vcol);
- oap->end = curwin->w_cursor;
-
- curwin->w_cursor = oap->start;
- coladvance(oap->start_vcol);
- oap->start = curwin->w_cursor;
- }
+ get_op_vcol(oap, redo_VIsual_vcol, TRUE);
if (!redo_VIsual_busy && !gui_yank)
{
@@ -2088,7 +2035,11 @@ do_pending_operator(cap, old_col, gui_ya
#ifdef FEAT_LINEBREAK
/* Restore linebreak, so that when the user edits it looks as
* before. */
- curwin->w_p_lbr = lbr_saved;
+ if (curwin->w_p_lbr != lbr_saved)
+ {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, FALSE);
+ }
#endif
op_insert(oap, cap->count1);
#ifdef FEAT_LINEBREAK
@@ -2123,7 +2074,11 @@ do_pending_operator(cap, old_col, gui_ya
#ifdef FEAT_LINEBREAK
/* Restore linebreak, so that when the user edits it looks as
* before. */
- curwin->w_p_lbr = lbr_saved;
+ if (curwin->w_p_lbr != lbr_saved)
+ {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, FALSE);
+ }
#endif
op_replace(oap, cap->nchar);
}
@@ -9543,3 +9498,70 @@ nv_cursorhold(cap)
cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */
}
#endif
+
+/*
+ * calculate start/end virtual columns for operating in block mode
+ */
+ static void
+get_op_vcol(oap, redo_VIsual_vcol, adjust_select)
+ oparg_T *oap;
+ colnr_T redo_VIsual_vcol;
+ int adjust_select; /* adjust position for 'selectmode' */
+{
+ colnr_T start, end;
+
+ if (VIsual_mode != Ctrl_V)
+ return;
+
+ oap->block_mode = TRUE;
+
+#ifdef FEAT_MBYTE
+ /* prevent from moving onto a trail byte */
+ if (has_mbyte)
+ mb_adjustpos(curwin->w_buffer, &oap->end);
+#endif
+
+ getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
+ getvvcol(curwin, &(oap->end), &start, NULL, &end);
+
+ if (start < oap->start_vcol)
+ oap->start_vcol = start;
+ if (end > oap->end_vcol)
+ {
+ if (adjust_select && *p_sel == 'e' && start >= 1
+ && start - 1 >= oap->end_vcol)
+ oap->end_vcol = start - 1;
+ else
+ oap->end_vcol = end;
+ }
+ /* if '$' was used, get oap->end_vcol from longest line */
+ if (curwin->w_curswant == MAXCOL)
+ {
+ curwin->w_cursor.col = MAXCOL;
+ oap->end_vcol = 0;
+ for (curwin->w_cursor.lnum = oap->start.lnum;
+ curwin->w_cursor.lnum <= oap->end.lnum;
+ ++curwin->w_cursor.lnum)
+ {
+ getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
+ if (end > oap->end_vcol)
+ oap->end_vcol = end;
+ }
+ }
+ else if (redo_VIsual_busy)
+ oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
+ /*
+ * Correct oap->end.col and oap->start.col to be the
+ * upper-left and lower-right corner of the block area.
+ *
+ * (Actually, this does convert column positions into character
+ * positions)
+ */
+ curwin->w_cursor.lnum = oap->end.lnum;
+ coladvance(oap->end_vcol);
+ oap->end = curwin->w_cursor;
+
+ curwin->w_cursor = oap->start;
+ coladvance(oap->start_vcol);
+ oap->start = curwin->w_cursor;
+}
diff --git a/src/testdir/test_listlbr.in b/src/testdir/test_listlbr.in
--- a/src/testdir/test_listlbr.in
+++ b/src/testdir/test_listlbr.in
@@ -59,11 +59,17 @@ STARTTEST
:set cpo&vim linebreak
:let g:test ="Test 6: set linebreak with visual block mode"
:let line="REMOVE: this not"
+:$put =g:test
:$put =line
:let line="REMOVE: aaaaaaaaaaaaa"
:$put =line
:1/^REMOVE:
0jf x:$put
+:set cpo&vim linebreak
+:let g:test ="Test 7: set linebreak with visual block mode and v_b_A"
+:$put =g:test
+Golong line: 40afoobar aTARGET at end
+:exe "norm! $3B\<C-v>eAx\<Esc>"
:%w! test.out
:qa!
ENDTEST
diff --git a/src/testdir/test_listlbr.ok b/src/testdir/test_listlbr.ok
--- a/src/testdir/test_listlbr.ok
+++ b/src/testdir/test_listlbr.ok
@@ -32,7 +32,10 @@ Sabbbbbb bla
~
~
~
+Test 6: set linebreak with visual block mode
this not
aaaaaaaaaaaaa
REMOVE:
REMOVE:
+Test 7: set linebreak with visual block mode and v_b_A
+long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETx at end
diff --git a/src/testdir/test_listlbr_utf8.in b/src/testdir/test_listlbr_utf8.in
--- a/src/testdir/test_listlbr_utf8.in
+++ b/src/testdir/test_listlbr_utf8.in
@@ -91,6 +91,11 @@ GGlGGlGGlGGlGGlGGlGGlGGlGGlGGl
:else
: call append('$', "Not all attributes are different")
:endif
+:set cpo&vim linebreak selection=exclusive
+:let g:test ="Test 8: set linebreak with visual block mode and v_b_A and selection=exclusive and multibyte char"
+:$put =g:test
+Golong line: 40afoobar aTARGETÃ at end
+:exe "norm! $3B\<C-v>eAx\<Esc>"
:%w! test.out
:qa!
ENDTEST
diff --git a/src/testdir/test_listlbr_utf8.ok b/src/testdir/test_listlbr_utf8.ok
--- a/src/testdir/test_listlbr_utf8.ok
+++ b/src/testdir/test_listlbr_utf8.ok
@@ -44,3 +44,5 @@ Test 6: Screenattributes for comment
/* and some more */
ScreenAttributes for test6:
Attribut 0 and 1 and 3 and 5 are different!
+Test 8: set linebreak with visual block mode and v_b_A and selection=exclusive and multibyte char
+long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETÃx at end