patch 9.0.1921: not possible to use the jumplist like a stack

Commit: 
https://github.com/vim/vim/commit/87018255e3ad0f4dfa03e20318836d24af721caf
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Wed Sep 20 20:20:04 2023 +0200

    patch 9.0.1921: not possible to use the jumplist like a stack
    
    Problem:  not possible to use the jumplist like a stack
    Solution: Add the 'jumpoptions' setting to make the jumplist
              a stack.
    
    Add an option for using jumplist like tag stack
    
    related: #7738
    closes: #13134
    
    ported from NeoVim:
    
    - https://neovim.io/doc/user/motion.html#jumplist-stack
    - neovim/neovim@39094b3
    - neovim/neovim#11530
    - 
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior
    
    Based on the feedback in the previous PR, it looks like many people like
    this option.
    
    Signed-off-by: Christian Brabandt <c...@256bit.org>
    Co-authored-by: Yegappan Lakshmanan <yegap...@yahoo.com>
    Co-authored-by: butwerenotthereyet 
<58348703+butwerenotthere...@users.noreply.github.com>

diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index c89eead63..9bdbfb493 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -1135,7 +1135,46 @@ When you split a window, the jumplist will be copied to 
the new window.
 If you have included the ' item in the 'viminfo' option the jumplist will be
 stored in the viminfo file and restored when starting Vim.
 
+                                                       *jumplist-stack*
+When 'jumpoptions' option includes "stack", the jumplist behaves like the tag
+stack.  When jumping to a new location from the middle of the jumplist, the
+locations after the current position will be discarded. With this option set
+you can move through a tree of jump locations. When going back up a branch and
+then down another branch, CTRL-O still takes you further up the tree.
+
+Given a jumplist like the following in which CTRL-O has been used to move back
+three times to location X: >
+
+     jump line  col file/text
+       2  1260    8 mark.c             <-- location X-2
+       1   685    0 eval.c             <-- location X-1
+    >  0   462   36 eval.c             <-- location X
+       1   479   39 eval.c
+       2   213    2 mark.c
+       3   181    0 mark.c
+<
+jumping to (new) location Y results in the locations after the current
+locations being removed: >
+
+     jump line  col file/text
+       3  1260    8 mark.c             <-- location X-2
+       2   685    0 eval.c             <-- location X-1
+       1   462   36 eval.c             <-- location X
+    >
+<
 
+Then, when yet another location Z is jumped to, the new location Y appears
+directly after location X in the jumplist and location X remains in the same
+position relative to the locations (X-1, X-2, etc., ...) that had been before
+it prior to the original jump from X to Y: >
+
+     jump line  col file/text
+       4  1260    8 mark.c             <-- location X-2
+       3   685    0 eval.c             <-- location X-1
+       2   462   36 eval.c             <-- location X
+       1   100    0 buffer.c   <-- location Y
+    >
+<
 CHANGE LIST JUMPS                      *changelist* *change-list-jumps* *E664*
 
 When making a change the cursor position is remembered.  One position is
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 6c82fa495..c5123289a 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4899,6 +4899,16 @@ A jump table for the options with a short description 
can be found at |Q_op|.
        Otherwise only one space is inserted.
        NOTE: This option is set when 'compatible' is set.
 
+                                               *'jumpoptions'* *'jop'*
+'jumpoptions' 'jop'    string  (default "")
+                       global
+       List of words that change the behavior of the |jumplist|.
+         stack         Make the jumplist behave like the tagstack.
+                       Relative location of entries in the jumplist is
+                       preserved at the cost of discarding subsequent entries
+                       when navigating backwards in the jumplist and then
+                       jumping to a location.  |jumplist-stack|
+
                                                        *'key'*
 'key'                  string  (default "")
                        local to buffer
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index ffdfd108a..65a560a30 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -772,6 +772,7 @@ Short explanation of each option:           *option-list*
 'iskeyword'      'isk'     characters included in keywords
 'isprint'        'isp'     printable characters
 'joinspaces'     'js'      two spaces after a period with a join command
+'jumpoptions'    'jop'     specifies how jumping is done
 'key'                      encryption key
 'keymap'         'kmp'     name of a keyboard mapping
 'keymodel'       'km'      enable starting/stopping selection with keys
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 8cfd1881c..38d6b09fd 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -433,7 +433,9 @@ $quote      eval.txt        /*$quote*
 'isp'  options.txt     /*'isp'*
 'isprint'      options.txt     /*'isprint'*
 'joinspaces'   options.txt     /*'joinspaces'*
+'jop'  options.txt     /*'jop'*
 'js'   options.txt     /*'js'*
+'jumpoptions'  options.txt     /*'jumpoptions'*
 'key'  options.txt     /*'key'*
 'keymap'       options.txt     /*'keymap'*
 'keymodel'     options.txt     /*'keymodel'*
@@ -8300,6 +8302,7 @@ json_encode()     builtin.txt     /*json_encode()*
 jtags  tagsrch.txt     /*jtags*
 jump-motions   motion.txt      /*jump-motions*
 jumplist       motion.txt      /*jumplist*
+jumplist-stack motion.txt      /*jumplist-stack*
 jumpto-diffs   diff.txt        /*jumpto-diffs*
 k      motion.txt      /*k*
 kcc    uganda.txt      /*kcc*
diff --git a/src/mark.c b/src/mark.c
index b3c644b14..22e3c6257 100644
--- a/src/mark.c
+++ b/src/mark.c
@@ -146,6 +146,16 @@ setpcmark(void)
     curwin->w_prev_pcmark = curwin->w_pcmark;
     curwin->w_pcmark = curwin->w_cursor;
 
+    if (jop_flags & JOP_STACK)
+    {
+       // jumpoptions=stack: if we're somewhere in the middle of the jumplist
+       // discard everything after the current index.
+       if (curwin->w_jumplistidx < curwin->w_jumplistlen - 1)
+           // Discard the rest of the jumplist by cutting the length down to
+           // contain nothing beyond the current index.
+           curwin->w_jumplistlen = curwin->w_jumplistidx + 1;
+    }
+
     // If jumplist is full: remove oldest entry
     if (++curwin->w_jumplistlen > JUMPLISTSIZE)
     {
@@ -1288,6 +1298,7 @@ cleanup_jumplist(win_T *wp, int loadfiles)
 {
     int            i;
     int            from, to;
+    int            mustfree;
 
     if (loadfiles)
     {
@@ -1314,10 +1325,18 @@ cleanup_jumplist(win_T *wp, int loadfiles)
                    && wp->w_jumplist[i].fmark.mark.lnum
                                  == wp->w_jumplist[from].fmark.mark.lnum)
                break;
-       if (i >= wp->w_jumplistlen)         // no duplicate
-           wp->w_jumplist[to++] = wp->w_jumplist[from];
-       else
+       if (i >= wp->w_jumplistlen)     // not duplicate
+           mustfree = FALSE;
+       else if (i > from + 1)          // non-adjacent duplicate
+           // jumpoptions=stack: remove duplicates only when adjacent.
+           mustfree = !(jop_flags & JOP_STACK);
+       else                            // adjacent duplicate
+           mustfree = TRUE;
+
+       if (mustfree)
            vim_free(wp->w_jumplist[from].fname);
+       else
+           wp->w_jumplist[to++] = wp->w_jumplist[from];
     }
     if (wp->w_jumplistidx == wp->w_jumplistlen)
        wp->w_jumplistidx = to;
diff --git a/src/option.h b/src/option.h
index 3bd2eb969..68748304b 100644
--- a/src/option.h
+++ b/src/option.h
@@ -601,6 +601,9 @@ EXTERN char_u       *p_fp;          // 'formatprg'
 EXTERN int     p_fs;           // 'fsync'
 #endif
 EXTERN int     p_gd;           // 'gdefault'
+EXTERN char_u  *p_jop;         // 'jumpoptions'
+EXTERN unsigned        jop_flags;      //
+#define JOP_STACK              0x001
 #ifdef FEAT_PROP_POPUP
 # ifdef FEAT_QUICKFIX
 EXTERN char_u  *p_cpp;         // 'completepopup'
diff --git a/src/optiondefs.h b/src/optiondefs.h
index aeb3b5798..4f3a1524a 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -1459,6 +1459,9 @@ static struct vimoption options[] =
     {"joinspaces",  "js",   P_BOOL|P_VI_DEF|P_VIM,
                            (char_u *)&p_js, PV_NONE, NULL,
                            {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+    {"jumpoptions", "jop",  P_STRING|P_VI_DEF|P_VIM|P_ONECOMMA|P_NODUP,
+                           (char_u *)&p_jop, PV_NONE, did_set_jumpoptions,
+                           {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"key",        NULL,   P_STRING|P_ALLOCED|P_VI_DEF|P_NO_MKRC,
 #ifdef FEAT_CRYPT
                            (char_u *)&p_key, PV_KEY, did_set_cryptkey,
diff --git a/src/optionstr.c b/src/optionstr.c
index 31e30e195..aeeab2789 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -35,6 +35,7 @@ static char *(p_cm_values[]) = {"zip", "blowfish", 
"blowfish2",
 #endif
 static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
 static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
+static char *(p_jop_values[]) = {"stack", NULL};
 #ifdef FEAT_FOLDING
 static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent",
                                 "quickfix", "search", "tag", "insert",
@@ -120,6 +121,7 @@ didset_string_options(void)
     (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
 #endif
     (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE);
+    (void)opt_strings_flags(p_jop, p_jop_values, &jop_flags, TRUE);
     (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, FALSE);
     (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE);
 #if defined(UNIX) || defined(VMS)
@@ -1852,6 +1854,18 @@ did_set_isopt(optset_T *args)
     return NULL;
 }
 
+/*
+ * The 'jumpoptions' option is changed.
+ */
+    char *
+did_set_jumpoptions(optset_T *args)
+{
+    if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, TRUE) != OK)
+       return e_invalid_argument;
+
+    return NULL;
+}
+
 #if defined(FEAT_KEYMAP) || defined(PROTO)
 /*
  * The 'keymap' option is changed.
diff --git a/src/proto/optionstr.pro b/src/proto/optionstr.pro
index db13f10d9..c1253b1c4 100644
--- a/src/proto/optionstr.pro
+++ b/src/proto/optionstr.pro
@@ -64,6 +64,7 @@ char *did_set_highlight(optset_T *args);
 char *did_set_iconstring(optset_T *args);
 char *did_set_imactivatekey(optset_T *args);
 char *did_set_isopt(optset_T *args);
+char *did_set_jumpoptions(optset_T *args);
 char *did_set_keymap(optset_T *args);
 char *did_set_keymodel(optset_T *args);
 char *did_set_keyprotocol(optset_T *args);
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index f205d4391..a195bcaea 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -112,6 +112,7 @@ let test_values = {
       \ 'isident': [['', '@', '@,48-52'], ['xxx', '@48']],
       \ 'iskeyword': [['', '@', '@,48-52'], ['xxx', '@48']],
       \ 'isprint': [['', '@', '@,48-52'], ['xxx', '@48']],
+      \ 'jumpoptions': [['', 'stack'], ['xxx']],
       \ 'keymap': [['', 'accents'], ['xxx']],
       \ 'keymodel': [['', 'startsel', 'startsel,stopsel'], ['xxx']],
       \ 'keyprotocol': [['', 'xxx:none', 'yyy:mok2', 'zzz:kitty'],
diff --git a/src/testdir/test_jumplist.vim b/src/testdir/test_jumplist.vim
index 4b5e3213f..8fbf39f55 100644
--- a/src/testdir/test_jumplist.vim
+++ b/src/testdir/test_jumplist.vim
@@ -98,4 +98,68 @@ d
   bwipe!
 endfunc
 
+" Test for 'jumpoptions'
+func Test_jumpoptions()
+  new
+  call setline(1, range(1, 200))
+  clearjumps
+  set jumpoptions=stack
+
+  " Jump around to add some locations to the jump list.
+  normal 10G
+  normal 20G
+  normal 30G
+  normal 40G
+  normal 50G
+  let bnr = bufnr()
+
+  " discards the tail when navigating from the middle
+  exe "normal \<C-O>\<C-O>"
+  call assert_equal([
+        \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 40, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 50, 'bufnr': bnr, 'col': 0, 'coladd': 0}
+        \ ], 3], getjumplist())
+
+  " new jump location is added immediately after the last one
+  normal 90G
+  call assert_equal([
+        \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \ ], 4], getjumplist())
+
+  " does not add the same location twice adjacently
+  normal 60G
+  normal 60G
+  call assert_equal([
+        \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 90, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 60, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \ ], 6], getjumplist())
+
+  " does add the same location twice non adjacently
+  normal 10G
+  normal 20G
+  call assert_equal([
+        \ [{'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 20, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 30, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 90, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 60, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \  {'lnum': 10, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+        \ ], 7], getjumplist())
+
+  set jumpoptions&
+  %bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 5abc4f733..5f362340e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1921,
 /**/
     1920,
 /**/

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qj1xe-003mMv-2s%40256bit.org.

Raspunde prin e-mail lui