vim-patch:9.0.0640: cannot scroll by screen line if a line wraps

Problem:    Cannot scroll by screen line if a line wraps.
Solution:   Add the 'smoothscroll' option.  Only works for CTRL-E and CTRL-Y
            so far.

f6196f4244

vim-patch:9.0.0641: missing part of the new option code

Problem:    Missing part of the new option code.
Solution:   Add missing WV_SMS.

bbbda8fd81

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
Luuk van Baal
2023-04-26 01:55:00 +02:00
parent fba18a3b62
commit be11f80d01
11 changed files with 311 additions and 22 deletions

View File

@@ -192,6 +192,8 @@ typedef struct {
#define w_p_rlc w_onebuf_opt.wo_rlc // 'rightleftcmd'
long wo_scr;
#define w_p_scr w_onebuf_opt.wo_scr // 'scroll'
int wo_sms;
#define w_p_sms w_onebuf_opt.wo_sms // 'smoothscroll'
int wo_spell;
#define w_p_spell w_onebuf_opt.wo_spell // 'spell'
int wo_cuc;
@@ -1163,11 +1165,12 @@ struct window_S {
bool w_botfill; // true when filler lines are actually
// below w_topline (at end of file)
bool w_old_botfill; // w_botfill at last redraw
colnr_T w_leftcol; // window column number of the left most
colnr_T w_leftcol; // screen column number of the left most
// character in the window; used when
// 'wrap' is off
colnr_T w_skipcol; // starting column when a single line
// doesn't fit in the window
colnr_T w_skipcol; // starting screen column for the first
// line in the window; used when 'wrap' is
// on
// six fields that are only used when there is a WinScrolled autocommand
linenr_T w_last_topline; ///< last known value for w_topline

View File

@@ -607,7 +607,7 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int si
// Draw the line number (empty space after wrapping).
if (wlv->row == wlv->startrow + wlv->filler_lines) {
get_line_number_str(wp, wlv->lnum, wlv->extra, sizeof(wlv->extra));
if (wp->w_skipcol > 0) {
if (wp->w_skipcol > 0 && wlv->startrow == 0) {
for (wlv->p_extra = wlv->extra; *wlv->p_extra == ' '; wlv->p_extra++) {
*wlv->p_extra = '-';
}
@@ -754,7 +754,7 @@ static void handle_breakindent(win_T *wp, winlinevars_T *wlv)
wlv->n_extra = 0;
}
}
if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) {
if (wp->w_skipcol > 0 && wlv->startrow == 0 && wp->w_p_wrap && wp->w_briopt_sbr) {
wlv->need_showbreak = false;
}
// Correct end of highlighted area for 'breakindent',
@@ -804,7 +804,7 @@ static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv)
wlv->c_final = NUL;
wlv->n_extra = (int)strlen(sbr);
wlv->char_attr = win_hl_attr(wp, HLF_AT);
if (wp->w_skipcol == 0 || !wp->w_p_wrap) {
if ((wp->w_skipcol == 0 && wlv->startrow == 0) || !wp->w_p_wrap) {
wlv->need_showbreak = false;
}
wlv->vcol_sbr = wlv->vcol + mb_charlen(sbr);
@@ -1379,7 +1379,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
// 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
// first character to be displayed.
if (wp->w_p_wrap) {
v = wp->w_skipcol;
v = startrow == 0 ? wp->w_skipcol : 0;
} else {
v = wp->w_leftcol;
}
@@ -2595,7 +2595,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
if (c == NUL) {
// Highlight 'cursorcolumn' & 'colorcolumn' past end of the line.
if (wp->w_p_wrap) {
v = wp->w_skipcol;
v = wlv.startrow == 0 ? wp->w_skipcol : 0;
} else {
v = wp->w_leftcol;
}

View File

@@ -57,6 +57,28 @@ typedef struct {
# include "move.c.generated.h"
#endif
/// Reduce "n" for the screen lines skipped with "wp->w_skipcol".
static int adjust_plines_for_skipcol(win_T *wp, int n)
{
if (wp->w_skipcol == 0) {
return n;
}
int off = 0;
int width = wp->w_width - win_col_off(wp);
if (wp->w_skipcol >= width) {
off++;
int skip = wp->w_skipcol - width;
width -= win_col_off2(wp);
while (skip >= width) {
off++;
skip -= width;
}
}
wp->w_valid &= ~VALID_WROW;
return n - off;
}
// Compute wp->w_botline for the current wp->w_topline. Can be called after
// wp->w_topline changed.
static void comp_botline(win_T *wp)
@@ -79,6 +101,9 @@ static void comp_botline(win_T *wp)
linenr_T last = lnum;
bool folded;
int n = plines_win_full(wp, lnum, &last, &folded, true);
if (lnum == wp->w_topline) {
n = adjust_plines_for_skipcol(wp, n);
}
if (lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum) {
wp->w_cline_row = done;
wp->w_cline_height = n;
@@ -565,6 +590,9 @@ static void curs_rows(win_T *wp)
linenr_T last = lnum;
bool folded;
int n = plines_win_full(wp, lnum, &last, &folded, false);
if (lnum == wp->w_topline) {
n = adjust_plines_for_skipcol(wp, n);
}
lnum = last + 1;
if (folded && lnum > wp->w_cursor.lnum) {
break;
@@ -907,7 +935,7 @@ void curs_columns(win_T *wp, int may_scroll)
// extra could be either positive or negative
extra = ((int)prev_skipcol - (int)wp->w_skipcol) / width;
win_scroll_lines(wp, 0, extra);
} else {
} else if (!wp->w_p_sms) {
wp->w_skipcol = 0;
}
if (prev_skipcol != wp->w_skipcol) {
@@ -1064,6 +1092,13 @@ void f_virtcol2col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
bool scrolldown(long line_count, int byfold)
{
int done = 0; // total # of physical lines done
int width1 = 0;
int width2 = 0;
if (curwin->w_p_wrap && curwin->w_p_sms) {
width1 = curwin->w_width - curwin_col_off();
width2 = width1 - curwin_col_off2();
}
// Make sure w_topline is at the first of a sequence of folded lines.
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
@@ -1074,22 +1109,48 @@ bool scrolldown(long line_count, int byfold)
curwin->w_topfill++;
done++;
} else {
if (curwin->w_topline == 1) {
if (curwin->w_topline == 1 && curwin->w_skipcol < width1) {
break;
}
curwin->w_topline--;
curwin->w_topfill = 0;
// A sequence of folded lines only counts for one logical line
linenr_T first;
if (hasFolding(curwin->w_topline, &first, NULL)) {
done++;
if (!byfold) {
line_count -= curwin->w_topline - first - 1;
if (curwin->w_p_wrap && curwin->w_p_sms && curwin->w_skipcol >= width1) {
if (curwin->w_skipcol >= width1 + width2) {
curwin->w_skipcol -= width2;
} else {
curwin->w_skipcol -= width1;
}
curwin->w_botline -= curwin->w_topline - first;
curwin->w_topline = first;
redraw_later(curwin, UPD_NOT_VALID);
done++;
} else {
done += plines_win_nofill(curwin, curwin->w_topline, true);
curwin->w_topline--;
curwin->w_skipcol = 0;
curwin->w_topfill = 0;
// A sequence of folded lines only counts for one logical line
linenr_T first;
if (hasFolding(curwin->w_topline, &first, NULL)) {
done++;
if (!byfold) {
line_count -= curwin->w_topline - first - 1;
}
curwin->w_botline -= curwin->w_topline - first;
curwin->w_topline = first;
} else {
if (curwin->w_p_wrap && curwin->w_p_sms) {
int size = (int)win_linetabsize(curwin, curwin->w_topline,
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
if (size > width1) {
curwin->w_skipcol = width1;
size -= width1;
redraw_later(curwin, UPD_NOT_VALID);
}
while (size > width2) {
curwin->w_skipcol += width2;
size -= width2;
}
done++;
} else {
done += plines_win_nofill(curwin, curwin->w_topline, true);
}
}
}
}
curwin->w_botline--; // approximate w_botline
@@ -1167,6 +1228,37 @@ bool scrollup(long line_count, int byfold)
// approximate w_botline
curwin->w_botline += lnum - curwin->w_topline;
curwin->w_topline = lnum;
} else if (curwin->w_p_wrap && curwin->w_p_sms) {
int off1 = curwin_col_off();
int off2 = off1 + curwin_col_off2();
int add;
int size = (int)win_linetabsize(curwin, curwin->w_topline,
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
linenr_T prev_topline = curwin->w_topline;
// 'smoothscroll': increase "w_skipcol" until it goes over the end of
// the line, then advance to the next line.
for (long todo = line_count; todo > 0; todo--) {
add = curwin->w_width - (curwin->w_skipcol > 0 ? off2 : off1);
curwin->w_skipcol += add;
if (curwin->w_skipcol >= size) {
if (curwin->w_topline == curbuf->b_ml.ml_line_count) {
curwin->w_skipcol -= add;
break;
}
curwin->w_topline++;
curwin->w_botline++; // approximate w_botline
curwin->w_skipcol = 0;
if (todo > 1) {
size = (int)win_linetabsize(curwin, curwin->w_topline,
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
}
}
}
if (curwin->w_topline == prev_topline) {
// need to redraw even though w_topline didn't change
redraw_later(curwin, UPD_NOT_VALID);
}
} else {
curwin->w_topline += (linenr_T)line_count;
curwin->w_botline += (linenr_T)line_count; // approximate w_botline

View File

@@ -2621,6 +2621,19 @@ static const char *did_set_showtabline(optset_T *args FUNC_ATTR_UNUSED)
return NULL;
}
/// Process the updated 'smoothscroll' option value.
static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED)
{
win_T *win = (win_T *)args->os_win;
if (win->w_p_sms) {
return NULL;
}
win->w_skipcol = 0;
changed_line_abv_curs_win(win);
return NULL;
}
/// Process the new 'foldlevel' option value.
static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED)
{
@@ -4417,6 +4430,8 @@ static char *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return (char *)&(win->w_p_rlc);
case PV_SCROLL:
return (char *)&(win->w_p_scr);
case PV_SMS:
return (char *)&(win->w_p_sms);
case PV_WRAP:
return (char *)&(win->w_p_wrap);
case PV_LBR:

View File

@@ -949,6 +949,7 @@ enum {
WV_RLC,
WV_SCBIND,
WV_SCROLL,
WV_SMS,
WV_SISO,
WV_SO,
WV_SPELL,

View File

@@ -2011,6 +2011,15 @@ return {
pv_name='p_scroll',
defaults={if_true=0}
},
{
full_name='smoothscroll', abbreviation='sms',
short_desc=N_("scroll by screen lines when 'wrap' is set"),
type='bool', scope={'window'},
pv_name='p_sms',
redraw={'current_window'},
defaults={if_true=0},
cb='did_set_smoothscroll'
},
{
full_name='scrollback', abbreviation='scbk',
short_desc=N_("lines to scroll with CTRL-U and CTRL-D"),