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