xref: /vim-8.2.3635/src/move.c (revision fb094e14)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 /*
10  * move.c: Functions for moving the cursor and scrolling text.
11  *
12  * There are two ways to move the cursor:
13  * 1. Move the cursor directly, the text is scrolled to keep the cursor in the
14  *    window.
15  * 2. Scroll the text, the cursor is moved into the text visible in the
16  *    window.
17  * The 'scrolloff' option makes this a bit complicated.
18  */
19 
20 #include "vim.h"
21 
22 static void comp_botline(win_T *wp);
23 static void redraw_for_cursorline(win_T *wp);
24 static int scrolljump_value(void);
25 static int check_top_offset(void);
26 static void curs_rows(win_T *wp);
27 static void validate_cheight(void);
28 
29 typedef struct
30 {
31     linenr_T	    lnum;	/* line number */
32 #ifdef FEAT_DIFF
33     int		    fill;	/* filler lines */
34 #endif
35     int		    height;	/* height of added line */
36 } lineoff_T;
37 
38 static void topline_back(lineoff_T *lp);
39 static void botline_forw(lineoff_T *lp);
40 #ifdef FEAT_DIFF
41 static void botline_topline(lineoff_T *lp);
42 static void topline_botline(lineoff_T *lp);
43 static void max_topfill(void);
44 #endif
45 
46 /*
47  * Compute wp->w_botline for the current wp->w_topline.  Can be called after
48  * wp->w_topline changed.
49  */
50     static void
51 comp_botline(win_T *wp)
52 {
53     int		n;
54     linenr_T	lnum;
55     int		done;
56 #ifdef FEAT_FOLDING
57     linenr_T    last;
58     int		folded;
59 #endif
60 
61     /*
62      * If w_cline_row is valid, start there.
63      * Otherwise have to start at w_topline.
64      */
65     check_cursor_moved(wp);
66     if (wp->w_valid & VALID_CROW)
67     {
68 	lnum = wp->w_cursor.lnum;
69 	done = wp->w_cline_row;
70     }
71     else
72     {
73 	lnum = wp->w_topline;
74 	done = 0;
75     }
76 
77     for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
78     {
79 #ifdef FEAT_FOLDING
80 	last = lnum;
81 	folded = FALSE;
82 	if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
83 	{
84 	    n = 1;
85 	    folded = TRUE;
86 	}
87 	else
88 #endif
89 #ifdef FEAT_DIFF
90 	    if (lnum == wp->w_topline)
91 		n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
92 	    else
93 #endif
94 		n = plines_win(wp, lnum, TRUE);
95 	if (
96 #ifdef FEAT_FOLDING
97 		lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum
98 #else
99 		lnum == wp->w_cursor.lnum
100 #endif
101 	   )
102 	{
103 	    wp->w_cline_row = done;
104 	    wp->w_cline_height = n;
105 #ifdef FEAT_FOLDING
106 	    wp->w_cline_folded = folded;
107 #endif
108 	    redraw_for_cursorline(wp);
109 	    wp->w_valid |= (VALID_CROW|VALID_CHEIGHT);
110 	}
111 	if (done + n > wp->w_height)
112 	    break;
113 	done += n;
114 #ifdef FEAT_FOLDING
115 	lnum = last;
116 #endif
117     }
118 
119     /* wp->w_botline is the line that is just below the window */
120     wp->w_botline = lnum;
121     wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
122 
123     set_empty_rows(wp, done);
124 }
125 
126 /*
127  * Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is
128  * set.
129  */
130     static void
131 redraw_for_cursorline(win_T *wp)
132 {
133     if ((wp->w_p_rnu
134 #ifdef FEAT_SYN_HL
135 		|| wp->w_p_cul
136 #endif
137 		)
138 	    && (wp->w_valid & VALID_CROW) == 0
139 # ifdef FEAT_INS_EXPAND
140 	    && !pum_visible()
141 # endif
142 	    )
143 	redraw_win_later(wp, SOME_VALID);
144 }
145 
146 /*
147  * Update curwin->w_topline and redraw if necessary.
148  * Used to update the screen before printing a message.
149  */
150     void
151 update_topline_redraw(void)
152 {
153     update_topline();
154     if (must_redraw)
155 	update_screen(0);
156 }
157 
158 /*
159  * Update curwin->w_topline to move the cursor onto the screen.
160  */
161     void
162 update_topline(void)
163 {
164     long	line_count;
165     int		halfheight;
166     int		n;
167     linenr_T	old_topline;
168 #ifdef FEAT_DIFF
169     int		old_topfill;
170 #endif
171 #ifdef FEAT_FOLDING
172     linenr_T	lnum;
173 #endif
174     int		check_topline = FALSE;
175     int		check_botline = FALSE;
176 #ifdef FEAT_MOUSE
177     int		save_so = p_so;
178 #endif
179 
180     /* If there is no valid screen and when the window height is zero just use
181      * the cursor line. */
182     if (!screen_valid(TRUE) || curwin->w_height == 0)
183     {
184 	curwin->w_topline = curwin->w_cursor.lnum;
185 	curwin->w_botline = curwin->w_topline;
186 	curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
187 #ifdef FEAT_SCROLLBIND
188 	curwin->w_scbind_pos = 1;
189 #endif
190 	return;
191     }
192 
193     check_cursor_moved(curwin);
194     if (curwin->w_valid & VALID_TOPLINE)
195 	return;
196 
197 #ifdef FEAT_MOUSE
198     /* When dragging with the mouse, don't scroll that quickly */
199     if (mouse_dragging > 0)
200 	p_so = mouse_dragging - 1;
201 #endif
202 
203     old_topline = curwin->w_topline;
204 #ifdef FEAT_DIFF
205     old_topfill = curwin->w_topfill;
206 #endif
207 
208     /*
209      * If the buffer is empty, always set topline to 1.
210      */
211     if (BUFEMPTY())		/* special case - file is empty */
212     {
213 	if (curwin->w_topline != 1)
214 	    redraw_later(NOT_VALID);
215 	curwin->w_topline = 1;
216 	curwin->w_botline = 2;
217 	curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
218 #ifdef FEAT_SCROLLBIND
219 	curwin->w_scbind_pos = 1;
220 #endif
221     }
222 
223     /*
224      * If the cursor is above or near the top of the window, scroll the window
225      * to show the line the cursor is in, with 'scrolloff' context.
226      */
227     else
228     {
229 	if (curwin->w_topline > 1)
230 	{
231 	    /* If the cursor is above topline, scrolling is always needed.
232 	     * If the cursor is far below topline and there is no folding,
233 	     * scrolling down is never needed. */
234 	    if (curwin->w_cursor.lnum < curwin->w_topline)
235 		check_topline = TRUE;
236 	    else if (check_top_offset())
237 		check_topline = TRUE;
238 	}
239 #ifdef FEAT_DIFF
240 	    /* Check if there are more filler lines than allowed. */
241 	if (!check_topline && curwin->w_topfill > diff_check_fill(curwin,
242 							   curwin->w_topline))
243 	    check_topline = TRUE;
244 #endif
245 
246 	if (check_topline)
247 	{
248 	    halfheight = curwin->w_height / 2 - 1;
249 	    if (halfheight < 2)
250 		halfheight = 2;
251 
252 #ifdef FEAT_FOLDING
253 	    if (hasAnyFolding(curwin))
254 	    {
255 		/* Count the number of logical lines between the cursor and
256 		 * topline + p_so (approximation of how much will be
257 		 * scrolled). */
258 		n = 0;
259 		for (lnum = curwin->w_cursor.lnum;
260 				      lnum < curwin->w_topline + p_so; ++lnum)
261 		{
262 		    ++n;
263 		    /* stop at end of file or when we know we are far off */
264 		    if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight)
265 			break;
266 		    (void)hasFolding(lnum, NULL, &lnum);
267 		}
268 	    }
269 	    else
270 #endif
271 		n = curwin->w_topline + p_so - curwin->w_cursor.lnum;
272 
273 	    /* If we weren't very close to begin with, we scroll to put the
274 	     * cursor in the middle of the window.  Otherwise put the cursor
275 	     * near the top of the window. */
276 	    if (n >= halfheight)
277 		scroll_cursor_halfway(FALSE);
278 	    else
279 	    {
280 		scroll_cursor_top(scrolljump_value(), FALSE);
281 		check_botline = TRUE;
282 	    }
283 	}
284 
285 	else
286 	{
287 #ifdef FEAT_FOLDING
288 	    /* Make sure topline is the first line of a fold. */
289 	    (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
290 #endif
291 	    check_botline = TRUE;
292 	}
293     }
294 
295     /*
296      * If the cursor is below the bottom of the window, scroll the window
297      * to put the cursor on the window.
298      * When w_botline is invalid, recompute it first, to avoid a redraw later.
299      * If w_botline was approximated, we might need a redraw later in a few
300      * cases, but we don't want to spend (a lot of) time recomputing w_botline
301      * for every small change.
302      */
303     if (check_botline)
304     {
305 	if (!(curwin->w_valid & VALID_BOTLINE_AP))
306 	    validate_botline();
307 
308 	if (curwin->w_botline <= curbuf->b_ml.ml_line_count)
309 	{
310 	    if (curwin->w_cursor.lnum < curwin->w_botline)
311 	    {
312 	      if (((long)curwin->w_cursor.lnum
313 					     >= (long)curwin->w_botline - p_so
314 #ifdef FEAT_FOLDING
315 			|| hasAnyFolding(curwin)
316 #endif
317 			))
318 	      {
319 		lineoff_T	loff;
320 
321 		/* Cursor is (a few lines) above botline, check if there are
322 		 * 'scrolloff' window lines below the cursor.  If not, need to
323 		 * scroll. */
324 		n = curwin->w_empty_rows;
325 		loff.lnum = curwin->w_cursor.lnum;
326 #ifdef FEAT_FOLDING
327 		/* In a fold go to its last line. */
328 		(void)hasFolding(loff.lnum, NULL, &loff.lnum);
329 #endif
330 #ifdef FEAT_DIFF
331 		loff.fill = 0;
332 		n += curwin->w_filler_rows;
333 #endif
334 		loff.height = 0;
335 		while (loff.lnum < curwin->w_botline
336 #ifdef FEAT_DIFF
337 			&& (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
338 #endif
339 			)
340 		{
341 		    n += loff.height;
342 		    if (n >= p_so)
343 			break;
344 		    botline_forw(&loff);
345 		}
346 		if (n >= p_so)
347 		    /* sufficient context, no need to scroll */
348 		    check_botline = FALSE;
349 	      }
350 	      else
351 		  /* sufficient context, no need to scroll */
352 		  check_botline = FALSE;
353 	    }
354 	    if (check_botline)
355 	    {
356 #ifdef FEAT_FOLDING
357 		if (hasAnyFolding(curwin))
358 		{
359 		    /* Count the number of logical lines between the cursor and
360 		     * botline - p_so (approximation of how much will be
361 		     * scrolled). */
362 		    line_count = 0;
363 		    for (lnum = curwin->w_cursor.lnum;
364 				     lnum >= curwin->w_botline - p_so; --lnum)
365 		    {
366 			++line_count;
367 			/* stop at end of file or when we know we are far off */
368 			if (lnum <= 0 || line_count > curwin->w_height + 1)
369 			    break;
370 			(void)hasFolding(lnum, &lnum, NULL);
371 		    }
372 		}
373 		else
374 #endif
375 		    line_count = curwin->w_cursor.lnum - curwin->w_botline
376 								   + 1 + p_so;
377 		if (line_count <= curwin->w_height + 1)
378 		    scroll_cursor_bot(scrolljump_value(), FALSE);
379 		else
380 		    scroll_cursor_halfway(FALSE);
381 	    }
382 	}
383     }
384     curwin->w_valid |= VALID_TOPLINE;
385 
386     /*
387      * Need to redraw when topline changed.
388      */
389     if (curwin->w_topline != old_topline
390 #ifdef FEAT_DIFF
391 	    || curwin->w_topfill != old_topfill
392 #endif
393 	    )
394     {
395 	dollar_vcol = -1;
396 	if (curwin->w_skipcol != 0)
397 	{
398 	    curwin->w_skipcol = 0;
399 	    redraw_later(NOT_VALID);
400 	}
401 	else
402 	    redraw_later(VALID);
403 	/* May need to set w_skipcol when cursor in w_topline. */
404 	if (curwin->w_cursor.lnum == curwin->w_topline)
405 	    validate_cursor();
406     }
407 
408 #ifdef FEAT_MOUSE
409     p_so = save_so;
410 #endif
411 }
412 
413 /*
414  * Return the scrolljump value to use for the current window.
415  * When 'scrolljump' is positive use it as-is.
416  * When 'scrolljump' is negative use it as a percentage of the window height.
417  */
418     static int
419 scrolljump_value(void)
420 {
421     if (p_sj >= 0)
422 	return (int)p_sj;
423     return (curwin->w_height * -p_sj) / 100;
424 }
425 
426 /*
427  * Return TRUE when there are not 'scrolloff' lines above the cursor for the
428  * current window.
429  */
430     static int
431 check_top_offset(void)
432 {
433     lineoff_T	loff;
434     int		n;
435 
436     if (curwin->w_cursor.lnum < curwin->w_topline + p_so
437 #ifdef FEAT_FOLDING
438 		    || hasAnyFolding(curwin)
439 #endif
440 	    )
441     {
442 	loff.lnum = curwin->w_cursor.lnum;
443 #ifdef FEAT_DIFF
444 	loff.fill = 0;
445 	n = curwin->w_topfill;	    /* always have this context */
446 #else
447 	n = 0;
448 #endif
449 	/* Count the visible screen lines above the cursor line. */
450 	while (n < p_so)
451 	{
452 	    topline_back(&loff);
453 	    /* Stop when included a line above the window. */
454 	    if (loff.lnum < curwin->w_topline
455 #ifdef FEAT_DIFF
456 		    || (loff.lnum == curwin->w_topline && loff.fill > 0)
457 #endif
458 		    )
459 		break;
460 	    n += loff.height;
461 	}
462 	if (n < p_so)
463 	    return TRUE;
464     }
465     return FALSE;
466 }
467 
468     void
469 update_curswant(void)
470 {
471     if (curwin->w_set_curswant)
472     {
473 	validate_virtcol();
474 	curwin->w_curswant = curwin->w_virtcol;
475 	curwin->w_set_curswant = FALSE;
476     }
477 }
478 
479 /*
480  * Check if the cursor has moved.  Set the w_valid flag accordingly.
481  */
482     void
483 check_cursor_moved(win_T *wp)
484 {
485     if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
486     {
487 	wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
488 				     |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
489 	wp->w_valid_cursor = wp->w_cursor;
490 	wp->w_valid_leftcol = wp->w_leftcol;
491     }
492     else if (wp->w_cursor.col != wp->w_valid_cursor.col
493 	     || wp->w_leftcol != wp->w_valid_leftcol
494 #ifdef FEAT_VIRTUALEDIT
495 	     || wp->w_cursor.coladd != wp->w_valid_cursor.coladd
496 #endif
497 	     )
498     {
499 	wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
500 	wp->w_valid_cursor.col = wp->w_cursor.col;
501 	wp->w_valid_leftcol = wp->w_leftcol;
502 #ifdef FEAT_VIRTUALEDIT
503 	wp->w_valid_cursor.coladd = wp->w_cursor.coladd;
504 #endif
505     }
506 }
507 
508 /*
509  * Call this function when some window settings have changed, which require
510  * the cursor position, botline and topline to be recomputed and the window to
511  * be redrawn.  E.g, when changing the 'wrap' option or folding.
512  */
513     void
514 changed_window_setting(void)
515 {
516     changed_window_setting_win(curwin);
517 }
518 
519     void
520 changed_window_setting_win(win_T *wp)
521 {
522     wp->w_lines_valid = 0;
523     changed_line_abv_curs_win(wp);
524     wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE);
525     redraw_win_later(wp, NOT_VALID);
526 }
527 
528 /*
529  * Set wp->w_topline to a certain number.
530  */
531     void
532 set_topline(win_T *wp, linenr_T lnum)
533 {
534 #ifdef FEAT_FOLDING
535     /* go to first of folded lines */
536     (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
537 #endif
538     /* Approximate the value of w_botline */
539     wp->w_botline += lnum - wp->w_topline;
540     wp->w_topline = lnum;
541 #ifdef FEAT_AUTOCMD
542     wp->w_topline_was_set = TRUE;
543 #endif
544 #ifdef FEAT_DIFF
545     wp->w_topfill = 0;
546 #endif
547     wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
548     /* Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. */
549     redraw_later(VALID);
550 }
551 
552 /*
553  * Call this function when the length of the cursor line (in screen
554  * characters) has changed, and the change is before the cursor.
555  * Need to take care of w_botline separately!
556  */
557     void
558 changed_cline_bef_curs(void)
559 {
560     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
561 						|VALID_CHEIGHT|VALID_TOPLINE);
562 }
563 
564     void
565 changed_cline_bef_curs_win(win_T *wp)
566 {
567     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
568 						|VALID_CHEIGHT|VALID_TOPLINE);
569 }
570 
571 /*
572  * Call this function when the length of a line (in screen characters) above
573  * the cursor have changed.
574  * Need to take care of w_botline separately!
575  */
576     void
577 changed_line_abv_curs(void)
578 {
579     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
580 						|VALID_CHEIGHT|VALID_TOPLINE);
581 }
582 
583     void
584 changed_line_abv_curs_win(win_T *wp)
585 {
586     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
587 						|VALID_CHEIGHT|VALID_TOPLINE);
588 }
589 
590 /*
591  * Make sure the value of curwin->w_botline is valid.
592  */
593     void
594 validate_botline(void)
595 {
596     if (!(curwin->w_valid & VALID_BOTLINE))
597 	comp_botline(curwin);
598 }
599 
600 /*
601  * Mark curwin->w_botline as invalid (because of some change in the buffer).
602  */
603     void
604 invalidate_botline(void)
605 {
606     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
607 }
608 
609     void
610 invalidate_botline_win(win_T *wp)
611 {
612     wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
613 }
614 
615     void
616 approximate_botline_win(
617     win_T	*wp)
618 {
619     wp->w_valid &= ~VALID_BOTLINE;
620 }
621 
622 /*
623  * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
624  */
625     int
626 cursor_valid(void)
627 {
628     check_cursor_moved(curwin);
629     return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
630 						      (VALID_WROW|VALID_WCOL));
631 }
632 
633 /*
634  * Validate cursor position.  Makes sure w_wrow and w_wcol are valid.
635  * w_topline must be valid, you may need to call update_topline() first!
636  */
637     void
638 validate_cursor(void)
639 {
640     check_cursor_moved(curwin);
641     if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
642 	curs_columns(TRUE);
643 }
644 
645 #if defined(FEAT_GUI) || defined(PROTO)
646 /*
647  * validate w_cline_row.
648  */
649     void
650 validate_cline_row(void)
651 {
652     /*
653      * First make sure that w_topline is valid (after moving the cursor).
654      */
655     update_topline();
656     check_cursor_moved(curwin);
657     if (!(curwin->w_valid & VALID_CROW))
658 	curs_rows(curwin);
659 }
660 #endif
661 
662 /*
663  * Compute wp->w_cline_row and wp->w_cline_height, based on the current value
664  * of wp->w_topline.
665  */
666     static void
667 curs_rows(win_T *wp)
668 {
669     linenr_T	lnum;
670     int		i;
671     int		all_invalid;
672     int		valid;
673 #ifdef FEAT_FOLDING
674     long	fold_count;
675 #endif
676 
677     /* Check if wp->w_lines[].wl_size is invalid */
678     all_invalid = (!redrawing()
679 			|| wp->w_lines_valid == 0
680 			|| wp->w_lines[0].wl_lnum > wp->w_topline);
681     i = 0;
682     wp->w_cline_row = 0;
683     for (lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i)
684     {
685 	valid = FALSE;
686 	if (!all_invalid && i < wp->w_lines_valid)
687 	{
688 	    if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid)
689 		continue;		/* skip changed or deleted lines */
690 	    if (wp->w_lines[i].wl_lnum == lnum)
691 	    {
692 #ifdef FEAT_FOLDING
693 		/* Check for newly inserted lines below this row, in which
694 		 * case we need to check for folded lines. */
695 		if (!wp->w_buffer->b_mod_set
696 			|| wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum
697 			|| wp->w_buffer->b_mod_top
698 					     > wp->w_lines[i].wl_lastlnum + 1)
699 #endif
700 		valid = TRUE;
701 	    }
702 	    else if (wp->w_lines[i].wl_lnum > lnum)
703 		--i;			/* hold at inserted lines */
704 	}
705 	if (valid
706 #ifdef FEAT_DIFF
707 		&& (lnum != wp->w_topline || !wp->w_p_diff)
708 #endif
709 		)
710 	{
711 #ifdef FEAT_FOLDING
712 	    lnum = wp->w_lines[i].wl_lastlnum + 1;
713 	    /* Cursor inside folded lines, don't count this row */
714 	    if (lnum > wp->w_cursor.lnum)
715 		break;
716 #else
717 	    ++lnum;
718 #endif
719 	    wp->w_cline_row += wp->w_lines[i].wl_size;
720 	}
721 	else
722 	{
723 #ifdef FEAT_FOLDING
724 	    fold_count = foldedCount(wp, lnum, NULL);
725 	    if (fold_count)
726 	    {
727 		lnum += fold_count;
728 		if (lnum > wp->w_cursor.lnum)
729 		    break;
730 		++wp->w_cline_row;
731 	    }
732 	    else
733 #endif
734 #ifdef FEAT_DIFF
735 		if (lnum == wp->w_topline)
736 		    wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE)
737 							      + wp->w_topfill;
738 		else
739 #endif
740 		    wp->w_cline_row += plines_win(wp, lnum++, TRUE);
741 	}
742     }
743 
744     check_cursor_moved(wp);
745     if (!(wp->w_valid & VALID_CHEIGHT))
746     {
747 	if (all_invalid
748 		|| i == wp->w_lines_valid
749 		|| (i < wp->w_lines_valid
750 		    && (!wp->w_lines[i].wl_valid
751 			|| wp->w_lines[i].wl_lnum != wp->w_cursor.lnum)))
752 	{
753 #ifdef FEAT_DIFF
754 	    if (wp->w_cursor.lnum == wp->w_topline)
755 		wp->w_cline_height = plines_win_nofill(wp, wp->w_cursor.lnum,
756 							TRUE) + wp->w_topfill;
757 	    else
758 #endif
759 		wp->w_cline_height = plines_win(wp, wp->w_cursor.lnum, TRUE);
760 #ifdef FEAT_FOLDING
761 	    wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
762 						      NULL, NULL, TRUE, NULL);
763 #endif
764 	}
765 	else if (i > wp->w_lines_valid)
766 	{
767 	    /* a line that is too long to fit on the last screen line */
768 	    wp->w_cline_height = 0;
769 #ifdef FEAT_FOLDING
770 	    wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
771 						      NULL, NULL, TRUE, NULL);
772 #endif
773 	}
774 	else
775 	{
776 	    wp->w_cline_height = wp->w_lines[i].wl_size;
777 #ifdef FEAT_FOLDING
778 	    wp->w_cline_folded = wp->w_lines[i].wl_folded;
779 #endif
780 	}
781     }
782 
783     redraw_for_cursorline(curwin);
784     wp->w_valid |= VALID_CROW|VALID_CHEIGHT;
785 
786 }
787 
788 /*
789  * Validate curwin->w_virtcol only.
790  */
791     void
792 validate_virtcol(void)
793 {
794     validate_virtcol_win(curwin);
795 }
796 
797 /*
798  * Validate wp->w_virtcol only.
799  */
800     void
801 validate_virtcol_win(win_T *wp)
802 {
803     check_cursor_moved(wp);
804     if (!(wp->w_valid & VALID_VIRTCOL))
805     {
806 	getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
807 	wp->w_valid |= VALID_VIRTCOL;
808 #ifdef FEAT_SYN_HL
809 	if (wp->w_p_cuc
810 # ifdef FEAT_INS_EXPAND
811 		&& !pum_visible()
812 # endif
813 		)
814 	    redraw_win_later(wp, SOME_VALID);
815 #endif
816     }
817 }
818 
819 /*
820  * Validate curwin->w_cline_height only.
821  */
822     static void
823 validate_cheight(void)
824 {
825     check_cursor_moved(curwin);
826     if (!(curwin->w_valid & VALID_CHEIGHT))
827     {
828 #ifdef FEAT_DIFF
829 	if (curwin->w_cursor.lnum == curwin->w_topline)
830 	    curwin->w_cline_height = plines_nofill(curwin->w_cursor.lnum)
831 							  + curwin->w_topfill;
832 	else
833 #endif
834 	    curwin->w_cline_height = plines(curwin->w_cursor.lnum);
835 #ifdef FEAT_FOLDING
836 	curwin->w_cline_folded = hasFolding(curwin->w_cursor.lnum, NULL, NULL);
837 #endif
838 	curwin->w_valid |= VALID_CHEIGHT;
839     }
840 }
841 
842 /*
843  * Validate w_wcol and w_virtcol only.
844  */
845     void
846 validate_cursor_col(void)
847 {
848     colnr_T off;
849     colnr_T col;
850     int     width;
851 
852     validate_virtcol();
853     if (!(curwin->w_valid & VALID_WCOL))
854     {
855 	col = curwin->w_virtcol;
856 	off = curwin_col_off();
857 	col += off;
858 	width = curwin->w_width - off + curwin_col_off2();
859 
860 	/* long line wrapping, adjust curwin->w_wrow */
861 	if (curwin->w_p_wrap
862 		&& col >= (colnr_T)curwin->w_width
863 		&& width > 0)
864 	    /* use same formula as what is used in curs_columns() */
865 	    col -= ((col - curwin->w_width) / width + 1) * width;
866 	if (col > (int)curwin->w_leftcol)
867 	    col -= curwin->w_leftcol;
868 	else
869 	    col = 0;
870 	curwin->w_wcol = col;
871 
872 	curwin->w_valid |= VALID_WCOL;
873     }
874 }
875 
876 /*
877  * Compute offset of a window, occupied by absolute or relative line number,
878  * fold column and sign column (these don't move when scrolling horizontally).
879  */
880     int
881 win_col_off(win_T *wp)
882 {
883     return (((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
884 #ifdef FEAT_CMDWIN
885 	    + (cmdwin_type == 0 || wp != curwin ? 0 : 1)
886 #endif
887 #ifdef FEAT_FOLDING
888 	    + wp->w_p_fdc
889 #endif
890 #ifdef FEAT_SIGNS
891 	    + (signcolumn_on(wp) ? 2 : 0)
892 #endif
893 	   );
894 }
895 
896     int
897 curwin_col_off(void)
898 {
899     return win_col_off(curwin);
900 }
901 
902 /*
903  * Return the difference in column offset for the second screen line of a
904  * wrapped line.  It's 8 if 'number' or 'relativenumber' is on and 'n' is in
905  * 'cpoptions'.
906  */
907     int
908 win_col_off2(win_T *wp)
909 {
910     if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
911 	return number_width(wp) + 1;
912     return 0;
913 }
914 
915     int
916 curwin_col_off2(void)
917 {
918     return win_col_off2(curwin);
919 }
920 
921 /*
922  * compute curwin->w_wcol and curwin->w_virtcol.
923  * Also updates curwin->w_wrow and curwin->w_cline_row.
924  * Also updates curwin->w_leftcol.
925  */
926     void
927 curs_columns(
928     int		may_scroll)	/* when TRUE, may scroll horizontally */
929 {
930     int		diff;
931     int		extra;		/* offset for first screen line */
932     int		off_left, off_right;
933     int		n;
934     int		p_lines;
935     int		width = 0;
936     int		textwidth;
937     int		new_leftcol;
938     colnr_T	startcol;
939     colnr_T	endcol;
940     colnr_T	prev_skipcol;
941 
942     /*
943      * First make sure that w_topline is valid (after moving the cursor).
944      */
945     update_topline();
946 
947     /*
948      * Next make sure that w_cline_row is valid.
949      */
950     if (!(curwin->w_valid & VALID_CROW))
951 	curs_rows(curwin);
952 
953     /*
954      * Compute the number of virtual columns.
955      */
956 #ifdef FEAT_FOLDING
957     if (curwin->w_cline_folded)
958 	/* In a folded line the cursor is always in the first column */
959 	startcol = curwin->w_virtcol = endcol = curwin->w_leftcol;
960     else
961 #endif
962 	getvvcol(curwin, &curwin->w_cursor,
963 				&startcol, &(curwin->w_virtcol), &endcol);
964 
965     /* remove '$' from change command when cursor moves onto it */
966     if (startcol > dollar_vcol)
967 	dollar_vcol = -1;
968 
969     extra = curwin_col_off();
970     curwin->w_wcol = curwin->w_virtcol + extra;
971     endcol += extra;
972 
973     /*
974      * Now compute w_wrow, counting screen lines from w_cline_row.
975      */
976     curwin->w_wrow = curwin->w_cline_row;
977 
978     textwidth = curwin->w_width - extra;
979     if (textwidth <= 0)
980     {
981 	/* No room for text, put cursor in last char of window. */
982 	curwin->w_wcol = curwin->w_width - 1;
983 	curwin->w_wrow = curwin->w_height - 1;
984     }
985     else if (curwin->w_p_wrap && curwin->w_width != 0)
986     {
987 	width = textwidth + curwin_col_off2();
988 
989 	/* long line wrapping, adjust curwin->w_wrow */
990 	if (curwin->w_wcol >= curwin->w_width)
991 	{
992 	    /* this same formula is used in validate_cursor_col() */
993 	    n = (curwin->w_wcol - curwin->w_width) / width + 1;
994 	    curwin->w_wcol -= n * width;
995 	    curwin->w_wrow += n;
996 
997 #ifdef FEAT_LINEBREAK
998 	    /* When cursor wraps to first char of next line in Insert
999 	     * mode, the 'showbreak' string isn't shown, backup to first
1000 	     * column */
1001 	    if (*p_sbr && *ml_get_cursor() == NUL
1002 		    && curwin->w_wcol == (int)vim_strsize(p_sbr))
1003 		curwin->w_wcol = 0;
1004 #endif
1005 	}
1006     }
1007 
1008     /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
1009      * is not folded.
1010      * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
1011     else if (may_scroll
1012 #ifdef FEAT_FOLDING
1013 	    && !curwin->w_cline_folded
1014 #endif
1015 	    )
1016     {
1017 	/*
1018 	 * If Cursor is left of the screen, scroll rightwards.
1019 	 * If Cursor is right of the screen, scroll leftwards
1020 	 * If we get closer to the edge than 'sidescrolloff', scroll a little
1021 	 * extra
1022 	 */
1023 	off_left = (int)startcol - (int)curwin->w_leftcol - p_siso;
1024 	off_right = (int)endcol - (int)(curwin->w_leftcol + curwin->w_width
1025 								- p_siso) + 1;
1026 	if (off_left < 0 || off_right > 0)
1027 	{
1028 	    if (off_left < 0)
1029 		diff = -off_left;
1030 	    else
1031 		diff = off_right;
1032 
1033 	    /* When far off or not enough room on either side, put cursor in
1034 	     * middle of window. */
1035 	    if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left)
1036 		new_leftcol = curwin->w_wcol - extra - textwidth / 2;
1037 	    else
1038 	    {
1039 		if (diff < p_ss)
1040 		    diff = p_ss;
1041 		if (off_left < 0)
1042 		    new_leftcol = curwin->w_leftcol - diff;
1043 		else
1044 		    new_leftcol = curwin->w_leftcol + diff;
1045 	    }
1046 	    if (new_leftcol < 0)
1047 		new_leftcol = 0;
1048 	    if (new_leftcol != (int)curwin->w_leftcol)
1049 	    {
1050 		curwin->w_leftcol = new_leftcol;
1051 		/* screen has to be redrawn with new curwin->w_leftcol */
1052 		redraw_later(NOT_VALID);
1053 	    }
1054 	}
1055 	curwin->w_wcol -= curwin->w_leftcol;
1056     }
1057     else if (curwin->w_wcol > (int)curwin->w_leftcol)
1058 	curwin->w_wcol -= curwin->w_leftcol;
1059     else
1060 	curwin->w_wcol = 0;
1061 
1062 #ifdef FEAT_DIFF
1063     /* Skip over filler lines.  At the top use w_topfill, there
1064      * may be some filler lines above the window. */
1065     if (curwin->w_cursor.lnum == curwin->w_topline)
1066 	curwin->w_wrow += curwin->w_topfill;
1067     else
1068 	curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
1069 #endif
1070 
1071     prev_skipcol = curwin->w_skipcol;
1072 
1073     p_lines = 0;
1074     if ((curwin->w_wrow >= curwin->w_height
1075 		|| ((prev_skipcol > 0
1076 			|| curwin->w_wrow + p_so >= curwin->w_height)
1077 		    && (p_lines =
1078 #ifdef FEAT_DIFF
1079 			plines_win_nofill
1080 #else
1081 			plines_win
1082 #endif
1083 			(curwin, curwin->w_cursor.lnum, FALSE))
1084 						    - 1 >= curwin->w_height))
1085 	    && curwin->w_height != 0
1086 	    && curwin->w_cursor.lnum == curwin->w_topline
1087 	    && width > 0
1088 	    && curwin->w_width != 0)
1089     {
1090 	/* Cursor past end of screen.  Happens with a single line that does
1091 	 * not fit on screen.  Find a skipcol to show the text around the
1092 	 * cursor.  Avoid scrolling all the time. compute value of "extra":
1093 	 * 1: Less than "p_so" lines above
1094 	 * 2: Less than "p_so" lines below
1095 	 * 3: both of them */
1096 	extra = 0;
1097 	if (curwin->w_skipcol + p_so * width > curwin->w_virtcol)
1098 	    extra = 1;
1099 	/* Compute last display line of the buffer line that we want at the
1100 	 * bottom of the window. */
1101 	if (p_lines == 0)
1102 	    p_lines = plines_win(curwin, curwin->w_cursor.lnum, FALSE);
1103 	--p_lines;
1104 	if (p_lines > curwin->w_wrow + p_so)
1105 	    n = curwin->w_wrow + p_so;
1106 	else
1107 	    n = p_lines;
1108 	if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width)
1109 	    extra += 2;
1110 
1111 	if (extra == 3 || p_lines < p_so * 2)
1112 	{
1113 	    /* not enough room for 'scrolloff', put cursor in the middle */
1114 	    n = curwin->w_virtcol / width;
1115 	    if (n > curwin->w_height / 2)
1116 		n -= curwin->w_height / 2;
1117 	    else
1118 		n = 0;
1119 	    /* don't skip more than necessary */
1120 	    if (n > p_lines - curwin->w_height + 1)
1121 		n = p_lines - curwin->w_height + 1;
1122 	    curwin->w_skipcol = n * width;
1123 	}
1124 	else if (extra == 1)
1125 	{
1126 	    /* less then 'scrolloff' lines above, decrease skipcol */
1127 	    extra = (curwin->w_skipcol + p_so * width - curwin->w_virtcol
1128 				     + width - 1) / width;
1129 	    if (extra > 0)
1130 	    {
1131 		if ((colnr_T)(extra * width) > curwin->w_skipcol)
1132 		    extra = curwin->w_skipcol / width;
1133 		curwin->w_skipcol -= extra * width;
1134 	    }
1135 	}
1136 	else if (extra == 2)
1137 	{
1138 	    /* less then 'scrolloff' lines below, increase skipcol */
1139 	    endcol = (n - curwin->w_height + 1) * width;
1140 	    while (endcol > curwin->w_virtcol)
1141 		endcol -= width;
1142 	    if (endcol > curwin->w_skipcol)
1143 		curwin->w_skipcol = endcol;
1144 	}
1145 
1146 	curwin->w_wrow -= curwin->w_skipcol / width;
1147 	if (curwin->w_wrow >= curwin->w_height)
1148 	{
1149 	    /* small window, make sure cursor is in it */
1150 	    extra = curwin->w_wrow - curwin->w_height + 1;
1151 	    curwin->w_skipcol += extra * width;
1152 	    curwin->w_wrow -= extra;
1153 	}
1154 
1155 	extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
1156 	if (extra > 0)
1157 	    win_ins_lines(curwin, 0, extra, FALSE, FALSE);
1158 	else if (extra < 0)
1159 	    win_del_lines(curwin, 0, -extra, FALSE, FALSE, 0);
1160     }
1161     else
1162 	curwin->w_skipcol = 0;
1163     if (prev_skipcol != curwin->w_skipcol)
1164 	redraw_later(NOT_VALID);
1165 
1166 #ifdef FEAT_SYN_HL
1167     /* Redraw when w_virtcol changes and 'cursorcolumn' is set */
1168     if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0
1169 # ifdef FEAT_INS_EXPAND
1170 	    && !pum_visible()
1171 # endif
1172 	)
1173 	redraw_later(SOME_VALID);
1174 #endif
1175 
1176     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
1177 }
1178 
1179 /*
1180  * Scroll the current window down by "line_count" logical lines.  "CTRL-Y"
1181  */
1182     void
1183 scrolldown(
1184     long	line_count,
1185     int		byfold UNUSED)	/* TRUE: count a closed fold as one line */
1186 {
1187     long	done = 0;	/* total # of physical lines done */
1188     int		wrow;
1189     int		moved = FALSE;
1190 
1191 #ifdef FEAT_FOLDING
1192     linenr_T	first;
1193 
1194     /* Make sure w_topline is at the first of a sequence of folded lines. */
1195     (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1196 #endif
1197     validate_cursor();		/* w_wrow needs to be valid */
1198     while (line_count-- > 0)
1199     {
1200 #ifdef FEAT_DIFF
1201 	if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)
1202 		&& curwin->w_topfill < curwin->w_height - 1)
1203 	{
1204 	    ++curwin->w_topfill;
1205 	    ++done;
1206 	}
1207 	else
1208 #endif
1209 	{
1210 	    if (curwin->w_topline == 1)
1211 		break;
1212 	    --curwin->w_topline;
1213 #ifdef FEAT_DIFF
1214 	    curwin->w_topfill = 0;
1215 #endif
1216 #ifdef FEAT_FOLDING
1217 	    /* A sequence of folded lines only counts for one logical line */
1218 	    if (hasFolding(curwin->w_topline, &first, NULL))
1219 	    {
1220 		++done;
1221 		if (!byfold)
1222 		    line_count -= curwin->w_topline - first - 1;
1223 		curwin->w_botline -= curwin->w_topline - first;
1224 		curwin->w_topline = first;
1225 	    }
1226 	    else
1227 #endif
1228 		done += PLINES_NOFILL(curwin->w_topline);
1229 	}
1230 	--curwin->w_botline;		/* approximate w_botline */
1231 	invalidate_botline();
1232     }
1233     curwin->w_wrow += done;		/* keep w_wrow updated */
1234     curwin->w_cline_row += done;	/* keep w_cline_row updated */
1235 
1236 #ifdef FEAT_DIFF
1237     if (curwin->w_cursor.lnum == curwin->w_topline)
1238 	curwin->w_cline_row = 0;
1239     check_topfill(curwin, TRUE);
1240 #endif
1241 
1242     /*
1243      * Compute the row number of the last row of the cursor line
1244      * and move the cursor onto the displayed part of the window.
1245      */
1246     wrow = curwin->w_wrow;
1247     if (curwin->w_p_wrap && curwin->w_width != 0)
1248     {
1249 	validate_virtcol();
1250 	validate_cheight();
1251 	wrow += curwin->w_cline_height - 1 -
1252 	    curwin->w_virtcol / curwin->w_width;
1253     }
1254     while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
1255     {
1256 #ifdef FEAT_FOLDING
1257 	if (hasFolding(curwin->w_cursor.lnum, &first, NULL))
1258 	{
1259 	    --wrow;
1260 	    if (first == 1)
1261 		curwin->w_cursor.lnum = 1;
1262 	    else
1263 		curwin->w_cursor.lnum = first - 1;
1264 	}
1265 	else
1266 #endif
1267 	    wrow -= plines(curwin->w_cursor.lnum--);
1268 	curwin->w_valid &=
1269 	      ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
1270 	moved = TRUE;
1271     }
1272     if (moved)
1273     {
1274 #ifdef FEAT_FOLDING
1275 	/* Move cursor to first line of closed fold. */
1276 	foldAdjustCursor();
1277 #endif
1278 	coladvance(curwin->w_curswant);
1279     }
1280 }
1281 
1282 /*
1283  * Scroll the current window up by "line_count" logical lines.  "CTRL-E"
1284  */
1285     void
1286 scrollup(
1287     long	line_count,
1288     int		byfold UNUSED)	/* TRUE: count a closed fold as one line */
1289 {
1290 #if defined(FEAT_FOLDING) || defined(FEAT_DIFF)
1291     linenr_T	lnum;
1292 
1293     if (
1294 # ifdef FEAT_FOLDING
1295 	    (byfold && hasAnyFolding(curwin))
1296 #  ifdef FEAT_DIFF
1297 	    ||
1298 #  endif
1299 # endif
1300 # ifdef FEAT_DIFF
1301 	    curwin->w_p_diff
1302 # endif
1303 	    )
1304     {
1305 	/* count each sequence of folded lines as one logical line */
1306 	lnum = curwin->w_topline;
1307 	while (line_count--)
1308 	{
1309 # ifdef FEAT_DIFF
1310 	    if (curwin->w_topfill > 0)
1311 		--curwin->w_topfill;
1312 	    else
1313 # endif
1314 	    {
1315 # ifdef FEAT_FOLDING
1316 		if (byfold)
1317 		    (void)hasFolding(lnum, NULL, &lnum);
1318 # endif
1319 		if (lnum >= curbuf->b_ml.ml_line_count)
1320 		    break;
1321 		++lnum;
1322 # ifdef FEAT_DIFF
1323 		curwin->w_topfill = diff_check_fill(curwin, lnum);
1324 # endif
1325 	    }
1326 	}
1327 	/* approximate w_botline */
1328 	curwin->w_botline += lnum - curwin->w_topline;
1329 	curwin->w_topline = lnum;
1330     }
1331     else
1332 #endif
1333     {
1334 	curwin->w_topline += line_count;
1335 	curwin->w_botline += line_count;	/* approximate w_botline */
1336     }
1337 
1338     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1339 	curwin->w_topline = curbuf->b_ml.ml_line_count;
1340     if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1)
1341 	curwin->w_botline = curbuf->b_ml.ml_line_count + 1;
1342 
1343 #ifdef FEAT_DIFF
1344     check_topfill(curwin, FALSE);
1345 #endif
1346 
1347 #ifdef FEAT_FOLDING
1348     if (hasAnyFolding(curwin))
1349 	/* Make sure w_topline is at the first of a sequence of folded lines. */
1350 	(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1351 #endif
1352 
1353     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1354     if (curwin->w_cursor.lnum < curwin->w_topline)
1355     {
1356 	curwin->w_cursor.lnum = curwin->w_topline;
1357 	curwin->w_valid &=
1358 	      ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
1359 	coladvance(curwin->w_curswant);
1360     }
1361 }
1362 
1363 #ifdef FEAT_DIFF
1364 /*
1365  * Don't end up with too many filler lines in the window.
1366  */
1367     void
1368 check_topfill(
1369     win_T	*wp,
1370     int		down)	/* when TRUE scroll down when not enough space */
1371 {
1372     int		n;
1373 
1374     if (wp->w_topfill > 0)
1375     {
1376 	n = plines_win_nofill(wp, wp->w_topline, TRUE);
1377 	if (wp->w_topfill + n > wp->w_height)
1378 	{
1379 	    if (down && wp->w_topline > 1)
1380 	    {
1381 		--wp->w_topline;
1382 		wp->w_topfill = 0;
1383 	    }
1384 	    else
1385 	    {
1386 		wp->w_topfill = wp->w_height - n;
1387 		if (wp->w_topfill < 0)
1388 		    wp->w_topfill = 0;
1389 	    }
1390 	}
1391     }
1392 }
1393 
1394 /*
1395  * Use as many filler lines as possible for w_topline.  Make sure w_topline
1396  * is still visible.
1397  */
1398     static void
1399 max_topfill(void)
1400 {
1401     int		n;
1402 
1403     n = plines_nofill(curwin->w_topline);
1404     if (n >= curwin->w_height)
1405 	curwin->w_topfill = 0;
1406     else
1407     {
1408 	curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
1409 	if (curwin->w_topfill + n > curwin->w_height)
1410 	    curwin->w_topfill = curwin->w_height - n;
1411     }
1412 }
1413 #endif
1414 
1415 #if defined(FEAT_INS_EXPAND) || defined(PROTO)
1416 /*
1417  * Scroll the screen one line down, but don't do it if it would move the
1418  * cursor off the screen.
1419  */
1420     void
1421 scrolldown_clamp(void)
1422 {
1423     int		end_row;
1424 #ifdef FEAT_DIFF
1425     int		can_fill = (curwin->w_topfill
1426 				< diff_check_fill(curwin, curwin->w_topline));
1427 #endif
1428 
1429     if (curwin->w_topline <= 1
1430 #ifdef FEAT_DIFF
1431 	    && !can_fill
1432 #endif
1433 	    )
1434 	return;
1435 
1436     validate_cursor();	    /* w_wrow needs to be valid */
1437 
1438     /*
1439      * Compute the row number of the last row of the cursor line
1440      * and make sure it doesn't go off the screen. Make sure the cursor
1441      * doesn't go past 'scrolloff' lines from the screen end.
1442      */
1443     end_row = curwin->w_wrow;
1444 #ifdef FEAT_DIFF
1445     if (can_fill)
1446 	++end_row;
1447     else
1448 	end_row += plines_nofill(curwin->w_topline - 1);
1449 #else
1450     end_row += plines(curwin->w_topline - 1);
1451 #endif
1452     if (curwin->w_p_wrap && curwin->w_width != 0)
1453     {
1454 	validate_cheight();
1455 	validate_virtcol();
1456 	end_row += curwin->w_cline_height - 1 -
1457 	    curwin->w_virtcol / curwin->w_width;
1458     }
1459     if (end_row < curwin->w_height - p_so)
1460     {
1461 #ifdef FEAT_DIFF
1462 	if (can_fill)
1463 	{
1464 	    ++curwin->w_topfill;
1465 	    check_topfill(curwin, TRUE);
1466 	}
1467 	else
1468 	{
1469 	    --curwin->w_topline;
1470 	    curwin->w_topfill = 0;
1471 	}
1472 #else
1473 	--curwin->w_topline;
1474 #endif
1475 #ifdef FEAT_FOLDING
1476 	(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1477 #endif
1478 	--curwin->w_botline;	    /* approximate w_botline */
1479 	curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1480     }
1481 }
1482 
1483 /*
1484  * Scroll the screen one line up, but don't do it if it would move the cursor
1485  * off the screen.
1486  */
1487     void
1488 scrollup_clamp(void)
1489 {
1490     int	    start_row;
1491 
1492     if (curwin->w_topline == curbuf->b_ml.ml_line_count
1493 #ifdef FEAT_DIFF
1494 	    && curwin->w_topfill == 0
1495 #endif
1496 	    )
1497 	return;
1498 
1499     validate_cursor();	    /* w_wrow needs to be valid */
1500 
1501     /*
1502      * Compute the row number of the first row of the cursor line
1503      * and make sure it doesn't go off the screen. Make sure the cursor
1504      * doesn't go before 'scrolloff' lines from the screen start.
1505      */
1506 #ifdef FEAT_DIFF
1507     start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
1508 							  - curwin->w_topfill;
1509 #else
1510     start_row = curwin->w_wrow - plines(curwin->w_topline);
1511 #endif
1512     if (curwin->w_p_wrap && curwin->w_width != 0)
1513     {
1514 	validate_virtcol();
1515 	start_row -= curwin->w_virtcol / curwin->w_width;
1516     }
1517     if (start_row >= p_so)
1518     {
1519 #ifdef FEAT_DIFF
1520 	if (curwin->w_topfill > 0)
1521 	    --curwin->w_topfill;
1522 	else
1523 #endif
1524 	{
1525 #ifdef FEAT_FOLDING
1526 	    (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
1527 #endif
1528 	    ++curwin->w_topline;
1529 	}
1530 	++curwin->w_botline;		/* approximate w_botline */
1531 	curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1532     }
1533 }
1534 #endif /* FEAT_INS_EXPAND */
1535 
1536 /*
1537  * Add one line above "lp->lnum".  This can be a filler line, a closed fold or
1538  * a (wrapped) text line.  Uses and sets "lp->fill".
1539  * Returns the height of the added line in "lp->height".
1540  * Lines above the first one are incredibly high: MAXCOL.
1541  */
1542     static void
1543 topline_back(lineoff_T *lp)
1544 {
1545 #ifdef FEAT_DIFF
1546     if (lp->fill < diff_check_fill(curwin, lp->lnum))
1547     {
1548 	/* Add a filler line. */
1549 	++lp->fill;
1550 	lp->height = 1;
1551     }
1552     else
1553 #endif
1554     {
1555 	--lp->lnum;
1556 #ifdef FEAT_DIFF
1557 	lp->fill = 0;
1558 #endif
1559 	if (lp->lnum < 1)
1560 	    lp->height = MAXCOL;
1561 	else
1562 #ifdef FEAT_FOLDING
1563 	    if (hasFolding(lp->lnum, &lp->lnum, NULL))
1564 	    /* Add a closed fold */
1565 	    lp->height = 1;
1566 	else
1567 #endif
1568 	    lp->height = PLINES_NOFILL(lp->lnum);
1569     }
1570 }
1571 
1572 /*
1573  * Add one line below "lp->lnum".  This can be a filler line, a closed fold or
1574  * a (wrapped) text line.  Uses and sets "lp->fill".
1575  * Returns the height of the added line in "lp->height".
1576  * Lines below the last one are incredibly high.
1577  */
1578     static void
1579 botline_forw(lineoff_T *lp)
1580 {
1581 #ifdef FEAT_DIFF
1582     if (lp->fill < diff_check_fill(curwin, lp->lnum + 1))
1583     {
1584 	/* Add a filler line. */
1585 	++lp->fill;
1586 	lp->height = 1;
1587     }
1588     else
1589 #endif
1590     {
1591 	++lp->lnum;
1592 #ifdef FEAT_DIFF
1593 	lp->fill = 0;
1594 #endif
1595 	if (lp->lnum > curbuf->b_ml.ml_line_count)
1596 	    lp->height = MAXCOL;
1597 	else
1598 #ifdef FEAT_FOLDING
1599 	    if (hasFolding(lp->lnum, NULL, &lp->lnum))
1600 	    /* Add a closed fold */
1601 	    lp->height = 1;
1602 	else
1603 #endif
1604 	{
1605 	    lp->height = PLINES_NOFILL(lp->lnum);
1606 	}
1607     }
1608 }
1609 
1610 #ifdef FEAT_DIFF
1611 /*
1612  * Switch from including filler lines below lp->lnum to including filler
1613  * lines above loff.lnum + 1.  This keeps pointing to the same line.
1614  * When there are no filler lines nothing changes.
1615  */
1616     static void
1617 botline_topline(lineoff_T *lp)
1618 {
1619     if (lp->fill > 0)
1620     {
1621 	++lp->lnum;
1622 	lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
1623     }
1624 }
1625 
1626 /*
1627  * Switch from including filler lines above lp->lnum to including filler
1628  * lines below loff.lnum - 1.  This keeps pointing to the same line.
1629  * When there are no filler lines nothing changes.
1630  */
1631     static void
1632 topline_botline(lineoff_T *lp)
1633 {
1634     if (lp->fill > 0)
1635     {
1636 	lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
1637 	--lp->lnum;
1638     }
1639 }
1640 #endif
1641 
1642 /*
1643  * Recompute topline to put the cursor at the top of the window.
1644  * Scroll at least "min_scroll" lines.
1645  * If "always" is TRUE, always set topline (for "zt").
1646  */
1647     void
1648 scroll_cursor_top(int min_scroll, int always)
1649 {
1650     int		scrolled = 0;
1651     int		extra = 0;
1652     int		used;
1653     int		i;
1654     linenr_T	top;		/* just above displayed lines */
1655     linenr_T	bot;		/* just below displayed lines */
1656     linenr_T	old_topline = curwin->w_topline;
1657 #ifdef FEAT_DIFF
1658     linenr_T	old_topfill = curwin->w_topfill;
1659 #endif
1660     linenr_T	new_topline;
1661     int		off = p_so;
1662 
1663 #ifdef FEAT_MOUSE
1664     if (mouse_dragging > 0)
1665 	off = mouse_dragging - 1;
1666 #endif
1667 
1668     /*
1669      * Decrease topline until:
1670      * - it has become 1
1671      * - (part of) the cursor line is moved off the screen or
1672      * - moved at least 'scrolljump' lines and
1673      * - at least 'scrolloff' lines above and below the cursor
1674      */
1675     validate_cheight();
1676     used = curwin->w_cline_height; /* includes filler lines above */
1677     if (curwin->w_cursor.lnum < curwin->w_topline)
1678 	scrolled = used;
1679 
1680 #ifdef FEAT_FOLDING
1681     if (hasFolding(curwin->w_cursor.lnum, &top, &bot))
1682     {
1683 	--top;
1684 	++bot;
1685     }
1686     else
1687 #endif
1688     {
1689 	top = curwin->w_cursor.lnum - 1;
1690 	bot = curwin->w_cursor.lnum + 1;
1691     }
1692     new_topline = top + 1;
1693 
1694 #ifdef FEAT_DIFF
1695     /* "used" already contains the number of filler lines above, don't add it
1696      * again.
1697      * Hide filler lines above cursor line by adding them to "extra". */
1698     extra += diff_check_fill(curwin, curwin->w_cursor.lnum);
1699 #endif
1700 
1701     /*
1702      * Check if the lines from "top" to "bot" fit in the window.  If they do,
1703      * set new_topline and advance "top" and "bot" to include more lines.
1704      */
1705     while (top > 0)
1706     {
1707 #ifdef FEAT_FOLDING
1708 	if (hasFolding(top, &top, NULL))
1709 	    /* count one logical line for a sequence of folded lines */
1710 	    i = 1;
1711 	else
1712 #endif
1713 	    i = PLINES_NOFILL(top);
1714 	used += i;
1715 	if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
1716 	{
1717 #ifdef FEAT_FOLDING
1718 	    if (hasFolding(bot, NULL, &bot))
1719 		/* count one logical line for a sequence of folded lines */
1720 		++used;
1721 	    else
1722 #endif
1723 		used += plines(bot);
1724 	}
1725 	if (used > curwin->w_height)
1726 	    break;
1727 	if (top < curwin->w_topline)
1728 	    scrolled += i;
1729 
1730 	/*
1731 	 * If scrolling is needed, scroll at least 'sj' lines.
1732 	 */
1733 	if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
1734 		&& extra >= off)
1735 	    break;
1736 
1737 	extra += i;
1738 	new_topline = top;
1739 	--top;
1740 	++bot;
1741     }
1742 
1743     /*
1744      * If we don't have enough space, put cursor in the middle.
1745      * This makes sure we get the same position when using "k" and "j"
1746      * in a small window.
1747      */
1748     if (used > curwin->w_height)
1749 	scroll_cursor_halfway(FALSE);
1750     else
1751     {
1752 	/*
1753 	 * If "always" is FALSE, only adjust topline to a lower value, higher
1754 	 * value may happen with wrapping lines
1755 	 */
1756 	if (new_topline < curwin->w_topline || always)
1757 	    curwin->w_topline = new_topline;
1758 	if (curwin->w_topline > curwin->w_cursor.lnum)
1759 	    curwin->w_topline = curwin->w_cursor.lnum;
1760 #ifdef FEAT_DIFF
1761 	curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
1762 	if (curwin->w_topfill > 0 && extra > off)
1763 	{
1764 	    curwin->w_topfill -= extra - off;
1765 	    if (curwin->w_topfill < 0)
1766 		curwin->w_topfill = 0;
1767 	}
1768 	check_topfill(curwin, FALSE);
1769 #endif
1770 	if (curwin->w_topline != old_topline
1771 #ifdef FEAT_DIFF
1772 		|| curwin->w_topfill != old_topfill
1773 #endif
1774 		)
1775 	    curwin->w_valid &=
1776 		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
1777 	curwin->w_valid |= VALID_TOPLINE;
1778     }
1779 }
1780 
1781 /*
1782  * Set w_empty_rows and w_filler_rows for window "wp", having used up "used"
1783  * screen lines for text lines.
1784  */
1785     void
1786 set_empty_rows(win_T *wp, int used)
1787 {
1788 #ifdef FEAT_DIFF
1789     wp->w_filler_rows = 0;
1790 #endif
1791     if (used == 0)
1792 	wp->w_empty_rows = 0;	/* single line that doesn't fit */
1793     else
1794     {
1795 	wp->w_empty_rows = wp->w_height - used;
1796 #ifdef FEAT_DIFF
1797 	if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count)
1798 	{
1799 	    wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
1800 	    if (wp->w_empty_rows > wp->w_filler_rows)
1801 		wp->w_empty_rows -= wp->w_filler_rows;
1802 	    else
1803 	    {
1804 		wp->w_filler_rows = wp->w_empty_rows;
1805 		wp->w_empty_rows = 0;
1806 	    }
1807 	}
1808 #endif
1809     }
1810 }
1811 
1812 /*
1813  * Recompute topline to put the cursor at the bottom of the window.
1814  * Scroll at least "min_scroll" lines.
1815  * If "set_topbot" is TRUE, set topline and botline first (for "zb").
1816  * This is messy stuff!!!
1817  */
1818     void
1819 scroll_cursor_bot(int min_scroll, int set_topbot)
1820 {
1821     int		used;
1822     int		scrolled = 0;
1823     int		extra = 0;
1824     int		i;
1825     linenr_T	line_count;
1826     linenr_T	old_topline = curwin->w_topline;
1827     lineoff_T	loff;
1828     lineoff_T	boff;
1829 #ifdef FEAT_DIFF
1830     int		old_topfill = curwin->w_topfill;
1831     int		fill_below_window;
1832 #endif
1833     linenr_T	old_botline = curwin->w_botline;
1834     linenr_T	old_valid = curwin->w_valid;
1835     int		old_empty_rows = curwin->w_empty_rows;
1836     linenr_T	cln;		    /* Cursor Line Number */
1837 
1838     cln = curwin->w_cursor.lnum;
1839     if (set_topbot)
1840     {
1841 	used = 0;
1842 	curwin->w_botline = cln + 1;
1843 #ifdef FEAT_DIFF
1844 	loff.fill = 0;
1845 #endif
1846 	for (curwin->w_topline = curwin->w_botline;
1847 		curwin->w_topline > 1;
1848 		curwin->w_topline = loff.lnum)
1849 	{
1850 	    loff.lnum = curwin->w_topline;
1851 	    topline_back(&loff);
1852 	    if (loff.height == MAXCOL || used + loff.height > curwin->w_height)
1853 		break;
1854 	    used += loff.height;
1855 #ifdef FEAT_DIFF
1856 	    curwin->w_topfill = loff.fill;
1857 #endif
1858 	}
1859 	set_empty_rows(curwin, used);
1860 	curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
1861 	if (curwin->w_topline != old_topline
1862 #ifdef FEAT_DIFF
1863 		|| curwin->w_topfill != old_topfill
1864 #endif
1865 		)
1866 	    curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
1867     }
1868     else
1869 	validate_botline();
1870 
1871     /* The lines of the cursor line itself are always used. */
1872 #ifdef FEAT_DIFF
1873     used = plines_nofill(cln);
1874 #else
1875     validate_cheight();
1876     used = curwin->w_cline_height;
1877 #endif
1878 
1879     /* If the cursor is below botline, we will at least scroll by the height
1880      * of the cursor line.  Correct for empty lines, which are really part of
1881      * botline. */
1882     if (cln >= curwin->w_botline)
1883     {
1884 	scrolled = used;
1885 	if (cln == curwin->w_botline)
1886 	    scrolled -= curwin->w_empty_rows;
1887     }
1888 
1889     /*
1890      * Stop counting lines to scroll when
1891      * - hitting start of the file
1892      * - scrolled nothing or at least 'sj' lines
1893      * - at least 'so' lines below the cursor
1894      * - lines between botline and cursor have been counted
1895      */
1896 #ifdef FEAT_FOLDING
1897     if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum))
1898 #endif
1899     {
1900 	loff.lnum = cln;
1901 	boff.lnum = cln;
1902     }
1903 #ifdef FEAT_DIFF
1904     loff.fill = 0;
1905     boff.fill = 0;
1906     fill_below_window = diff_check_fill(curwin, curwin->w_botline)
1907 						      - curwin->w_filler_rows;
1908 #endif
1909 
1910     while (loff.lnum > 1)
1911     {
1912 	/* Stop when scrolled nothing or at least "min_scroll", found "extra"
1913 	 * context for 'scrolloff' and counted all lines below the window. */
1914 	if ((((scrolled <= 0 || scrolled >= min_scroll)
1915 			&& extra >= (
1916 #ifdef FEAT_MOUSE
1917 			    mouse_dragging > 0 ? mouse_dragging - 1 :
1918 #endif
1919 			    p_so))
1920 		    || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
1921 		&& loff.lnum <= curwin->w_botline
1922 #ifdef FEAT_DIFF
1923 		&& (loff.lnum < curwin->w_botline
1924 		    || loff.fill >= fill_below_window)
1925 #endif
1926 		)
1927 	    break;
1928 
1929 	/* Add one line above */
1930 	topline_back(&loff);
1931 	if (loff.height == MAXCOL)
1932 	    used = MAXCOL;
1933 	else
1934 	    used += loff.height;
1935 	if (used > curwin->w_height)
1936 	    break;
1937 	if (loff.lnum >= curwin->w_botline
1938 #ifdef FEAT_DIFF
1939 		&& (loff.lnum > curwin->w_botline
1940 		    || loff.fill <= fill_below_window)
1941 #endif
1942 		)
1943 	{
1944 	    /* Count screen lines that are below the window. */
1945 	    scrolled += loff.height;
1946 	    if (loff.lnum == curwin->w_botline
1947 #ifdef FEAT_DIFF
1948 			    && boff.fill == 0
1949 #endif
1950 		    )
1951 		scrolled -= curwin->w_empty_rows;
1952 	}
1953 
1954 	if (boff.lnum < curbuf->b_ml.ml_line_count)
1955 	{
1956 	    /* Add one line below */
1957 	    botline_forw(&boff);
1958 	    used += boff.height;
1959 	    if (used > curwin->w_height)
1960 		break;
1961 	    if (extra < (
1962 #ifdef FEAT_MOUSE
1963 			mouse_dragging > 0 ? mouse_dragging - 1 :
1964 #endif
1965 			p_so) || scrolled < min_scroll)
1966 	    {
1967 		extra += boff.height;
1968 		if (boff.lnum >= curwin->w_botline
1969 #ifdef FEAT_DIFF
1970 			|| (boff.lnum + 1 == curwin->w_botline
1971 			    && boff.fill > curwin->w_filler_rows)
1972 #endif
1973 		   )
1974 		{
1975 		    /* Count screen lines that are below the window. */
1976 		    scrolled += boff.height;
1977 		    if (boff.lnum == curwin->w_botline
1978 #ifdef FEAT_DIFF
1979 			    && boff.fill == 0
1980 #endif
1981 			    )
1982 			scrolled -= curwin->w_empty_rows;
1983 		}
1984 	    }
1985 	}
1986     }
1987 
1988     /* curwin->w_empty_rows is larger, no need to scroll */
1989     if (scrolled <= 0)
1990 	line_count = 0;
1991     /* more than a screenfull, don't scroll but redraw */
1992     else if (used > curwin->w_height)
1993 	line_count = used;
1994     /* scroll minimal number of lines */
1995     else
1996     {
1997 	line_count = 0;
1998 #ifdef FEAT_DIFF
1999 	boff.fill = curwin->w_topfill;
2000 #endif
2001 	boff.lnum = curwin->w_topline - 1;
2002 	for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; )
2003 	{
2004 	    botline_forw(&boff);
2005 	    i += boff.height;
2006 	    ++line_count;
2007 	}
2008 	if (i < scrolled)	/* below curwin->w_botline, don't scroll */
2009 	    line_count = 9999;
2010     }
2011 
2012     /*
2013      * Scroll up if the cursor is off the bottom of the screen a bit.
2014      * Otherwise put it at 1/2 of the screen.
2015      */
2016     if (line_count >= curwin->w_height && line_count > min_scroll)
2017 	scroll_cursor_halfway(FALSE);
2018     else
2019 	scrollup(line_count, TRUE);
2020 
2021     /*
2022      * If topline didn't change we need to restore w_botline and w_empty_rows
2023      * (we changed them).
2024      * If topline did change, update_screen() will set botline.
2025      */
2026     if (curwin->w_topline == old_topline && set_topbot)
2027     {
2028 	curwin->w_botline = old_botline;
2029 	curwin->w_empty_rows = old_empty_rows;
2030 	curwin->w_valid = old_valid;
2031     }
2032     curwin->w_valid |= VALID_TOPLINE;
2033 }
2034 
2035 /*
2036  * Recompute topline to put the cursor halfway the window
2037  * If "atend" is TRUE, also put it halfway at the end of the file.
2038  */
2039     void
2040 scroll_cursor_halfway(int atend)
2041 {
2042     int		above = 0;
2043     linenr_T	topline;
2044 #ifdef FEAT_DIFF
2045     int		topfill = 0;
2046 #endif
2047     int		below = 0;
2048     int		used;
2049     lineoff_T	loff;
2050     lineoff_T	boff;
2051 #ifdef FEAT_DIFF
2052     linenr_T	old_topline = curwin->w_topline;
2053 #endif
2054 
2055     loff.lnum = boff.lnum = curwin->w_cursor.lnum;
2056 #ifdef FEAT_FOLDING
2057     (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum);
2058 #endif
2059 #ifdef FEAT_DIFF
2060     used = plines_nofill(loff.lnum);
2061     loff.fill = 0;
2062     boff.fill = 0;
2063 #else
2064     used = plines(loff.lnum);
2065 #endif
2066     topline = loff.lnum;
2067     while (topline > 1)
2068     {
2069 	if (below <= above)	    /* add a line below the cursor first */
2070 	{
2071 	    if (boff.lnum < curbuf->b_ml.ml_line_count)
2072 	    {
2073 		botline_forw(&boff);
2074 		used += boff.height;
2075 		if (used > curwin->w_height)
2076 		    break;
2077 		below += boff.height;
2078 	    }
2079 	    else
2080 	    {
2081 		++below;	    /* count a "~" line */
2082 		if (atend)
2083 		    ++used;
2084 	    }
2085 	}
2086 
2087 	if (below > above)	    /* add a line above the cursor */
2088 	{
2089 	    topline_back(&loff);
2090 	    if (loff.height == MAXCOL)
2091 		used = MAXCOL;
2092 	    else
2093 		used += loff.height;
2094 	    if (used > curwin->w_height)
2095 		break;
2096 	    above += loff.height;
2097 	    topline = loff.lnum;
2098 #ifdef FEAT_DIFF
2099 	    topfill = loff.fill;
2100 #endif
2101 	}
2102     }
2103 #ifdef FEAT_FOLDING
2104     if (!hasFolding(topline, &curwin->w_topline, NULL))
2105 #endif
2106 	curwin->w_topline = topline;
2107 #ifdef FEAT_DIFF
2108     curwin->w_topfill = topfill;
2109     if (old_topline > curwin->w_topline + curwin->w_height)
2110 	curwin->w_botfill = FALSE;
2111     check_topfill(curwin, FALSE);
2112 #endif
2113     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2114     curwin->w_valid |= VALID_TOPLINE;
2115 }
2116 
2117 /*
2118  * Correct the cursor position so that it is in a part of the screen at least
2119  * 'so' lines from the top and bottom, if possible.
2120  * If not possible, put it at the same position as scroll_cursor_halfway().
2121  * When called topline must be valid!
2122  */
2123     void
2124 cursor_correct(void)
2125 {
2126     int		above = 0;	    /* screen lines above topline */
2127     linenr_T	topline;
2128     int		below = 0;	    /* screen lines below botline */
2129     linenr_T	botline;
2130     int		above_wanted, below_wanted;
2131     linenr_T	cln;		    /* Cursor Line Number */
2132     int		max_off;
2133 
2134     /*
2135      * How many lines we would like to have above/below the cursor depends on
2136      * whether the first/last line of the file is on screen.
2137      */
2138     above_wanted = p_so;
2139     below_wanted = p_so;
2140 #ifdef FEAT_MOUSE
2141     if (mouse_dragging > 0)
2142     {
2143 	above_wanted = mouse_dragging - 1;
2144 	below_wanted = mouse_dragging - 1;
2145     }
2146 #endif
2147     if (curwin->w_topline == 1)
2148     {
2149 	above_wanted = 0;
2150 	max_off = curwin->w_height / 2;
2151 	if (below_wanted > max_off)
2152 	    below_wanted = max_off;
2153     }
2154     validate_botline();
2155     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
2156 #ifdef FEAT_MOUSE
2157 	    && mouse_dragging == 0
2158 #endif
2159 	    )
2160     {
2161 	below_wanted = 0;
2162 	max_off = (curwin->w_height - 1) / 2;
2163 	if (above_wanted > max_off)
2164 	    above_wanted = max_off;
2165     }
2166 
2167     /*
2168      * If there are sufficient file-lines above and below the cursor, we can
2169      * return now.
2170      */
2171     cln = curwin->w_cursor.lnum;
2172     if (cln >= curwin->w_topline + above_wanted
2173 	    && cln < curwin->w_botline - below_wanted
2174 #ifdef FEAT_FOLDING
2175 	    && !hasAnyFolding(curwin)
2176 #endif
2177 	    )
2178 	return;
2179 
2180     /*
2181      * Narrow down the area where the cursor can be put by taking lines from
2182      * the top and the bottom until:
2183      * - the desired context lines are found
2184      * - the lines from the top is past the lines from the bottom
2185      */
2186     topline = curwin->w_topline;
2187     botline = curwin->w_botline - 1;
2188 #ifdef FEAT_DIFF
2189     /* count filler lines as context */
2190     above = curwin->w_topfill;
2191     below = curwin->w_filler_rows;
2192 #endif
2193     while ((above < above_wanted || below < below_wanted) && topline < botline)
2194     {
2195 	if (below < below_wanted && (below <= above || above >= above_wanted))
2196 	{
2197 #ifdef FEAT_FOLDING
2198 	    if (hasFolding(botline, &botline, NULL))
2199 		++below;
2200 	    else
2201 #endif
2202 		below += plines(botline);
2203 	    --botline;
2204 	}
2205 	if (above < above_wanted && (above < below || below >= below_wanted))
2206 	{
2207 #ifdef FEAT_FOLDING
2208 	    if (hasFolding(topline, NULL, &topline))
2209 		++above;
2210 	    else
2211 #endif
2212 		above += PLINES_NOFILL(topline);
2213 #ifdef FEAT_DIFF
2214 	    /* Count filler lines below this line as context. */
2215 	    if (topline < botline)
2216 		above += diff_check_fill(curwin, topline + 1);
2217 #endif
2218 	    ++topline;
2219 	}
2220     }
2221     if (topline == botline || botline == 0)
2222 	curwin->w_cursor.lnum = topline;
2223     else if (topline > botline)
2224 	curwin->w_cursor.lnum = botline;
2225     else
2226     {
2227 	if (cln < topline && curwin->w_topline > 1)
2228 	{
2229 	    curwin->w_cursor.lnum = topline;
2230 	    curwin->w_valid &=
2231 			    ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
2232 	}
2233 	if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2234 	{
2235 	    curwin->w_cursor.lnum = botline;
2236 	    curwin->w_valid &=
2237 			    ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
2238 	}
2239     }
2240     curwin->w_valid |= VALID_TOPLINE;
2241 }
2242 
2243 static void get_scroll_overlap(lineoff_T *lp, int dir);
2244 
2245 /*
2246  * move screen 'count' pages up or down and update screen
2247  *
2248  * return FAIL for failure, OK otherwise
2249  */
2250     int
2251 onepage(int dir, long count)
2252 {
2253     long	n;
2254     int		retval = OK;
2255     lineoff_T	loff;
2256     linenr_T	old_topline = curwin->w_topline;
2257 
2258     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
2259     {
2260 	beep_flush();
2261 	return FAIL;
2262     }
2263 
2264     for ( ; count > 0; --count)
2265     {
2266 	validate_botline();
2267 	/*
2268 	 * It's an error to move a page up when the first line is already on
2269 	 * the screen.	It's an error to move a page down when the last line
2270 	 * is on the screen and the topline is 'scrolloff' lines from the
2271 	 * last line.
2272 	 */
2273 	if (dir == FORWARD
2274 		? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so)
2275 		    && curwin->w_botline > curbuf->b_ml.ml_line_count)
2276 		: (curwin->w_topline == 1
2277 #ifdef FEAT_DIFF
2278 		    && curwin->w_topfill ==
2279 				    diff_check_fill(curwin, curwin->w_topline)
2280 #endif
2281 		    ))
2282 	{
2283 	    beep_flush();
2284 	    retval = FAIL;
2285 	    break;
2286 	}
2287 
2288 #ifdef FEAT_DIFF
2289 	loff.fill = 0;
2290 #endif
2291 	if (dir == FORWARD)
2292 	{
2293 	    if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
2294 	    {
2295 		/* Vi compatible scrolling */
2296 		if (p_window <= 2)
2297 		    ++curwin->w_topline;
2298 		else
2299 		    curwin->w_topline += p_window - 2;
2300 		if (curwin->w_topline > curbuf->b_ml.ml_line_count)
2301 		    curwin->w_topline = curbuf->b_ml.ml_line_count;
2302 		curwin->w_cursor.lnum = curwin->w_topline;
2303 	    }
2304 	    else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
2305 	    {
2306 		/* at end of file */
2307 		curwin->w_topline = curbuf->b_ml.ml_line_count;
2308 #ifdef FEAT_DIFF
2309 		curwin->w_topfill = 0;
2310 #endif
2311 		curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
2312 	    }
2313 	    else
2314 	    {
2315 		/* For the overlap, start with the line just below the window
2316 		 * and go upwards. */
2317 		loff.lnum = curwin->w_botline;
2318 #ifdef FEAT_DIFF
2319 		loff.fill = diff_check_fill(curwin, loff.lnum)
2320 						      - curwin->w_filler_rows;
2321 #endif
2322 		get_scroll_overlap(&loff, -1);
2323 		curwin->w_topline = loff.lnum;
2324 #ifdef FEAT_DIFF
2325 		curwin->w_topfill = loff.fill;
2326 		check_topfill(curwin, FALSE);
2327 #endif
2328 		curwin->w_cursor.lnum = curwin->w_topline;
2329 		curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
2330 				   VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2331 	    }
2332 	}
2333 	else	/* dir == BACKWARDS */
2334 	{
2335 #ifdef FEAT_DIFF
2336 	    if (curwin->w_topline == 1)
2337 	    {
2338 		/* Include max number of filler lines */
2339 		max_topfill();
2340 		continue;
2341 	    }
2342 #endif
2343 	    if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
2344 	    {
2345 		/* Vi compatible scrolling (sort of) */
2346 		if (p_window <= 2)
2347 		    --curwin->w_topline;
2348 		else
2349 		    curwin->w_topline -= p_window - 2;
2350 		if (curwin->w_topline < 1)
2351 		    curwin->w_topline = 1;
2352 		curwin->w_cursor.lnum = curwin->w_topline + p_window - 1;
2353 		if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
2354 		    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2355 		continue;
2356 	    }
2357 
2358 	    /* Find the line at the top of the window that is going to be the
2359 	     * line at the bottom of the window.  Make sure this results in
2360 	     * the same line as before doing CTRL-F. */
2361 	    loff.lnum = curwin->w_topline - 1;
2362 #ifdef FEAT_DIFF
2363 	    loff.fill = diff_check_fill(curwin, loff.lnum + 1)
2364 							  - curwin->w_topfill;
2365 #endif
2366 	    get_scroll_overlap(&loff, 1);
2367 
2368 	    if (loff.lnum >= curbuf->b_ml.ml_line_count)
2369 	    {
2370 		loff.lnum = curbuf->b_ml.ml_line_count;
2371 #ifdef FEAT_DIFF
2372 		loff.fill = 0;
2373 	    }
2374 	    else
2375 	    {
2376 		botline_topline(&loff);
2377 #endif
2378 	    }
2379 	    curwin->w_cursor.lnum = loff.lnum;
2380 
2381 	    /* Find the line just above the new topline to get the right line
2382 	     * at the bottom of the window. */
2383 	    n = 0;
2384 	    while (n <= curwin->w_height && loff.lnum >= 1)
2385 	    {
2386 		topline_back(&loff);
2387 		if (loff.height == MAXCOL)
2388 		    n = MAXCOL;
2389 		else
2390 		    n += loff.height;
2391 	    }
2392 	    if (loff.lnum < 1)			/* at begin of file */
2393 	    {
2394 		curwin->w_topline = 1;
2395 #ifdef FEAT_DIFF
2396 		max_topfill();
2397 #endif
2398 		curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
2399 	    }
2400 	    else
2401 	    {
2402 		/* Go two lines forward again. */
2403 #ifdef FEAT_DIFF
2404 		topline_botline(&loff);
2405 #endif
2406 		botline_forw(&loff);
2407 		botline_forw(&loff);
2408 #ifdef FEAT_DIFF
2409 		botline_topline(&loff);
2410 #endif
2411 #ifdef FEAT_FOLDING
2412 		/* We're at the wrong end of a fold now. */
2413 		(void)hasFolding(loff.lnum, &loff.lnum, NULL);
2414 #endif
2415 
2416 		/* Always scroll at least one line.  Avoid getting stuck on
2417 		 * very long lines. */
2418 		if (loff.lnum >= curwin->w_topline
2419 #ifdef FEAT_DIFF
2420 			&& (loff.lnum > curwin->w_topline
2421 			    || loff.fill >= curwin->w_topfill)
2422 #endif
2423 			)
2424 		{
2425 #ifdef FEAT_DIFF
2426 		    /* First try using the maximum number of filler lines.  If
2427 		     * that's not enough, backup one line. */
2428 		    loff.fill = curwin->w_topfill;
2429 		    if (curwin->w_topfill < diff_check_fill(curwin,
2430 							   curwin->w_topline))
2431 			max_topfill();
2432 		    if (curwin->w_topfill == loff.fill)
2433 #endif
2434 		    {
2435 			--curwin->w_topline;
2436 #ifdef FEAT_DIFF
2437 			curwin->w_topfill = 0;
2438 #endif
2439 		    }
2440 		    comp_botline(curwin);
2441 		    curwin->w_cursor.lnum = curwin->w_botline - 1;
2442 		    curwin->w_valid &=
2443 			    ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW);
2444 		}
2445 		else
2446 		{
2447 		    curwin->w_topline = loff.lnum;
2448 #ifdef FEAT_DIFF
2449 		    curwin->w_topfill = loff.fill;
2450 		    check_topfill(curwin, FALSE);
2451 #endif
2452 		    curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
2453 		}
2454 	    }
2455 	}
2456     }
2457 #ifdef FEAT_FOLDING
2458     foldAdjustCursor();
2459 #endif
2460     cursor_correct();
2461     check_cursor_col();
2462     if (retval == OK)
2463 	beginline(BL_SOL | BL_FIX);
2464     curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
2465 
2466     /*
2467      * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
2468      * But make sure we scroll at least one line (happens with mix of long
2469      * wrapping lines and non-wrapping line).
2470      */
2471     if (retval == OK && dir == FORWARD && check_top_offset())
2472     {
2473 	scroll_cursor_top(1, FALSE);
2474 	if (curwin->w_topline <= old_topline
2475 				  && old_topline < curbuf->b_ml.ml_line_count)
2476 	{
2477 	    curwin->w_topline = old_topline + 1;
2478 #ifdef FEAT_FOLDING
2479 	    (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2480 #endif
2481 	}
2482     }
2483 
2484     redraw_later(VALID);
2485     return retval;
2486 }
2487 
2488 /*
2489  * Decide how much overlap to use for page-up or page-down scrolling.
2490  * This is symmetric, so that doing both keeps the same lines displayed.
2491  * Three lines are examined:
2492  *
2493  *  before CTRL-F	    after CTRL-F / before CTRL-B
2494  *     etc.			l1
2495  *  l1 last but one line	------------
2496  *  l2 last text line		l2 top text line
2497  *  -------------		l3 second text line
2498  *  l3				   etc.
2499  */
2500     static void
2501 get_scroll_overlap(lineoff_T *lp, int dir)
2502 {
2503     int		h1, h2, h3, h4;
2504     int		min_height = curwin->w_height - 2;
2505     lineoff_T	loff0, loff1, loff2;
2506 
2507 #ifdef FEAT_DIFF
2508     if (lp->fill > 0)
2509 	lp->height = 1;
2510     else
2511 	lp->height = plines_nofill(lp->lnum);
2512 #else
2513     lp->height = plines(lp->lnum);
2514 #endif
2515     h1 = lp->height;
2516     if (h1 > min_height)
2517 	return;		/* no overlap */
2518 
2519     loff0 = *lp;
2520     if (dir > 0)
2521 	botline_forw(lp);
2522     else
2523 	topline_back(lp);
2524     h2 = lp->height;
2525     if (h2 == MAXCOL || h2 + h1 > min_height)
2526     {
2527 	*lp = loff0;	/* no overlap */
2528 	return;
2529     }
2530 
2531     loff1 = *lp;
2532     if (dir > 0)
2533 	botline_forw(lp);
2534     else
2535 	topline_back(lp);
2536     h3 = lp->height;
2537     if (h3 == MAXCOL || h3 + h2 > min_height)
2538     {
2539 	*lp = loff0;	/* no overlap */
2540 	return;
2541     }
2542 
2543     loff2 = *lp;
2544     if (dir > 0)
2545 	botline_forw(lp);
2546     else
2547 	topline_back(lp);
2548     h4 = lp->height;
2549     if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
2550 	*lp = loff1;	/* 1 line overlap */
2551     else
2552 	*lp = loff2;	/* 2 lines overlap */
2553     return;
2554 }
2555 
2556 /* #define KEEP_SCREEN_LINE */
2557 /*
2558  * Scroll 'scroll' lines up or down.
2559  */
2560     void
2561 halfpage(int flag, linenr_T Prenum)
2562 {
2563     long	scrolled = 0;
2564     int		i;
2565     int		n;
2566     int		room;
2567 
2568     if (Prenum)
2569 	curwin->w_p_scr = (Prenum > curwin->w_height) ?
2570 						curwin->w_height : Prenum;
2571     n = (curwin->w_p_scr <= curwin->w_height) ?
2572 				    curwin->w_p_scr : curwin->w_height;
2573 
2574     update_topline();
2575     validate_botline();
2576     room = curwin->w_empty_rows;
2577 #ifdef FEAT_DIFF
2578     room += curwin->w_filler_rows;
2579 #endif
2580     if (flag)
2581     {
2582 	/*
2583 	 * scroll the text up
2584 	 */
2585 	while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2586 	{
2587 #ifdef FEAT_DIFF
2588 	    if (curwin->w_topfill > 0)
2589 	    {
2590 		i = 1;
2591 		if (--n < 0 && scrolled > 0)
2592 		    break;
2593 		--curwin->w_topfill;
2594 	    }
2595 	    else
2596 #endif
2597 	    {
2598 		i = PLINES_NOFILL(curwin->w_topline);
2599 		n -= i;
2600 		if (n < 0 && scrolled > 0)
2601 		    break;
2602 #ifdef FEAT_FOLDING
2603 		(void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
2604 #endif
2605 		++curwin->w_topline;
2606 #ifdef FEAT_DIFF
2607 		curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
2608 #endif
2609 
2610 #ifndef KEEP_SCREEN_LINE
2611 		if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2612 		{
2613 		    ++curwin->w_cursor.lnum;
2614 		    curwin->w_valid &=
2615 				    ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
2616 		}
2617 #endif
2618 	    }
2619 	    curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
2620 	    scrolled += i;
2621 
2622 	    /*
2623 	     * Correct w_botline for changed w_topline.
2624 	     * Won't work when there are filler lines.
2625 	     */
2626 #ifdef FEAT_DIFF
2627 	    if (curwin->w_p_diff)
2628 		curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
2629 	    else
2630 #endif
2631 	    {
2632 		room += i;
2633 		do
2634 		{
2635 		    i = plines(curwin->w_botline);
2636 		    if (i > room)
2637 			break;
2638 #ifdef FEAT_FOLDING
2639 		    (void)hasFolding(curwin->w_botline, NULL,
2640 							  &curwin->w_botline);
2641 #endif
2642 		    ++curwin->w_botline;
2643 		    room -= i;
2644 		} while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
2645 	    }
2646 	}
2647 
2648 #ifndef KEEP_SCREEN_LINE
2649 	/*
2650 	 * When hit bottom of the file: move cursor down.
2651 	 */
2652 	if (n > 0)
2653 	{
2654 # ifdef FEAT_FOLDING
2655 	    if (hasAnyFolding(curwin))
2656 	    {
2657 		while (--n >= 0
2658 			&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2659 		{
2660 		    (void)hasFolding(curwin->w_cursor.lnum, NULL,
2661 						      &curwin->w_cursor.lnum);
2662 		    ++curwin->w_cursor.lnum;
2663 		}
2664 	    }
2665 	    else
2666 # endif
2667 		curwin->w_cursor.lnum += n;
2668 	    check_cursor_lnum();
2669 	}
2670 #else
2671 	/* try to put the cursor in the same screen line */
2672 	while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
2673 			     && curwin->w_cursor.lnum < curwin->w_botline - 1)
2674 	{
2675 	    scrolled -= plines(curwin->w_cursor.lnum);
2676 	    if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
2677 		break;
2678 # ifdef FEAT_FOLDING
2679 	    (void)hasFolding(curwin->w_cursor.lnum, NULL,
2680 						      &curwin->w_cursor.lnum);
2681 # endif
2682 	    ++curwin->w_cursor.lnum;
2683 	}
2684 #endif
2685     }
2686     else
2687     {
2688 	/*
2689 	 * scroll the text down
2690 	 */
2691 	while (n > 0 && curwin->w_topline > 1)
2692 	{
2693 #ifdef FEAT_DIFF
2694 	    if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
2695 	    {
2696 		i = 1;
2697 		if (--n < 0 && scrolled > 0)
2698 		    break;
2699 		++curwin->w_topfill;
2700 	    }
2701 	    else
2702 #endif
2703 	    {
2704 		i = PLINES_NOFILL(curwin->w_topline - 1);
2705 		n -= i;
2706 		if (n < 0 && scrolled > 0)
2707 		    break;
2708 		--curwin->w_topline;
2709 #ifdef FEAT_FOLDING
2710 		(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2711 #endif
2712 #ifdef FEAT_DIFF
2713 		curwin->w_topfill = 0;
2714 #endif
2715 	    }
2716 	    curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
2717 					      VALID_BOTLINE|VALID_BOTLINE_AP);
2718 	    scrolled += i;
2719 #ifndef KEEP_SCREEN_LINE
2720 	    if (curwin->w_cursor.lnum > 1)
2721 	    {
2722 		--curwin->w_cursor.lnum;
2723 		curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
2724 	    }
2725 #endif
2726 	}
2727 #ifndef KEEP_SCREEN_LINE
2728 	/*
2729 	 * When hit top of the file: move cursor up.
2730 	 */
2731 	if (n > 0)
2732 	{
2733 	    if (curwin->w_cursor.lnum <= (linenr_T)n)
2734 		curwin->w_cursor.lnum = 1;
2735 	    else
2736 # ifdef FEAT_FOLDING
2737 	    if (hasAnyFolding(curwin))
2738 	    {
2739 		while (--n >= 0 && curwin->w_cursor.lnum > 1)
2740 		{
2741 		    --curwin->w_cursor.lnum;
2742 		    (void)hasFolding(curwin->w_cursor.lnum,
2743 						&curwin->w_cursor.lnum, NULL);
2744 		}
2745 	    }
2746 	    else
2747 # endif
2748 		curwin->w_cursor.lnum -= n;
2749 	}
2750 #else
2751 	/* try to put the cursor in the same screen line */
2752 	scrolled += n;	    /* move cursor when topline is 1 */
2753 	while (curwin->w_cursor.lnum > curwin->w_topline
2754 	      && (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
2755 	{
2756 	    scrolled -= plines(curwin->w_cursor.lnum - 1);
2757 	    if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
2758 		break;
2759 	    --curwin->w_cursor.lnum;
2760 # ifdef FEAT_FOLDING
2761 	    foldAdjustCursor();
2762 # endif
2763 	}
2764 #endif
2765     }
2766 # ifdef FEAT_FOLDING
2767     /* Move cursor to first line of closed fold. */
2768     foldAdjustCursor();
2769 # endif
2770 #ifdef FEAT_DIFF
2771     check_topfill(curwin, !flag);
2772 #endif
2773     cursor_correct();
2774     beginline(BL_SOL | BL_FIX);
2775     redraw_later(VALID);
2776 }
2777 
2778 #if defined(FEAT_CURSORBIND) || defined(PROTO)
2779     void
2780 do_check_cursorbind(void)
2781 {
2782     linenr_T	line = curwin->w_cursor.lnum;
2783     colnr_T	col = curwin->w_cursor.col;
2784 # ifdef FEAT_VIRTUALEDIT
2785     colnr_T	coladd = curwin->w_cursor.coladd;
2786 # endif
2787     colnr_T	curswant = curwin->w_curswant;
2788     int		set_curswant = curwin->w_set_curswant;
2789     win_T	*old_curwin = curwin;
2790     buf_T	*old_curbuf = curbuf;
2791     int		restart_edit_save;
2792     int		old_VIsual_select = VIsual_select;
2793     int		old_VIsual_active = VIsual_active;
2794 
2795     /*
2796      * loop through the cursorbound windows
2797      */
2798     VIsual_select = VIsual_active = 0;
2799     FOR_ALL_WINDOWS(curwin)
2800     {
2801 	curbuf = curwin->w_buffer;
2802 	/* skip original window  and windows with 'noscrollbind' */
2803 	if (curwin != old_curwin && curwin->w_p_crb)
2804 	{
2805 # ifdef FEAT_DIFF
2806 	    if (curwin->w_p_diff)
2807 		curwin->w_cursor.lnum =
2808 				 diff_get_corresponding_line(old_curbuf, line);
2809 	    else
2810 # endif
2811 		curwin->w_cursor.lnum = line;
2812 	    curwin->w_cursor.col = col;
2813 # ifdef FEAT_VIRTUALEDIT
2814 	    curwin->w_cursor.coladd = coladd;
2815 # endif
2816 	    curwin->w_curswant = curswant;
2817 	    curwin->w_set_curswant = set_curswant;
2818 
2819 	    /* Make sure the cursor is in a valid position.  Temporarily set
2820 	     * "restart_edit" to allow the cursor to be beyond the EOL. */
2821 	    restart_edit_save = restart_edit;
2822 	    restart_edit = TRUE;
2823 	    check_cursor();
2824 # ifdef FEAT_SYN_HL
2825 	    if (curwin->w_p_cul || curwin->w_p_cuc)
2826 		validate_cursor();
2827 # endif
2828 	    restart_edit = restart_edit_save;
2829 # ifdef FEAT_MBYTE
2830 	    /* Correct cursor for multi-byte character. */
2831 	    if (has_mbyte)
2832 		mb_adjust_cursor();
2833 # endif
2834 	    redraw_later(VALID);
2835 
2836 	    /* Only scroll when 'scrollbind' hasn't done this. */
2837 	    if (!curwin->w_p_scb)
2838 		update_topline();
2839 	    curwin->w_redr_status = TRUE;
2840 	}
2841     }
2842 
2843     /*
2844      * reset current-window
2845      */
2846     VIsual_select = old_VIsual_select;
2847     VIsual_active = old_VIsual_active;
2848     curwin = old_curwin;
2849     curbuf = old_curbuf;
2850 }
2851 #endif /* FEAT_CURSORBIND */
2852