]> granicus.if.org Git - vim/commitdiff
patch 8.1.1275: cannot navigate to errors before/after the cursor v8.1.1275
authorBram Moolenaar <Bram@vim.org>
Sun, 5 May 2019 13:02:30 +0000 (15:02 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 5 May 2019 13:02:30 +0000 (15:02 +0200)
Problem:    Cannot navigate to errors before/after the cursor.
Solution:   Add the :cbefore and :cafter commands. (Yegappan Lakshmanan,
            closes #4340)

runtime/doc/index.txt
runtime/doc/quickfix.txt
src/ex_cmdidxs.h
src/ex_cmds.h
src/quickfix.c
src/testdir/test_quickfix.vim
src/version.c

index 7192905561329d259a415c5bb83cce825d4aa939..9b5663e1e49758164265e68435ad3d427431c487 100644 (file)
@@ -1192,9 +1192,11 @@ tag              command         action ~
 |:caddbuffer|  :cad[dbuffer]   add errors from buffer
 |:caddexpr|    :cadde[xpr]     add errors from expr
 |:caddfile|    :caddf[ile]     add error message to current quickfix list
+|:cafter|      :caf[ter]       go to error after current cursor
 |:call|                :cal[l]         call a function
 |:catch|       :cat[ch]        part of a :try command
-|:cbelow|      :cbe[low]       got to error below current line
+|:cbefore|     :cbef[ore]      go to error before current cursor
+|:cbelow|      :cbel[ow]       go to error below current line
 |:cbottom|     :cbo[ttom]      scroll to the bottom of the quickfix window
 |:cbuffer|     :cb[uffer]      parse error messages and jump to first error
 |:cc|          :cc             go to specific error
@@ -1356,10 +1358,12 @@ tag             command         action ~
 |:laddexpr|    :lad[dexpr]     add locations from expr
 |:laddbuffer|  :laddb[uffer]   add locations from buffer
 |:laddfile|    :laddf[ile]     add locations to current location list
+|:lafter|      :laf[ter]       go to location after current cursor
 |:last|                :la[st]         go to the last file in the argument list
 |:language|    :lan[guage]     set the language (locale)
 |:later|       :lat[er]        go to newer change, redo
-|:lbelow|      :lbe[low]       go to location below current line
+|:lbefore|     :lbef[ore]      go to location before current cursor
+|:lbelow|      :lbel[ow]       go to location below current line
 |:lbottom|     :lbo[ttom]      scroll to the bottom of the location window
 |:lbuffer|     :lb[uffer]      parse locations and jump to first location
 |:lcd|         :lc[d]          change directory locally
index 1f28f9bf7e4b297c0dcd7550b47a9803c8d45681..ef084fac57be23c313c70e6d2ad325b9301c34ea 100644 (file)
@@ -152,8 +152,36 @@ processing a quickfix or location list command, it will be aborted.
                        exceeds the number of entries below the current line,
                        then the last error in the file is selected.
 
-                                                       *:lbe* *:lbelow*
-:[count]lbe[low]       Same as ":cbelow", except the location list for the
+                                                       *:lbel* *:lbelow*
+:[count]lbel[ow]       Same as ":cbelow", except the location list for the
+                       current window is used instead of the quickfix list.
+
+                                                       *:cbe* *:cbefore*
+:[count]cbe[fore]      Go to the [count] error before the current cursor
+                       position in the current buffer.  If [count] is
+                       omitted, then 1 is used.  If there are no errors, then
+                       an error message is displayed.  Assumes that the
+                       entries in a quickfix list are sorted by their buffer,
+                       line and column numbers.  If [count] exceeds the
+                       number of entries before the current position, then
+                       the first error in the file is selected.
+
+                                                       *:lbef* *:lbefore*
+:[count]lbef[ore]      Same as ":cbefore", except the location list for the
+                       current window is used instead of the quickfix list.
+
+                                                       *:caf* *:cafter*
+:[count]caf[ter]       Go to the [count] error after the current cursor
+                       position in the current buffer.  If [count] is
+                       omitted, then 1 is used.  If there are no errors, then
+                       an error message is displayed.  Assumes that the
+                       entries in a quickfix list are sorted by their buffer,
+                       line and column numbers.  If [count] exceeds the
+                       number of entries after the current position, then
+                       the last error in the file is selected.
+
+                                                       *:laf* *:lafter*
+:[count]laf[ter]       Same as ":cafter", except the location list for the
                        current window is used instead of the quickfix list.
 
                                                        *:cnf* *:cnfile*
index c63aa46f5a7bdf9eb77de64dadc72b8b1e73c4e0..6b96c6cfa1fe028dbabe870515dfc2214b9ba5a4 100644 (file)
@@ -8,29 +8,29 @@ static const unsigned short cmdidxs1[26] =
   /* a */ 0,
   /* b */ 19,
   /* c */ 42,
-  /* d */ 105,
-  /* e */ 127,
-  /* f */ 147,
-  /* g */ 163,
-  /* h */ 169,
-  /* i */ 178,
-  /* j */ 196,
-  /* k */ 198,
-  /* l */ 203,
-  /* m */ 263,
-  /* n */ 281,
-  /* o */ 301,
-  /* p */ 313,
-  /* q */ 352,
-  /* r */ 355,
-  /* s */ 375,
-  /* t */ 443,
-  /* u */ 488,
-  /* v */ 499,
-  /* w */ 517,
-  /* x */ 531,
-  /* y */ 540,
-  /* z */ 541
+  /* d */ 107,
+  /* e */ 129,
+  /* f */ 149,
+  /* g */ 165,
+  /* h */ 171,
+  /* i */ 180,
+  /* j */ 198,
+  /* k */ 200,
+  /* l */ 205,
+  /* m */ 267,
+  /* n */ 285,
+  /* o */ 305,
+  /* p */ 317,
+  /* q */ 356,
+  /* r */ 359,
+  /* s */ 379,
+  /* t */ 447,
+  /* u */ 492,
+  /* v */ 503,
+  /* w */ 521,
+  /* x */ 535,
+  /* y */ 544,
+  /* z */ 545
 };
 
 /*
@@ -43,7 +43,7 @@ static const unsigned char cmdidxs2[26][26] =
 { /*         a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t   u   v   w   x   y   z */
   /* a */ {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  5,  6,  0,  0,  0,  7, 15,  0, 16,  0,  0,  0,  0,  0 },
   /* b */ {  2,  0,  0,  4,  5,  7,  0,  0,  0,  0,  0,  8,  9, 10, 11, 12,  0, 13,  0,  0,  0,  0, 22,  0,  0,  0 },
-  /* c */ {  3, 11, 14, 16, 18, 20, 23,  0,  0,  0,  0, 31, 35, 38, 44, 53, 55, 56, 57,  0, 59,  0, 62,  0,  0,  0 },
+  /* c */ {  3, 12, 16, 18, 20, 22, 25,  0,  0,  0,  0, 33, 37, 40, 46, 55, 57, 58, 59,  0, 61,  0, 64,  0,  0,  0 },
   /* d */ {  0,  0,  0,  0,  0,  0,  0,  0,  6, 15,  0, 16,  0,  0, 17,  0,  0, 19, 20,  0,  0,  0,  0,  0,  0,  0 },
   /* e */ {  1,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  7,  9, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0, 16,  0,  0 },
   /* f */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0 },
@@ -52,7 +52,7 @@ static const unsigned char cmdidxs2[26][26] =
   /* i */ {  1,  0,  0,  0,  0,  3,  0,  0,  0,  4,  0,  5,  6,  0,  0,  0,  0,  0, 13,  0, 15,  0,  0,  0,  0,  0 },
   /* j */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0 },
   /* k */ {  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
-  /* l */ {  3, 10, 13, 17, 18, 22, 25, 30,  0,  0,  0, 32, 35, 38, 42, 48,  0, 50, 59, 51, 52, 56, 58,  0,  0,  0 },
+  /* l */ {  3, 11, 15, 19, 20, 24, 27, 32,  0,  0,  0, 34, 37, 40, 44, 50,  0, 52, 61, 53, 54, 58, 60,  0,  0,  0 },
   /* m */ {  1,  0,  0,  0,  7,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 16 },
   /* n */ {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  8, 10,  0,  0,  0,  0,  0, 17,  0,  0,  0,  0,  0 },
   /* o */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  5,  0,  0,  0,  0,  0,  0,  9,  0, 11,  0,  0,  0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
   /* z */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
 };
 
-static const int command_count = 554;
+static const int command_count = 558;
index 58aa8c313fc34d2080613d24e5f4a40f1ff403f8..9e420b3fd16e01e608173280e775b52b05257362 100644 (file)
@@ -266,6 +266,9 @@ EX(CMD_caddexpr,    "caddexpr",     ex_cexpr,
 EX(CMD_caddfile,       "caddfile",     ex_cfile,
                        TRLBAR|FILE1,
                        ADDR_NONE),
+EX(CMD_cafter,         "cafter",       ex_cbelow,
+                       RANGE|COUNT|TRLBAR,
+                       ADDR_UNSIGNED),
 EX(CMD_call,           "call",         ex_call,
                        RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
                        ADDR_LINES),
@@ -275,6 +278,9 @@ EX(CMD_catch,               "catch",        ex_catch,
 EX(CMD_cbuffer,                "cbuffer",      ex_cbuffer,
                        BANG|RANGE|WORD1|TRLBAR,
                        ADDR_OTHER),
+EX(CMD_cbefore,                "cbefore",      ex_cbelow,
+                       RANGE|COUNT|TRLBAR,
+                       ADDR_UNSIGNED),
 EX(CMD_cbelow,         "cbelow",       ex_cbelow,
                        RANGE|COUNT|TRLBAR,
                        ADDR_UNSIGNED),
@@ -749,12 +755,18 @@ EX(CMD_laddbuffer,        "laddbuffer",   ex_cbuffer,
 EX(CMD_laddfile,       "laddfile",     ex_cfile,
                        TRLBAR|FILE1,
                        ADDR_NONE),
+EX(CMD_lafter,         "lafter",       ex_cbelow,
+                       RANGE|COUNT|TRLBAR,
+                       ADDR_UNSIGNED),
 EX(CMD_later,          "later",        ex_later,
                        TRLBAR|EXTRA|NOSPC|CMDWIN,
                        ADDR_NONE),
 EX(CMD_lbuffer,                "lbuffer",      ex_cbuffer,
                        BANG|RANGE|WORD1|TRLBAR,
                        ADDR_OTHER),
+EX(CMD_lbefore,                "lbefore",      ex_cbelow,
+                       RANGE|COUNT|TRLBAR,
+                       ADDR_UNSIGNED),
 EX(CMD_lbelow,         "lbelow",       ex_cbelow,
                        RANGE|COUNT|TRLBAR,
                        ADDR_UNSIGNED),
index c11436a0069e7edb4f49f4fa08eae29630caa7fd..b4497ae754821110303f84d6229ffb5b3ad0dcd6 100644 (file)
@@ -5128,36 +5128,100 @@ qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
 }
 
 /*
- * Find the first quickfix entry below line 'lnum' in buffer 'bnr'.
+ * Returns TRUE if the specified quickfix entry is
+ *   after the given line (linewise is TRUE)
+ *   or after the line and column.
+ */
+    static int
+qf_entry_after_pos(qfline_T *qfp, pos_T *pos, int linewise)
+{
+    if (linewise)
+       return qfp->qf_lnum > pos->lnum;
+    else
+       return (qfp->qf_lnum > pos->lnum ||
+               (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col));
+}
+
+/*
+ * Returns TRUE if the specified quickfix entry is
+ *   before the given line (linewise is TRUE)
+ *   or before the line and column.
+ */
+    static int
+qf_entry_before_pos(qfline_T *qfp, pos_T *pos, int linewise)
+{
+    if (linewise)
+       return qfp->qf_lnum < pos->lnum;
+    else
+       return (qfp->qf_lnum < pos->lnum ||
+               (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col));
+}
+
+/*
+ * Returns TRUE if the specified quickfix entry is
+ *   on or after the given line (linewise is TRUE)
+ *   or on or after the line and column.
+ */
+    static int
+qf_entry_on_or_after_pos(qfline_T *qfp, pos_T *pos, int linewise)
+{
+    if (linewise)
+       return qfp->qf_lnum >= pos->lnum;
+    else
+       return (qfp->qf_lnum > pos->lnum ||
+               (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col));
+}
+
+/*
+ * Returns TRUE if the specified quickfix entry is
+ *   on or before the given line (linewise is TRUE)
+ *   or on or before the line and column.
+ */
+    static int
+qf_entry_on_or_before_pos(qfline_T *qfp, pos_T *pos, int linewise)
+{
+    if (linewise)
+       return qfp->qf_lnum <= pos->lnum;
+    else
+       return (qfp->qf_lnum < pos->lnum ||
+               (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col));
+}
+
+/*
+ * Find the first quickfix entry after position 'pos' in buffer 'bnr'.
+ * If 'linewise' is TRUE, returns the entry after the specified line and treats
+ * multiple entries on a single line as one. Otherwise returns the entry after
+ * the specified line and column.
  * 'qfp' points to the very first entry in the buffer and 'errornr' is the
  * index of the very first entry in the quickfix list.
- * Returns NULL if an entry is not found after 'lnum'.
+ * Returns NULL if an entry is not found after 'pos'.
  */
     static qfline_T *
-qf_find_entry_on_next_line(
+qf_find_entry_after_pos(
        int             bnr,
-       linenr_T        lnum,
+       pos_T           *pos,
+       int             linewise,
        qfline_T        *qfp,
        int             *errornr)
 {
-    if (qfp->qf_lnum > lnum)
-       // First entry is after line 'lnum'
+    if (qf_entry_after_pos(qfp, pos, linewise))
+       // First entry is after postion 'pos'
        return qfp;
 
-    // Find the entry just before or at the line 'lnum'
+    // Find the entry just before or at the position 'pos'
     while (qfp->qf_next != NULL
            && qfp->qf_next->qf_fnum == bnr
-           && qfp->qf_next->qf_lnum <= lnum)
+           && qf_entry_on_or_before_pos(qfp->qf_next, pos, linewise))
     {
        qfp = qfp->qf_next;
        ++*errornr;
     }
 
     if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr)
-       // No entries found after 'lnum'
+       // No entries found after position 'pos'
        return NULL;
 
-    // Use the entry just after line 'lnum'
+    // Use the entry just after position 'pos'
     qfp = qfp->qf_next;
     ++*errornr;
 
@@ -5165,46 +5229,52 @@ qf_find_entry_on_next_line(
 }
 
 /*
- * Find the first quickfix entry before line 'lnum' in buffer 'bnr'.
+ * Find the first quickfix entry before position 'pos' in buffer 'bnr'.
+ * If 'linewise' is TRUE, returns the entry before the specified line and
+ * treats multiple entries on a single line as one. Otherwise returns the entry
+ * before the specified line and column.
  * 'qfp' points to the very first entry in the buffer and 'errornr' is the
  * index of the very first entry in the quickfix list.
- * Returns NULL if an entry is not found before 'lnum'.
+ * Returns NULL if an entry is not found before 'pos'.
  */
     static qfline_T *
-qf_find_entry_on_prev_line(
+qf_find_entry_before_pos(
        int             bnr,
-       linenr_T        lnum,
+       pos_T           *pos,
+       int             linewise,
        qfline_T        *qfp,
        int             *errornr)
 {
-    // Find the entry just before the line 'lnum'
+    // Find the entry just before the position 'pos'
     while (qfp->qf_next != NULL
            && qfp->qf_next->qf_fnum == bnr
-           && qfp->qf_next->qf_lnum < lnum)
+           && qf_entry_before_pos(qfp->qf_next, pos, linewise))
     {
        qfp = qfp->qf_next;
        ++*errornr;
     }
 
-    if (qfp->qf_lnum >= lnum)  // entry is after 'lnum'
+    if (qf_entry_on_or_after_pos(qfp, pos, linewise))
        return NULL;
 
-    // If multiple entries are on the same line, then use the first entry
-    qfp = qf_find_first_entry_on_line(qfp, errornr);
+    if (linewise)
+       // If multiple entries are on the same line, then use the first entry
+       qfp = qf_find_first_entry_on_line(qfp, errornr);
 
     return qfp;
 }
 
 /*
- * Find a quickfix entry in 'qfl' closest to line 'lnum' in buffer 'bnr' in
+ * Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in
  * the direction 'dir'.
  */
     static qfline_T *
 qf_find_closest_entry(
        qf_list_T       *qfl,
        int             bnr,
-       linenr_T        lnum,
+       pos_T           *pos,
        int             dir,
+       int             linewise,
        int             *errornr)
 {
     qfline_T   *qfp;
@@ -5217,35 +5287,40 @@ qf_find_closest_entry(
        return NULL;            // no entry in this file
 
     if (dir == FORWARD)
-       qfp = qf_find_entry_on_next_line(bnr, lnum, qfp, errornr);
+       qfp = qf_find_entry_after_pos(bnr, pos, linewise, qfp, errornr);
     else
-       qfp = qf_find_entry_on_prev_line(bnr, lnum, qfp, errornr);
+       qfp = qf_find_entry_before_pos(bnr, pos, linewise, qfp, errornr);
 
     return qfp;
 }
 
 /*
- * Get the nth quickfix entry below the specified entry treating multiple
- * entries on a single line as one. Searches forward in the list.
+ * Get the nth quickfix entry below the specified entry.  Searches forward in
+ * the list. If linewise is TRUE, then treat multiple entries on a single line
+ * as one.
  */
     static qfline_T *
-qf_get_nth_below_entry(qfline_T *entry, int *errornr, int n)
+qf_get_nth_below_entry(qfline_T *entry, int n, int linewise, int *errornr)
 {
     while (n-- > 0 && !got_int)
     {
        qfline_T        *first_entry = entry;
        int             first_errornr = *errornr;
 
-       // Treat all the entries on the same line in this file as one
-       entry = qf_find_last_entry_on_line(entry, errornr);
+       if (linewise)
+           // Treat all the entries on the same line in this file as one
+           entry = qf_find_last_entry_on_line(entry, errornr);
 
        if (entry->qf_next == NULL
                || entry->qf_next->qf_fnum != entry->qf_fnum)
        {
-           // If multiple entries are on the same line, then use the first
-           // entry
-           entry = first_entry;
-           *errornr = first_errornr;
+           if (linewise)
+           {
+               // If multiple entries are on the same line, then use the first
+               // entry
+               entry = first_entry;
+               *errornr = first_errornr;
+           }
            break;
        }
 
@@ -5257,11 +5332,12 @@ qf_get_nth_below_entry(qfline_T *entry, int *errornr, int n)
 }
 
 /*
- * Get the nth quickfix entry above the specified entry treating multiple
- * entries on a single line as one. Searches backwards in the list.
+ * Get the nth quickfix entry above the specified entry.  Searches backwards in
+ * the list. If linewise is TRUE, then treat multiple entries on a single line
+ * as one.
  */
     static qfline_T *
-qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n)
+qf_get_nth_above_entry(qfline_T *entry, int n, int linewise, int *errornr)
 {
     while (n-- > 0 && !got_int)
     {
@@ -5273,25 +5349,32 @@ qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n)
        --*errornr;
 
        // If multiple entries are on the same line, then use the first entry
-       entry = qf_find_first_entry_on_line(entry, errornr);
+       if (linewise)
+           entry = qf_find_first_entry_on_line(entry, errornr);
     }
 
     return entry;
 }
 
 /*
- * Find the n'th quickfix entry adjacent to line 'lnum' in buffer 'bnr' in the
- * specified direction.
- * Returns the error number in the quickfix list or 0 if an entry is not found.
+ * Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in
+ * the specified direction.  Returns the error number in the quickfix list or 0
+ * if an entry is not found.
  */
     static int
-qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, linenr_T lnum, int n, int dir)
+qf_find_nth_adj_entry(
+       qf_list_T       *qfl,
+       int             bnr,
+       pos_T           *pos,
+       int             n,
+       int             dir,
+       int             linewise)
 {
     qfline_T   *adj_entry;
     int                errornr;
 
-    // Find an entry closest to the specified line
-    adj_entry = qf_find_closest_entry(qfl, bnr, lnum, dir, &errornr);
+    // Find an entry closest to the specified position
+    adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, linewise, &errornr);
     if (adj_entry == NULL)
        return 0;
 
@@ -5299,17 +5382,21 @@ qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, linenr_T lnum, int n, int dir)
     {
        // Go to the n'th entry in the current buffer
        if (dir == FORWARD)
-           adj_entry = qf_get_nth_below_entry(adj_entry, &errornr, n);
+           adj_entry = qf_get_nth_below_entry(adj_entry, n, linewise,
+                   &errornr);
        else
-           adj_entry = qf_get_nth_above_entry(adj_entry, &errornr, n);
+           adj_entry = qf_get_nth_above_entry(adj_entry, n, linewise,
+                   &errornr);
     }
 
     return errornr;
 }
 
 /*
- * Jump to a quickfix entry in the current file nearest to the current line.
- * ":cabove", ":cbelow", ":labove" and ":lbelow" commands
+ * Jump to a quickfix entry in the current file nearest to the current line or
+ * current line/col.
+ * ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore",
+ * ":lafter" and ":lbefore" commands
  */
     void
 ex_cbelow(exarg_T *eap)
@@ -5319,6 +5406,7 @@ ex_cbelow(exarg_T *eap)
     int                dir;
     int                buf_has_flag;
     int                errornr = 0;
+    pos_T      pos;
 
     if (eap->addr_count > 0 && eap->line2 <= 0)
     {
@@ -5327,7 +5415,8 @@ ex_cbelow(exarg_T *eap)
     }
 
     // Check whether the current buffer has any quickfix entries
-    if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow)
+    if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow
+           || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter)
        buf_has_flag = BUF_HAS_QF_ENTRY;
     else
        buf_has_flag = BUF_HAS_LL_ENTRY;
@@ -5348,13 +5437,25 @@ ex_cbelow(exarg_T *eap)
        return;
     }
 
-    if (eap->cmdidx == CMD_cbelow || eap->cmdidx == CMD_lbelow)
+    if (eap->cmdidx == CMD_cbelow
+           || eap->cmdidx == CMD_lbelow
+           || eap->cmdidx == CMD_cafter
+           || eap->cmdidx == CMD_lafter)
+       // Forward motion commands
        dir = FORWARD;
     else
        dir = BACKWARD;
 
-    errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, curwin->w_cursor.lnum,
-           eap->addr_count > 0 ? eap->line2 : 0, dir);
+    pos = curwin->w_cursor;
+    // A quickfix entry column number is 1 based whereas cursor column
+    // number is 0 based. Adjust the column number.
+    pos.col++;
+    errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, &pos,
+                               eap->addr_count > 0 ? eap->line2 : 0, dir,
+                               eap->cmdidx == CMD_cbelow
+                                       || eap->cmdidx == CMD_lbelow
+                                       || eap->cmdidx == CMD_cabove
+                                       || eap->cmdidx == CMD_labove);
 
     if (errornr > 0)
        qf_jump(qi, 0, errornr, FALSE);
index 092853c5005600277d6336b0f8270849de93414e..ae3aec5222340e26ebccc5edb25eacaf761da1d4 100644 (file)
@@ -39,6 +39,8 @@ func s:setup_commands(cchar)
     command! -nargs=0 -count Xcc <count>cc
     command! -count=1 -nargs=0 Xbelow <mods><count>cbelow
     command! -count=1 -nargs=0 Xabove <mods><count>cabove
+    command! -count=1 -nargs=0 Xbefore <mods><count>cbefore
+    command! -count=1 -nargs=0 Xafter <mods><count>cafter
     let g:Xgetlist = function('getqflist')
     let g:Xsetlist = function('setqflist')
     call setqflist([], 'f')
@@ -74,6 +76,8 @@ func s:setup_commands(cchar)
     command! -nargs=0 -count Xcc <count>ll
     command! -count=1 -nargs=0 Xbelow <mods><count>lbelow
     command! -count=1 -nargs=0 Xabove <mods><count>labove
+    command! -count=1 -nargs=0 Xbefore <mods><count>lbefore
+    command! -count=1 -nargs=0 Xafter <mods><count>lafter
     let g:Xgetlist = function('getloclist', [0])
     let g:Xsetlist = function('setloclist', [0])
     call setloclist(0, [], 'f')
@@ -4041,17 +4045,22 @@ func Test_empty_qfbuf()
 endfunc
 
 " Test for the :cbelow, :cabove, :lbelow and :labove commands.
+" And for the :cafter, :cbefore, :lafter and :lbefore commands.
 func Xtest_below(cchar)
   call s:setup_commands(a:cchar)
 
   " No quickfix/location list
   call assert_fails('Xbelow', 'E42:')
   call assert_fails('Xabove', 'E42:')
+  call assert_fails('Xbefore', 'E42:')
+  call assert_fails('Xafter', 'E42:')
 
   " Empty quickfix/location list
   call g:Xsetlist([])
   call assert_fails('Xbelow', 'E42:')
   call assert_fails('Xabove', 'E42:')
+  call assert_fails('Xbefore', 'E42:')
+  call assert_fails('Xafter', 'E42:')
 
   call s:create_test_file('X1')
   call s:create_test_file('X2')
@@ -4065,39 +4074,74 @@ func Xtest_below(cchar)
   call assert_fails('Xabove', 'E42:')
   call assert_fails('3Xbelow', 'E42:')
   call assert_fails('4Xabove', 'E42:')
+  call assert_fails('Xbefore', 'E42:')
+  call assert_fails('Xafter', 'E42:')
+  call assert_fails('3Xbefore', 'E42:')
+  call assert_fails('4Xafter', 'E42:')
 
   " Test the commands with various arguments
-  Xexpr ["X1:5:L5", "X2:5:L5", "X2:10:L10", "X2:15:L15", "X3:3:L3"]
+  Xexpr ["X1:5:3:L5", "X2:5:2:L5", "X2:10:3:L10", "X2:15:4:L15", "X3:3:5:L3"]
   edit +7 X2
   Xabove
   call assert_equal(['X2', 5], [bufname(''), line('.')])
   call assert_fails('Xabove', 'E553:')
+  normal 7G
+  Xbefore
+  call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
+  call assert_fails('Xbefore', 'E553:')
+
   normal 2j
   Xbelow
   call assert_equal(['X2', 10], [bufname(''), line('.')])
+  normal 7G
+  Xafter
+  call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
+
   " Last error in this file
   Xbelow 99
   call assert_equal(['X2', 15], [bufname(''), line('.')])
   call assert_fails('Xbelow', 'E553:')
+  normal gg
+  Xafter 99
+  call assert_equal(['X2', 15, 4], [bufname(''), line('.'), col('.')])
+  call assert_fails('Xafter', 'E553:')
+
   " First error in this file
   Xabove 99
   call assert_equal(['X2', 5], [bufname(''), line('.')])
   call assert_fails('Xabove', 'E553:')
+  normal G
+  Xbefore 99
+  call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
+  call assert_fails('Xbefore', 'E553:')
+
   normal gg
   Xbelow 2
   call assert_equal(['X2', 10], [bufname(''), line('.')])
+  normal gg
+  Xafter 2
+  call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
+
   normal G
   Xabove 2
   call assert_equal(['X2', 10], [bufname(''), line('.')])
+  normal G
+  Xbefore 2
+  call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
+
   edit X4
   call assert_fails('Xabove', 'E42:')
   call assert_fails('Xbelow', 'E42:')
+  call assert_fails('Xbefore', 'E42:')
+  call assert_fails('Xafter', 'E42:')
   if a:cchar == 'l'
     " If a buffer has location list entries from some other window but not
     " from the current window, then the commands should fail.
     edit X1 | split | call setloclist(0, [], 'f')
     call assert_fails('Xabove', 'E776:')
     call assert_fails('Xbelow', 'E776:')
+    call assert_fails('Xbefore', 'E776:')
+    call assert_fails('Xafter', 'E776:')
     close
   endif
 
@@ -4108,27 +4152,52 @@ func Xtest_below(cchar)
   edit +1 X2
   Xbelow 2
   call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
+  normal 1G
+  Xafter 2
+  call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
+
   normal gg
   Xbelow 99
   call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
+  normal gg
+  Xafter 99
+  call assert_equal(['X2', 15, 3], [bufname(''), line('.'), col('.')])
+
   normal G
   Xabove 2
   call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
+  normal G
+  Xbefore 2
+  call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
+
   normal G
   Xabove 99
   call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
+  normal G
+  Xbefore 99
+  call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
+
   normal 10G
   Xabove
   call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
+  normal 10G$
+  2Xbefore
+  call assert_equal(['X2', 10, 2], [bufname(''), line('.'), col('.')])
+
   normal 10G
   Xbelow
   call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
+  normal 9G
+  5Xafter
+  call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
 
   " Invalid range
   if a:cchar == 'c'
     call assert_fails('-2cbelow', 'E16:')
+    call assert_fails('-2cafter', 'E16:')
   else
     call assert_fails('-2lbelow', 'E16:')
+    call assert_fails('-2lafter', 'E16:')
   endif
 
   call delete('X1')
index a2e23978db768261e91c7e9445960a130efa6561..6838624550edf385bfbe54bd25c120b0eb915df3 100644 (file)
@@ -767,6 +767,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1275,
 /**/
     1274,
 /**/