xref: /vim-8.2.3635/src/move.c (revision cd5c8f82)
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 = W_WIDTH(curwin) - off + curwin_col_off2();
859 
860 	/* long line wrapping, adjust curwin->w_wrow */
861 	if (curwin->w_p_wrap
862 		&& col >= (colnr_T)W_WIDTH(curwin)
863 		&& width > 0)
864 	    /* use same formula as what is used in curs_columns() */
865 	    col -= ((col - W_WIDTH(curwin)) / 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 = W_WIDTH(curwin) - extra;
979     if (textwidth <= 0)
980     {
981 	/* No room for text, put cursor in last char of window. */
982 	curwin->w_wcol = W_WIDTH(curwin) - 1;
983 	curwin->w_wrow = curwin->w_height - 1;
984     }
985     else if (curwin->w_p_wrap
986 #ifdef FEAT_WINDOWS
987 	    && curwin->w_width != 0
988 #endif
989 	    )
990     {
991 	width = textwidth + curwin_col_off2();
992 
993 	/* long line wrapping, adjust curwin->w_wrow */
994 	if (curwin->w_wcol >= W_WIDTH(curwin))
995 	{
996 	    /* this same formula is used in validate_cursor_col() */
997 	    n = (curwin->w_wcol - W_WIDTH(curwin)) / width + 1;
998 	    curwin->w_wcol -= n * width;
999 	    curwin->w_wrow += n;
1000 
1001 #ifdef FEAT_LINEBREAK
1002 	    /* When cursor wraps to first char of next line in Insert
1003 	     * mode, the 'showbreak' string isn't shown, backup to first
1004 	     * column */
1005 	    if (*p_sbr && *ml_get_cursor() == NUL
1006 		    && curwin->w_wcol == (int)vim_strsize(p_sbr))
1007 		curwin->w_wcol = 0;
1008 #endif
1009 	}
1010     }
1011 
1012     /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
1013      * is not folded.
1014      * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
1015     else if (may_scroll
1016 #ifdef FEAT_FOLDING
1017 	    && !curwin->w_cline_folded
1018 #endif
1019 	    )
1020     {
1021 	/*
1022 	 * If Cursor is left of the screen, scroll rightwards.
1023 	 * If Cursor is right of the screen, scroll leftwards
1024 	 * If we get closer to the edge than 'sidescrolloff', scroll a little
1025 	 * extra
1026 	 */
1027 	off_left = (int)startcol - (int)curwin->w_leftcol - p_siso;
1028 	off_right = (int)endcol - (int)(curwin->w_leftcol + W_WIDTH(curwin)
1029 								- p_siso) + 1;
1030 	if (off_left < 0 || off_right > 0)
1031 	{
1032 	    if (off_left < 0)
1033 		diff = -off_left;
1034 	    else
1035 		diff = off_right;
1036 
1037 	    /* When far off or not enough room on either side, put cursor in
1038 	     * middle of window. */
1039 	    if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left)
1040 		new_leftcol = curwin->w_wcol - extra - textwidth / 2;
1041 	    else
1042 	    {
1043 		if (diff < p_ss)
1044 		    diff = p_ss;
1045 		if (off_left < 0)
1046 		    new_leftcol = curwin->w_leftcol - diff;
1047 		else
1048 		    new_leftcol = curwin->w_leftcol + diff;
1049 	    }
1050 	    if (new_leftcol < 0)
1051 		new_leftcol = 0;
1052 	    if (new_leftcol != (int)curwin->w_leftcol)
1053 	    {
1054 		curwin->w_leftcol = new_leftcol;
1055 		/* screen has to be redrawn with new curwin->w_leftcol */
1056 		redraw_later(NOT_VALID);
1057 	    }
1058 	}
1059 	curwin->w_wcol -= curwin->w_leftcol;
1060     }
1061     else if (curwin->w_wcol > (int)curwin->w_leftcol)
1062 	curwin->w_wcol -= curwin->w_leftcol;
1063     else
1064 	curwin->w_wcol = 0;
1065 
1066 #ifdef FEAT_DIFF
1067     /* Skip over filler lines.  At the top use w_topfill, there
1068      * may be some filler lines above the window. */
1069     if (curwin->w_cursor.lnum == curwin->w_topline)
1070 	curwin->w_wrow += curwin->w_topfill;
1071     else
1072 	curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
1073 #endif
1074 
1075     prev_skipcol = curwin->w_skipcol;
1076 
1077     p_lines = 0;
1078     if ((curwin->w_wrow >= curwin->w_height
1079 		|| ((prev_skipcol > 0
1080 			|| curwin->w_wrow + p_so >= curwin->w_height)
1081 		    && (p_lines =
1082 #ifdef FEAT_DIFF
1083 			plines_win_nofill
1084 #else
1085 			plines_win
1086 #endif
1087 			(curwin, curwin->w_cursor.lnum, FALSE))
1088 						    - 1 >= curwin->w_height))
1089 	    && curwin->w_height != 0
1090 	    && curwin->w_cursor.lnum == curwin->w_topline
1091 	    && width > 0
1092 #ifdef FEAT_WINDOWS
1093 	    && curwin->w_width != 0
1094 #endif
1095 	    )
1096     {
1097 	/* Cursor past end of screen.  Happens with a single line that does
1098 	 * not fit on screen.  Find a skipcol to show the text around the
1099 	 * cursor.  Avoid scrolling all the time. compute value of "extra":
1100 	 * 1: Less than "p_so" lines above
1101 	 * 2: Less than "p_so" lines below
1102 	 * 3: both of them */
1103 	extra = 0;
1104 	if (curwin->w_skipcol + p_so * width > curwin->w_virtcol)
1105 	    extra = 1;
1106 	/* Compute last display line of the buffer line that we want at the
1107 	 * bottom of the window. */
1108 	if (p_lines == 0)
1109 	    p_lines = plines_win(curwin, curwin->w_cursor.lnum, FALSE);
1110 	--p_lines;
1111 	if (p_lines > curwin->w_wrow + p_so)
1112 	    n = curwin->w_wrow + p_so;
1113 	else
1114 	    n = p_lines;
1115 	if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width)
1116 	    extra += 2;
1117 
1118 	if (extra == 3 || p_lines < p_so * 2)
1119 	{
1120 	    /* not enough room for 'scrolloff', put cursor in the middle */
1121 	    n = curwin->w_virtcol / width;
1122 	    if (n > curwin->w_height / 2)
1123 		n -= curwin->w_height / 2;
1124 	    else
1125 		n = 0;
1126 	    /* don't skip more than necessary */
1127 	    if (n > p_lines - curwin->w_height + 1)
1128 		n = p_lines - curwin->w_height + 1;
1129 	    curwin->w_skipcol = n * width;
1130 	}
1131 	else if (extra == 1)
1132 	{
1133 	    /* less then 'scrolloff' lines above, decrease skipcol */
1134 	    extra = (curwin->w_skipcol + p_so * width - curwin->w_virtcol
1135 				     + width - 1) / width;
1136 	    if (extra > 0)
1137 	    {
1138 		if ((colnr_T)(extra * width) > curwin->w_skipcol)
1139 		    extra = curwin->w_skipcol / width;
1140 		curwin->w_skipcol -= extra * width;
1141 	    }
1142 	}
1143 	else if (extra == 2)
1144 	{
1145 	    /* less then 'scrolloff' lines below, increase skipcol */
1146 	    endcol = (n - curwin->w_height + 1) * width;
1147 	    while (endcol > curwin->w_virtcol)
1148 		endcol -= width;
1149 	    if (endcol > curwin->w_skipcol)
1150 		curwin->w_skipcol = endcol;
1151 	}
1152 
1153 	curwin->w_wrow -= curwin->w_skipcol / width;
1154 	if (curwin->w_wrow >= curwin->w_height)
1155 	{
1156 	    /* small window, make sure cursor is in it */
1157 	    extra = curwin->w_wrow - curwin->w_height + 1;
1158 	    curwin->w_skipcol += extra * width;
1159 	    curwin->w_wrow -= extra;
1160 	}
1161 
1162 	extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
1163 	if (extra > 0)
1164 	    win_ins_lines(curwin, 0, extra, FALSE, FALSE);
1165 	else if (extra < 0)
1166 	    win_del_lines(curwin, 0, -extra, FALSE, FALSE);
1167     }
1168     else
1169 	curwin->w_skipcol = 0;
1170     if (prev_skipcol != curwin->w_skipcol)
1171 	redraw_later(NOT_VALID);
1172 
1173 #ifdef FEAT_SYN_HL
1174     /* Redraw when w_virtcol changes and 'cursorcolumn' is set */
1175     if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0
1176 # ifdef FEAT_INS_EXPAND
1177 	    && !pum_visible()
1178 # endif
1179 	)
1180 	redraw_later(SOME_VALID);
1181 #endif
1182 
1183     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
1184 }
1185 
1186 /*
1187  * Scroll the current window down by "line_count" logical lines.  "CTRL-Y"
1188  */
1189     void
1190 scrolldown(
1191     long	line_count,
1192     int		byfold UNUSED)	/* TRUE: count a closed fold as one line */
1193 {
1194     long	done = 0;	/* total # of physical lines done */
1195     int		wrow;
1196     int		moved = FALSE;
1197 
1198 #ifdef FEAT_FOLDING
1199     linenr_T	first;
1200 
1201     /* Make sure w_topline is at the first of a sequence of folded lines. */
1202     (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1203 #endif
1204     validate_cursor();		/* w_wrow needs to be valid */
1205     while (line_count-- > 0)
1206     {
1207 #ifdef FEAT_DIFF
1208 	if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)
1209 		&& curwin->w_topfill < curwin->w_height - 1)
1210 	{
1211 	    ++curwin->w_topfill;
1212 	    ++done;
1213 	}
1214 	else
1215 #endif
1216 	{
1217 	    if (curwin->w_topline == 1)
1218 		break;
1219 	    --curwin->w_topline;
1220 #ifdef FEAT_DIFF
1221 	    curwin->w_topfill = 0;
1222 #endif
1223 #ifdef FEAT_FOLDING
1224 	    /* A sequence of folded lines only counts for one logical line */
1225 	    if (hasFolding(curwin->w_topline, &first, NULL))
1226 	    {
1227 		++done;
1228 		if (!byfold)
1229 		    line_count -= curwin->w_topline - first - 1;
1230 		curwin->w_botline -= curwin->w_topline - first;
1231 		curwin->w_topline = first;
1232 	    }
1233 	    else
1234 #endif
1235 		done += PLINES_NOFILL(curwin->w_topline);
1236 	}
1237 	--curwin->w_botline;		/* approximate w_botline */
1238 	invalidate_botline();
1239     }
1240     curwin->w_wrow += done;		/* keep w_wrow updated */
1241     curwin->w_cline_row += done;	/* keep w_cline_row updated */
1242 
1243 #ifdef FEAT_DIFF
1244     if (curwin->w_cursor.lnum == curwin->w_topline)
1245 	curwin->w_cline_row = 0;
1246     check_topfill(curwin, TRUE);
1247 #endif
1248 
1249     /*
1250      * Compute the row number of the last row of the cursor line
1251      * and move the cursor onto the displayed part of the window.
1252      */
1253     wrow = curwin->w_wrow;
1254     if (curwin->w_p_wrap
1255 #ifdef FEAT_WINDOWS
1256 		&& curwin->w_width != 0
1257 #endif
1258 	    )
1259     {
1260 	validate_virtcol();
1261 	validate_cheight();
1262 	wrow += curwin->w_cline_height - 1 -
1263 	    curwin->w_virtcol / W_WIDTH(curwin);
1264     }
1265     while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
1266     {
1267 #ifdef FEAT_FOLDING
1268 	if (hasFolding(curwin->w_cursor.lnum, &first, NULL))
1269 	{
1270 	    --wrow;
1271 	    if (first == 1)
1272 		curwin->w_cursor.lnum = 1;
1273 	    else
1274 		curwin->w_cursor.lnum = first - 1;
1275 	}
1276 	else
1277 #endif
1278 	    wrow -= plines(curwin->w_cursor.lnum--);
1279 	curwin->w_valid &=
1280 	      ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
1281 	moved = TRUE;
1282     }
1283     if (moved)
1284     {
1285 #ifdef FEAT_FOLDING
1286 	/* Move cursor to first line of closed fold. */
1287 	foldAdjustCursor();
1288 #endif
1289 	coladvance(curwin->w_curswant);
1290     }
1291 }
1292 
1293 /*
1294  * Scroll the current window up by "line_count" logical lines.  "CTRL-E"
1295  */
1296     void
1297 scrollup(
1298     long	line_count,
1299     int		byfold UNUSED)	/* TRUE: count a closed fold as one line */
1300 {
1301 #if defined(FEAT_FOLDING) || defined(FEAT_DIFF)
1302     linenr_T	lnum;
1303 
1304     if (
1305 # ifdef FEAT_FOLDING
1306 	    (byfold && hasAnyFolding(curwin))
1307 #  ifdef FEAT_DIFF
1308 	    ||
1309 #  endif
1310 # endif
1311 # ifdef FEAT_DIFF
1312 	    curwin->w_p_diff
1313 # endif
1314 	    )
1315     {
1316 	/* count each sequence of folded lines as one logical line */
1317 	lnum = curwin->w_topline;
1318 	while (line_count--)
1319 	{
1320 # ifdef FEAT_DIFF
1321 	    if (curwin->w_topfill > 0)
1322 		--curwin->w_topfill;
1323 	    else
1324 # endif
1325 	    {
1326 # ifdef FEAT_FOLDING
1327 		if (byfold)
1328 		    (void)hasFolding(lnum, NULL, &lnum);
1329 # endif
1330 		if (lnum >= curbuf->b_ml.ml_line_count)
1331 		    break;
1332 		++lnum;
1333 # ifdef FEAT_DIFF
1334 		curwin->w_topfill = diff_check_fill(curwin, lnum);
1335 # endif
1336 	    }
1337 	}
1338 	/* approximate w_botline */
1339 	curwin->w_botline += lnum - curwin->w_topline;
1340 	curwin->w_topline = lnum;
1341     }
1342     else
1343 #endif
1344     {
1345 	curwin->w_topline += line_count;
1346 	curwin->w_botline += line_count;	/* approximate w_botline */
1347     }
1348 
1349     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1350 	curwin->w_topline = curbuf->b_ml.ml_line_count;
1351     if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1)
1352 	curwin->w_botline = curbuf->b_ml.ml_line_count + 1;
1353 
1354 #ifdef FEAT_DIFF
1355     check_topfill(curwin, FALSE);
1356 #endif
1357 
1358 #ifdef FEAT_FOLDING
1359     if (hasAnyFolding(curwin))
1360 	/* Make sure w_topline is at the first of a sequence of folded lines. */
1361 	(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1362 #endif
1363 
1364     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1365     if (curwin->w_cursor.lnum < curwin->w_topline)
1366     {
1367 	curwin->w_cursor.lnum = curwin->w_topline;
1368 	curwin->w_valid &=
1369 	      ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
1370 	coladvance(curwin->w_curswant);
1371     }
1372 }
1373 
1374 #ifdef FEAT_DIFF
1375 /*
1376  * Don't end up with too many filler lines in the window.
1377  */
1378     void
1379 check_topfill(
1380     win_T	*wp,
1381     int		down)	/* when TRUE scroll down when not enough space */
1382 {
1383     int		n;
1384 
1385     if (wp->w_topfill > 0)
1386     {
1387 	n = plines_win_nofill(wp, wp->w_topline, TRUE);
1388 	if (wp->w_topfill + n > wp->w_height)
1389 	{
1390 	    if (down && wp->w_topline > 1)
1391 	    {
1392 		--wp->w_topline;
1393 		wp->w_topfill = 0;
1394 	    }
1395 	    else
1396 	    {
1397 		wp->w_topfill = wp->w_height - n;
1398 		if (wp->w_topfill < 0)
1399 		    wp->w_topfill = 0;
1400 	    }
1401 	}
1402     }
1403 }
1404 
1405 /*
1406  * Use as many filler lines as possible for w_topline.  Make sure w_topline
1407  * is still visible.
1408  */
1409     static void
1410 max_topfill(void)
1411 {
1412     int		n;
1413 
1414     n = plines_nofill(curwin->w_topline);
1415     if (n >= curwin->w_height)
1416 	curwin->w_topfill = 0;
1417     else
1418     {
1419 	curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
1420 	if (curwin->w_topfill + n > curwin->w_height)
1421 	    curwin->w_topfill = curwin->w_height - n;
1422     }
1423 }
1424 #endif
1425 
1426 #if defined(FEAT_INS_EXPAND) || defined(PROTO)
1427 /*
1428  * Scroll the screen one line down, but don't do it if it would move the
1429  * cursor off the screen.
1430  */
1431     void
1432 scrolldown_clamp(void)
1433 {
1434     int		end_row;
1435 #ifdef FEAT_DIFF
1436     int		can_fill = (curwin->w_topfill
1437 				< diff_check_fill(curwin, curwin->w_topline));
1438 #endif
1439 
1440     if (curwin->w_topline <= 1
1441 #ifdef FEAT_DIFF
1442 	    && !can_fill
1443 #endif
1444 	    )
1445 	return;
1446 
1447     validate_cursor();	    /* w_wrow needs to be valid */
1448 
1449     /*
1450      * Compute the row number of the last row of the cursor line
1451      * and make sure it doesn't go off the screen. Make sure the cursor
1452      * doesn't go past 'scrolloff' lines from the screen end.
1453      */
1454     end_row = curwin->w_wrow;
1455 #ifdef FEAT_DIFF
1456     if (can_fill)
1457 	++end_row;
1458     else
1459 	end_row += plines_nofill(curwin->w_topline - 1);
1460 #else
1461     end_row += plines(curwin->w_topline - 1);
1462 #endif
1463     if (curwin->w_p_wrap
1464 #ifdef FEAT_WINDOWS
1465 		&& curwin->w_width != 0
1466 #endif
1467 	    )
1468     {
1469 	validate_cheight();
1470 	validate_virtcol();
1471 	end_row += curwin->w_cline_height - 1 -
1472 	    curwin->w_virtcol / W_WIDTH(curwin);
1473     }
1474     if (end_row < curwin->w_height - p_so)
1475     {
1476 #ifdef FEAT_DIFF
1477 	if (can_fill)
1478 	{
1479 	    ++curwin->w_topfill;
1480 	    check_topfill(curwin, TRUE);
1481 	}
1482 	else
1483 	{
1484 	    --curwin->w_topline;
1485 	    curwin->w_topfill = 0;
1486 	}
1487 #else
1488 	--curwin->w_topline;
1489 #endif
1490 #ifdef FEAT_FOLDING
1491 	(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1492 #endif
1493 	--curwin->w_botline;	    /* approximate w_botline */
1494 	curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1495     }
1496 }
1497 
1498 /*
1499  * Scroll the screen one line up, but don't do it if it would move the cursor
1500  * off the screen.
1501  */
1502     void
1503 scrollup_clamp(void)
1504 {
1505     int	    start_row;
1506 
1507     if (curwin->w_topline == curbuf->b_ml.ml_line_count
1508 #ifdef FEAT_DIFF
1509 	    && curwin->w_topfill == 0
1510 #endif
1511 	    )
1512 	return;
1513 
1514     validate_cursor();	    /* w_wrow needs to be valid */
1515 
1516     /*
1517      * Compute the row number of the first row of the cursor line
1518      * and make sure it doesn't go off the screen. Make sure the cursor
1519      * doesn't go before 'scrolloff' lines from the screen start.
1520      */
1521 #ifdef FEAT_DIFF
1522     start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
1523 							  - curwin->w_topfill;
1524 #else
1525     start_row = curwin->w_wrow - plines(curwin->w_topline);
1526 #endif
1527     if (curwin->w_p_wrap
1528 #ifdef FEAT_WINDOWS
1529 		&& curwin->w_width != 0
1530 #endif
1531 	    )
1532     {
1533 	validate_virtcol();
1534 	start_row -= curwin->w_virtcol / W_WIDTH(curwin);
1535     }
1536     if (start_row >= p_so)
1537     {
1538 #ifdef FEAT_DIFF
1539 	if (curwin->w_topfill > 0)
1540 	    --curwin->w_topfill;
1541 	else
1542 #endif
1543 	{
1544 #ifdef FEAT_FOLDING
1545 	    (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
1546 #endif
1547 	    ++curwin->w_topline;
1548 	}
1549 	++curwin->w_botline;		/* approximate w_botline */
1550 	curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1551     }
1552 }
1553 #endif /* FEAT_INS_EXPAND */
1554 
1555 /*
1556  * Add one line above "lp->lnum".  This can be a filler line, a closed fold or
1557  * a (wrapped) text line.  Uses and sets "lp->fill".
1558  * Returns the height of the added line in "lp->height".
1559  * Lines above the first one are incredibly high: MAXCOL.
1560  */
1561     static void
1562 topline_back(lineoff_T *lp)
1563 {
1564 #ifdef FEAT_DIFF
1565     if (lp->fill < diff_check_fill(curwin, lp->lnum))
1566     {
1567 	/* Add a filler line. */
1568 	++lp->fill;
1569 	lp->height = 1;
1570     }
1571     else
1572 #endif
1573     {
1574 	--lp->lnum;
1575 #ifdef FEAT_DIFF
1576 	lp->fill = 0;
1577 #endif
1578 	if (lp->lnum < 1)
1579 	    lp->height = MAXCOL;
1580 	else
1581 #ifdef FEAT_FOLDING
1582 	    if (hasFolding(lp->lnum, &lp->lnum, NULL))
1583 	    /* Add a closed fold */
1584 	    lp->height = 1;
1585 	else
1586 #endif
1587 	    lp->height = PLINES_NOFILL(lp->lnum);
1588     }
1589 }
1590 
1591 /*
1592  * Add one line below "lp->lnum".  This can be a filler line, a closed fold or
1593  * a (wrapped) text line.  Uses and sets "lp->fill".
1594  * Returns the height of the added line in "lp->height".
1595  * Lines below the last one are incredibly high.
1596  */
1597     static void
1598 botline_forw(lineoff_T *lp)
1599 {
1600 #ifdef FEAT_DIFF
1601     if (lp->fill < diff_check_fill(curwin, lp->lnum + 1))
1602     {
1603 	/* Add a filler line. */
1604 	++lp->fill;
1605 	lp->height = 1;
1606     }
1607     else
1608 #endif
1609     {
1610 	++lp->lnum;
1611 #ifdef FEAT_DIFF
1612 	lp->fill = 0;
1613 #endif
1614 	if (lp->lnum > curbuf->b_ml.ml_line_count)
1615 	    lp->height = MAXCOL;
1616 	else
1617 #ifdef FEAT_FOLDING
1618 	    if (hasFolding(lp->lnum, NULL, &lp->lnum))
1619 	    /* Add a closed fold */
1620 	    lp->height = 1;
1621 	else
1622 #endif
1623 	{
1624 	    lp->height = PLINES_NOFILL(lp->lnum);
1625 	}
1626     }
1627 }
1628 
1629 #ifdef FEAT_DIFF
1630 /*
1631  * Switch from including filler lines below lp->lnum to including filler
1632  * lines above loff.lnum + 1.  This keeps pointing to the same line.
1633  * When there are no filler lines nothing changes.
1634  */
1635     static void
1636 botline_topline(lineoff_T *lp)
1637 {
1638     if (lp->fill > 0)
1639     {
1640 	++lp->lnum;
1641 	lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
1642     }
1643 }
1644 
1645 /*
1646  * Switch from including filler lines above lp->lnum to including filler
1647  * lines below loff.lnum - 1.  This keeps pointing to the same line.
1648  * When there are no filler lines nothing changes.
1649  */
1650     static void
1651 topline_botline(lineoff_T *lp)
1652 {
1653     if (lp->fill > 0)
1654     {
1655 	lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
1656 	--lp->lnum;
1657     }
1658 }
1659 #endif
1660 
1661 /*
1662  * Recompute topline to put the cursor at the top of the window.
1663  * Scroll at least "min_scroll" lines.
1664  * If "always" is TRUE, always set topline (for "zt").
1665  */
1666     void
1667 scroll_cursor_top(int min_scroll, int always)
1668 {
1669     int		scrolled = 0;
1670     int		extra = 0;
1671     int		used;
1672     int		i;
1673     linenr_T	top;		/* just above displayed lines */
1674     linenr_T	bot;		/* just below displayed lines */
1675     linenr_T	old_topline = curwin->w_topline;
1676 #ifdef FEAT_DIFF
1677     linenr_T	old_topfill = curwin->w_topfill;
1678 #endif
1679     linenr_T	new_topline;
1680     int		off = p_so;
1681 
1682 #ifdef FEAT_MOUSE
1683     if (mouse_dragging > 0)
1684 	off = mouse_dragging - 1;
1685 #endif
1686 
1687     /*
1688      * Decrease topline until:
1689      * - it has become 1
1690      * - (part of) the cursor line is moved off the screen or
1691      * - moved at least 'scrolljump' lines and
1692      * - at least 'scrolloff' lines above and below the cursor
1693      */
1694     validate_cheight();
1695     used = curwin->w_cline_height; /* includes filler lines above */
1696     if (curwin->w_cursor.lnum < curwin->w_topline)
1697 	scrolled = used;
1698 
1699 #ifdef FEAT_FOLDING
1700     if (hasFolding(curwin->w_cursor.lnum, &top, &bot))
1701     {
1702 	--top;
1703 	++bot;
1704     }
1705     else
1706 #endif
1707     {
1708 	top = curwin->w_cursor.lnum - 1;
1709 	bot = curwin->w_cursor.lnum + 1;
1710     }
1711     new_topline = top + 1;
1712 
1713 #ifdef FEAT_DIFF
1714     /* "used" already contains the number of filler lines above, don't add it
1715      * again.
1716      * Hide filler lines above cursor line by adding them to "extra". */
1717     extra += diff_check_fill(curwin, curwin->w_cursor.lnum);
1718 #endif
1719 
1720     /*
1721      * Check if the lines from "top" to "bot" fit in the window.  If they do,
1722      * set new_topline and advance "top" and "bot" to include more lines.
1723      */
1724     while (top > 0)
1725     {
1726 #ifdef FEAT_FOLDING
1727 	if (hasFolding(top, &top, NULL))
1728 	    /* count one logical line for a sequence of folded lines */
1729 	    i = 1;
1730 	else
1731 #endif
1732 	    i = PLINES_NOFILL(top);
1733 	used += i;
1734 	if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
1735 	{
1736 #ifdef FEAT_FOLDING
1737 	    if (hasFolding(bot, NULL, &bot))
1738 		/* count one logical line for a sequence of folded lines */
1739 		++used;
1740 	    else
1741 #endif
1742 		used += plines(bot);
1743 	}
1744 	if (used > curwin->w_height)
1745 	    break;
1746 	if (top < curwin->w_topline)
1747 	    scrolled += i;
1748 
1749 	/*
1750 	 * If scrolling is needed, scroll at least 'sj' lines.
1751 	 */
1752 	if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
1753 		&& extra >= off)
1754 	    break;
1755 
1756 	extra += i;
1757 	new_topline = top;
1758 	--top;
1759 	++bot;
1760     }
1761 
1762     /*
1763      * If we don't have enough space, put cursor in the middle.
1764      * This makes sure we get the same position when using "k" and "j"
1765      * in a small window.
1766      */
1767     if (used > curwin->w_height)
1768 	scroll_cursor_halfway(FALSE);
1769     else
1770     {
1771 	/*
1772 	 * If "always" is FALSE, only adjust topline to a lower value, higher
1773 	 * value may happen with wrapping lines
1774 	 */
1775 	if (new_topline < curwin->w_topline || always)
1776 	    curwin->w_topline = new_topline;
1777 	if (curwin->w_topline > curwin->w_cursor.lnum)
1778 	    curwin->w_topline = curwin->w_cursor.lnum;
1779 #ifdef FEAT_DIFF
1780 	curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
1781 	if (curwin->w_topfill > 0 && extra > off)
1782 	{
1783 	    curwin->w_topfill -= extra - off;
1784 	    if (curwin->w_topfill < 0)
1785 		curwin->w_topfill = 0;
1786 	}
1787 	check_topfill(curwin, FALSE);
1788 #endif
1789 	if (curwin->w_topline != old_topline
1790 #ifdef FEAT_DIFF
1791 		|| curwin->w_topfill != old_topfill
1792 #endif
1793 		)
1794 	    curwin->w_valid &=
1795 		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
1796 	curwin->w_valid |= VALID_TOPLINE;
1797     }
1798 }
1799 
1800 /*
1801  * Set w_empty_rows and w_filler_rows for window "wp", having used up "used"
1802  * screen lines for text lines.
1803  */
1804     void
1805 set_empty_rows(win_T *wp, int used)
1806 {
1807 #ifdef FEAT_DIFF
1808     wp->w_filler_rows = 0;
1809 #endif
1810     if (used == 0)
1811 	wp->w_empty_rows = 0;	/* single line that doesn't fit */
1812     else
1813     {
1814 	wp->w_empty_rows = wp->w_height - used;
1815 #ifdef FEAT_DIFF
1816 	if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count)
1817 	{
1818 	    wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
1819 	    if (wp->w_empty_rows > wp->w_filler_rows)
1820 		wp->w_empty_rows -= wp->w_filler_rows;
1821 	    else
1822 	    {
1823 		wp->w_filler_rows = wp->w_empty_rows;
1824 		wp->w_empty_rows = 0;
1825 	    }
1826 	}
1827 #endif
1828     }
1829 }
1830 
1831 /*
1832  * Recompute topline to put the cursor at the bottom of the window.
1833  * Scroll at least "min_scroll" lines.
1834  * If "set_topbot" is TRUE, set topline and botline first (for "zb").
1835  * This is messy stuff!!!
1836  */
1837     void
1838 scroll_cursor_bot(int min_scroll, int set_topbot)
1839 {
1840     int		used;
1841     int		scrolled = 0;
1842     int		extra = 0;
1843     int		i;
1844     linenr_T	line_count;
1845     linenr_T	old_topline = curwin->w_topline;
1846     lineoff_T	loff;
1847     lineoff_T	boff;
1848 #ifdef FEAT_DIFF
1849     int		old_topfill = curwin->w_topfill;
1850     int		fill_below_window;
1851 #endif
1852     linenr_T	old_botline = curwin->w_botline;
1853     linenr_T	old_valid = curwin->w_valid;
1854     int		old_empty_rows = curwin->w_empty_rows;
1855     linenr_T	cln;		    /* Cursor Line Number */
1856 
1857     cln = curwin->w_cursor.lnum;
1858     if (set_topbot)
1859     {
1860 	used = 0;
1861 	curwin->w_botline = cln + 1;
1862 #ifdef FEAT_DIFF
1863 	loff.fill = 0;
1864 #endif
1865 	for (curwin->w_topline = curwin->w_botline;
1866 		curwin->w_topline > 1;
1867 		curwin->w_topline = loff.lnum)
1868 	{
1869 	    loff.lnum = curwin->w_topline;
1870 	    topline_back(&loff);
1871 	    if (loff.height == MAXCOL || used + loff.height > curwin->w_height)
1872 		break;
1873 	    used += loff.height;
1874 #ifdef FEAT_DIFF
1875 	    curwin->w_topfill = loff.fill;
1876 #endif
1877 	}
1878 	set_empty_rows(curwin, used);
1879 	curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
1880 	if (curwin->w_topline != old_topline
1881 #ifdef FEAT_DIFF
1882 		|| curwin->w_topfill != old_topfill
1883 #endif
1884 		)
1885 	    curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
1886     }
1887     else
1888 	validate_botline();
1889 
1890     /* The lines of the cursor line itself are always used. */
1891 #ifdef FEAT_DIFF
1892     used = plines_nofill(cln);
1893 #else
1894     validate_cheight();
1895     used = curwin->w_cline_height;
1896 #endif
1897 
1898     /* If the cursor is below botline, we will at least scroll by the height
1899      * of the cursor line.  Correct for empty lines, which are really part of
1900      * botline. */
1901     if (cln >= curwin->w_botline)
1902     {
1903 	scrolled = used;
1904 	if (cln == curwin->w_botline)
1905 	    scrolled -= curwin->w_empty_rows;
1906     }
1907 
1908     /*
1909      * Stop counting lines to scroll when
1910      * - hitting start of the file
1911      * - scrolled nothing or at least 'sj' lines
1912      * - at least 'so' lines below the cursor
1913      * - lines between botline and cursor have been counted
1914      */
1915 #ifdef FEAT_FOLDING
1916     if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum))
1917 #endif
1918     {
1919 	loff.lnum = cln;
1920 	boff.lnum = cln;
1921     }
1922 #ifdef FEAT_DIFF
1923     loff.fill = 0;
1924     boff.fill = 0;
1925     fill_below_window = diff_check_fill(curwin, curwin->w_botline)
1926 						      - curwin->w_filler_rows;
1927 #endif
1928 
1929     while (loff.lnum > 1)
1930     {
1931 	/* Stop when scrolled nothing or at least "min_scroll", found "extra"
1932 	 * context for 'scrolloff' and counted all lines below the window. */
1933 	if ((((scrolled <= 0 || scrolled >= min_scroll)
1934 			&& extra >= (
1935 #ifdef FEAT_MOUSE
1936 			    mouse_dragging > 0 ? mouse_dragging - 1 :
1937 #endif
1938 			    p_so))
1939 		    || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
1940 		&& loff.lnum <= curwin->w_botline
1941 #ifdef FEAT_DIFF
1942 		&& (loff.lnum < curwin->w_botline
1943 		    || loff.fill >= fill_below_window)
1944 #endif
1945 		)
1946 	    break;
1947 
1948 	/* Add one line above */
1949 	topline_back(&loff);
1950 	if (loff.height == MAXCOL)
1951 	    used = MAXCOL;
1952 	else
1953 	    used += loff.height;
1954 	if (used > curwin->w_height)
1955 	    break;
1956 	if (loff.lnum >= curwin->w_botline
1957 #ifdef FEAT_DIFF
1958 		&& (loff.lnum > curwin->w_botline
1959 		    || loff.fill <= fill_below_window)
1960 #endif
1961 		)
1962 	{
1963 	    /* Count screen lines that are below the window. */
1964 	    scrolled += loff.height;
1965 	    if (loff.lnum == curwin->w_botline
1966 #ifdef FEAT_DIFF
1967 			    && boff.fill == 0
1968 #endif
1969 		    )
1970 		scrolled -= curwin->w_empty_rows;
1971 	}
1972 
1973 	if (boff.lnum < curbuf->b_ml.ml_line_count)
1974 	{
1975 	    /* Add one line below */
1976 	    botline_forw(&boff);
1977 	    used += boff.height;
1978 	    if (used > curwin->w_height)
1979 		break;
1980 	    if (extra < (
1981 #ifdef FEAT_MOUSE
1982 			mouse_dragging > 0 ? mouse_dragging - 1 :
1983 #endif
1984 			p_so) || scrolled < min_scroll)
1985 	    {
1986 		extra += boff.height;
1987 		if (boff.lnum >= curwin->w_botline
1988 #ifdef FEAT_DIFF
1989 			|| (boff.lnum + 1 == curwin->w_botline
1990 			    && boff.fill > curwin->w_filler_rows)
1991 #endif
1992 		   )
1993 		{
1994 		    /* Count screen lines that are below the window. */
1995 		    scrolled += boff.height;
1996 		    if (boff.lnum == curwin->w_botline
1997 #ifdef FEAT_DIFF
1998 			    && boff.fill == 0
1999 #endif
2000 			    )
2001 			scrolled -= curwin->w_empty_rows;
2002 		}
2003 	    }
2004 	}
2005     }
2006 
2007     /* curwin->w_empty_rows is larger, no need to scroll */
2008     if (scrolled <= 0)
2009 	line_count = 0;
2010     /* more than a screenfull, don't scroll but redraw */
2011     else if (used > curwin->w_height)
2012 	line_count = used;
2013     /* scroll minimal number of lines */
2014     else
2015     {
2016 	line_count = 0;
2017 #ifdef FEAT_DIFF
2018 	boff.fill = curwin->w_topfill;
2019 #endif
2020 	boff.lnum = curwin->w_topline - 1;
2021 	for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; )
2022 	{
2023 	    botline_forw(&boff);
2024 	    i += boff.height;
2025 	    ++line_count;
2026 	}
2027 	if (i < scrolled)	/* below curwin->w_botline, don't scroll */
2028 	    line_count = 9999;
2029     }
2030 
2031     /*
2032      * Scroll up if the cursor is off the bottom of the screen a bit.
2033      * Otherwise put it at 1/2 of the screen.
2034      */
2035     if (line_count >= curwin->w_height && line_count > min_scroll)
2036 	scroll_cursor_halfway(FALSE);
2037     else
2038 	scrollup(line_count, TRUE);
2039 
2040     /*
2041      * If topline didn't change we need to restore w_botline and w_empty_rows
2042      * (we changed them).
2043      * If topline did change, update_screen() will set botline.
2044      */
2045     if (curwin->w_topline == old_topline && set_topbot)
2046     {
2047 	curwin->w_botline = old_botline;
2048 	curwin->w_empty_rows = old_empty_rows;
2049 	curwin->w_valid = old_valid;
2050     }
2051     curwin->w_valid |= VALID_TOPLINE;
2052 }
2053 
2054 /*
2055  * Recompute topline to put the cursor halfway the window
2056  * If "atend" is TRUE, also put it halfway at the end of the file.
2057  */
2058     void
2059 scroll_cursor_halfway(int atend)
2060 {
2061     int		above = 0;
2062     linenr_T	topline;
2063 #ifdef FEAT_DIFF
2064     int		topfill = 0;
2065 #endif
2066     int		below = 0;
2067     int		used;
2068     lineoff_T	loff;
2069     lineoff_T	boff;
2070 #ifdef FEAT_DIFF
2071     linenr_T	old_topline = curwin->w_topline;
2072 #endif
2073 
2074     loff.lnum = boff.lnum = curwin->w_cursor.lnum;
2075 #ifdef FEAT_FOLDING
2076     (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum);
2077 #endif
2078 #ifdef FEAT_DIFF
2079     used = plines_nofill(loff.lnum);
2080     loff.fill = 0;
2081     boff.fill = 0;
2082 #else
2083     used = plines(loff.lnum);
2084 #endif
2085     topline = loff.lnum;
2086     while (topline > 1)
2087     {
2088 	if (below <= above)	    /* add a line below the cursor first */
2089 	{
2090 	    if (boff.lnum < curbuf->b_ml.ml_line_count)
2091 	    {
2092 		botline_forw(&boff);
2093 		used += boff.height;
2094 		if (used > curwin->w_height)
2095 		    break;
2096 		below += boff.height;
2097 	    }
2098 	    else
2099 	    {
2100 		++below;	    /* count a "~" line */
2101 		if (atend)
2102 		    ++used;
2103 	    }
2104 	}
2105 
2106 	if (below > above)	    /* add a line above the cursor */
2107 	{
2108 	    topline_back(&loff);
2109 	    if (loff.height == MAXCOL)
2110 		used = MAXCOL;
2111 	    else
2112 		used += loff.height;
2113 	    if (used > curwin->w_height)
2114 		break;
2115 	    above += loff.height;
2116 	    topline = loff.lnum;
2117 #ifdef FEAT_DIFF
2118 	    topfill = loff.fill;
2119 #endif
2120 	}
2121     }
2122 #ifdef FEAT_FOLDING
2123     if (!hasFolding(topline, &curwin->w_topline, NULL))
2124 #endif
2125 	curwin->w_topline = topline;
2126 #ifdef FEAT_DIFF
2127     curwin->w_topfill = topfill;
2128     if (old_topline > curwin->w_topline + curwin->w_height)
2129 	curwin->w_botfill = FALSE;
2130     check_topfill(curwin, FALSE);
2131 #endif
2132     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2133     curwin->w_valid |= VALID_TOPLINE;
2134 }
2135 
2136 /*
2137  * Correct the cursor position so that it is in a part of the screen at least
2138  * 'so' lines from the top and bottom, if possible.
2139  * If not possible, put it at the same position as scroll_cursor_halfway().
2140  * When called topline must be valid!
2141  */
2142     void
2143 cursor_correct(void)
2144 {
2145     int		above = 0;	    /* screen lines above topline */
2146     linenr_T	topline;
2147     int		below = 0;	    /* screen lines below botline */
2148     linenr_T	botline;
2149     int		above_wanted, below_wanted;
2150     linenr_T	cln;		    /* Cursor Line Number */
2151     int		max_off;
2152 
2153     /*
2154      * How many lines we would like to have above/below the cursor depends on
2155      * whether the first/last line of the file is on screen.
2156      */
2157     above_wanted = p_so;
2158     below_wanted = p_so;
2159 #ifdef FEAT_MOUSE
2160     if (mouse_dragging > 0)
2161     {
2162 	above_wanted = mouse_dragging - 1;
2163 	below_wanted = mouse_dragging - 1;
2164     }
2165 #endif
2166     if (curwin->w_topline == 1)
2167     {
2168 	above_wanted = 0;
2169 	max_off = curwin->w_height / 2;
2170 	if (below_wanted > max_off)
2171 	    below_wanted = max_off;
2172     }
2173     validate_botline();
2174     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
2175 #ifdef FEAT_MOUSE
2176 	    && mouse_dragging == 0
2177 #endif
2178 	    )
2179     {
2180 	below_wanted = 0;
2181 	max_off = (curwin->w_height - 1) / 2;
2182 	if (above_wanted > max_off)
2183 	    above_wanted = max_off;
2184     }
2185 
2186     /*
2187      * If there are sufficient file-lines above and below the cursor, we can
2188      * return now.
2189      */
2190     cln = curwin->w_cursor.lnum;
2191     if (cln >= curwin->w_topline + above_wanted
2192 	    && cln < curwin->w_botline - below_wanted
2193 #ifdef FEAT_FOLDING
2194 	    && !hasAnyFolding(curwin)
2195 #endif
2196 	    )
2197 	return;
2198 
2199     /*
2200      * Narrow down the area where the cursor can be put by taking lines from
2201      * the top and the bottom until:
2202      * - the desired context lines are found
2203      * - the lines from the top is past the lines from the bottom
2204      */
2205     topline = curwin->w_topline;
2206     botline = curwin->w_botline - 1;
2207 #ifdef FEAT_DIFF
2208     /* count filler lines as context */
2209     above = curwin->w_topfill;
2210     below = curwin->w_filler_rows;
2211 #endif
2212     while ((above < above_wanted || below < below_wanted) && topline < botline)
2213     {
2214 	if (below < below_wanted && (below <= above || above >= above_wanted))
2215 	{
2216 #ifdef FEAT_FOLDING
2217 	    if (hasFolding(botline, &botline, NULL))
2218 		++below;
2219 	    else
2220 #endif
2221 		below += plines(botline);
2222 	    --botline;
2223 	}
2224 	if (above < above_wanted && (above < below || below >= below_wanted))
2225 	{
2226 #ifdef FEAT_FOLDING
2227 	    if (hasFolding(topline, NULL, &topline))
2228 		++above;
2229 	    else
2230 #endif
2231 		above += PLINES_NOFILL(topline);
2232 #ifdef FEAT_DIFF
2233 	    /* Count filler lines below this line as context. */
2234 	    if (topline < botline)
2235 		above += diff_check_fill(curwin, topline + 1);
2236 #endif
2237 	    ++topline;
2238 	}
2239     }
2240     if (topline == botline || botline == 0)
2241 	curwin->w_cursor.lnum = topline;
2242     else if (topline > botline)
2243 	curwin->w_cursor.lnum = botline;
2244     else
2245     {
2246 	if (cln < topline && curwin->w_topline > 1)
2247 	{
2248 	    curwin->w_cursor.lnum = topline;
2249 	    curwin->w_valid &=
2250 			    ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
2251 	}
2252 	if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2253 	{
2254 	    curwin->w_cursor.lnum = botline;
2255 	    curwin->w_valid &=
2256 			    ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
2257 	}
2258     }
2259     curwin->w_valid |= VALID_TOPLINE;
2260 }
2261 
2262 static void get_scroll_overlap(lineoff_T *lp, int dir);
2263 
2264 /*
2265  * move screen 'count' pages up or down and update screen
2266  *
2267  * return FAIL for failure, OK otherwise
2268  */
2269     int
2270 onepage(int dir, long count)
2271 {
2272     long	n;
2273     int		retval = OK;
2274     lineoff_T	loff;
2275     linenr_T	old_topline = curwin->w_topline;
2276 
2277     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
2278     {
2279 	beep_flush();
2280 	return FAIL;
2281     }
2282 
2283     for ( ; count > 0; --count)
2284     {
2285 	validate_botline();
2286 	/*
2287 	 * It's an error to move a page up when the first line is already on
2288 	 * the screen.	It's an error to move a page down when the last line
2289 	 * is on the screen and the topline is 'scrolloff' lines from the
2290 	 * last line.
2291 	 */
2292 	if (dir == FORWARD
2293 		? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so)
2294 		    && curwin->w_botline > curbuf->b_ml.ml_line_count)
2295 		: (curwin->w_topline == 1
2296 #ifdef FEAT_DIFF
2297 		    && curwin->w_topfill ==
2298 				    diff_check_fill(curwin, curwin->w_topline)
2299 #endif
2300 		    ))
2301 	{
2302 	    beep_flush();
2303 	    retval = FAIL;
2304 	    break;
2305 	}
2306 
2307 #ifdef FEAT_DIFF
2308 	loff.fill = 0;
2309 #endif
2310 	if (dir == FORWARD)
2311 	{
2312 	    if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
2313 	    {
2314 		/* Vi compatible scrolling */
2315 		if (p_window <= 2)
2316 		    ++curwin->w_topline;
2317 		else
2318 		    curwin->w_topline += p_window - 2;
2319 		if (curwin->w_topline > curbuf->b_ml.ml_line_count)
2320 		    curwin->w_topline = curbuf->b_ml.ml_line_count;
2321 		curwin->w_cursor.lnum = curwin->w_topline;
2322 	    }
2323 	    else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
2324 	    {
2325 		/* at end of file */
2326 		curwin->w_topline = curbuf->b_ml.ml_line_count;
2327 #ifdef FEAT_DIFF
2328 		curwin->w_topfill = 0;
2329 #endif
2330 		curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
2331 	    }
2332 	    else
2333 	    {
2334 		/* For the overlap, start with the line just below the window
2335 		 * and go upwards. */
2336 		loff.lnum = curwin->w_botline;
2337 #ifdef FEAT_DIFF
2338 		loff.fill = diff_check_fill(curwin, loff.lnum)
2339 						      - curwin->w_filler_rows;
2340 #endif
2341 		get_scroll_overlap(&loff, -1);
2342 		curwin->w_topline = loff.lnum;
2343 #ifdef FEAT_DIFF
2344 		curwin->w_topfill = loff.fill;
2345 		check_topfill(curwin, FALSE);
2346 #endif
2347 		curwin->w_cursor.lnum = curwin->w_topline;
2348 		curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
2349 				   VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2350 	    }
2351 	}
2352 	else	/* dir == BACKWARDS */
2353 	{
2354 #ifdef FEAT_DIFF
2355 	    if (curwin->w_topline == 1)
2356 	    {
2357 		/* Include max number of filler lines */
2358 		max_topfill();
2359 		continue;
2360 	    }
2361 #endif
2362 	    if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
2363 	    {
2364 		/* Vi compatible scrolling (sort of) */
2365 		if (p_window <= 2)
2366 		    --curwin->w_topline;
2367 		else
2368 		    curwin->w_topline -= p_window - 2;
2369 		if (curwin->w_topline < 1)
2370 		    curwin->w_topline = 1;
2371 		curwin->w_cursor.lnum = curwin->w_topline + p_window - 1;
2372 		if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
2373 		    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2374 		continue;
2375 	    }
2376 
2377 	    /* Find the line at the top of the window that is going to be the
2378 	     * line at the bottom of the window.  Make sure this results in
2379 	     * the same line as before doing CTRL-F. */
2380 	    loff.lnum = curwin->w_topline - 1;
2381 #ifdef FEAT_DIFF
2382 	    loff.fill = diff_check_fill(curwin, loff.lnum + 1)
2383 							  - curwin->w_topfill;
2384 #endif
2385 	    get_scroll_overlap(&loff, 1);
2386 
2387 	    if (loff.lnum >= curbuf->b_ml.ml_line_count)
2388 	    {
2389 		loff.lnum = curbuf->b_ml.ml_line_count;
2390 #ifdef FEAT_DIFF
2391 		loff.fill = 0;
2392 	    }
2393 	    else
2394 	    {
2395 		botline_topline(&loff);
2396 #endif
2397 	    }
2398 	    curwin->w_cursor.lnum = loff.lnum;
2399 
2400 	    /* Find the line just above the new topline to get the right line
2401 	     * at the bottom of the window. */
2402 	    n = 0;
2403 	    while (n <= curwin->w_height && loff.lnum >= 1)
2404 	    {
2405 		topline_back(&loff);
2406 		if (loff.height == MAXCOL)
2407 		    n = MAXCOL;
2408 		else
2409 		    n += loff.height;
2410 	    }
2411 	    if (loff.lnum < 1)			/* at begin of file */
2412 	    {
2413 		curwin->w_topline = 1;
2414 #ifdef FEAT_DIFF
2415 		max_topfill();
2416 #endif
2417 		curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
2418 	    }
2419 	    else
2420 	    {
2421 		/* Go two lines forward again. */
2422 #ifdef FEAT_DIFF
2423 		topline_botline(&loff);
2424 #endif
2425 		botline_forw(&loff);
2426 		botline_forw(&loff);
2427 #ifdef FEAT_DIFF
2428 		botline_topline(&loff);
2429 #endif
2430 #ifdef FEAT_FOLDING
2431 		/* We're at the wrong end of a fold now. */
2432 		(void)hasFolding(loff.lnum, &loff.lnum, NULL);
2433 #endif
2434 
2435 		/* Always scroll at least one line.  Avoid getting stuck on
2436 		 * very long lines. */
2437 		if (loff.lnum >= curwin->w_topline
2438 #ifdef FEAT_DIFF
2439 			&& (loff.lnum > curwin->w_topline
2440 			    || loff.fill >= curwin->w_topfill)
2441 #endif
2442 			)
2443 		{
2444 #ifdef FEAT_DIFF
2445 		    /* First try using the maximum number of filler lines.  If
2446 		     * that's not enough, backup one line. */
2447 		    loff.fill = curwin->w_topfill;
2448 		    if (curwin->w_topfill < diff_check_fill(curwin,
2449 							   curwin->w_topline))
2450 			max_topfill();
2451 		    if (curwin->w_topfill == loff.fill)
2452 #endif
2453 		    {
2454 			--curwin->w_topline;
2455 #ifdef FEAT_DIFF
2456 			curwin->w_topfill = 0;
2457 #endif
2458 		    }
2459 		    comp_botline(curwin);
2460 		    curwin->w_cursor.lnum = curwin->w_botline - 1;
2461 		    curwin->w_valid &=
2462 			    ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW);
2463 		}
2464 		else
2465 		{
2466 		    curwin->w_topline = loff.lnum;
2467 #ifdef FEAT_DIFF
2468 		    curwin->w_topfill = loff.fill;
2469 		    check_topfill(curwin, FALSE);
2470 #endif
2471 		    curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
2472 		}
2473 	    }
2474 	}
2475     }
2476 #ifdef FEAT_FOLDING
2477     foldAdjustCursor();
2478 #endif
2479     cursor_correct();
2480     check_cursor_col();
2481     if (retval == OK)
2482 	beginline(BL_SOL | BL_FIX);
2483     curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
2484 
2485     /*
2486      * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
2487      * But make sure we scroll at least one line (happens with mix of long
2488      * wrapping lines and non-wrapping line).
2489      */
2490     if (retval == OK && dir == FORWARD && check_top_offset())
2491     {
2492 	scroll_cursor_top(1, FALSE);
2493 	if (curwin->w_topline <= old_topline
2494 				  && old_topline < curbuf->b_ml.ml_line_count)
2495 	{
2496 	    curwin->w_topline = old_topline + 1;
2497 #ifdef FEAT_FOLDING
2498 	    (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2499 #endif
2500 	}
2501     }
2502 
2503     redraw_later(VALID);
2504     return retval;
2505 }
2506 
2507 /*
2508  * Decide how much overlap to use for page-up or page-down scrolling.
2509  * This is symmetric, so that doing both keeps the same lines displayed.
2510  * Three lines are examined:
2511  *
2512  *  before CTRL-F	    after CTRL-F / before CTRL-B
2513  *     etc.			l1
2514  *  l1 last but one line	------------
2515  *  l2 last text line		l2 top text line
2516  *  -------------		l3 second text line
2517  *  l3				   etc.
2518  */
2519     static void
2520 get_scroll_overlap(lineoff_T *lp, int dir)
2521 {
2522     int		h1, h2, h3, h4;
2523     int		min_height = curwin->w_height - 2;
2524     lineoff_T	loff0, loff1, loff2;
2525 
2526 #ifdef FEAT_DIFF
2527     if (lp->fill > 0)
2528 	lp->height = 1;
2529     else
2530 	lp->height = plines_nofill(lp->lnum);
2531 #else
2532     lp->height = plines(lp->lnum);
2533 #endif
2534     h1 = lp->height;
2535     if (h1 > min_height)
2536 	return;		/* no overlap */
2537 
2538     loff0 = *lp;
2539     if (dir > 0)
2540 	botline_forw(lp);
2541     else
2542 	topline_back(lp);
2543     h2 = lp->height;
2544     if (h2 == MAXCOL || h2 + h1 > min_height)
2545     {
2546 	*lp = loff0;	/* no overlap */
2547 	return;
2548     }
2549 
2550     loff1 = *lp;
2551     if (dir > 0)
2552 	botline_forw(lp);
2553     else
2554 	topline_back(lp);
2555     h3 = lp->height;
2556     if (h3 == MAXCOL || h3 + h2 > min_height)
2557     {
2558 	*lp = loff0;	/* no overlap */
2559 	return;
2560     }
2561 
2562     loff2 = *lp;
2563     if (dir > 0)
2564 	botline_forw(lp);
2565     else
2566 	topline_back(lp);
2567     h4 = lp->height;
2568     if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
2569 	*lp = loff1;	/* 1 line overlap */
2570     else
2571 	*lp = loff2;	/* 2 lines overlap */
2572     return;
2573 }
2574 
2575 /* #define KEEP_SCREEN_LINE */
2576 /*
2577  * Scroll 'scroll' lines up or down.
2578  */
2579     void
2580 halfpage(int flag, linenr_T Prenum)
2581 {
2582     long	scrolled = 0;
2583     int		i;
2584     int		n;
2585     int		room;
2586 
2587     if (Prenum)
2588 	curwin->w_p_scr = (Prenum > curwin->w_height) ?
2589 						curwin->w_height : Prenum;
2590     n = (curwin->w_p_scr <= curwin->w_height) ?
2591 				    curwin->w_p_scr : curwin->w_height;
2592 
2593     update_topline();
2594     validate_botline();
2595     room = curwin->w_empty_rows;
2596 #ifdef FEAT_DIFF
2597     room += curwin->w_filler_rows;
2598 #endif
2599     if (flag)
2600     {
2601 	/*
2602 	 * scroll the text up
2603 	 */
2604 	while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2605 	{
2606 #ifdef FEAT_DIFF
2607 	    if (curwin->w_topfill > 0)
2608 	    {
2609 		i = 1;
2610 		if (--n < 0 && scrolled > 0)
2611 		    break;
2612 		--curwin->w_topfill;
2613 	    }
2614 	    else
2615 #endif
2616 	    {
2617 		i = PLINES_NOFILL(curwin->w_topline);
2618 		n -= i;
2619 		if (n < 0 && scrolled > 0)
2620 		    break;
2621 #ifdef FEAT_FOLDING
2622 		(void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
2623 #endif
2624 		++curwin->w_topline;
2625 #ifdef FEAT_DIFF
2626 		curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
2627 #endif
2628 
2629 #ifndef KEEP_SCREEN_LINE
2630 		if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2631 		{
2632 		    ++curwin->w_cursor.lnum;
2633 		    curwin->w_valid &=
2634 				    ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
2635 		}
2636 #endif
2637 	    }
2638 	    curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
2639 	    scrolled += i;
2640 
2641 	    /*
2642 	     * Correct w_botline for changed w_topline.
2643 	     * Won't work when there are filler lines.
2644 	     */
2645 #ifdef FEAT_DIFF
2646 	    if (curwin->w_p_diff)
2647 		curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
2648 	    else
2649 #endif
2650 	    {
2651 		room += i;
2652 		do
2653 		{
2654 		    i = plines(curwin->w_botline);
2655 		    if (i > room)
2656 			break;
2657 #ifdef FEAT_FOLDING
2658 		    (void)hasFolding(curwin->w_botline, NULL,
2659 							  &curwin->w_botline);
2660 #endif
2661 		    ++curwin->w_botline;
2662 		    room -= i;
2663 		} while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
2664 	    }
2665 	}
2666 
2667 #ifndef KEEP_SCREEN_LINE
2668 	/*
2669 	 * When hit bottom of the file: move cursor down.
2670 	 */
2671 	if (n > 0)
2672 	{
2673 # ifdef FEAT_FOLDING
2674 	    if (hasAnyFolding(curwin))
2675 	    {
2676 		while (--n >= 0
2677 			&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2678 		{
2679 		    (void)hasFolding(curwin->w_cursor.lnum, NULL,
2680 						      &curwin->w_cursor.lnum);
2681 		    ++curwin->w_cursor.lnum;
2682 		}
2683 	    }
2684 	    else
2685 # endif
2686 		curwin->w_cursor.lnum += n;
2687 	    check_cursor_lnum();
2688 	}
2689 #else
2690 	/* try to put the cursor in the same screen line */
2691 	while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
2692 			     && curwin->w_cursor.lnum < curwin->w_botline - 1)
2693 	{
2694 	    scrolled -= plines(curwin->w_cursor.lnum);
2695 	    if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
2696 		break;
2697 # ifdef FEAT_FOLDING
2698 	    (void)hasFolding(curwin->w_cursor.lnum, NULL,
2699 						      &curwin->w_cursor.lnum);
2700 # endif
2701 	    ++curwin->w_cursor.lnum;
2702 	}
2703 #endif
2704     }
2705     else
2706     {
2707 	/*
2708 	 * scroll the text down
2709 	 */
2710 	while (n > 0 && curwin->w_topline > 1)
2711 	{
2712 #ifdef FEAT_DIFF
2713 	    if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
2714 	    {
2715 		i = 1;
2716 		if (--n < 0 && scrolled > 0)
2717 		    break;
2718 		++curwin->w_topfill;
2719 	    }
2720 	    else
2721 #endif
2722 	    {
2723 		i = PLINES_NOFILL(curwin->w_topline - 1);
2724 		n -= i;
2725 		if (n < 0 && scrolled > 0)
2726 		    break;
2727 		--curwin->w_topline;
2728 #ifdef FEAT_FOLDING
2729 		(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2730 #endif
2731 #ifdef FEAT_DIFF
2732 		curwin->w_topfill = 0;
2733 #endif
2734 	    }
2735 	    curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
2736 					      VALID_BOTLINE|VALID_BOTLINE_AP);
2737 	    scrolled += i;
2738 #ifndef KEEP_SCREEN_LINE
2739 	    if (curwin->w_cursor.lnum > 1)
2740 	    {
2741 		--curwin->w_cursor.lnum;
2742 		curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
2743 	    }
2744 #endif
2745 	}
2746 #ifndef KEEP_SCREEN_LINE
2747 	/*
2748 	 * When hit top of the file: move cursor up.
2749 	 */
2750 	if (n > 0)
2751 	{
2752 	    if (curwin->w_cursor.lnum <= (linenr_T)n)
2753 		curwin->w_cursor.lnum = 1;
2754 	    else
2755 # ifdef FEAT_FOLDING
2756 	    if (hasAnyFolding(curwin))
2757 	    {
2758 		while (--n >= 0 && curwin->w_cursor.lnum > 1)
2759 		{
2760 		    --curwin->w_cursor.lnum;
2761 		    (void)hasFolding(curwin->w_cursor.lnum,
2762 						&curwin->w_cursor.lnum, NULL);
2763 		}
2764 	    }
2765 	    else
2766 # endif
2767 		curwin->w_cursor.lnum -= n;
2768 	}
2769 #else
2770 	/* try to put the cursor in the same screen line */
2771 	scrolled += n;	    /* move cursor when topline is 1 */
2772 	while (curwin->w_cursor.lnum > curwin->w_topline
2773 	      && (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
2774 	{
2775 	    scrolled -= plines(curwin->w_cursor.lnum - 1);
2776 	    if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
2777 		break;
2778 	    --curwin->w_cursor.lnum;
2779 # ifdef FEAT_FOLDING
2780 	    foldAdjustCursor();
2781 # endif
2782 	}
2783 #endif
2784     }
2785 # ifdef FEAT_FOLDING
2786     /* Move cursor to first line of closed fold. */
2787     foldAdjustCursor();
2788 # endif
2789 #ifdef FEAT_DIFF
2790     check_topfill(curwin, !flag);
2791 #endif
2792     cursor_correct();
2793     beginline(BL_SOL | BL_FIX);
2794     redraw_later(VALID);
2795 }
2796 
2797 #if defined(FEAT_CURSORBIND) || defined(PROTO)
2798     void
2799 do_check_cursorbind(void)
2800 {
2801     linenr_T	line = curwin->w_cursor.lnum;
2802     colnr_T	col = curwin->w_cursor.col;
2803 # ifdef FEAT_VIRTUALEDIT
2804     colnr_T	coladd = curwin->w_cursor.coladd;
2805 # endif
2806     colnr_T	curswant = curwin->w_curswant;
2807     int		set_curswant = curwin->w_set_curswant;
2808     win_T	*old_curwin = curwin;
2809     buf_T	*old_curbuf = curbuf;
2810     int		restart_edit_save;
2811     int		old_VIsual_select = VIsual_select;
2812     int		old_VIsual_active = VIsual_active;
2813 
2814     /*
2815      * loop through the cursorbound windows
2816      */
2817     VIsual_select = VIsual_active = 0;
2818     FOR_ALL_WINDOWS(curwin)
2819     {
2820 	curbuf = curwin->w_buffer;
2821 	/* skip original window  and windows with 'noscrollbind' */
2822 	if (curwin != old_curwin && curwin->w_p_crb)
2823 	{
2824 # ifdef FEAT_DIFF
2825 	    if (curwin->w_p_diff)
2826 		curwin->w_cursor.lnum =
2827 				 diff_get_corresponding_line(old_curbuf, line);
2828 	    else
2829 # endif
2830 		curwin->w_cursor.lnum = line;
2831 	    curwin->w_cursor.col = col;
2832 # ifdef FEAT_VIRTUALEDIT
2833 	    curwin->w_cursor.coladd = coladd;
2834 # endif
2835 	    curwin->w_curswant = curswant;
2836 	    curwin->w_set_curswant = set_curswant;
2837 
2838 	    /* Make sure the cursor is in a valid position.  Temporarily set
2839 	     * "restart_edit" to allow the cursor to be beyond the EOL. */
2840 	    restart_edit_save = restart_edit;
2841 	    restart_edit = TRUE;
2842 	    check_cursor();
2843 # ifdef FEAT_SYN_HL
2844 	    if (curwin->w_p_cul || curwin->w_p_cuc)
2845 		validate_cursor();
2846 # endif
2847 	    restart_edit = restart_edit_save;
2848 # ifdef FEAT_MBYTE
2849 	    /* Correct cursor for multi-byte character. */
2850 	    if (has_mbyte)
2851 		mb_adjust_cursor();
2852 # endif
2853 	    redraw_later(VALID);
2854 
2855 	    /* Only scroll when 'scrollbind' hasn't done this. */
2856 	    if (!curwin->w_p_scb)
2857 		update_topline();
2858 # ifdef FEAT_WINDOWS
2859 	    curwin->w_redr_status = TRUE;
2860 # endif
2861 	}
2862     }
2863 
2864     /*
2865      * reset current-window
2866      */
2867     VIsual_select = old_VIsual_select;
2868     VIsual_active = old_VIsual_active;
2869     curwin = old_curwin;
2870     curbuf = old_curbuf;
2871 }
2872 #endif /* FEAT_CURSORBIND */
2873