blob: cc399ec9e7cc78170200061a4d76de43a8accfdb [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +010022static void redraw_for_cursorline(win_T *wp);
23static int scrolljump_value(void);
24static int check_top_offset(void);
25static void curs_rows(win_T *wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +000026
27typedef struct
28{
29 linenr_T lnum; /* line number */
30#ifdef FEAT_DIFF
31 int fill; /* filler lines */
32#endif
33 int height; /* height of added line */
34} lineoff_T;
35
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +010036static void topline_back(lineoff_T *lp);
37static void botline_forw(lineoff_T *lp);
Bram Moolenaar071d4272004-06-13 20:20:40 +000038
39/*
40 * Compute wp->w_botline for the current wp->w_topline. Can be called after
41 * wp->w_topline changed.
42 */
43 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +010044comp_botline(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +000045{
46 int n;
47 linenr_T lnum;
48 int done;
49#ifdef FEAT_FOLDING
50 linenr_T last;
51 int folded;
52#endif
53
54 /*
55 * If w_cline_row is valid, start there.
56 * Otherwise have to start at w_topline.
57 */
58 check_cursor_moved(wp);
59 if (wp->w_valid & VALID_CROW)
60 {
61 lnum = wp->w_cursor.lnum;
62 done = wp->w_cline_row;
63 }
64 else
65 {
66 lnum = wp->w_topline;
67 done = 0;
68 }
69
70 for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
71 {
72#ifdef FEAT_FOLDING
73 last = lnum;
74 folded = FALSE;
75 if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
76 {
77 n = 1;
78 folded = TRUE;
79 }
80 else
81#endif
82#ifdef FEAT_DIFF
83 if (lnum == wp->w_topline)
84 n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
85 else
86#endif
87 n = plines_win(wp, lnum, TRUE);
88 if (
89#ifdef FEAT_FOLDING
90 lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum
91#else
92 lnum == wp->w_cursor.lnum
93#endif
94 )
95 {
96 wp->w_cline_row = done;
97 wp->w_cline_height = n;
98#ifdef FEAT_FOLDING
99 wp->w_cline_folded = folded;
100#endif
Bram Moolenaar3d6db142014-03-28 21:49:32 +0100101 redraw_for_cursorline(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102 wp->w_valid |= (VALID_CROW|VALID_CHEIGHT);
103 }
104 if (done + n > wp->w_height)
105 break;
106 done += n;
107#ifdef FEAT_FOLDING
108 lnum = last;
109#endif
110 }
111
112 /* wp->w_botline is the line that is just below the window */
113 wp->w_botline = lnum;
114 wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
115
116 set_empty_rows(wp, done);
117}
118
Bram Moolenaar90a99792018-09-12 21:52:18 +0200119#ifdef FEAT_SYN_HL
120static linenr_T last_cursorline = 0;
Bram Moolenaar8c63e0e2018-09-25 22:17:54 +0200121
122 void
123reset_cursorline(void)
124{
125 last_cursorline = 0;
126}
Bram Moolenaar90a99792018-09-12 21:52:18 +0200127#endif
128
Bram Moolenaar071d4272004-06-13 20:20:40 +0000129/*
Bram Moolenaar3d6db142014-03-28 21:49:32 +0100130 * Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is
131 * set.
132 */
133 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100134redraw_for_cursorline(win_T *wp)
Bram Moolenaar3d6db142014-03-28 21:49:32 +0100135{
136 if ((wp->w_p_rnu
137#ifdef FEAT_SYN_HL
138 || wp->w_p_cul
139#endif
140 )
141 && (wp->w_valid & VALID_CROW) == 0
142# ifdef FEAT_INS_EXPAND
143 && !pum_visible()
144# endif
145 )
Bram Moolenaar90a99792018-09-12 21:52:18 +0200146 {
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +0200147 if (wp->w_p_rnu)
148 // win_line() will redraw the number column only.
Bram Moolenaar90a99792018-09-12 21:52:18 +0200149 redraw_win_later(wp, VALID);
Bram Moolenaar1b7fefc2018-09-12 22:27:15 +0200150#ifdef FEAT_SYN_HL
Bram Moolenaarbd9a53c2018-09-12 23:15:48 +0200151 if (wp->w_p_cul)
152 {
153 if (wp->w_redr_type <= VALID && last_cursorline != 0)
154 {
155 // "last_cursorline" may be set for another window, worst case
156 // we redraw too much. This is optimized for moving the cursor
157 // around in the same window.
158 redrawWinline(wp, last_cursorline, FALSE);
159 redrawWinline(wp, wp->w_cursor.lnum, FALSE);
160 redraw_win_later(wp, VALID);
161 }
162 else
163 redraw_win_later(wp, SOME_VALID);
164 last_cursorline = wp->w_cursor.lnum;
165 }
Bram Moolenaar1b7fefc2018-09-12 22:27:15 +0200166#endif
Bram Moolenaar90a99792018-09-12 21:52:18 +0200167 }
Bram Moolenaar3d6db142014-03-28 21:49:32 +0100168}
169
170/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 * Update curwin->w_topline and redraw if necessary.
172 * Used to update the screen before printing a message.
173 */
174 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100175update_topline_redraw(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176{
177 update_topline();
178 if (must_redraw)
179 update_screen(0);
180}
181
182/*
183 * Update curwin->w_topline to move the cursor onto the screen.
184 */
185 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100186update_topline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187{
188 long line_count;
189 int halfheight;
190 int n;
191 linenr_T old_topline;
192#ifdef FEAT_DIFF
193 int old_topfill;
194#endif
195#ifdef FEAT_FOLDING
196 linenr_T lnum;
197#endif
198 int check_topline = FALSE;
199 int check_botline = FALSE;
200#ifdef FEAT_MOUSE
201 int save_so = p_so;
202#endif
203
Bram Moolenaard5d37532017-03-27 23:02:07 +0200204 /* If there is no valid screen and when the window height is zero just use
205 * the cursor line. */
206 if (!screen_valid(TRUE) || curwin->w_height == 0)
Bram Moolenaarcfc216e2014-09-23 18:37:56 +0200207 {
208 curwin->w_topline = curwin->w_cursor.lnum;
209 curwin->w_botline = curwin->w_topline;
210 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
Bram Moolenaarcfc216e2014-09-23 18:37:56 +0200211 curwin->w_scbind_pos = 1;
Bram Moolenaarcfc216e2014-09-23 18:37:56 +0200212 return;
213 }
214
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215 check_cursor_moved(curwin);
216 if (curwin->w_valid & VALID_TOPLINE)
217 return;
218
219#ifdef FEAT_MOUSE
220 /* When dragging with the mouse, don't scroll that quickly */
Bram Moolenaar9964e462007-05-05 17:54:07 +0000221 if (mouse_dragging > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000222 p_so = mouse_dragging - 1;
223#endif
224
225 old_topline = curwin->w_topline;
226#ifdef FEAT_DIFF
227 old_topfill = curwin->w_topfill;
228#endif
229
230 /*
231 * If the buffer is empty, always set topline to 1.
232 */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100233 if (BUFEMPTY()) /* special case - file is empty */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 {
235 if (curwin->w_topline != 1)
236 redraw_later(NOT_VALID);
237 curwin->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238 curwin->w_botline = 2;
239 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240 curwin->w_scbind_pos = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 }
242
243 /*
244 * If the cursor is above or near the top of the window, scroll the window
245 * to show the line the cursor is in, with 'scrolloff' context.
246 */
247 else
248 {
249 if (curwin->w_topline > 1)
250 {
251 /* If the cursor is above topline, scrolling is always needed.
252 * If the cursor is far below topline and there is no folding,
253 * scrolling down is never needed. */
254 if (curwin->w_cursor.lnum < curwin->w_topline)
255 check_topline = TRUE;
256 else if (check_top_offset())
257 check_topline = TRUE;
258 }
259#ifdef FEAT_DIFF
260 /* Check if there are more filler lines than allowed. */
261 if (!check_topline && curwin->w_topfill > diff_check_fill(curwin,
262 curwin->w_topline))
263 check_topline = TRUE;
264#endif
265
266 if (check_topline)
267 {
268 halfheight = curwin->w_height / 2 - 1;
269 if (halfheight < 2)
270 halfheight = 2;
271
272#ifdef FEAT_FOLDING
273 if (hasAnyFolding(curwin))
274 {
275 /* Count the number of logical lines between the cursor and
276 * topline + p_so (approximation of how much will be
277 * scrolled). */
278 n = 0;
279 for (lnum = curwin->w_cursor.lnum;
280 lnum < curwin->w_topline + p_so; ++lnum)
281 {
282 ++n;
283 /* stop at end of file or when we know we are far off */
284 if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight)
285 break;
286 (void)hasFolding(lnum, NULL, &lnum);
287 }
288 }
289 else
290#endif
291 n = curwin->w_topline + p_so - curwin->w_cursor.lnum;
292
293 /* If we weren't very close to begin with, we scroll to put the
294 * cursor in the middle of the window. Otherwise put the cursor
295 * near the top of the window. */
296 if (n >= halfheight)
297 scroll_cursor_halfway(FALSE);
298 else
299 {
Bram Moolenaar1e015462005-09-25 22:16:38 +0000300 scroll_cursor_top(scrolljump_value(), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 check_botline = TRUE;
302 }
303 }
304
305 else
306 {
307#ifdef FEAT_FOLDING
308 /* Make sure topline is the first line of a fold. */
309 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
310#endif
311 check_botline = TRUE;
312 }
313 }
314
315 /*
316 * If the cursor is below the bottom of the window, scroll the window
317 * to put the cursor on the window.
318 * When w_botline is invalid, recompute it first, to avoid a redraw later.
319 * If w_botline was approximated, we might need a redraw later in a few
320 * cases, but we don't want to spend (a lot of) time recomputing w_botline
321 * for every small change.
322 */
323 if (check_botline)
324 {
325 if (!(curwin->w_valid & VALID_BOTLINE_AP))
326 validate_botline();
327
328 if (curwin->w_botline <= curbuf->b_ml.ml_line_count)
329 {
Bram Moolenaard4153d42008-11-15 15:06:17 +0000330 if (curwin->w_cursor.lnum < curwin->w_botline)
331 {
332 if (((long)curwin->w_cursor.lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +0000333 >= (long)curwin->w_botline - p_so
334#ifdef FEAT_FOLDING
335 || hasAnyFolding(curwin)
336#endif
337 ))
Bram Moolenaard4153d42008-11-15 15:06:17 +0000338 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000339 lineoff_T loff;
340
Bram Moolenaard4153d42008-11-15 15:06:17 +0000341 /* Cursor is (a few lines) above botline, check if there are
342 * 'scrolloff' window lines below the cursor. If not, need to
343 * scroll. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 n = curwin->w_empty_rows;
345 loff.lnum = curwin->w_cursor.lnum;
346#ifdef FEAT_FOLDING
347 /* In a fold go to its last line. */
348 (void)hasFolding(loff.lnum, NULL, &loff.lnum);
349#endif
350#ifdef FEAT_DIFF
351 loff.fill = 0;
352 n += curwin->w_filler_rows;
353#endif
354 loff.height = 0;
355 while (loff.lnum < curwin->w_botline
356#ifdef FEAT_DIFF
357 && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
358#endif
359 )
360 {
361 n += loff.height;
362 if (n >= p_so)
363 break;
364 botline_forw(&loff);
365 }
366 if (n >= p_so)
367 /* sufficient context, no need to scroll */
368 check_botline = FALSE;
Bram Moolenaard4153d42008-11-15 15:06:17 +0000369 }
370 else
371 /* sufficient context, no need to scroll */
372 check_botline = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 }
374 if (check_botline)
375 {
376#ifdef FEAT_FOLDING
377 if (hasAnyFolding(curwin))
378 {
379 /* Count the number of logical lines between the cursor and
380 * botline - p_so (approximation of how much will be
381 * scrolled). */
382 line_count = 0;
383 for (lnum = curwin->w_cursor.lnum;
384 lnum >= curwin->w_botline - p_so; --lnum)
385 {
386 ++line_count;
387 /* stop at end of file or when we know we are far off */
388 if (lnum <= 0 || line_count > curwin->w_height + 1)
389 break;
390 (void)hasFolding(lnum, &lnum, NULL);
391 }
392 }
393 else
394#endif
395 line_count = curwin->w_cursor.lnum - curwin->w_botline
396 + 1 + p_so;
397 if (line_count <= curwin->w_height + 1)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000398 scroll_cursor_bot(scrolljump_value(), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399 else
400 scroll_cursor_halfway(FALSE);
401 }
402 }
403 }
404 curwin->w_valid |= VALID_TOPLINE;
405
406 /*
407 * Need to redraw when topline changed.
408 */
409 if (curwin->w_topline != old_topline
410#ifdef FEAT_DIFF
411 || curwin->w_topfill != old_topfill
412#endif
413 )
414 {
Bram Moolenaar76b9b362012-02-04 23:35:00 +0100415 dollar_vcol = -1;
Bram Moolenaar2b48ad52006-03-12 21:56:11 +0000416 if (curwin->w_skipcol != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 {
418 curwin->w_skipcol = 0;
419 redraw_later(NOT_VALID);
420 }
421 else
422 redraw_later(VALID);
423 /* May need to set w_skipcol when cursor in w_topline. */
424 if (curwin->w_cursor.lnum == curwin->w_topline)
425 validate_cursor();
426 }
427
428#ifdef FEAT_MOUSE
429 p_so = save_so;
430#endif
431}
432
433/*
Bram Moolenaar1e015462005-09-25 22:16:38 +0000434 * Return the scrolljump value to use for the current window.
435 * When 'scrolljump' is positive use it as-is.
436 * When 'scrolljump' is negative use it as a percentage of the window height.
437 */
438 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100439scrolljump_value(void)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000440{
441 if (p_sj >= 0)
442 return (int)p_sj;
443 return (curwin->w_height * -p_sj) / 100;
444}
445
446/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447 * Return TRUE when there are not 'scrolloff' lines above the cursor for the
448 * current window.
449 */
450 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100451check_top_offset(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452{
453 lineoff_T loff;
454 int n;
455
456 if (curwin->w_cursor.lnum < curwin->w_topline + p_so
457#ifdef FEAT_FOLDING
458 || hasAnyFolding(curwin)
459#endif
460 )
461 {
462 loff.lnum = curwin->w_cursor.lnum;
463#ifdef FEAT_DIFF
464 loff.fill = 0;
465 n = curwin->w_topfill; /* always have this context */
466#else
467 n = 0;
468#endif
469 /* Count the visible screen lines above the cursor line. */
470 while (n < p_so)
471 {
472 topline_back(&loff);
473 /* Stop when included a line above the window. */
474 if (loff.lnum < curwin->w_topline
475#ifdef FEAT_DIFF
476 || (loff.lnum == curwin->w_topline && loff.fill > 0)
477#endif
478 )
479 break;
480 n += loff.height;
481 }
482 if (n < p_so)
483 return TRUE;
484 }
485 return FALSE;
486}
487
488 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100489update_curswant(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490{
491 if (curwin->w_set_curswant)
492 {
493 validate_virtcol();
494 curwin->w_curswant = curwin->w_virtcol;
495 curwin->w_set_curswant = FALSE;
496 }
497}
498
499/*
500 * Check if the cursor has moved. Set the w_valid flag accordingly.
501 */
502 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100503check_cursor_moved(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504{
505 if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
506 {
507 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
508 |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
509 wp->w_valid_cursor = wp->w_cursor;
510 wp->w_valid_leftcol = wp->w_leftcol;
511 }
512 else if (wp->w_cursor.col != wp->w_valid_cursor.col
513 || wp->w_leftcol != wp->w_valid_leftcol
514#ifdef FEAT_VIRTUALEDIT
515 || wp->w_cursor.coladd != wp->w_valid_cursor.coladd
516#endif
517 )
518 {
519 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
520 wp->w_valid_cursor.col = wp->w_cursor.col;
521 wp->w_valid_leftcol = wp->w_leftcol;
522#ifdef FEAT_VIRTUALEDIT
523 wp->w_valid_cursor.coladd = wp->w_cursor.coladd;
524#endif
525 }
526}
527
528/*
529 * Call this function when some window settings have changed, which require
530 * the cursor position, botline and topline to be recomputed and the window to
531 * be redrawn. E.g, when changing the 'wrap' option or folding.
532 */
533 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100534changed_window_setting(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535{
536 changed_window_setting_win(curwin);
537}
538
539 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100540changed_window_setting_win(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541{
542 wp->w_lines_valid = 0;
543 changed_line_abv_curs_win(wp);
544 wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE);
545 redraw_win_later(wp, NOT_VALID);
546}
547
548/*
549 * Set wp->w_topline to a certain number.
550 */
551 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100552set_topline(win_T *wp, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553{
554#ifdef FEAT_FOLDING
555 /* go to first of folded lines */
556 (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
557#endif
558 /* Approximate the value of w_botline */
559 wp->w_botline += lnum - wp->w_topline;
560 wp->w_topline = lnum;
Bram Moolenaard4153d42008-11-15 15:06:17 +0000561 wp->w_topline_was_set = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562#ifdef FEAT_DIFF
563 wp->w_topfill = 0;
564#endif
565 wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
566 /* Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. */
567 redraw_later(VALID);
568}
569
570/*
571 * Call this function when the length of the cursor line (in screen
572 * characters) has changed, and the change is before the cursor.
573 * Need to take care of w_botline separately!
574 */
575 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100576changed_cline_bef_curs(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577{
578 curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
579 |VALID_CHEIGHT|VALID_TOPLINE);
580}
581
582 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100583changed_cline_bef_curs_win(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584{
585 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
586 |VALID_CHEIGHT|VALID_TOPLINE);
587}
588
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589/*
590 * Call this function when the length of a line (in screen characters) above
591 * the cursor have changed.
592 * Need to take care of w_botline separately!
593 */
594 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100595changed_line_abv_curs(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596{
597 curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
598 |VALID_CHEIGHT|VALID_TOPLINE);
599}
600
601 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100602changed_line_abv_curs_win(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603{
604 wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
605 |VALID_CHEIGHT|VALID_TOPLINE);
606}
607
608/*
609 * Make sure the value of curwin->w_botline is valid.
610 */
611 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100612validate_botline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613{
614 if (!(curwin->w_valid & VALID_BOTLINE))
615 comp_botline(curwin);
616}
617
618/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619 * Mark curwin->w_botline as invalid (because of some change in the buffer).
620 */
621 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100622invalidate_botline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623{
624 curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
625}
626
627 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100628invalidate_botline_win(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629{
630 wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
631}
632
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100634approximate_botline_win(
635 win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000636{
637 wp->w_valid &= ~VALID_BOTLINE;
638}
639
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640/*
641 * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
642 */
643 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100644cursor_valid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645{
646 check_cursor_moved(curwin);
647 return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
648 (VALID_WROW|VALID_WCOL));
649}
650
651/*
652 * Validate cursor position. Makes sure w_wrow and w_wcol are valid.
653 * w_topline must be valid, you may need to call update_topline() first!
654 */
655 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100656validate_cursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657{
658 check_cursor_moved(curwin);
659 if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
660 curs_columns(TRUE);
661}
662
663#if defined(FEAT_GUI) || defined(PROTO)
664/*
665 * validate w_cline_row.
666 */
667 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100668validate_cline_row(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669{
670 /*
671 * First make sure that w_topline is valid (after moving the cursor).
672 */
673 update_topline();
674 check_cursor_moved(curwin);
675 if (!(curwin->w_valid & VALID_CROW))
Bram Moolenaar3f9be972014-12-13 21:09:57 +0100676 curs_rows(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677}
678#endif
679
680/*
681 * Compute wp->w_cline_row and wp->w_cline_height, based on the current value
Bram Moolenaarfff2bee2010-05-15 13:56:02 +0200682 * of wp->w_topline.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683 */
684 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100685curs_rows(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686{
687 linenr_T lnum;
688 int i;
689 int all_invalid;
690 int valid;
691#ifdef FEAT_FOLDING
692 long fold_count;
693#endif
694
695 /* Check if wp->w_lines[].wl_size is invalid */
696 all_invalid = (!redrawing()
697 || wp->w_lines_valid == 0
698 || wp->w_lines[0].wl_lnum > wp->w_topline);
699 i = 0;
700 wp->w_cline_row = 0;
701 for (lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i)
702 {
703 valid = FALSE;
704 if (!all_invalid && i < wp->w_lines_valid)
705 {
706 if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid)
707 continue; /* skip changed or deleted lines */
708 if (wp->w_lines[i].wl_lnum == lnum)
709 {
710#ifdef FEAT_FOLDING
711 /* Check for newly inserted lines below this row, in which
712 * case we need to check for folded lines. */
713 if (!wp->w_buffer->b_mod_set
714 || wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum
715 || wp->w_buffer->b_mod_top
716 > wp->w_lines[i].wl_lastlnum + 1)
717#endif
718 valid = TRUE;
719 }
720 else if (wp->w_lines[i].wl_lnum > lnum)
721 --i; /* hold at inserted lines */
722 }
723 if (valid
724#ifdef FEAT_DIFF
725 && (lnum != wp->w_topline || !wp->w_p_diff)
726#endif
727 )
728 {
729#ifdef FEAT_FOLDING
730 lnum = wp->w_lines[i].wl_lastlnum + 1;
731 /* Cursor inside folded lines, don't count this row */
732 if (lnum > wp->w_cursor.lnum)
733 break;
734#else
735 ++lnum;
736#endif
737 wp->w_cline_row += wp->w_lines[i].wl_size;
738 }
739 else
740 {
741#ifdef FEAT_FOLDING
742 fold_count = foldedCount(wp, lnum, NULL);
743 if (fold_count)
744 {
745 lnum += fold_count;
746 if (lnum > wp->w_cursor.lnum)
747 break;
748 ++wp->w_cline_row;
749 }
750 else
751#endif
752#ifdef FEAT_DIFF
753 if (lnum == wp->w_topline)
754 wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE)
755 + wp->w_topfill;
756 else
757#endif
758 wp->w_cline_row += plines_win(wp, lnum++, TRUE);
759 }
760 }
761
762 check_cursor_moved(wp);
763 if (!(wp->w_valid & VALID_CHEIGHT))
764 {
765 if (all_invalid
766 || i == wp->w_lines_valid
767 || (i < wp->w_lines_valid
768 && (!wp->w_lines[i].wl_valid
769 || wp->w_lines[i].wl_lnum != wp->w_cursor.lnum)))
770 {
771#ifdef FEAT_DIFF
772 if (wp->w_cursor.lnum == wp->w_topline)
773 wp->w_cline_height = plines_win_nofill(wp, wp->w_cursor.lnum,
774 TRUE) + wp->w_topfill;
775 else
776#endif
777 wp->w_cline_height = plines_win(wp, wp->w_cursor.lnum, TRUE);
778#ifdef FEAT_FOLDING
779 wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
780 NULL, NULL, TRUE, NULL);
781#endif
782 }
783 else if (i > wp->w_lines_valid)
784 {
785 /* a line that is too long to fit on the last screen line */
786 wp->w_cline_height = 0;
787#ifdef FEAT_FOLDING
788 wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
789 NULL, NULL, TRUE, NULL);
790#endif
791 }
792 else
793 {
794 wp->w_cline_height = wp->w_lines[i].wl_size;
795#ifdef FEAT_FOLDING
796 wp->w_cline_folded = wp->w_lines[i].wl_folded;
797#endif
798 }
799 }
800
Bram Moolenaar3d6db142014-03-28 21:49:32 +0100801 redraw_for_cursorline(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 wp->w_valid |= VALID_CROW|VALID_CHEIGHT;
803
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804}
805
806/*
807 * Validate curwin->w_virtcol only.
808 */
809 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100810validate_virtcol(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811{
812 validate_virtcol_win(curwin);
813}
814
815/*
816 * Validate wp->w_virtcol only.
817 */
818 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100819validate_virtcol_win(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820{
821 check_cursor_moved(wp);
822 if (!(wp->w_valid & VALID_VIRTCOL))
823 {
824 getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
825 wp->w_valid |= VALID_VIRTCOL;
Bram Moolenaar2b48ad52006-03-12 21:56:11 +0000826#ifdef FEAT_SYN_HL
Bram Moolenaar019ff682006-03-13 22:10:45 +0000827 if (wp->w_p_cuc
828# ifdef FEAT_INS_EXPAND
829 && !pum_visible()
830# endif
831 )
Bram Moolenaar2b48ad52006-03-12 21:56:11 +0000832 redraw_win_later(wp, SOME_VALID);
833#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 }
835}
836
837/*
838 * Validate curwin->w_cline_height only.
839 */
840 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100841validate_cheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842{
843 check_cursor_moved(curwin);
844 if (!(curwin->w_valid & VALID_CHEIGHT))
845 {
846#ifdef FEAT_DIFF
847 if (curwin->w_cursor.lnum == curwin->w_topline)
848 curwin->w_cline_height = plines_nofill(curwin->w_cursor.lnum)
849 + curwin->w_topfill;
850 else
851#endif
852 curwin->w_cline_height = plines(curwin->w_cursor.lnum);
853#ifdef FEAT_FOLDING
854 curwin->w_cline_folded = hasFolding(curwin->w_cursor.lnum, NULL, NULL);
855#endif
856 curwin->w_valid |= VALID_CHEIGHT;
857 }
858}
859
860/*
Bram Moolenaarc236c162008-07-13 17:41:49 +0000861 * Validate w_wcol and w_virtcol only.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 */
863 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100864validate_cursor_col(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865{
866 colnr_T off;
867 colnr_T col;
Bram Moolenaar6427c602010-02-03 17:43:07 +0100868 int width;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869
870 validate_virtcol();
871 if (!(curwin->w_valid & VALID_WCOL))
872 {
873 col = curwin->w_virtcol;
874 off = curwin_col_off();
875 col += off;
Bram Moolenaar02631462017-09-22 15:20:32 +0200876 width = curwin->w_width - off + curwin_col_off2();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877
878 /* long line wrapping, adjust curwin->w_wrow */
Bram Moolenaarc236c162008-07-13 17:41:49 +0000879 if (curwin->w_p_wrap
Bram Moolenaar02631462017-09-22 15:20:32 +0200880 && col >= (colnr_T)curwin->w_width
Bram Moolenaar6427c602010-02-03 17:43:07 +0100881 && width > 0)
882 /* use same formula as what is used in curs_columns() */
Bram Moolenaar02631462017-09-22 15:20:32 +0200883 col -= ((col - curwin->w_width) / width + 1) * width;
Bram Moolenaarc236c162008-07-13 17:41:49 +0000884 if (col > (int)curwin->w_leftcol)
885 col -= curwin->w_leftcol;
886 else
887 col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 curwin->w_wcol = col;
Bram Moolenaarc236c162008-07-13 17:41:49 +0000889
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 curwin->w_valid |= VALID_WCOL;
891 }
892}
893
894/*
Bram Moolenaar64486672010-05-16 15:46:46 +0200895 * Compute offset of a window, occupied by absolute or relative line number,
896 * fold column and sign column (these don't move when scrolling horizontally).
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 */
898 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100899win_col_off(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900{
Bram Moolenaar64486672010-05-16 15:46:46 +0200901 return (((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902#ifdef FEAT_CMDWIN
903 + (cmdwin_type == 0 || wp != curwin ? 0 : 1)
904#endif
905#ifdef FEAT_FOLDING
906 + wp->w_p_fdc
907#endif
908#ifdef FEAT_SIGNS
Bram Moolenaar95ec9d62016-08-12 18:29:59 +0200909 + (signcolumn_on(wp) ? 2 : 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910#endif
911 );
912}
913
914 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100915curwin_col_off(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916{
917 return win_col_off(curwin);
918}
919
920/*
921 * Return the difference in column offset for the second screen line of a
Bram Moolenaar64486672010-05-16 15:46:46 +0200922 * wrapped line. It's 8 if 'number' or 'relativenumber' is on and 'n' is in
923 * 'cpoptions'.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 */
925 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100926win_col_off2(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927{
Bram Moolenaar64486672010-05-16 15:46:46 +0200928 if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000929 return number_width(wp) + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930 return 0;
931}
932
933 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100934curwin_col_off2(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935{
936 return win_col_off2(curwin);
937}
938
939/*
940 * compute curwin->w_wcol and curwin->w_virtcol.
941 * Also updates curwin->w_wrow and curwin->w_cline_row.
942 * Also updates curwin->w_leftcol.
943 */
944 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100945curs_columns(
946 int may_scroll) /* when TRUE, may scroll horizontally */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000947{
948 int diff;
949 int extra; /* offset for first screen line */
950 int off_left, off_right;
951 int n;
952 int p_lines;
953 int width = 0;
954 int textwidth;
955 int new_leftcol;
956 colnr_T startcol;
957 colnr_T endcol;
958 colnr_T prev_skipcol;
959
960 /*
961 * First make sure that w_topline is valid (after moving the cursor).
962 */
963 update_topline();
964
965 /*
966 * Next make sure that w_cline_row is valid.
967 */
968 if (!(curwin->w_valid & VALID_CROW))
Bram Moolenaar3f9be972014-12-13 21:09:57 +0100969 curs_rows(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970
971 /*
972 * Compute the number of virtual columns.
973 */
974#ifdef FEAT_FOLDING
975 if (curwin->w_cline_folded)
976 /* In a folded line the cursor is always in the first column */
977 startcol = curwin->w_virtcol = endcol = curwin->w_leftcol;
978 else
979#endif
980 getvvcol(curwin, &curwin->w_cursor,
981 &startcol, &(curwin->w_virtcol), &endcol);
982
983 /* remove '$' from change command when cursor moves onto it */
984 if (startcol > dollar_vcol)
Bram Moolenaar76b9b362012-02-04 23:35:00 +0100985 dollar_vcol = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000986
987 extra = curwin_col_off();
988 curwin->w_wcol = curwin->w_virtcol + extra;
989 endcol += extra;
990
991 /*
992 * Now compute w_wrow, counting screen lines from w_cline_row.
993 */
994 curwin->w_wrow = curwin->w_cline_row;
995
Bram Moolenaar02631462017-09-22 15:20:32 +0200996 textwidth = curwin->w_width - extra;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997 if (textwidth <= 0)
998 {
999 /* No room for text, put cursor in last char of window. */
Bram Moolenaar02631462017-09-22 15:20:32 +02001000 curwin->w_wcol = curwin->w_width - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 curwin->w_wrow = curwin->w_height - 1;
1002 }
Bram Moolenaar4033c552017-09-16 20:54:51 +02001003 else if (curwin->w_p_wrap && curwin->w_width != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001004 {
1005 width = textwidth + curwin_col_off2();
1006
1007 /* long line wrapping, adjust curwin->w_wrow */
Bram Moolenaar02631462017-09-22 15:20:32 +02001008 if (curwin->w_wcol >= curwin->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 {
Bram Moolenaar6427c602010-02-03 17:43:07 +01001010 /* this same formula is used in validate_cursor_col() */
Bram Moolenaar02631462017-09-22 15:20:32 +02001011 n = (curwin->w_wcol - curwin->w_width) / width + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012 curwin->w_wcol -= n * width;
1013 curwin->w_wrow += n;
1014
1015#ifdef FEAT_LINEBREAK
1016 /* When cursor wraps to first char of next line in Insert
1017 * mode, the 'showbreak' string isn't shown, backup to first
1018 * column */
1019 if (*p_sbr && *ml_get_cursor() == NUL
1020 && curwin->w_wcol == (int)vim_strsize(p_sbr))
1021 curwin->w_wcol = 0;
1022#endif
1023 }
1024 }
1025
1026 /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
1027 * is not folded.
1028 * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001029 else if (may_scroll
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030#ifdef FEAT_FOLDING
1031 && !curwin->w_cline_folded
1032#endif
1033 )
1034 {
1035 /*
1036 * If Cursor is left of the screen, scroll rightwards.
1037 * If Cursor is right of the screen, scroll leftwards
1038 * If we get closer to the edge than 'sidescrolloff', scroll a little
1039 * extra
1040 */
1041 off_left = (int)startcol - (int)curwin->w_leftcol - p_siso;
Bram Moolenaar02631462017-09-22 15:20:32 +02001042 off_right = (int)endcol - (int)(curwin->w_leftcol + curwin->w_width
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 - p_siso) + 1;
1044 if (off_left < 0 || off_right > 0)
1045 {
1046 if (off_left < 0)
1047 diff = -off_left;
1048 else
1049 diff = off_right;
1050
1051 /* When far off or not enough room on either side, put cursor in
1052 * middle of window. */
1053 if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left)
1054 new_leftcol = curwin->w_wcol - extra - textwidth / 2;
1055 else
1056 {
1057 if (diff < p_ss)
1058 diff = p_ss;
1059 if (off_left < 0)
1060 new_leftcol = curwin->w_leftcol - diff;
1061 else
1062 new_leftcol = curwin->w_leftcol + diff;
1063 }
1064 if (new_leftcol < 0)
1065 new_leftcol = 0;
1066 if (new_leftcol != (int)curwin->w_leftcol)
1067 {
1068 curwin->w_leftcol = new_leftcol;
1069 /* screen has to be redrawn with new curwin->w_leftcol */
1070 redraw_later(NOT_VALID);
1071 }
1072 }
1073 curwin->w_wcol -= curwin->w_leftcol;
1074 }
1075 else if (curwin->w_wcol > (int)curwin->w_leftcol)
1076 curwin->w_wcol -= curwin->w_leftcol;
1077 else
1078 curwin->w_wcol = 0;
1079
1080#ifdef FEAT_DIFF
1081 /* Skip over filler lines. At the top use w_topfill, there
1082 * may be some filler lines above the window. */
1083 if (curwin->w_cursor.lnum == curwin->w_topline)
1084 curwin->w_wrow += curwin->w_topfill;
1085 else
1086 curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
1087#endif
1088
1089 prev_skipcol = curwin->w_skipcol;
1090
1091 p_lines = 0;
1092 if ((curwin->w_wrow >= curwin->w_height
1093 || ((prev_skipcol > 0
1094 || curwin->w_wrow + p_so >= curwin->w_height)
1095 && (p_lines =
1096#ifdef FEAT_DIFF
1097 plines_win_nofill
1098#else
1099 plines_win
1100#endif
1101 (curwin, curwin->w_cursor.lnum, FALSE))
1102 - 1 >= curwin->w_height))
1103 && curwin->w_height != 0
1104 && curwin->w_cursor.lnum == curwin->w_topline
1105 && width > 0
Bram Moolenaar4033c552017-09-16 20:54:51 +02001106 && curwin->w_width != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 {
1108 /* Cursor past end of screen. Happens with a single line that does
1109 * not fit on screen. Find a skipcol to show the text around the
1110 * cursor. Avoid scrolling all the time. compute value of "extra":
1111 * 1: Less than "p_so" lines above
1112 * 2: Less than "p_so" lines below
1113 * 3: both of them */
1114 extra = 0;
1115 if (curwin->w_skipcol + p_so * width > curwin->w_virtcol)
1116 extra = 1;
1117 /* Compute last display line of the buffer line that we want at the
1118 * bottom of the window. */
1119 if (p_lines == 0)
1120 p_lines = plines_win(curwin, curwin->w_cursor.lnum, FALSE);
1121 --p_lines;
1122 if (p_lines > curwin->w_wrow + p_so)
1123 n = curwin->w_wrow + p_so;
1124 else
1125 n = p_lines;
1126 if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width)
1127 extra += 2;
1128
1129 if (extra == 3 || p_lines < p_so * 2)
1130 {
1131 /* not enough room for 'scrolloff', put cursor in the middle */
1132 n = curwin->w_virtcol / width;
1133 if (n > curwin->w_height / 2)
1134 n -= curwin->w_height / 2;
1135 else
1136 n = 0;
1137 /* don't skip more than necessary */
1138 if (n > p_lines - curwin->w_height + 1)
1139 n = p_lines - curwin->w_height + 1;
1140 curwin->w_skipcol = n * width;
1141 }
1142 else if (extra == 1)
1143 {
1144 /* less then 'scrolloff' lines above, decrease skipcol */
1145 extra = (curwin->w_skipcol + p_so * width - curwin->w_virtcol
1146 + width - 1) / width;
1147 if (extra > 0)
1148 {
1149 if ((colnr_T)(extra * width) > curwin->w_skipcol)
1150 extra = curwin->w_skipcol / width;
1151 curwin->w_skipcol -= extra * width;
1152 }
1153 }
1154 else if (extra == 2)
1155 {
1156 /* less then 'scrolloff' lines below, increase skipcol */
1157 endcol = (n - curwin->w_height + 1) * width;
1158 while (endcol > curwin->w_virtcol)
1159 endcol -= width;
1160 if (endcol > curwin->w_skipcol)
1161 curwin->w_skipcol = endcol;
1162 }
1163
1164 curwin->w_wrow -= curwin->w_skipcol / width;
1165 if (curwin->w_wrow >= curwin->w_height)
1166 {
1167 /* small window, make sure cursor is in it */
1168 extra = curwin->w_wrow - curwin->w_height + 1;
1169 curwin->w_skipcol += extra * width;
1170 curwin->w_wrow -= extra;
1171 }
1172
1173 extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
1174 if (extra > 0)
1175 win_ins_lines(curwin, 0, extra, FALSE, FALSE);
1176 else if (extra < 0)
Bram Moolenaarcfce7172017-08-17 20:31:48 +02001177 win_del_lines(curwin, 0, -extra, FALSE, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 }
1179 else
1180 curwin->w_skipcol = 0;
1181 if (prev_skipcol != curwin->w_skipcol)
1182 redraw_later(NOT_VALID);
1183
Bram Moolenaar2b48ad52006-03-12 21:56:11 +00001184#ifdef FEAT_SYN_HL
Bram Moolenaarb6798752014-03-27 12:11:48 +01001185 /* Redraw when w_virtcol changes and 'cursorcolumn' is set */
1186 if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0
Bram Moolenaar64486672010-05-16 15:46:46 +02001187# ifdef FEAT_INS_EXPAND
Bram Moolenaarb6798752014-03-27 12:11:48 +01001188 && !pum_visible()
Bram Moolenaar64486672010-05-16 15:46:46 +02001189# endif
Bram Moolenaarb6798752014-03-27 12:11:48 +01001190 )
1191 redraw_later(SOME_VALID);
1192#endif
Bram Moolenaar2b48ad52006-03-12 21:56:11 +00001193
Bram Moolenaar071d4272004-06-13 20:20:40 +00001194 curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
1195}
1196
1197/*
1198 * Scroll the current window down by "line_count" logical lines. "CTRL-Y"
1199 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001201scrolldown(
1202 long line_count,
1203 int byfold UNUSED) /* TRUE: count a closed fold as one line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204{
1205 long done = 0; /* total # of physical lines done */
1206 int wrow;
1207 int moved = FALSE;
1208
1209#ifdef FEAT_FOLDING
1210 linenr_T first;
1211
1212 /* Make sure w_topline is at the first of a sequence of folded lines. */
1213 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
1214#endif
1215 validate_cursor(); /* w_wrow needs to be valid */
1216 while (line_count-- > 0)
1217 {
1218#ifdef FEAT_DIFF
Bram Moolenaarfa316dd2009-11-03 15:23:14 +00001219 if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)
1220 && curwin->w_topfill < curwin->w_height - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001221 {
1222 ++curwin->w_topfill;
1223 ++done;
1224 }
1225 else
1226#endif
1227 {
1228 if (curwin->w_topline == 1)
1229 break;
1230 --curwin->w_topline;
1231#ifdef FEAT_DIFF
1232 curwin->w_topfill = 0;
1233#endif
1234#ifdef FEAT_FOLDING
1235 /* A sequence of folded lines only counts for one logical line */
1236 if (hasFolding(curwin->w_topline, &first, NULL))
1237 {
1238 ++done;
1239 if (!byfold)
1240 line_count -= curwin->w_topline - first - 1;
1241 curwin->w_botline -= curwin->w_topline - first;
1242 curwin->w_topline = first;
1243 }
1244 else
1245#endif
Bram Moolenaar43335ea2015-09-09 20:59:37 +02001246 done += PLINES_NOFILL(curwin->w_topline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247 }
1248 --curwin->w_botline; /* approximate w_botline */
1249 invalidate_botline();
1250 }
1251 curwin->w_wrow += done; /* keep w_wrow updated */
1252 curwin->w_cline_row += done; /* keep w_cline_row updated */
1253
1254#ifdef FEAT_DIFF
1255 if (curwin->w_cursor.lnum == curwin->w_topline)
1256 curwin->w_cline_row = 0;
1257 check_topfill(curwin, TRUE);
1258#endif
1259
1260 /*
1261 * Compute the row number of the last row of the cursor line
1262 * and move the cursor onto the displayed part of the window.
1263 */
1264 wrow = curwin->w_wrow;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001265 if (curwin->w_p_wrap && curwin->w_width != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 {
1267 validate_virtcol();
1268 validate_cheight();
1269 wrow += curwin->w_cline_height - 1 -
Bram Moolenaar02631462017-09-22 15:20:32 +02001270 curwin->w_virtcol / curwin->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 }
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 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001304scrollup(
1305 long line_count,
1306 int byfold UNUSED) /* TRUE: count a closed fold as one line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307{
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
Bram Moolenaar9b578142016-01-30 19:39:49 +01001386check_topfill(
1387 win_T *wp,
1388 int down) /* when TRUE scroll down when not enough space */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001389{
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
Bram Moolenaar9b578142016-01-30 19:39:49 +01001417max_topfill(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001418{
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
Bram Moolenaar9b578142016-01-30 19:39:49 +01001439scrolldown_clamp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001440{
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
Bram Moolenaar4033c552017-09-16 20:54:51 +02001470 if (curwin->w_p_wrap && curwin->w_width != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001471 {
1472 validate_cheight();
1473 validate_virtcol();
1474 end_row += curwin->w_cline_height - 1 -
Bram Moolenaar02631462017-09-22 15:20:32 +02001475 curwin->w_virtcol / curwin->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476 }
1477 if (end_row < curwin->w_height - p_so)
1478 {
1479#ifdef FEAT_DIFF
1480 if (can_fill)
1481 {
1482 ++curwin->w_topfill;
1483 check_topfill(curwin, TRUE);
1484 }
1485 else
1486 {
1487 --curwin->w_topline;
1488 curwin->w_topfill = 0;
1489 }
1490#else
1491 --curwin->w_topline;
1492#endif
1493#ifdef FEAT_FOLDING
Bram Moolenaarcde88542015-08-11 19:14:00 +02001494 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495#endif
1496 --curwin->w_botline; /* approximate w_botline */
1497 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1498 }
1499}
1500
1501/*
1502 * Scroll the screen one line up, but don't do it if it would move the cursor
1503 * off the screen.
1504 */
1505 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001506scrollup_clamp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507{
1508 int start_row;
1509
1510 if (curwin->w_topline == curbuf->b_ml.ml_line_count
1511#ifdef FEAT_DIFF
1512 && curwin->w_topfill == 0
1513#endif
1514 )
1515 return;
1516
1517 validate_cursor(); /* w_wrow needs to be valid */
1518
1519 /*
1520 * Compute the row number of the first row of the cursor line
1521 * and make sure it doesn't go off the screen. Make sure the cursor
1522 * doesn't go before 'scrolloff' lines from the screen start.
1523 */
1524#ifdef FEAT_DIFF
1525 start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
1526 - curwin->w_topfill;
1527#else
1528 start_row = curwin->w_wrow - plines(curwin->w_topline);
1529#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02001530 if (curwin->w_p_wrap && curwin->w_width != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001531 {
1532 validate_virtcol();
Bram Moolenaar02631462017-09-22 15:20:32 +02001533 start_row -= curwin->w_virtcol / curwin->w_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001534 }
1535 if (start_row >= p_so)
1536 {
1537#ifdef FEAT_DIFF
1538 if (curwin->w_topfill > 0)
1539 --curwin->w_topfill;
1540 else
1541#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001542 {
1543#ifdef FEAT_FOLDING
1544 (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
1545#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001546 ++curwin->w_topline;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001547 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548 ++curwin->w_botline; /* approximate w_botline */
1549 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
1550 }
1551}
1552#endif /* FEAT_INS_EXPAND */
1553
1554/*
1555 * Add one line above "lp->lnum". This can be a filler line, a closed fold or
1556 * a (wrapped) text line. Uses and sets "lp->fill".
1557 * Returns the height of the added line in "lp->height".
Bram Moolenaarbacd9da2010-02-17 18:20:37 +01001558 * Lines above the first one are incredibly high: MAXCOL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559 */
1560 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001561topline_back(lineoff_T *lp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001562{
1563#ifdef FEAT_DIFF
1564 if (lp->fill < diff_check_fill(curwin, lp->lnum))
1565 {
1566 /* Add a filler line. */
1567 ++lp->fill;
1568 lp->height = 1;
1569 }
1570 else
1571#endif
1572 {
1573 --lp->lnum;
1574#ifdef FEAT_DIFF
1575 lp->fill = 0;
1576#endif
1577 if (lp->lnum < 1)
1578 lp->height = MAXCOL;
1579 else
1580#ifdef FEAT_FOLDING
1581 if (hasFolding(lp->lnum, &lp->lnum, NULL))
1582 /* Add a closed fold */
1583 lp->height = 1;
1584 else
1585#endif
Bram Moolenaar43335ea2015-09-09 20:59:37 +02001586 lp->height = PLINES_NOFILL(lp->lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587 }
1588}
1589
1590/*
1591 * Add one line below "lp->lnum". This can be a filler line, a closed fold or
1592 * a (wrapped) text line. Uses and sets "lp->fill".
1593 * Returns the height of the added line in "lp->height".
1594 * Lines below the last one are incredibly high.
1595 */
1596 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001597botline_forw(lineoff_T *lp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001598{
1599#ifdef FEAT_DIFF
1600 if (lp->fill < diff_check_fill(curwin, lp->lnum + 1))
1601 {
1602 /* Add a filler line. */
1603 ++lp->fill;
1604 lp->height = 1;
1605 }
1606 else
1607#endif
1608 {
1609 ++lp->lnum;
1610#ifdef FEAT_DIFF
1611 lp->fill = 0;
1612#endif
1613 if (lp->lnum > curbuf->b_ml.ml_line_count)
1614 lp->height = MAXCOL;
1615 else
1616#ifdef FEAT_FOLDING
1617 if (hasFolding(lp->lnum, NULL, &lp->lnum))
1618 /* Add a closed fold */
1619 lp->height = 1;
1620 else
1621#endif
1622 {
Bram Moolenaar43335ea2015-09-09 20:59:37 +02001623 lp->height = PLINES_NOFILL(lp->lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001624 }
1625 }
1626}
1627
1628#ifdef FEAT_DIFF
1629/*
1630 * Switch from including filler lines below lp->lnum to including filler
1631 * lines above loff.lnum + 1. This keeps pointing to the same line.
1632 * When there are no filler lines nothing changes.
1633 */
1634 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001635botline_topline(lineoff_T *lp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636{
1637 if (lp->fill > 0)
1638 {
1639 ++lp->lnum;
1640 lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
1641 }
1642}
1643
1644/*
1645 * Switch from including filler lines above lp->lnum to including filler
1646 * lines below loff.lnum - 1. This keeps pointing to the same line.
1647 * When there are no filler lines nothing changes.
1648 */
1649 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001650topline_botline(lineoff_T *lp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651{
1652 if (lp->fill > 0)
1653 {
1654 lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
1655 --lp->lnum;
1656 }
1657}
1658#endif
1659
1660/*
1661 * Recompute topline to put the cursor at the top of the window.
1662 * Scroll at least "min_scroll" lines.
1663 * If "always" is TRUE, always set topline (for "zt").
1664 */
1665 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001666scroll_cursor_top(int min_scroll, int always)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667{
1668 int scrolled = 0;
1669 int extra = 0;
1670 int used;
1671 int i;
1672 linenr_T top; /* just above displayed lines */
1673 linenr_T bot; /* just below displayed lines */
1674 linenr_T old_topline = curwin->w_topline;
1675#ifdef FEAT_DIFF
1676 linenr_T old_topfill = curwin->w_topfill;
1677#endif
1678 linenr_T new_topline;
1679 int off = p_so;
1680
1681#ifdef FEAT_MOUSE
1682 if (mouse_dragging > 0)
1683 off = mouse_dragging - 1;
1684#endif
1685
1686 /*
1687 * Decrease topline until:
1688 * - it has become 1
1689 * - (part of) the cursor line is moved off the screen or
1690 * - moved at least 'scrolljump' lines and
1691 * - at least 'scrolloff' lines above and below the cursor
1692 */
1693 validate_cheight();
Bram Moolenaarcf619da2015-09-01 20:53:24 +02001694 used = curwin->w_cline_height; /* includes filler lines above */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695 if (curwin->w_cursor.lnum < curwin->w_topline)
1696 scrolled = used;
1697
1698#ifdef FEAT_FOLDING
1699 if (hasFolding(curwin->w_cursor.lnum, &top, &bot))
1700 {
1701 --top;
1702 ++bot;
1703 }
1704 else
1705#endif
1706 {
1707 top = curwin->w_cursor.lnum - 1;
1708 bot = curwin->w_cursor.lnum + 1;
1709 }
1710 new_topline = top + 1;
1711
1712#ifdef FEAT_DIFF
Bram Moolenaara09a2c52015-09-08 17:31:59 +02001713 /* "used" already contains the number of filler lines above, don't add it
Bram Moolenaarcf619da2015-09-01 20:53:24 +02001714 * again.
Bram Moolenaara09a2c52015-09-08 17:31:59 +02001715 * Hide filler lines above cursor line by adding them to "extra". */
1716 extra += diff_check_fill(curwin, curwin->w_cursor.lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717#endif
1718
1719 /*
1720 * Check if the lines from "top" to "bot" fit in the window. If they do,
1721 * set new_topline and advance "top" and "bot" to include more lines.
1722 */
1723 while (top > 0)
1724 {
1725#ifdef FEAT_FOLDING
1726 if (hasFolding(top, &top, NULL))
1727 /* count one logical line for a sequence of folded lines */
1728 i = 1;
1729 else
1730#endif
Bram Moolenaar43335ea2015-09-09 20:59:37 +02001731 i = PLINES_NOFILL(top);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 used += i;
1733 if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
1734 {
1735#ifdef FEAT_FOLDING
1736 if (hasFolding(bot, NULL, &bot))
1737 /* count one logical line for a sequence of folded lines */
1738 ++used;
1739 else
1740#endif
1741 used += plines(bot);
1742 }
1743 if (used > curwin->w_height)
1744 break;
1745 if (top < curwin->w_topline)
1746 scrolled += i;
1747
1748 /*
1749 * If scrolling is needed, scroll at least 'sj' lines.
1750 */
1751 if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
1752 && extra >= off)
1753 break;
1754
1755 extra += i;
1756 new_topline = top;
1757 --top;
1758 ++bot;
1759 }
1760
1761 /*
1762 * If we don't have enough space, put cursor in the middle.
1763 * This makes sure we get the same position when using "k" and "j"
1764 * in a small window.
1765 */
1766 if (used > curwin->w_height)
1767 scroll_cursor_halfway(FALSE);
1768 else
1769 {
1770 /*
1771 * If "always" is FALSE, only adjust topline to a lower value, higher
1772 * value may happen with wrapping lines
1773 */
1774 if (new_topline < curwin->w_topline || always)
1775 curwin->w_topline = new_topline;
1776 if (curwin->w_topline > curwin->w_cursor.lnum)
1777 curwin->w_topline = curwin->w_cursor.lnum;
1778#ifdef FEAT_DIFF
1779 curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
1780 if (curwin->w_topfill > 0 && extra > off)
1781 {
1782 curwin->w_topfill -= extra - off;
1783 if (curwin->w_topfill < 0)
1784 curwin->w_topfill = 0;
1785 }
1786 check_topfill(curwin, FALSE);
1787#endif
1788 if (curwin->w_topline != old_topline
1789#ifdef FEAT_DIFF
1790 || curwin->w_topfill != old_topfill
1791#endif
1792 )
1793 curwin->w_valid &=
1794 ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
1795 curwin->w_valid |= VALID_TOPLINE;
1796 }
1797}
1798
1799/*
1800 * Set w_empty_rows and w_filler_rows for window "wp", having used up "used"
1801 * screen lines for text lines.
1802 */
1803 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001804set_empty_rows(win_T *wp, int used)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805{
1806#ifdef FEAT_DIFF
1807 wp->w_filler_rows = 0;
1808#endif
1809 if (used == 0)
1810 wp->w_empty_rows = 0; /* single line that doesn't fit */
1811 else
1812 {
1813 wp->w_empty_rows = wp->w_height - used;
1814#ifdef FEAT_DIFF
1815 if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count)
1816 {
1817 wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
1818 if (wp->w_empty_rows > wp->w_filler_rows)
1819 wp->w_empty_rows -= wp->w_filler_rows;
1820 else
1821 {
1822 wp->w_filler_rows = wp->w_empty_rows;
1823 wp->w_empty_rows = 0;
1824 }
1825 }
1826#endif
1827 }
1828}
1829
1830/*
1831 * Recompute topline to put the cursor at the bottom of the window.
1832 * Scroll at least "min_scroll" lines.
1833 * If "set_topbot" is TRUE, set topline and botline first (for "zb").
1834 * This is messy stuff!!!
1835 */
1836 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001837scroll_cursor_bot(int min_scroll, int set_topbot)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838{
1839 int used;
1840 int scrolled = 0;
1841 int extra = 0;
1842 int i;
1843 linenr_T line_count;
1844 linenr_T old_topline = curwin->w_topline;
1845 lineoff_T loff;
1846 lineoff_T boff;
1847#ifdef FEAT_DIFF
1848 int old_topfill = curwin->w_topfill;
1849 int fill_below_window;
1850#endif
1851 linenr_T old_botline = curwin->w_botline;
1852 linenr_T old_valid = curwin->w_valid;
1853 int old_empty_rows = curwin->w_empty_rows;
1854 linenr_T cln; /* Cursor Line Number */
1855
1856 cln = curwin->w_cursor.lnum;
1857 if (set_topbot)
1858 {
1859 used = 0;
1860 curwin->w_botline = cln + 1;
1861#ifdef FEAT_DIFF
1862 loff.fill = 0;
1863#endif
1864 for (curwin->w_topline = curwin->w_botline;
1865 curwin->w_topline > 1;
1866 curwin->w_topline = loff.lnum)
1867 {
1868 loff.lnum = curwin->w_topline;
1869 topline_back(&loff);
Bram Moolenaarbacd9da2010-02-17 18:20:37 +01001870 if (loff.height == MAXCOL || used + loff.height > curwin->w_height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 break;
1872 used += loff.height;
1873#ifdef FEAT_DIFF
1874 curwin->w_topfill = loff.fill;
1875#endif
1876 }
1877 set_empty_rows(curwin, used);
1878 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
1879 if (curwin->w_topline != old_topline
1880#ifdef FEAT_DIFF
1881 || curwin->w_topfill != old_topfill
1882#endif
1883 )
1884 curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
1885 }
1886 else
1887 validate_botline();
1888
1889 /* The lines of the cursor line itself are always used. */
1890#ifdef FEAT_DIFF
1891 used = plines_nofill(cln);
1892#else
1893 validate_cheight();
1894 used = curwin->w_cline_height;
1895#endif
1896
1897 /* If the cursor is below botline, we will at least scroll by the height
1898 * of the cursor line. Correct for empty lines, which are really part of
1899 * botline. */
1900 if (cln >= curwin->w_botline)
1901 {
1902 scrolled = used;
1903 if (cln == curwin->w_botline)
1904 scrolled -= curwin->w_empty_rows;
1905 }
1906
1907 /*
1908 * Stop counting lines to scroll when
1909 * - hitting start of the file
1910 * - scrolled nothing or at least 'sj' lines
1911 * - at least 'so' lines below the cursor
1912 * - lines between botline and cursor have been counted
1913 */
1914#ifdef FEAT_FOLDING
1915 if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum))
1916#endif
1917 {
1918 loff.lnum = cln;
1919 boff.lnum = cln;
1920 }
1921#ifdef FEAT_DIFF
1922 loff.fill = 0;
1923 boff.fill = 0;
1924 fill_below_window = diff_check_fill(curwin, curwin->w_botline)
1925 - curwin->w_filler_rows;
1926#endif
1927
1928 while (loff.lnum > 1)
1929 {
1930 /* Stop when scrolled nothing or at least "min_scroll", found "extra"
1931 * context for 'scrolloff' and counted all lines below the window. */
1932 if ((((scrolled <= 0 || scrolled >= min_scroll)
1933 && extra >= (
1934#ifdef FEAT_MOUSE
Bram Moolenaar9964e462007-05-05 17:54:07 +00001935 mouse_dragging > 0 ? mouse_dragging - 1 :
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936#endif
1937 p_so))
1938 || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
1939 && loff.lnum <= curwin->w_botline
1940#ifdef FEAT_DIFF
1941 && (loff.lnum < curwin->w_botline
1942 || loff.fill >= fill_below_window)
1943#endif
1944 )
1945 break;
1946
1947 /* Add one line above */
1948 topline_back(&loff);
Bram Moolenaarbacd9da2010-02-17 18:20:37 +01001949 if (loff.height == MAXCOL)
1950 used = MAXCOL;
1951 else
1952 used += loff.height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953 if (used > curwin->w_height)
1954 break;
1955 if (loff.lnum >= curwin->w_botline
1956#ifdef FEAT_DIFF
1957 && (loff.lnum > curwin->w_botline
1958 || loff.fill <= fill_below_window)
1959#endif
1960 )
1961 {
1962 /* Count screen lines that are below the window. */
1963 scrolled += loff.height;
1964 if (loff.lnum == curwin->w_botline
1965#ifdef FEAT_DIFF
1966 && boff.fill == 0
1967#endif
1968 )
1969 scrolled -= curwin->w_empty_rows;
1970 }
1971
1972 if (boff.lnum < curbuf->b_ml.ml_line_count)
1973 {
1974 /* Add one line below */
1975 botline_forw(&boff);
1976 used += boff.height;
1977 if (used > curwin->w_height)
1978 break;
1979 if (extra < (
1980#ifdef FEAT_MOUSE
1981 mouse_dragging > 0 ? mouse_dragging - 1 :
1982#endif
1983 p_so) || scrolled < min_scroll)
1984 {
1985 extra += boff.height;
1986 if (boff.lnum >= curwin->w_botline
1987#ifdef FEAT_DIFF
1988 || (boff.lnum + 1 == curwin->w_botline
1989 && boff.fill > curwin->w_filler_rows)
1990#endif
1991 )
1992 {
1993 /* Count screen lines that are below the window. */
1994 scrolled += boff.height;
1995 if (boff.lnum == curwin->w_botline
1996#ifdef FEAT_DIFF
1997 && boff.fill == 0
1998#endif
1999 )
2000 scrolled -= curwin->w_empty_rows;
2001 }
2002 }
2003 }
2004 }
2005
2006 /* curwin->w_empty_rows is larger, no need to scroll */
2007 if (scrolled <= 0)
2008 line_count = 0;
2009 /* more than a screenfull, don't scroll but redraw */
2010 else if (used > curwin->w_height)
2011 line_count = used;
2012 /* scroll minimal number of lines */
2013 else
2014 {
2015 line_count = 0;
2016#ifdef FEAT_DIFF
2017 boff.fill = curwin->w_topfill;
2018#endif
2019 boff.lnum = curwin->w_topline - 1;
2020 for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; )
2021 {
2022 botline_forw(&boff);
2023 i += boff.height;
2024 ++line_count;
2025 }
2026 if (i < scrolled) /* below curwin->w_botline, don't scroll */
2027 line_count = 9999;
2028 }
2029
2030 /*
2031 * Scroll up if the cursor is off the bottom of the screen a bit.
2032 * Otherwise put it at 1/2 of the screen.
2033 */
2034 if (line_count >= curwin->w_height && line_count > min_scroll)
2035 scroll_cursor_halfway(FALSE);
2036 else
2037 scrollup(line_count, TRUE);
2038
2039 /*
2040 * If topline didn't change we need to restore w_botline and w_empty_rows
2041 * (we changed them).
2042 * If topline did change, update_screen() will set botline.
2043 */
2044 if (curwin->w_topline == old_topline && set_topbot)
2045 {
2046 curwin->w_botline = old_botline;
2047 curwin->w_empty_rows = old_empty_rows;
2048 curwin->w_valid = old_valid;
2049 }
2050 curwin->w_valid |= VALID_TOPLINE;
2051}
2052
2053/*
2054 * Recompute topline to put the cursor halfway the window
2055 * If "atend" is TRUE, also put it halfway at the end of the file.
2056 */
2057 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002058scroll_cursor_halfway(int atend)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059{
2060 int above = 0;
2061 linenr_T topline;
2062#ifdef FEAT_DIFF
2063 int topfill = 0;
2064#endif
2065 int below = 0;
2066 int used;
2067 lineoff_T loff;
2068 lineoff_T boff;
Bram Moolenaarb8e23052014-02-11 18:58:09 +01002069#ifdef FEAT_DIFF
Bram Moolenaar12a0f222014-02-11 15:47:46 +01002070 linenr_T old_topline = curwin->w_topline;
Bram Moolenaarb8e23052014-02-11 18:58:09 +01002071#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072
2073 loff.lnum = boff.lnum = curwin->w_cursor.lnum;
2074#ifdef FEAT_FOLDING
2075 (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum);
2076#endif
2077#ifdef FEAT_DIFF
2078 used = plines_nofill(loff.lnum);
2079 loff.fill = 0;
2080 boff.fill = 0;
2081#else
2082 used = plines(loff.lnum);
2083#endif
2084 topline = loff.lnum;
2085 while (topline > 1)
2086 {
2087 if (below <= above) /* add a line below the cursor first */
2088 {
2089 if (boff.lnum < curbuf->b_ml.ml_line_count)
2090 {
2091 botline_forw(&boff);
2092 used += boff.height;
2093 if (used > curwin->w_height)
2094 break;
2095 below += boff.height;
2096 }
2097 else
2098 {
2099 ++below; /* count a "~" line */
2100 if (atend)
2101 ++used;
2102 }
2103 }
2104
2105 if (below > above) /* add a line above the cursor */
2106 {
2107 topline_back(&loff);
Bram Moolenaarbacd9da2010-02-17 18:20:37 +01002108 if (loff.height == MAXCOL)
2109 used = MAXCOL;
2110 else
2111 used += loff.height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112 if (used > curwin->w_height)
2113 break;
2114 above += loff.height;
2115 topline = loff.lnum;
2116#ifdef FEAT_DIFF
2117 topfill = loff.fill;
2118#endif
2119 }
2120 }
2121#ifdef FEAT_FOLDING
2122 if (!hasFolding(topline, &curwin->w_topline, NULL))
2123#endif
2124 curwin->w_topline = topline;
2125#ifdef FEAT_DIFF
2126 curwin->w_topfill = topfill;
Bram Moolenaar12a0f222014-02-11 15:47:46 +01002127 if (old_topline > curwin->w_topline + curwin->w_height)
2128 curwin->w_botfill = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 check_topfill(curwin, FALSE);
2130#endif
2131 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2132 curwin->w_valid |= VALID_TOPLINE;
2133}
2134
2135/*
2136 * Correct the cursor position so that it is in a part of the screen at least
2137 * 'so' lines from the top and bottom, if possible.
2138 * If not possible, put it at the same position as scroll_cursor_halfway().
2139 * When called topline must be valid!
2140 */
2141 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002142cursor_correct(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143{
2144 int above = 0; /* screen lines above topline */
2145 linenr_T topline;
2146 int below = 0; /* screen lines below botline */
2147 linenr_T botline;
2148 int above_wanted, below_wanted;
2149 linenr_T cln; /* Cursor Line Number */
2150 int max_off;
2151
2152 /*
2153 * How many lines we would like to have above/below the cursor depends on
2154 * whether the first/last line of the file is on screen.
2155 */
2156 above_wanted = p_so;
2157 below_wanted = p_so;
2158#ifdef FEAT_MOUSE
Bram Moolenaar9964e462007-05-05 17:54:07 +00002159 if (mouse_dragging > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160 {
2161 above_wanted = mouse_dragging - 1;
2162 below_wanted = mouse_dragging - 1;
2163 }
2164#endif
2165 if (curwin->w_topline == 1)
2166 {
2167 above_wanted = 0;
2168 max_off = curwin->w_height / 2;
2169 if (below_wanted > max_off)
2170 below_wanted = max_off;
2171 }
2172 validate_botline();
2173 if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
2174#ifdef FEAT_MOUSE
Bram Moolenaar9964e462007-05-05 17:54:07 +00002175 && mouse_dragging == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176#endif
2177 )
2178 {
2179 below_wanted = 0;
2180 max_off = (curwin->w_height - 1) / 2;
2181 if (above_wanted > max_off)
2182 above_wanted = max_off;
2183 }
2184
2185 /*
2186 * If there are sufficient file-lines above and below the cursor, we can
2187 * return now.
2188 */
2189 cln = curwin->w_cursor.lnum;
2190 if (cln >= curwin->w_topline + above_wanted
2191 && cln < curwin->w_botline - below_wanted
2192#ifdef FEAT_FOLDING
2193 && !hasAnyFolding(curwin)
2194#endif
2195 )
2196 return;
2197
2198 /*
2199 * Narrow down the area where the cursor can be put by taking lines from
2200 * the top and the bottom until:
2201 * - the desired context lines are found
2202 * - the lines from the top is past the lines from the bottom
2203 */
2204 topline = curwin->w_topline;
2205 botline = curwin->w_botline - 1;
2206#ifdef FEAT_DIFF
2207 /* count filler lines as context */
2208 above = curwin->w_topfill;
2209 below = curwin->w_filler_rows;
2210#endif
2211 while ((above < above_wanted || below < below_wanted) && topline < botline)
2212 {
2213 if (below < below_wanted && (below <= above || above >= above_wanted))
2214 {
2215#ifdef FEAT_FOLDING
2216 if (hasFolding(botline, &botline, NULL))
2217 ++below;
2218 else
2219#endif
2220 below += plines(botline);
2221 --botline;
2222 }
2223 if (above < above_wanted && (above < below || below >= below_wanted))
2224 {
2225#ifdef FEAT_FOLDING
2226 if (hasFolding(topline, NULL, &topline))
2227 ++above;
2228 else
2229#endif
Bram Moolenaar43335ea2015-09-09 20:59:37 +02002230 above += PLINES_NOFILL(topline);
2231#ifdef FEAT_DIFF
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232 /* Count filler lines below this line as context. */
2233 if (topline < botline)
2234 above += diff_check_fill(curwin, topline + 1);
2235#endif
2236 ++topline;
2237 }
2238 }
2239 if (topline == botline || botline == 0)
2240 curwin->w_cursor.lnum = topline;
2241 else if (topline > botline)
2242 curwin->w_cursor.lnum = botline;
2243 else
2244 {
2245 if (cln < topline && curwin->w_topline > 1)
2246 {
2247 curwin->w_cursor.lnum = topline;
2248 curwin->w_valid &=
2249 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
2250 }
2251 if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2252 {
2253 curwin->w_cursor.lnum = botline;
2254 curwin->w_valid &=
2255 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
2256 }
2257 }
2258 curwin->w_valid |= VALID_TOPLINE;
2259}
2260
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01002261static void get_scroll_overlap(lineoff_T *lp, int dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262
2263/*
2264 * move screen 'count' pages up or down and update screen
2265 *
2266 * return FAIL for failure, OK otherwise
2267 */
2268 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002269onepage(int dir, long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270{
2271 long n;
2272 int retval = OK;
2273 lineoff_T loff;
2274 linenr_T old_topline = curwin->w_topline;
2275
2276 if (curbuf->b_ml.ml_line_count == 1) /* nothing to do */
2277 {
2278 beep_flush();
2279 return FAIL;
2280 }
2281
2282 for ( ; count > 0; --count)
2283 {
2284 validate_botline();
2285 /*
2286 * It's an error to move a page up when the first line is already on
2287 * the screen. It's an error to move a page down when the last line
2288 * is on the screen and the topline is 'scrolloff' lines from the
2289 * last line.
2290 */
2291 if (dir == FORWARD
2292 ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so)
2293 && curwin->w_botline > curbuf->b_ml.ml_line_count)
2294 : (curwin->w_topline == 1
2295#ifdef FEAT_DIFF
2296 && curwin->w_topfill ==
2297 diff_check_fill(curwin, curwin->w_topline)
2298#endif
2299 ))
2300 {
2301 beep_flush();
2302 retval = FAIL;
2303 break;
2304 }
2305
2306#ifdef FEAT_DIFF
2307 loff.fill = 0;
2308#endif
2309 if (dir == FORWARD)
2310 {
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002311 if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002313 /* Vi compatible scrolling */
2314 if (p_window <= 2)
2315 ++curwin->w_topline;
2316 else
2317 curwin->w_topline += p_window - 2;
2318 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
2319 curwin->w_topline = curbuf->b_ml.ml_line_count;
2320 curwin->w_cursor.lnum = curwin->w_topline;
2321 }
2322 else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
2323 {
2324 /* at end of file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325 curwin->w_topline = curbuf->b_ml.ml_line_count;
2326#ifdef FEAT_DIFF
2327 curwin->w_topfill = 0;
2328#endif
2329 curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
2330 }
2331 else
2332 {
2333 /* For the overlap, start with the line just below the window
2334 * and go upwards. */
2335 loff.lnum = curwin->w_botline;
2336#ifdef FEAT_DIFF
2337 loff.fill = diff_check_fill(curwin, loff.lnum)
2338 - curwin->w_filler_rows;
2339#endif
2340 get_scroll_overlap(&loff, -1);
2341 curwin->w_topline = loff.lnum;
2342#ifdef FEAT_DIFF
2343 curwin->w_topfill = loff.fill;
2344 check_topfill(curwin, FALSE);
2345#endif
2346 curwin->w_cursor.lnum = curwin->w_topline;
2347 curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
2348 VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2349 }
2350 }
2351 else /* dir == BACKWARDS */
2352 {
2353#ifdef FEAT_DIFF
2354 if (curwin->w_topline == 1)
2355 {
2356 /* Include max number of filler lines */
2357 max_topfill();
2358 continue;
2359 }
2360#endif
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002361 if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002362 {
2363 /* Vi compatible scrolling (sort of) */
2364 if (p_window <= 2)
2365 --curwin->w_topline;
2366 else
2367 curwin->w_topline -= p_window - 2;
2368 if (curwin->w_topline < 1)
2369 curwin->w_topline = 1;
2370 curwin->w_cursor.lnum = curwin->w_topline + p_window - 1;
2371 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
2372 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2373 continue;
2374 }
2375
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 /* Find the line at the top of the window that is going to be the
2377 * line at the bottom of the window. Make sure this results in
2378 * the same line as before doing CTRL-F. */
2379 loff.lnum = curwin->w_topline - 1;
2380#ifdef FEAT_DIFF
2381 loff.fill = diff_check_fill(curwin, loff.lnum + 1)
2382 - curwin->w_topfill;
2383#endif
2384 get_scroll_overlap(&loff, 1);
2385
2386 if (loff.lnum >= curbuf->b_ml.ml_line_count)
2387 {
2388 loff.lnum = curbuf->b_ml.ml_line_count;
2389#ifdef FEAT_DIFF
2390 loff.fill = 0;
2391 }
2392 else
2393 {
2394 botline_topline(&loff);
2395#endif
2396 }
2397 curwin->w_cursor.lnum = loff.lnum;
2398
2399 /* Find the line just above the new topline to get the right line
2400 * at the bottom of the window. */
2401 n = 0;
2402 while (n <= curwin->w_height && loff.lnum >= 1)
2403 {
2404 topline_back(&loff);
Bram Moolenaarbacd9da2010-02-17 18:20:37 +01002405 if (loff.height == MAXCOL)
2406 n = MAXCOL;
2407 else
2408 n += loff.height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 }
Bram Moolenaarbacd9da2010-02-17 18:20:37 +01002410 if (loff.lnum < 1) /* at begin of file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411 {
2412 curwin->w_topline = 1;
2413#ifdef FEAT_DIFF
2414 max_topfill();
2415#endif
2416 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
2417 }
2418 else
2419 {
2420 /* Go two lines forward again. */
2421#ifdef FEAT_DIFF
2422 topline_botline(&loff);
2423#endif
2424 botline_forw(&loff);
2425 botline_forw(&loff);
2426#ifdef FEAT_DIFF
2427 botline_topline(&loff);
2428#endif
2429#ifdef FEAT_FOLDING
2430 /* We're at the wrong end of a fold now. */
2431 (void)hasFolding(loff.lnum, &loff.lnum, NULL);
2432#endif
2433
2434 /* Always scroll at least one line. Avoid getting stuck on
2435 * very long lines. */
2436 if (loff.lnum >= curwin->w_topline
2437#ifdef FEAT_DIFF
2438 && (loff.lnum > curwin->w_topline
2439 || loff.fill >= curwin->w_topfill)
2440#endif
2441 )
2442 {
2443#ifdef FEAT_DIFF
2444 /* First try using the maximum number of filler lines. If
2445 * that's not enough, backup one line. */
2446 loff.fill = curwin->w_topfill;
2447 if (curwin->w_topfill < diff_check_fill(curwin,
2448 curwin->w_topline))
2449 max_topfill();
2450 if (curwin->w_topfill == loff.fill)
2451#endif
2452 {
2453 --curwin->w_topline;
2454#ifdef FEAT_DIFF
2455 curwin->w_topfill = 0;
2456#endif
2457 }
2458 comp_botline(curwin);
2459 curwin->w_cursor.lnum = curwin->w_botline - 1;
Bram Moolenaar3d6db142014-03-28 21:49:32 +01002460 curwin->w_valid &=
2461 ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 }
2463 else
2464 {
2465 curwin->w_topline = loff.lnum;
2466#ifdef FEAT_DIFF
2467 curwin->w_topfill = loff.fill;
2468 check_topfill(curwin, FALSE);
2469#endif
2470 curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
2471 }
2472 }
2473 }
2474 }
2475#ifdef FEAT_FOLDING
2476 foldAdjustCursor();
2477#endif
2478 cursor_correct();
Bram Moolenaarbc54f3f2016-09-04 14:34:28 +02002479 check_cursor_col();
Bram Moolenaar7c626922005-02-07 22:01:03 +00002480 if (retval == OK)
2481 beginline(BL_SOL | BL_FIX);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
2483
Bram Moolenaar907dad72018-07-10 15:07:15 +02002484 if (retval == OK && dir == FORWARD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485 {
Bram Moolenaar907dad72018-07-10 15:07:15 +02002486 // Avoid the screen jumping up and down when 'scrolloff' is non-zero.
2487 // But make sure we scroll at least one line (happens with mix of long
2488 // wrapping lines and non-wrapping line).
2489 if (check_top_offset())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490 {
Bram Moolenaar907dad72018-07-10 15:07:15 +02002491 scroll_cursor_top(1, FALSE);
2492 if (curwin->w_topline <= old_topline
2493 && old_topline < curbuf->b_ml.ml_line_count)
2494 {
2495 curwin->w_topline = old_topline + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002496#ifdef FEAT_FOLDING
Bram Moolenaar907dad72018-07-10 15:07:15 +02002497 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2498#endif
2499 }
2500 }
2501#ifdef FEAT_FOLDING
2502 else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2504#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505 }
2506
2507 redraw_later(VALID);
2508 return retval;
2509}
2510
2511/*
2512 * Decide how much overlap to use for page-up or page-down scrolling.
2513 * This is symmetric, so that doing both keeps the same lines displayed.
2514 * Three lines are examined:
2515 *
2516 * before CTRL-F after CTRL-F / before CTRL-B
2517 * etc. l1
2518 * l1 last but one line ------------
2519 * l2 last text line l2 top text line
2520 * ------------- l3 second text line
2521 * l3 etc.
2522 */
2523 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002524get_scroll_overlap(lineoff_T *lp, int dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525{
2526 int h1, h2, h3, h4;
2527 int min_height = curwin->w_height - 2;
2528 lineoff_T loff0, loff1, loff2;
2529
2530#ifdef FEAT_DIFF
2531 if (lp->fill > 0)
2532 lp->height = 1;
2533 else
2534 lp->height = plines_nofill(lp->lnum);
2535#else
2536 lp->height = plines(lp->lnum);
2537#endif
2538 h1 = lp->height;
2539 if (h1 > min_height)
2540 return; /* no overlap */
2541
2542 loff0 = *lp;
2543 if (dir > 0)
2544 botline_forw(lp);
2545 else
2546 topline_back(lp);
2547 h2 = lp->height;
Bram Moolenaarf4f19562012-11-28 18:22:11 +01002548 if (h2 == MAXCOL || h2 + h1 > min_height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002549 {
2550 *lp = loff0; /* no overlap */
2551 return;
2552 }
2553
2554 loff1 = *lp;
2555 if (dir > 0)
2556 botline_forw(lp);
2557 else
2558 topline_back(lp);
2559 h3 = lp->height;
Bram Moolenaarf4f19562012-11-28 18:22:11 +01002560 if (h3 == MAXCOL || h3 + h2 > min_height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 {
2562 *lp = loff0; /* no overlap */
2563 return;
2564 }
2565
2566 loff2 = *lp;
2567 if (dir > 0)
2568 botline_forw(lp);
2569 else
2570 topline_back(lp);
2571 h4 = lp->height;
Bram Moolenaarf4f19562012-11-28 18:22:11 +01002572 if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 *lp = loff1; /* 1 line overlap */
2574 else
2575 *lp = loff2; /* 2 lines overlap */
2576 return;
2577}
2578
2579/* #define KEEP_SCREEN_LINE */
2580/*
2581 * Scroll 'scroll' lines up or down.
2582 */
2583 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002584halfpage(int flag, linenr_T Prenum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585{
2586 long scrolled = 0;
2587 int i;
2588 int n;
2589 int room;
2590
2591 if (Prenum)
2592 curwin->w_p_scr = (Prenum > curwin->w_height) ?
2593 curwin->w_height : Prenum;
2594 n = (curwin->w_p_scr <= curwin->w_height) ?
2595 curwin->w_p_scr : curwin->w_height;
2596
Bram Moolenaard5d37532017-03-27 23:02:07 +02002597 update_topline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 validate_botline();
2599 room = curwin->w_empty_rows;
2600#ifdef FEAT_DIFF
2601 room += curwin->w_filler_rows;
2602#endif
2603 if (flag)
2604 {
2605 /*
2606 * scroll the text up
2607 */
2608 while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2609 {
2610#ifdef FEAT_DIFF
2611 if (curwin->w_topfill > 0)
2612 {
2613 i = 1;
2614 if (--n < 0 && scrolled > 0)
2615 break;
2616 --curwin->w_topfill;
2617 }
2618 else
2619#endif
2620 {
Bram Moolenaar43335ea2015-09-09 20:59:37 +02002621 i = PLINES_NOFILL(curwin->w_topline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002622 n -= i;
2623 if (n < 0 && scrolled > 0)
2624 break;
2625#ifdef FEAT_FOLDING
2626 (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
2627#endif
2628 ++curwin->w_topline;
2629#ifdef FEAT_DIFF
2630 curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
2631#endif
2632
2633#ifndef KEEP_SCREEN_LINE
2634 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2635 {
2636 ++curwin->w_cursor.lnum;
2637 curwin->w_valid &=
2638 ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
2639 }
2640#endif
2641 }
2642 curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
2643 scrolled += i;
2644
2645 /*
2646 * Correct w_botline for changed w_topline.
2647 * Won't work when there are filler lines.
2648 */
2649#ifdef FEAT_DIFF
2650 if (curwin->w_p_diff)
2651 curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
2652 else
2653#endif
2654 {
2655 room += i;
2656 do
2657 {
2658 i = plines(curwin->w_botline);
2659 if (i > room)
2660 break;
2661#ifdef FEAT_FOLDING
2662 (void)hasFolding(curwin->w_botline, NULL,
2663 &curwin->w_botline);
2664#endif
2665 ++curwin->w_botline;
2666 room -= i;
2667 } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
2668 }
2669 }
2670
2671#ifndef KEEP_SCREEN_LINE
2672 /*
2673 * When hit bottom of the file: move cursor down.
2674 */
2675 if (n > 0)
2676 {
2677# ifdef FEAT_FOLDING
2678 if (hasAnyFolding(curwin))
2679 {
2680 while (--n >= 0
2681 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2682 {
2683 (void)hasFolding(curwin->w_cursor.lnum, NULL,
2684 &curwin->w_cursor.lnum);
2685 ++curwin->w_cursor.lnum;
2686 }
2687 }
2688 else
2689# endif
2690 curwin->w_cursor.lnum += n;
2691 check_cursor_lnum();
2692 }
2693#else
2694 /* try to put the cursor in the same screen line */
2695 while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
2696 && curwin->w_cursor.lnum < curwin->w_botline - 1)
2697 {
2698 scrolled -= plines(curwin->w_cursor.lnum);
2699 if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
2700 break;
2701# ifdef FEAT_FOLDING
2702 (void)hasFolding(curwin->w_cursor.lnum, NULL,
2703 &curwin->w_cursor.lnum);
2704# endif
2705 ++curwin->w_cursor.lnum;
2706 }
2707#endif
2708 }
2709 else
2710 {
2711 /*
2712 * scroll the text down
2713 */
2714 while (n > 0 && curwin->w_topline > 1)
2715 {
2716#ifdef FEAT_DIFF
2717 if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
2718 {
2719 i = 1;
2720 if (--n < 0 && scrolled > 0)
2721 break;
2722 ++curwin->w_topfill;
2723 }
2724 else
2725#endif
2726 {
Bram Moolenaar43335ea2015-09-09 20:59:37 +02002727 i = PLINES_NOFILL(curwin->w_topline - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728 n -= i;
2729 if (n < 0 && scrolled > 0)
2730 break;
2731 --curwin->w_topline;
2732#ifdef FEAT_FOLDING
2733 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2734#endif
2735#ifdef FEAT_DIFF
2736 curwin->w_topfill = 0;
2737#endif
2738 }
2739 curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
2740 VALID_BOTLINE|VALID_BOTLINE_AP);
2741 scrolled += i;
2742#ifndef KEEP_SCREEN_LINE
2743 if (curwin->w_cursor.lnum > 1)
2744 {
2745 --curwin->w_cursor.lnum;
2746 curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
2747 }
2748#endif
2749 }
2750#ifndef KEEP_SCREEN_LINE
2751 /*
2752 * When hit top of the file: move cursor up.
2753 */
2754 if (n > 0)
2755 {
2756 if (curwin->w_cursor.lnum <= (linenr_T)n)
2757 curwin->w_cursor.lnum = 1;
2758 else
2759# ifdef FEAT_FOLDING
2760 if (hasAnyFolding(curwin))
2761 {
2762 while (--n >= 0 && curwin->w_cursor.lnum > 1)
2763 {
2764 --curwin->w_cursor.lnum;
2765 (void)hasFolding(curwin->w_cursor.lnum,
2766 &curwin->w_cursor.lnum, NULL);
2767 }
2768 }
2769 else
2770# endif
2771 curwin->w_cursor.lnum -= n;
2772 }
2773#else
2774 /* try to put the cursor in the same screen line */
2775 scrolled += n; /* move cursor when topline is 1 */
2776 while (curwin->w_cursor.lnum > curwin->w_topline
2777 && (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
2778 {
2779 scrolled -= plines(curwin->w_cursor.lnum - 1);
2780 if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
2781 break;
2782 --curwin->w_cursor.lnum;
2783# ifdef FEAT_FOLDING
2784 foldAdjustCursor();
2785# endif
2786 }
2787#endif
2788 }
2789# ifdef FEAT_FOLDING
2790 /* Move cursor to first line of closed fold. */
2791 foldAdjustCursor();
2792# endif
2793#ifdef FEAT_DIFF
2794 check_topfill(curwin, !flag);
2795#endif
2796 cursor_correct();
2797 beginline(BL_SOL | BL_FIX);
2798 redraw_later(VALID);
2799}
Bram Moolenaar860cae12010-06-05 23:22:07 +02002800
Bram Moolenaar860cae12010-06-05 23:22:07 +02002801 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002802do_check_cursorbind(void)
Bram Moolenaar860cae12010-06-05 23:22:07 +02002803{
2804 linenr_T line = curwin->w_cursor.lnum;
Bram Moolenaar1ea69b72012-03-16 19:24:26 +01002805 colnr_T col = curwin->w_cursor.col;
2806# ifdef FEAT_VIRTUALEDIT
2807 colnr_T coladd = curwin->w_cursor.coladd;
2808# endif
Bram Moolenaar524780d2012-03-28 14:19:50 +02002809 colnr_T curswant = curwin->w_curswant;
2810 int set_curswant = curwin->w_set_curswant;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002811 win_T *old_curwin = curwin;
2812 buf_T *old_curbuf = curbuf;
Bram Moolenaar61452852011-02-01 18:01:11 +01002813 int restart_edit_save;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002814 int old_VIsual_select = VIsual_select;
2815 int old_VIsual_active = VIsual_active;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002816
2817 /*
2818 * loop through the cursorbound windows
2819 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002820 VIsual_select = VIsual_active = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +02002821 FOR_ALL_WINDOWS(curwin)
Bram Moolenaar860cae12010-06-05 23:22:07 +02002822 {
2823 curbuf = curwin->w_buffer;
2824 /* skip original window and windows with 'noscrollbind' */
2825 if (curwin != old_curwin && curwin->w_p_crb)
2826 {
2827# ifdef FEAT_DIFF
2828 if (curwin->w_p_diff)
Bram Moolenaar025e3e02016-10-18 14:50:18 +02002829 curwin->w_cursor.lnum =
2830 diff_get_corresponding_line(old_curbuf, line);
Bram Moolenaar860cae12010-06-05 23:22:07 +02002831 else
2832# endif
2833 curwin->w_cursor.lnum = line;
2834 curwin->w_cursor.col = col;
Bram Moolenaar1ea69b72012-03-16 19:24:26 +01002835# ifdef FEAT_VIRTUALEDIT
2836 curwin->w_cursor.coladd = coladd;
2837# endif
Bram Moolenaar524780d2012-03-28 14:19:50 +02002838 curwin->w_curswant = curswant;
2839 curwin->w_set_curswant = set_curswant;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002840
Bram Moolenaar61452852011-02-01 18:01:11 +01002841 /* Make sure the cursor is in a valid position. Temporarily set
2842 * "restart_edit" to allow the cursor to be beyond the EOL. */
2843 restart_edit_save = restart_edit;
2844 restart_edit = TRUE;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002845 check_cursor();
Bram Moolenaar1b9750d2017-01-15 20:51:37 +01002846# ifdef FEAT_SYN_HL
Bram Moolenaar9506cad2017-01-15 13:53:49 +01002847 if (curwin->w_p_cul || curwin->w_p_cuc)
Bram Moolenaar519d7782017-01-14 14:54:33 +01002848 validate_cursor();
Bram Moolenaar1b9750d2017-01-15 20:51:37 +01002849# endif
Bram Moolenaar61452852011-02-01 18:01:11 +01002850 restart_edit = restart_edit_save;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002851# ifdef FEAT_MBYTE
2852 /* Correct cursor for multi-byte character. */
2853 if (has_mbyte)
2854 mb_adjust_cursor();
2855# endif
Bram Moolenaar9506cad2017-01-15 13:53:49 +01002856 redraw_later(VALID);
Bram Moolenaarf3d419d2011-01-22 21:05:07 +01002857
2858 /* Only scroll when 'scrollbind' hasn't done this. */
2859 if (!curwin->w_p_scb)
2860 update_topline();
Bram Moolenaar860cae12010-06-05 23:22:07 +02002861 curwin->w_redr_status = TRUE;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002862 }
2863 }
2864
2865 /*
2866 * reset current-window
2867 */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002868 VIsual_select = old_VIsual_select;
2869 VIsual_active = old_VIsual_active;
Bram Moolenaar860cae12010-06-05 23:22:07 +02002870 curwin = old_curwin;
2871 curbuf = old_curbuf;
2872}