Buggy "gj" behavior with breakindent and showbreak

47 views
Skip to first unread message

Nazri Ramliy

unread,
Aug 27, 2014, 10:32:05 PM8/27/14
to vim_dev
Here's how to reproduce it in an 80-column terminal:

$ vi --version|head -2
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug 27 2014 13:10:11)
Included patches: 1-417
$ echo $COLUMNS
80
$ vi -u NONE -U NONE -c 'exec "normal 6i\<tab>\<esc>31Aa\<esc>A a"' -c
'set breakindent showbreak=\> ' -c 'normal ^'

The cursor is now placed on the first "a" character on the first line,
preceeded with 6 tabs, and we can see that the last "a" character is
breakindent-ed with ">" showbreak character on the "virtual" line due
to the breakindent. So far so good.

Here's the bug: Pressing "gj" in normal mode should move the cursor to
the virtual line below but in this case the cursors jumps to the end
of the first line instead.

Nazri.

Christian Brabandt

unread,
Aug 28, 2014, 4:32:59 PM8/28/14
to vim_dev
Looks like a breakindent bug, but also isn't ;)

you can also trigger the bug in a 80 column terminal with something like
this:
:let &sbr=repeat('>', 49)

Here is a patch:
diff --git a/src/normal.c b/src/normal.c
--- a/src/normal.c
+++ b/src/normal.c
@@ -4515,7 +4515,8 @@ nv_screengo(oap, dir, dist)
* screenline or move two screenlines.
*/
validate_virtcol();
- if (curwin->w_virtcol > curwin->w_curswant
+ if ((curwin->w_virtcol - (*p_sbr != NUL ? vim_strsize(p_sbr) : 0))
+ > curwin->w_curswant
&& (curwin->w_curswant < (colnr_T)width1
? (curwin->w_curswant > (colnr_T)width1 / 2)
: ((curwin->w_curswant - width1) % width2


I have to admit, I do not understand the comment right above it:

,----
| * Check for landing on a character that got split at the end of the
| * last line. We want to advance a screenline, not end up in the same
| * screenline or move two screenlines.
| */
`----

I am not sure, what kind of characters can be split at the end of a line
(screen line I guess)?

BTW: I just noticed, there is a similar bug in gj/gk and listmode

In this window:

,----------------------------------------
| 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
| --bbb
`----------------------------------------

And the cursor on the second a of line 1, pressing gj will move the
cursor the <Tab> at the last screen column in that window.

(To reproduce, in a 75 column terminal: vim -u NONE -N -c 'call
setline(1, repeat("a",73)."\tBBB")' -c ':set list listchars=tab:>-' -c
':norm! gj'

Ah, I just noticed this happens, because when listmode is off, the
cursor is always displayed at the end of a tab char, while when list
mode is on and there is a 'tab:' lcs-setting, the cursor will always be
drawn at the start of the tab. I didn't know that, so this should at
least be documented.

Best,
Christian
--
Man errät die Menschen am besten, wenn man sie bei Erzählungen um ihre
Vermutungen der unerzählten Zukunft fragt.
-- Jean Paul

Christian Brabandt

unread,
Aug 29, 2014, 6:14:59 AM8/29/14
to vim_dev
Better would be, to check, that the cursor is actually on a line, where
'sbr' is set, so here is an update:

diff --git a/src/normal.c b/src/normal.c
--- a/src/normal.c
+++ b/src/normal.c
@@ -4509,13 +4509,20 @@ nv_screengo(oap, dir, dist)
#if defined(FEAT_LINEBREAK) || defined(FEAT_MBYTE)
if (curwin->w_cursor.col > 0 && curwin->w_p_wrap)
{
+ colnr_T virtcol;
/*
* Check for landing on a character that got split at the end of the
* last line. We want to advance a screenline, not end up in the same
* screenline or move two screenlines.
*/
validate_virtcol();
- if (curwin->w_virtcol > curwin->w_curswant
+ virtcol = curwin->w_virtcol;
+
+ if (virtcol > (colnr_T)width1 &&
+ *p_sbr != NUL)
+ virtcol -= vim_strsize(p_sbr);
+
+ if (virtcol > curwin->w_curswant
&& (curwin->w_curswant < (colnr_T)width1
? (curwin->w_curswant > (colnr_T)width1 / 2)
: ((curwin->w_curswant - width1) % width2


Best,
Christian
--
Bisher hat der Glaube der Massen noch immer über die Vernunft der wenigen gesiegt.
Reply all
Reply to author
Forward
0 new messages