2024-04-20 08:44:13 -07:00
|
|
|
local t = require('test.testutil')
|
|
|
|
local n = require('test.functional.testnvim')()
|
feat(marks): restore viewport on jump #15831
** Refactor
Previously most functions used to "get" a mark returned a position,
changed the line number and sometimes changed even the current buffer.
Now functions return a {x}fmark_T making calling context aware whether
the mark is in another buffer without arcane casting. A new function is
provided for switching to the mark buffer and returning a flag style
Enum to convey what happen in the movement. If the cursor changed, line,
columns, if it changed buffer, etc.
The function to get named mark was split into multiple functions.
- mark_get() -> fmark_T
- mark_get_global() -> xfmark_T
- mark_get_local() -> fmark_T
- mark_get_motion() -> fmark_T
- mark_get_visual() -> fmark_T
Functions that manage the changelist and jumplist were also modified to
return mark types.
- get_jumplist -> fmark_T
- get_changelist -> fmark_T
The refactor is also seen mainly on normal.c, where all the mark
movement has been siphoned through one function nv_gomark, while the
other functions handle getting the mark and setting their movement
flags. To handle whether context marks should be left, etc.
** Mark View
While doing the refactor the concept of a mark view was also
implemented:
The view of a mark currently implemented as the number of lines between
the mark position on creation and the window topline. This allows for
moving not only back to the position of a mark but having the window
look similar to when the mark was defined. This is done by carrying and
extra element in the fmark_T struct, which can be extended later to also
restore horizontal shift.
*** User space features
1. There's a new option, jumpoptions+=view enables the mark view restoring
automatically when using the jumplist, changelist, alternate-file and
mark motions. <C-O> <C-I> g; g, <C-^> '[mark] `[mark]
** Limitations
- The view information is not saved in shada.
- Calls to get_mark should copy the value in the pointer since we are
using pos_to_mark() to wrap and provide a homogeneous interfaces. This
was also a limitation in the previous state of things.
2022-06-30 05:59:52 -07:00
|
|
|
local Screen = require('test.functional.ui.screen')
|
2019-04-01 15:50:28 -07:00
|
|
|
|
2024-04-20 08:44:13 -07:00
|
|
|
local clear = n.clear
|
|
|
|
local command = n.command
|
2024-04-08 02:03:20 -07:00
|
|
|
local dedent = t.dedent
|
|
|
|
local eq = t.eq
|
2024-04-20 08:44:13 -07:00
|
|
|
local fn = n.fn
|
|
|
|
local feed = n.feed
|
|
|
|
local exec_capture = n.exec_capture
|
2024-04-08 02:03:20 -07:00
|
|
|
local write_file = t.write_file
|
2024-04-20 08:44:13 -07:00
|
|
|
local api = n.api
|
2019-04-01 15:50:28 -07:00
|
|
|
|
|
|
|
describe('jumplist', function()
|
|
|
|
local fname1 = 'Xtest-functional-normal-jump'
|
|
|
|
local fname2 = fname1 .. '2'
|
|
|
|
before_each(clear)
|
|
|
|
after_each(function()
|
|
|
|
os.remove(fname1)
|
|
|
|
os.remove(fname2)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('does not add a new entry on startup', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('\n jump line col file/text\n>', fn.execute('jumps'))
|
2019-04-01 15:50:28 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('does not require two <C-O> strokes to jump back', function()
|
|
|
|
write_file(fname1, 'first file contents')
|
|
|
|
write_file(fname2, 'second file contents')
|
|
|
|
|
|
|
|
command('args ' .. fname1 .. ' ' .. fname2)
|
2024-01-12 10:59:57 -07:00
|
|
|
local buf1 = fn.bufnr(fname1)
|
|
|
|
local buf2 = fn.bufnr(fname2)
|
2019-04-01 15:50:28 -07:00
|
|
|
|
|
|
|
command('next')
|
|
|
|
feed('<C-O>')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(buf1, fn.bufnr('%'))
|
2019-04-01 15:50:28 -07:00
|
|
|
|
|
|
|
command('first')
|
|
|
|
command('snext')
|
|
|
|
feed('<C-O>')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(buf1, fn.bufnr('%'))
|
2019-04-01 15:50:28 -07:00
|
|
|
feed('<C-I>')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(buf2, fn.bufnr('%'))
|
2019-04-01 15:50:28 -07:00
|
|
|
feed('<C-O>')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(buf1, fn.bufnr('%'))
|
2019-04-01 15:50:28 -07:00
|
|
|
|
|
|
|
command('drop ' .. fname2)
|
|
|
|
feed('<C-O>')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(buf1, fn.bufnr('%'))
|
2019-04-01 15:50:28 -07:00
|
|
|
end)
|
2023-10-24 01:10:36 -07:00
|
|
|
|
|
|
|
it('<C-O> scrolls cursor halfway when switching buffer #25763', function()
|
|
|
|
write_file(fname1, ('foobar\n'):rep(100))
|
|
|
|
write_file(fname2, 'baz')
|
|
|
|
|
|
|
|
local screen = Screen.new(5, 25)
|
|
|
|
command('set number')
|
|
|
|
command('edit ' .. fname1)
|
|
|
|
feed('35gg')
|
|
|
|
command('edit ' .. fname2)
|
|
|
|
feed('<C-O>')
|
|
|
|
screen:expect {
|
|
|
|
grid = [[
|
|
|
|
{1: 24 }foobar |
|
|
|
|
{1: 25 }foobar |
|
|
|
|
{1: 26 }foobar |
|
|
|
|
{1: 27 }foobar |
|
|
|
|
{1: 28 }foobar |
|
|
|
|
{1: 29 }foobar |
|
|
|
|
{1: 30 }foobar |
|
|
|
|
{1: 31 }foobar |
|
|
|
|
{1: 32 }foobar |
|
|
|
|
{1: 33 }foobar |
|
|
|
|
{1: 34 }foobar |
|
|
|
|
{1: 35 }^foobar |
|
|
|
|
{1: 36 }foobar |
|
|
|
|
{1: 37 }foobar |
|
|
|
|
{1: 38 }foobar |
|
|
|
|
{1: 39 }foobar |
|
|
|
|
{1: 40 }foobar |
|
|
|
|
{1: 41 }foobar |
|
|
|
|
{1: 42 }foobar |
|
|
|
|
{1: 43 }foobar |
|
|
|
|
{1: 44 }foobar |
|
|
|
|
{1: 45 }foobar |
|
|
|
|
{1: 46 }foobar |
|
|
|
|
{1: 47 }foobar |
|
|
|
|
|
|
|
|
|
]],
|
|
|
|
attr_ids = {
|
|
|
|
[1] = { foreground = Screen.colors.Brown },
|
2024-01-02 18:09:18 -07:00
|
|
|
},
|
2023-10-24 01:10:36 -07:00
|
|
|
}
|
|
|
|
end)
|
2019-04-01 15:50:28 -07:00
|
|
|
end)
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
|
2019-12-10 02:24:20 -07:00
|
|
|
describe("jumpoptions=stack behaves like 'tagstack'", function()
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
before_each(function()
|
|
|
|
clear()
|
|
|
|
feed(':clearjumps<cr>')
|
|
|
|
|
|
|
|
-- Add lines so that we have locations to jump to.
|
|
|
|
for i = 1, 101, 1 do
|
|
|
|
feed('iLine ' .. i .. '<cr><esc>')
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Jump around to add some locations to the jump list.
|
|
|
|
feed('0gg')
|
|
|
|
feed('10gg')
|
|
|
|
feed('20gg')
|
|
|
|
feed('30gg')
|
|
|
|
feed('40gg')
|
|
|
|
feed('50gg')
|
|
|
|
|
|
|
|
feed(':set jumpoptions=stack<cr>')
|
|
|
|
end)
|
|
|
|
|
|
|
|
after_each(function()
|
|
|
|
feed('set jumpoptions=')
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('discards the tail when navigating from the middle', function()
|
|
|
|
feed('<C-O>')
|
|
|
|
feed('<C-O>')
|
|
|
|
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
''
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
.. ' jump line col file/text\n'
|
|
|
|
.. ' 4 102 0 \n'
|
|
|
|
.. ' 3 1 0 Line 1\n'
|
|
|
|
.. ' 2 10 0 Line 10\n'
|
|
|
|
.. ' 1 20 0 Line 20\n'
|
|
|
|
.. '> 0 30 0 Line 30\n'
|
|
|
|
.. ' 1 40 0 Line 40\n'
|
|
|
|
.. ' 2 50 0 Line 50',
|
2021-09-19 02:29:37 -07:00
|
|
|
exec_capture('jumps')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
|
|
|
|
feed('90gg')
|
|
|
|
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
''
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
.. ' jump line col file/text\n'
|
|
|
|
.. ' 5 102 0 \n'
|
|
|
|
.. ' 4 1 0 Line 1\n'
|
|
|
|
.. ' 3 10 0 Line 10\n'
|
|
|
|
.. ' 2 20 0 Line 20\n'
|
|
|
|
.. ' 1 30 0 Line 30\n'
|
|
|
|
.. '>',
|
2021-09-19 02:29:37 -07:00
|
|
|
exec_capture('jumps')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('does not add the same location twice adjacently', function()
|
|
|
|
feed('60gg')
|
|
|
|
feed('60gg')
|
|
|
|
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
''
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
.. ' jump line col file/text\n'
|
|
|
|
.. ' 7 102 0 \n'
|
|
|
|
.. ' 6 1 0 Line 1\n'
|
|
|
|
.. ' 5 10 0 Line 10\n'
|
|
|
|
.. ' 4 20 0 Line 20\n'
|
|
|
|
.. ' 3 30 0 Line 30\n'
|
|
|
|
.. ' 2 40 0 Line 40\n'
|
|
|
|
.. ' 1 50 0 Line 50\n'
|
|
|
|
.. '>',
|
2021-09-19 02:29:37 -07:00
|
|
|
exec_capture('jumps')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('does add the same location twice nonadjacently', function()
|
|
|
|
feed('10gg')
|
|
|
|
feed('20gg')
|
|
|
|
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
''
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
.. ' jump line col file/text\n'
|
|
|
|
.. ' 8 102 0 \n'
|
|
|
|
.. ' 7 1 0 Line 1\n'
|
|
|
|
.. ' 6 10 0 Line 10\n'
|
|
|
|
.. ' 5 20 0 Line 20\n'
|
|
|
|
.. ' 4 30 0 Line 30\n'
|
|
|
|
.. ' 3 40 0 Line 40\n'
|
|
|
|
.. ' 2 50 0 Line 50\n'
|
|
|
|
.. ' 1 10 0 Line 10\n'
|
|
|
|
.. '>',
|
2021-09-19 02:29:37 -07:00
|
|
|
exec_capture('jumps')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
jumplist: browser-style (or 'tagstack') navigation #11530
Traditionally, when navigating to a specific location from the middle of
the jumplist results in shifting the current location to the bottom of
the list and adding the new location after it. This behavior is not
desireable to all users--see, for example
https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior.
Here, another jumplist behavior is introduced. When jumpoptions (a new
option set added here) includes stack, the jumplist behaves like the
tagstack or like history in a web browser. That is, when navigating to
a location from the middle of the jumplist
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
to a new location the locations after the current location in the jump
list are discarded
2 first
1 second
0 third
<-- current location
The result is that when moving forward from that location, the new
location will be appended to the jumplist:
3 first
2 second
1 third
0 new
If the new location is the same
new == second
as some previous (but not immediately prior) entry in the jumplist,
2 first
1 second
0 third <-- current location
1 fourth
2 fifth
both occurrences preserved
3 first
2 second
1 third
0 second (new)
when moving forward from that location.
It would be desireable to go farther and, when the new location is the
same as the location that is currently next in the jumplist,
new == fourth
make the result of navigating to the new location by jumping (e.g. 50gg)
be the same as moving forward in the jumplist
2 first
1 second
0 third
1 new <-- current location
2 fifth
and simply increment the jumplist index. That change is NOT part of
this patch because it would require passing the new cursor location to
the function (setpcmark) from all of its callees. That in turn would
require those callees to know *before* calling what the new cursor
location is, which do they do not currently.
2019-12-10 01:56:56 -07:00
|
|
|
end)
|
|
|
|
end)
|
feat(marks): restore viewport on jump #15831
** Refactor
Previously most functions used to "get" a mark returned a position,
changed the line number and sometimes changed even the current buffer.
Now functions return a {x}fmark_T making calling context aware whether
the mark is in another buffer without arcane casting. A new function is
provided for switching to the mark buffer and returning a flag style
Enum to convey what happen in the movement. If the cursor changed, line,
columns, if it changed buffer, etc.
The function to get named mark was split into multiple functions.
- mark_get() -> fmark_T
- mark_get_global() -> xfmark_T
- mark_get_local() -> fmark_T
- mark_get_motion() -> fmark_T
- mark_get_visual() -> fmark_T
Functions that manage the changelist and jumplist were also modified to
return mark types.
- get_jumplist -> fmark_T
- get_changelist -> fmark_T
The refactor is also seen mainly on normal.c, where all the mark
movement has been siphoned through one function nv_gomark, while the
other functions handle getting the mark and setting their movement
flags. To handle whether context marks should be left, etc.
** Mark View
While doing the refactor the concept of a mark view was also
implemented:
The view of a mark currently implemented as the number of lines between
the mark position on creation and the window topline. This allows for
moving not only back to the position of a mark but having the window
look similar to when the mark was defined. This is done by carrying and
extra element in the fmark_T struct, which can be extended later to also
restore horizontal shift.
*** User space features
1. There's a new option, jumpoptions+=view enables the mark view restoring
automatically when using the jumplist, changelist, alternate-file and
mark motions. <C-O> <C-I> g; g, <C-^> '[mark] `[mark]
** Limitations
- The view information is not saved in shada.
- Calls to get_mark should copy the value in the pointer since we are
using pos_to_mark() to wrap and provide a homogeneous interfaces. This
was also a limitation in the previous state of things.
2022-06-30 05:59:52 -07:00
|
|
|
|
2024-09-19 03:05:27 -07:00
|
|
|
describe('buffer deletion with jumpoptions+=clean', function()
|
2024-01-28 20:08:51 -07:00
|
|
|
local base_file = 'Xtest-functional-buffer-deletion'
|
|
|
|
local file1 = base_file .. '1'
|
|
|
|
local file2 = base_file .. '2'
|
|
|
|
local file3 = base_file .. '3'
|
|
|
|
local base_content = 'text'
|
|
|
|
local content1 = base_content .. '1'
|
|
|
|
local content2 = base_content .. '2'
|
|
|
|
local content3 = base_content .. '3'
|
|
|
|
|
|
|
|
local function format_jumplist(input)
|
|
|
|
return dedent(input)
|
|
|
|
:gsub('%{file1%}', file1)
|
|
|
|
:gsub('%{file2%}', file2)
|
|
|
|
:gsub('%{file3%}', file3)
|
|
|
|
:gsub('%{content1%}', content1)
|
|
|
|
:gsub('%{content2%}', content2)
|
|
|
|
:gsub('%{content3%}', content3)
|
|
|
|
end
|
|
|
|
|
|
|
|
before_each(function()
|
|
|
|
clear()
|
|
|
|
command('clearjumps')
|
|
|
|
|
|
|
|
write_file(file1, content1, false, false)
|
|
|
|
write_file(file2, content2, false, false)
|
|
|
|
write_file(file3, content3, false, false)
|
|
|
|
|
|
|
|
command('edit ' .. file1)
|
|
|
|
command('edit ' .. file2)
|
|
|
|
command('edit ' .. file3)
|
|
|
|
end)
|
|
|
|
|
2024-06-29 15:40:31 -07:00
|
|
|
after_each(function()
|
|
|
|
os.remove(file1)
|
|
|
|
os.remove(file2)
|
|
|
|
os.remove(file3)
|
|
|
|
end)
|
|
|
|
|
2024-01-28 20:08:51 -07:00
|
|
|
it('deletes jump list entries when the current buffer is deleted', function()
|
|
|
|
command('edit ' .. file1)
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
3 1 0 {content1}
|
|
|
|
2 1 0 {file2}
|
|
|
|
1 1 0 {file3}
|
|
|
|
>]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
|
|
|
|
command('bwipeout')
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
1 1 0 {file2}
|
|
|
|
> 0 1 0 {content3}]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('deletes jump list entries when another buffer is deleted', function()
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
2 1 0 {file1}
|
|
|
|
1 1 0 {file2}
|
|
|
|
>]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
|
|
|
|
command('bwipeout ' .. file2)
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
1 1 0 {file1}
|
|
|
|
>]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('sets the correct jump index when the current buffer is deleted', function()
|
|
|
|
feed('<C-O>')
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
1 1 0 {file1}
|
|
|
|
> 0 1 0 {content2}
|
|
|
|
1 1 0 {file3}]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
|
|
|
|
command('bw')
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
1 1 0 {file1}
|
|
|
|
> 0 1 0 {content3}]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('sets the correct jump index when the another buffer is deleted', function()
|
|
|
|
feed('<C-O>')
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
1 1 0 {file1}
|
|
|
|
> 0 1 0 {content2}
|
|
|
|
1 1 0 {file3}]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
|
|
|
|
command('bwipeout ' .. file1)
|
|
|
|
|
|
|
|
eq(
|
|
|
|
format_jumplist([[
|
|
|
|
jump line col file/text
|
|
|
|
> 0 1 0 {content2}
|
|
|
|
1 1 0 {file3}]]),
|
|
|
|
exec_capture('jumps')
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
2024-09-19 03:05:27 -07:00
|
|
|
describe('buffer deletion with jumpoptions-=clean', function()
|
2024-06-29 15:40:31 -07:00
|
|
|
local base_file = 'Xtest-functional-buffer-deletion'
|
|
|
|
local file1 = base_file .. '1'
|
|
|
|
local file2 = base_file .. '2'
|
|
|
|
local base_content = 'text'
|
|
|
|
local content1 = base_content .. '1'
|
|
|
|
local content2 = base_content .. '2'
|
|
|
|
|
|
|
|
before_each(function()
|
|
|
|
clear()
|
|
|
|
command('clearjumps')
|
2024-09-19 03:05:27 -07:00
|
|
|
command('set jumpoptions-=clean')
|
2024-06-29 15:40:31 -07:00
|
|
|
|
|
|
|
write_file(file1, content1, false, false)
|
|
|
|
write_file(file2, content2, false, false)
|
|
|
|
|
|
|
|
command('edit ' .. file1)
|
|
|
|
command('edit ' .. file2)
|
|
|
|
end)
|
|
|
|
|
|
|
|
after_each(function()
|
|
|
|
os.remove(file1)
|
|
|
|
os.remove(file2)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('Ctrl-O reopens previous buffer with :bunload or :bdelete #28968', function()
|
|
|
|
eq(file2, fn.bufname(''))
|
|
|
|
command('bunload')
|
|
|
|
eq(file1, fn.bufname(''))
|
|
|
|
feed('<C-O>')
|
|
|
|
eq(file2, fn.bufname(''))
|
|
|
|
command('bdelete')
|
|
|
|
eq(file1, fn.bufname(''))
|
|
|
|
feed('<C-O>')
|
|
|
|
eq(file2, fn.bufname(''))
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
feat(marks): restore viewport on jump #15831
** Refactor
Previously most functions used to "get" a mark returned a position,
changed the line number and sometimes changed even the current buffer.
Now functions return a {x}fmark_T making calling context aware whether
the mark is in another buffer without arcane casting. A new function is
provided for switching to the mark buffer and returning a flag style
Enum to convey what happen in the movement. If the cursor changed, line,
columns, if it changed buffer, etc.
The function to get named mark was split into multiple functions.
- mark_get() -> fmark_T
- mark_get_global() -> xfmark_T
- mark_get_local() -> fmark_T
- mark_get_motion() -> fmark_T
- mark_get_visual() -> fmark_T
Functions that manage the changelist and jumplist were also modified to
return mark types.
- get_jumplist -> fmark_T
- get_changelist -> fmark_T
The refactor is also seen mainly on normal.c, where all the mark
movement has been siphoned through one function nv_gomark, while the
other functions handle getting the mark and setting their movement
flags. To handle whether context marks should be left, etc.
** Mark View
While doing the refactor the concept of a mark view was also
implemented:
The view of a mark currently implemented as the number of lines between
the mark position on creation and the window topline. This allows for
moving not only back to the position of a mark but having the window
look similar to when the mark was defined. This is done by carrying and
extra element in the fmark_T struct, which can be extended later to also
restore horizontal shift.
*** User space features
1. There's a new option, jumpoptions+=view enables the mark view restoring
automatically when using the jumplist, changelist, alternate-file and
mark motions. <C-O> <C-I> g; g, <C-^> '[mark] `[mark]
** Limitations
- The view information is not saved in shada.
- Calls to get_mark should copy the value in the pointer since we are
using pos_to_mark() to wrap and provide a homogeneous interfaces. This
was also a limitation in the previous state of things.
2022-06-30 05:59:52 -07:00
|
|
|
describe('jumpoptions=view', function()
|
|
|
|
local file1 = 'Xtestfile-functional-editor-jumps'
|
|
|
|
local file2 = 'Xtestfile-functional-editor-jumps-2'
|
|
|
|
local function content()
|
|
|
|
local c = {}
|
|
|
|
for i = 1, 30 do
|
|
|
|
c[i] = i .. ' line'
|
|
|
|
end
|
|
|
|
return table.concat(c, '\n')
|
|
|
|
end
|
|
|
|
before_each(function()
|
|
|
|
clear()
|
|
|
|
write_file(file1, content(), false, false)
|
|
|
|
write_file(file2, content(), false, false)
|
|
|
|
command('set jumpoptions=view')
|
|
|
|
end)
|
|
|
|
after_each(function()
|
|
|
|
os.remove(file1)
|
|
|
|
os.remove(file2)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('restores the view', function()
|
|
|
|
local screen = Screen.new(5, 8)
|
|
|
|
command('edit ' .. file1)
|
|
|
|
feed('12Gztj')
|
|
|
|
feed('gg<C-o>')
|
|
|
|
screen:expect([[
|
|
|
|
12 line |
|
|
|
|
^13 line |
|
|
|
|
14 line |
|
|
|
|
15 line |
|
|
|
|
16 line |
|
|
|
|
17 line |
|
|
|
|
18 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('restores the view across files', function()
|
|
|
|
local screen = Screen.new(5, 5)
|
|
|
|
command('args ' .. file1 .. ' ' .. file2)
|
|
|
|
feed('12Gzt')
|
|
|
|
command('next')
|
|
|
|
feed('G')
|
|
|
|
screen:expect([[
|
|
|
|
27 line |
|
|
|
|
28 line |
|
|
|
|
29 line |
|
|
|
|
^30 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
feed('<C-o><C-o>')
|
|
|
|
screen:expect([[
|
|
|
|
^12 line |
|
|
|
|
13 line |
|
|
|
|
14 line |
|
|
|
|
15 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('restores the view across files with <C-^>', function()
|
|
|
|
local screen = Screen.new(5, 5)
|
|
|
|
command('args ' .. file1 .. ' ' .. file2)
|
|
|
|
feed('12Gzt')
|
|
|
|
command('next')
|
|
|
|
feed('G')
|
|
|
|
screen:expect([[
|
|
|
|
27 line |
|
|
|
|
28 line |
|
|
|
|
29 line |
|
|
|
|
^30 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
feed('<C-^>')
|
|
|
|
screen:expect([[
|
|
|
|
^12 line |
|
|
|
|
13 line |
|
|
|
|
14 line |
|
|
|
|
15 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it("falls back to standard behavior when view can't be recovered", function()
|
|
|
|
local screen = Screen.new(5, 8)
|
|
|
|
command('edit ' .. file1)
|
|
|
|
feed('7GzbG')
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_buf_set_lines(0, 0, 2, true, {})
|
feat(marks): restore viewport on jump #15831
** Refactor
Previously most functions used to "get" a mark returned a position,
changed the line number and sometimes changed even the current buffer.
Now functions return a {x}fmark_T making calling context aware whether
the mark is in another buffer without arcane casting. A new function is
provided for switching to the mark buffer and returning a flag style
Enum to convey what happen in the movement. If the cursor changed, line,
columns, if it changed buffer, etc.
The function to get named mark was split into multiple functions.
- mark_get() -> fmark_T
- mark_get_global() -> xfmark_T
- mark_get_local() -> fmark_T
- mark_get_motion() -> fmark_T
- mark_get_visual() -> fmark_T
Functions that manage the changelist and jumplist were also modified to
return mark types.
- get_jumplist -> fmark_T
- get_changelist -> fmark_T
The refactor is also seen mainly on normal.c, where all the mark
movement has been siphoned through one function nv_gomark, while the
other functions handle getting the mark and setting their movement
flags. To handle whether context marks should be left, etc.
** Mark View
While doing the refactor the concept of a mark view was also
implemented:
The view of a mark currently implemented as the number of lines between
the mark position on creation and the window topline. This allows for
moving not only back to the position of a mark but having the window
look similar to when the mark was defined. This is done by carrying and
extra element in the fmark_T struct, which can be extended later to also
restore horizontal shift.
*** User space features
1. There's a new option, jumpoptions+=view enables the mark view restoring
automatically when using the jumplist, changelist, alternate-file and
mark motions. <C-O> <C-I> g; g, <C-^> '[mark] `[mark]
** Limitations
- The view information is not saved in shada.
- Calls to get_mark should copy the value in the pointer since we are
using pos_to_mark() to wrap and provide a homogeneous interfaces. This
was also a limitation in the previous state of things.
2022-06-30 05:59:52 -07:00
|
|
|
-- Move to line 7, and set it as the last line visible on the view with zb, meaning to recover
|
|
|
|
-- the view it needs to put the cursor 7 lines from the top line. Then go to the end of the
|
|
|
|
-- file, delete 2 lines before line 7, meaning the jump/mark is moved 2 lines up to line 5.
|
|
|
|
-- Therefore when trying to jump back to it it's not possible to set a 7 line offset from the
|
|
|
|
-- mark position to the top line, since there's only 5 lines from the mark position to line 0.
|
|
|
|
-- Therefore falls back to standard behavior which is centering the view/line.
|
|
|
|
feed('<C-o>')
|
|
|
|
screen:expect([[
|
|
|
|
4 line |
|
|
|
|
5 line |
|
|
|
|
6 line |
|
|
|
|
^7 line |
|
|
|
|
8 line |
|
|
|
|
9 line |
|
|
|
|
10 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
end)
|
2022-07-04 13:28:14 -07:00
|
|
|
|
|
|
|
it('falls back to standard behavior for a mark without a view', function()
|
|
|
|
local screen = Screen.new(5, 8)
|
|
|
|
command('edit ' .. file1)
|
|
|
|
feed('10ggzzvwy')
|
|
|
|
screen:expect([[
|
|
|
|
7 line |
|
|
|
|
8 line |
|
|
|
|
9 line |
|
|
|
|
^10 line |
|
|
|
|
11 line |
|
|
|
|
12 line |
|
|
|
|
13 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
feed('`]')
|
|
|
|
screen:expect([[
|
|
|
|
7 line |
|
|
|
|
8 line |
|
|
|
|
9 line |
|
|
|
|
10 ^line |
|
|
|
|
11 line |
|
|
|
|
12 line |
|
|
|
|
13 line |
|
|
|
|
|
|
|
|
|
]])
|
|
|
|
end)
|
feat(marks): restore viewport on jump #15831
** Refactor
Previously most functions used to "get" a mark returned a position,
changed the line number and sometimes changed even the current buffer.
Now functions return a {x}fmark_T making calling context aware whether
the mark is in another buffer without arcane casting. A new function is
provided for switching to the mark buffer and returning a flag style
Enum to convey what happen in the movement. If the cursor changed, line,
columns, if it changed buffer, etc.
The function to get named mark was split into multiple functions.
- mark_get() -> fmark_T
- mark_get_global() -> xfmark_T
- mark_get_local() -> fmark_T
- mark_get_motion() -> fmark_T
- mark_get_visual() -> fmark_T
Functions that manage the changelist and jumplist were also modified to
return mark types.
- get_jumplist -> fmark_T
- get_changelist -> fmark_T
The refactor is also seen mainly on normal.c, where all the mark
movement has been siphoned through one function nv_gomark, while the
other functions handle getting the mark and setting their movement
flags. To handle whether context marks should be left, etc.
** Mark View
While doing the refactor the concept of a mark view was also
implemented:
The view of a mark currently implemented as the number of lines between
the mark position on creation and the window topline. This allows for
moving not only back to the position of a mark but having the window
look similar to when the mark was defined. This is done by carrying and
extra element in the fmark_T struct, which can be extended later to also
restore horizontal shift.
*** User space features
1. There's a new option, jumpoptions+=view enables the mark view restoring
automatically when using the jumplist, changelist, alternate-file and
mark motions. <C-O> <C-I> g; g, <C-^> '[mark] `[mark]
** Limitations
- The view information is not saved in shada.
- Calls to get_mark should copy the value in the pointer since we are
using pos_to_mark() to wrap and provide a homogeneous interfaces. This
was also a limitation in the previous state of things.
2022-06-30 05:59:52 -07:00
|
|
|
end)
|