mirror of
https://github.com/neovim/neovim.git
synced 2026-03-28 03:12:00 +00:00
fix(marks): make jumpoptions=view work with 'smoothscroll' (#38339)
Problem: 'jumpoptions' "view" doesn't remember skipcol and may lead to
glitched display with 'smoothscroll'.
Solution: Save skipcol in the mark view. Also make sure skipcol doesn't
exceed line size.
This commit is contained in:
@@ -2764,7 +2764,7 @@ void buflist_setfpos(buf_T *const buf, win_T *const win, linenr_T lnum, colnr_T
|
||||
wip->wi_mark.mark.lnum = lnum;
|
||||
wip->wi_mark.mark.col = col;
|
||||
if (win != NULL) {
|
||||
wip->wi_mark.view = mark_view_make(win->w_topline, wip->wi_mark.mark);
|
||||
wip->wi_mark.view = mark_view_make(win, wip->wi_mark.mark);
|
||||
}
|
||||
}
|
||||
if (win != NULL) {
|
||||
|
||||
@@ -254,7 +254,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
|
||||
|
||||
if (curwin->w_buffer == buf) {
|
||||
if (lnum >= curwin->w_topline && lnum <= curwin->w_botline) {
|
||||
view = mark_view_make(curwin->w_topline, curwin->w_cursor);
|
||||
view = mark_view_make(curwin, curwin->w_cursor);
|
||||
}
|
||||
}
|
||||
RESET_FMARK(&buf->b_last_change, ((pos_T) { lnum, col, 0 }), buf->handle, view);
|
||||
|
||||
@@ -3087,7 +3087,7 @@ static bool ins_esc(int *count, int cmdchar, bool nomove)
|
||||
|
||||
// Remember the last Insert position in the '^ mark.
|
||||
if ((cmdmod.cmod_flags & CMOD_KEEPJUMPS) == 0) {
|
||||
fmarkv_T view = mark_view_make(curwin->w_topline, curwin->w_cursor);
|
||||
fmarkv_T view = mark_view_make(curwin, curwin->w_cursor);
|
||||
RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum, view);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "nvim/os/time.h"
|
||||
#include "nvim/os/time_defs.h"
|
||||
#include "nvim/path.h"
|
||||
#include "nvim/plines.h"
|
||||
#include "nvim/pos_defs.h"
|
||||
#include "nvim/quickfix.h"
|
||||
#include "nvim/strings.h"
|
||||
@@ -63,7 +64,7 @@
|
||||
// Returns OK on success, FAIL if bad name given.
|
||||
int setmark(int c)
|
||||
{
|
||||
fmarkv_T view = mark_view_make(curwin->w_topline, curwin->w_cursor);
|
||||
fmarkv_T view = mark_view_make(curwin, curwin->w_cursor);
|
||||
return setmark_pos(c, &curwin->w_cursor, curbuf->b_fnum, &view);
|
||||
}
|
||||
|
||||
@@ -283,7 +284,7 @@ void setpcmark(void)
|
||||
curwin->w_jumplistidx = curwin->w_jumplistlen;
|
||||
fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
|
||||
|
||||
fmarkv_T view = mark_view_make(curwin->w_topline, curwin->w_pcmark);
|
||||
fmarkv_T view = mark_view_make(curwin, curwin->w_pcmark);
|
||||
SET_XFMARK(fm, curwin->w_pcmark, curbuf->b_fnum, view, NULL);
|
||||
}
|
||||
|
||||
@@ -691,13 +692,17 @@ void mark_view_restore(fmark_T *fm)
|
||||
// and this check can prevent restoring mark view in that case.
|
||||
if (topline >= 1) {
|
||||
set_topline(curwin, topline);
|
||||
curwin->w_skipcol = (fm->view.skipcol > 0
|
||||
&& !hasFolding(curwin, topline, NULL, NULL)
|
||||
&& fm->view.skipcol < linetabsize_eol(curwin, topline))
|
||||
? fm->view.skipcol : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmarkv_T mark_view_make(linenr_T topline, pos_T pos)
|
||||
fmarkv_T mark_view_make(const win_T *wp, pos_T pos)
|
||||
{
|
||||
return (fmarkv_T){ pos.lnum - topline };
|
||||
return (fmarkv_T){ pos.lnum - wp->w_topline, wp->w_skipcol };
|
||||
}
|
||||
|
||||
/// Search for the next named mark in the current file from a start position.
|
||||
|
||||
@@ -74,9 +74,10 @@ typedef enum {
|
||||
typedef struct {
|
||||
linenr_T topline_offset; ///< Amount of lines from the mark lnum to the top of the window.
|
||||
///< Use MAXLNUM to indicate that the mark does not have a view.
|
||||
colnr_T skipcol;
|
||||
} fmarkv_T;
|
||||
|
||||
#define INIT_FMARKV { MAXLNUM }
|
||||
#define INIT_FMARKV { MAXLNUM, 0 }
|
||||
|
||||
/// Structure defining single local mark
|
||||
typedef struct {
|
||||
|
||||
@@ -534,7 +534,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose)
|
||||
if (save_pos) {
|
||||
tagstack[tagstackidx].fmark.mark = curwin->w_cursor;
|
||||
tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum;
|
||||
tagstack[tagstackidx].fmark.view = mark_view_make(curwin->w_topline, curwin->w_cursor);
|
||||
tagstack[tagstackidx].fmark.view = mark_view_make(curwin, curwin->w_cursor);
|
||||
}
|
||||
|
||||
// Curwin will change in the call to jumpto_tag() if ":stag" was
|
||||
|
||||
@@ -55,44 +55,39 @@ describe('jumplist', function()
|
||||
write_file(fname1, ('foobar\n'):rep(100))
|
||||
write_file(fname2, 'baz')
|
||||
|
||||
local screen = Screen.new(5, 25)
|
||||
local screen = Screen.new(12, 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 |
|
||||
screen:expect([[
|
||||
{8: 24 }foobar |
|
||||
{8: 25 }foobar |
|
||||
{8: 26 }foobar |
|
||||
{8: 27 }foobar |
|
||||
{8: 28 }foobar |
|
||||
{8: 29 }foobar |
|
||||
{8: 30 }foobar |
|
||||
{8: 31 }foobar |
|
||||
{8: 32 }foobar |
|
||||
{8: 33 }foobar |
|
||||
{8: 34 }foobar |
|
||||
{8: 35 }^foobar |
|
||||
{8: 36 }foobar |
|
||||
{8: 37 }foobar |
|
||||
{8: 38 }foobar |
|
||||
{8: 39 }foobar |
|
||||
{8: 40 }foobar |
|
||||
{8: 41 }foobar |
|
||||
{8: 42 }foobar |
|
||||
{8: 43 }foobar |
|
||||
{8: 44 }foobar |
|
||||
{8: 45 }foobar |
|
||||
{8: 46 }foobar |
|
||||
{8: 47 }foobar |
|
||||
|
|
||||
]],
|
||||
attr_ids = {
|
||||
[1] = { foreground = Screen.colors.Brown },
|
||||
},
|
||||
}
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -384,65 +379,134 @@ describe('jumpoptions=view', function()
|
||||
end)
|
||||
|
||||
it('restores the view', function()
|
||||
local screen = Screen.new(5, 8)
|
||||
local screen = Screen.new(12, 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 |
|
||||
|
|
||||
12 line |
|
||||
^13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
16 line |
|
||||
17 line |
|
||||
18 line |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it("restores the view with 'smoothscroll'", function()
|
||||
local screen = Screen.new(12, 8)
|
||||
command('edit ' .. file1)
|
||||
command('setlocal smoothscroll')
|
||||
command([[call setline(24, repeat('a', 55))]])
|
||||
feed('12Gzz')
|
||||
local s1 = [[
|
||||
9 line |
|
||||
10 line |
|
||||
11 line |
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
|
|
||||
]]
|
||||
screen:expect(s1)
|
||||
feed('G')
|
||||
local s2 = [[
|
||||
{1:<<<}aaaa |
|
||||
25 line |
|
||||
26 line |
|
||||
27 line |
|
||||
28 line |
|
||||
29 line |
|
||||
^30 line |
|
||||
|
|
||||
]]
|
||||
screen:expect(s2)
|
||||
feed('<C-o>')
|
||||
screen:expect(s1)
|
||||
feed('<C-i>')
|
||||
screen:expect(s2)
|
||||
feed('<C-o>')
|
||||
screen:expect(s1)
|
||||
command([[call setline(10, repeat('a', 55))]])
|
||||
feed('zz')
|
||||
local s3 = [[
|
||||
{1:<<<}aaaaaaaaa|
|
||||
aaaaaaa |
|
||||
11 line |
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
|
|
||||
]]
|
||||
screen:expect(s3)
|
||||
feed('G')
|
||||
screen:expect(s2)
|
||||
feed('<C-o>')
|
||||
screen:expect(s3)
|
||||
feed('<C-i>')
|
||||
screen:expect(s2)
|
||||
command([[call setline(10, '10 line')]])
|
||||
feed('<C-o>')
|
||||
-- Topline should still be line 10, but skipcol should be reset.
|
||||
screen:expect([[
|
||||
10 line |
|
||||
11 line |
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
16 line |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('restores the view across files', function()
|
||||
local screen = Screen.new(5, 5)
|
||||
local screen = Screen.new(12, 5)
|
||||
command('args ' .. file1 .. ' ' .. file2)
|
||||
feed('12Gzt')
|
||||
command('next')
|
||||
feed('G')
|
||||
screen:expect([[
|
||||
27 line |
|
||||
28 line |
|
||||
29 line |
|
||||
^30 line |
|
||||
|
|
||||
27 line |
|
||||
28 line |
|
||||
29 line |
|
||||
^30 line |
|
||||
|
|
||||
]])
|
||||
feed('<C-o><C-o>')
|
||||
screen:expect([[
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
|
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('restores the view across files with <C-^>/:bprevious/:bnext', function()
|
||||
local screen = Screen.new(5, 5)
|
||||
local screen = Screen.new(12, 5)
|
||||
command('args ' .. file1 .. ' ' .. file2)
|
||||
feed('12Gzt')
|
||||
local s1 = [[
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
|
|
||||
^12 line |
|
||||
13 line |
|
||||
14 line |
|
||||
15 line |
|
||||
|
|
||||
]]
|
||||
screen:expect(s1)
|
||||
command('next')
|
||||
feed('G')
|
||||
local s2 = [[
|
||||
27 line |
|
||||
28 line |
|
||||
29 line |
|
||||
^30 line |
|
||||
|
|
||||
27 line |
|
||||
28 line |
|
||||
29 line |
|
||||
^30 line |
|
||||
|
|
||||
]]
|
||||
screen:expect(s2)
|
||||
feed('<C-^>')
|
||||
@@ -456,7 +520,7 @@ describe('jumpoptions=view', function()
|
||||
end)
|
||||
|
||||
it("falls back to standard behavior when view can't be recovered", function()
|
||||
local screen = Screen.new(5, 8)
|
||||
local screen = Screen.new(12, 8)
|
||||
command('edit ' .. file1)
|
||||
feed('7GzbG')
|
||||
api.nvim_buf_set_lines(0, 0, 2, true, {})
|
||||
@@ -468,19 +532,19 @@ describe('jumpoptions=view', function()
|
||||
-- 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 |
|
||||
|
|
||||
4 line |
|
||||
5 line |
|
||||
6 line |
|
||||
^7 line |
|
||||
8 line |
|
||||
9 line |
|
||||
10 line |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('falls back to standard behavior for a mark without a view', function()
|
||||
local screen = Screen.new(5, 8)
|
||||
local screen = Screen.new(12, 8)
|
||||
command('edit ' .. file1)
|
||||
feed('10ggzzvwy')
|
||||
screen:expect([[
|
||||
@@ -524,7 +588,7 @@ describe('jumpoptions=view', function()
|
||||
end)
|
||||
|
||||
it('restores the view', function()
|
||||
local screen = Screen.new(5, 6)
|
||||
local screen = Screen.new(12, 6)
|
||||
command('set laststatus=2 | set statusline=%f | edit ' .. file1)
|
||||
feed('10Gzb<C-]>30Gzt<C-]>')
|
||||
screen:expect([[
|
||||
|
||||
@@ -350,7 +350,7 @@ describe('named marks view', function()
|
||||
end)
|
||||
|
||||
it('is restored in normal mode but not op-pending mode', function()
|
||||
local screen = Screen.new(5, 8)
|
||||
local screen = Screen.new(12, 8)
|
||||
command('edit ' .. file1)
|
||||
feed('<C-e>jWma')
|
||||
feed("G'a")
|
||||
@@ -363,7 +363,7 @@ describe('named marks view', function()
|
||||
7 line |
|
||||
8 line |
|
||||
|
|
||||
]]
|
||||
]]
|
||||
screen:expect({ grid = expected })
|
||||
feed('G`a')
|
||||
screen:expect([[
|
||||
@@ -375,7 +375,7 @@ describe('named marks view', function()
|
||||
7 line |
|
||||
8 line |
|
||||
|
|
||||
]])
|
||||
]])
|
||||
-- not in op-pending mode #20886
|
||||
feed('ggj=`a')
|
||||
screen:expect([[
|
||||
@@ -387,35 +387,35 @@ describe('named marks view', function()
|
||||
6 line |
|
||||
7 line |
|
||||
|
|
||||
]])
|
||||
]])
|
||||
end)
|
||||
|
||||
it('is restored across files', function()
|
||||
local screen = Screen.new(5, 5)
|
||||
local screen = Screen.new(12, 5)
|
||||
command('args ' .. file1 .. ' ' .. file2)
|
||||
feed('<C-e>mA')
|
||||
local mark_view = [[
|
||||
^2 line |
|
||||
3 line |
|
||||
4 line |
|
||||
5 line |
|
||||
|
|
||||
^2 line |
|
||||
3 line |
|
||||
4 line |
|
||||
5 line |
|
||||
|
|
||||
]]
|
||||
screen:expect(mark_view)
|
||||
command('next')
|
||||
screen:expect([[
|
||||
^1 line |
|
||||
2 line |
|
||||
3 line |
|
||||
4 line |
|
||||
|
|
||||
^1 line |
|
||||
2 line |
|
||||
3 line |
|
||||
4 line |
|
||||
|
|
||||
]])
|
||||
feed("'A")
|
||||
screen:expect(mark_view)
|
||||
end)
|
||||
|
||||
it("fallback to standard behavior when view can't be recovered", function()
|
||||
local screen = Screen.new(10, 10)
|
||||
local screen = Screen.new(12, 10)
|
||||
command('edit ' .. file1)
|
||||
feed('7GzbmaG') -- Seven lines from the top
|
||||
command('new') -- Screen size for window is now half the height can't be restored
|
||||
@@ -429,11 +429,11 @@ describe('named marks view', function()
|
||||
8 line |
|
||||
{3:<itor-marks }|
|
||||
|
|
||||
]])
|
||||
]])
|
||||
end)
|
||||
|
||||
it('fallback to standard behavior when mark is loaded from shada', function()
|
||||
local screen = Screen.new(10, 6)
|
||||
local screen = Screen.new(12, 6)
|
||||
command('edit ' .. file1)
|
||||
feed('G')
|
||||
feed('mA')
|
||||
|
||||
Reference in New Issue
Block a user