v_p at last line causes error "E315: ml_get: invalid lnum"

Steps to reproduce:

  $ vim -u NONE
  ox<Esc>ylv$p
  E315: ml_get: invalid lnum: 2
  E322: line number out of range: 1 past the end

This behavior was introduced by 7.4.034.

There is related another problem.

  $ vim -u NONE
  ix<CR>y<Esc>v$d
  :echo getline(1, '$')
  ["x"]

  Expected: ["x", ""]

This behavior was introduce by 7.3.251.  "v$d" delete line.  I think this
is not
expected behavior at last line.

v_p execute 'd' and 'p'.

normal.c:nv_put()
9411             /* Now delete the selected text. */
9412             cap->cmdchar = 'd';
9413             cap->nchar = NUL;
9414             cap->oap->regname = NUL;
9415             nv_operator(cap);
9416             do_pending_operator(cap, 0, FALSE);
9417             empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
...
9450         do_put(cap->oap->regname, dir, cap->count1, flags);

For the above behavior 'd' delete last line.  And 'p' put register to the
line
already deleted.  Then it causes error.

I wrote patch for this problem.  Please check the attached patch.  It revert
7.3.251 and add the following line.  It passes test.  But I'm not sure it
doesn't cause another problem.

diff -r 18d84ed365a5 src/normal.c
--- a/src/normal.c Wed Apr 22 22:18:22 2015 +0200
+++ b/src/normal.c Fri May 22 14:26:03 2015 +0900
@@ -1547,8 +1547,10 @@
     }

     /* In Select mode, a linewise selection is operated upon like a
-     * characterwise selection. */
-    if (VIsual_select && VIsual_mode == 'V')
+     * characterwise selection.
+     * Special case: gH<Del> deletes the last line. */
+    if (VIsual_select && VIsual_mode == 'V'
+    && cap->oap->op_type != OP_DELETE)
     {
  if (lt(VIsual, curwin->w_cursor))
  {

-- 
Yukihiro Nakadaira - [email protected]

-- 
-- 
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 -r 18d84ed365a5 src/normal.c
--- a/src/normal.c      Wed Apr 22 22:18:22 2015 +0200
+++ b/src/normal.c      Fri May 22 14:26:03 2015 +0900
@@ -1547,8 +1547,10 @@
            }
 
            /* In Select mode, a linewise selection is operated upon like a
-            * characterwise selection. */
-           if (VIsual_select && VIsual_mode == 'V')
+            * characterwise selection.
+            * Special case: gH<Del> deletes the last line. */
+           if (VIsual_select && VIsual_mode == 'V'
+                                           && cap->oap->op_type != OP_DELETE)
            {
                if (lt(VIsual, curwin->w_cursor))
                {
@@ -1770,24 +1772,16 @@
                    oap->inclusive = FALSE;
                    /* Try to include the newline, unless it's an operator
                     * that works on lines only. */
-                   if (*p_sel != 'o' && !op_on_lines(oap->op_type))
+                   if (*p_sel != 'o'
+                           && !op_on_lines(oap->op_type)
+                           && oap->end.lnum < curbuf->b_ml.ml_line_count)
                    {
-                       if (oap->end.lnum < curbuf->b_ml.ml_line_count)
-                       {
-                           ++oap->end.lnum;
-                           oap->end.col = 0;
+                       ++oap->end.lnum;
+                       oap->end.col = 0;
 #ifdef FEAT_VIRTUALEDIT
-                           oap->end.coladd = 0;
-#endif
-                           ++oap->line_count;
-                       }
-                       else
-                       {
-                           /* Cannot move below the last line, make the op
-                            * inclusive to tell the operation to include the
-                            * line break. */
-                           oap->inclusive = TRUE;
-                       }
+                       oap->end.coladd = 0;
+#endif
+                       ++oap->line_count;
                    }
                }
            }
diff -r 18d84ed365a5 src/ops.c
--- a/src/ops.c Wed Apr 22 22:18:22 2015 +0200
+++ b/src/ops.c Fri May 22 14:26:03 2015 +0900
@@ -1959,60 +1959,31 @@
                    curwin->w_cursor.coladd = 0;
            }
 #endif
-           if (oap->op_type == OP_DELETE
-                   && oap->inclusive
-                   && oap->end.lnum == curbuf->b_ml.ml_line_count
-                   && n > (int)STRLEN(ml_get(oap->end.lnum)))
-           {
-               /* Special case: gH<Del> deletes the last line. */
-               del_lines(1L, FALSE);
-           }
-           else
-           {
-               (void)del_bytes((long)n, !virtual_op,
-                               oap->op_type == OP_DELETE && !oap->is_VIsual);
-           }
+           (void)del_bytes((long)n, !virtual_op,
+                           oap->op_type == OP_DELETE && !oap->is_VIsual);
        }
        else                            /* delete characters between lines */
        {
            pos_T   curpos;
-           int     delete_last_line;
 
            /* save deleted and changed lines for undo */
            if (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
                 (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL)
                return FAIL;
 
-           delete_last_line = (oap->end.lnum == curbuf->b_ml.ml_line_count);
            truncate_line(TRUE);        /* delete from cursor to end of line */
 
            curpos = curwin->w_cursor;  /* remember curwin->w_cursor */
            ++curwin->w_cursor.lnum;
            del_lines((long)(oap->line_count - 2), FALSE);
 
-           if (delete_last_line)
-               oap->end.lnum = curbuf->b_ml.ml_line_count;
-
+           /* delete from start of line until op_end */
            n = (oap->end.col + 1 - !oap->inclusive);
-           if (oap->inclusive && delete_last_line
-                   && n > (int)STRLEN(ml_get(oap->end.lnum)))
-           {
-               /* Special case: gH<Del> deletes the last line. */
-               del_lines(1L, FALSE);
-               curwin->w_cursor = curpos;      /* restore curwin->w_cursor */
-               if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
-                   curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
-           }
-           else
-           {
-               /* delete from start of line until op_end */
-               curwin->w_cursor.col = 0;
-               (void)del_bytes((long)n, !virtual_op,
-                               oap->op_type == OP_DELETE && !oap->is_VIsual);
-               curwin->w_cursor = curpos;      /* restore curwin->w_cursor */
-           }
-           if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
-               (void)do_join(2, FALSE, FALSE, FALSE, FALSE);
+           curwin->w_cursor.col = 0;
+           (void)del_bytes((long)n, !virtual_op,
+                           oap->op_type == OP_DELETE && !oap->is_VIsual);
+           curwin->w_cursor = curpos;  /* restore curwin->w_cursor */
+           (void)do_join(2, FALSE, FALSE, FALSE, FALSE);
        }
     }
 
diff -r 18d84ed365a5 src/testdir/test94.in
--- a/src/testdir/test94.in     Wed Apr 22 22:18:22 2015 +0200
+++ b/src/testdir/test94.in     Fri May 22 14:26:03 2015 +0900
@@ -64,6 +64,116 @@
 d:
:set ma | put = v:errmsg =~# '^E21' ? 'ok' : 'failed'
 dv:dV::set noma | let v:errmsg = ''
 d::set ma | put = v:errmsg =~# '^E21' ? 'failed' : 'ok'
+:
+:$put =''
+:$put ='characterwise visual mode: replace last line'
+:$put ='a'
+:let @" = 'x'
+:let v:errmsg = ''
+v$p
+:$put ='---'
+:$put ='v:errmsg='.v:errmsg
+:
+:$put =''
+:$put ='characterwise visual mode: delete middle line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkv$d
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise visual mode: delete middle two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkvj$d
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise visual mode: delete last line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+v$d
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise visual mode: delete last two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kvj$d
+:$put ='---'
+:
+:" Select mode maps
+:snoremap <lt>End> <End>
+:snoremap <lt>Down> <Down>
+:snoremap <lt>Del> <Del>
+:
+:$put =''
+:$put ='characterwise select mode: delete middle line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgh<End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise select mode: delete middle two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgh<Down><End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise select mode: delete last line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+gh<End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise select mode: delete last two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kgh<Down><End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete middle line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgH<Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete middle two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgH<Down><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete last line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+gH<Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete last two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kgH<Down><Del>
+:$put ='---'
 :/^start:/+2,$w! test.out
 :q!
 ENDTEST
diff -r 18d84ed365a5 src/testdir/test94.ok
--- a/src/testdir/test94.ok     Wed Apr 22 22:18:22 2015 +0200
+++ b/src/testdir/test94.ok     Fri May 22 14:26:03 2015 +0900
@@ -18,3 +18,66 @@
 zzz
 ok
 ok
+
+characterwise visual mode: replace last line
+x
+---
+v:errmsg=
+
+characterwise visual mode: delete middle line
+b
+c
+---
+
+characterwise visual mode: delete middle two line
+c
+---
+
+characterwise visual mode: delete last line
+a
+b
+
+---
+
+characterwise visual mode: delete last two line
+a
+
+---
+
+characterwise select mode: delete middle line
+b
+c
+---
+
+characterwise select mode: delete middle two line
+c
+---
+
+characterwise select mode: delete last line
+a
+b
+
+---
+
+characterwise select mode: delete last two line
+a
+
+---
+
+linewise select mode: delete middle line
+b
+c
+---
+
+linewise select mode: delete middle two line
+c
+---
+
+linewise select mode: delete last line
+a
+b
+---
+
+linewise select mode: delete last two line
+a
+---

Raspunde prin e-mail lui