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