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