Annotation of src/usr.bin/vim/screen.c, Revision 1.3
1.3 ! downsj 1: /* $OpenBSD: screen.c,v 1.2 1996/09/21 06:23:18 downsj Exp $ */
1.1 downsj 2: /* vi:set ts=4 sw=4:
3: *
4: * VIM - Vi IMproved by Bram Moolenaar
5: *
6: * Do ":help uganda" in Vim to read copying and usage conditions.
7: * Do ":help credits" in Vim to see a list of people who contributed.
8: */
9:
10: /*
11: * screen.c: code for displaying on the screen
12: */
13:
14: #include "vim.h"
15: #include "globals.h"
16: #include "proto.h"
17: #include "option.h"
18: #include "ops.h" /* For op_inclusive */
19:
20: char *tgoto __PARMS((char *cm, int col, int line));
21:
22: static int canopt; /* TRUE when cursor goto can be optimized */
23: static int attributes = 0; /* current attributes for screen character*/
24: static int highlight_attr = 0; /* attributes when highlighting on */
25: #ifdef RIGHTLEFT
26: static int rightleft = 0; /* set to 1 for right to left in screen_fill */
27: #endif
28:
29: static int win_line __ARGS((WIN *, linenr_t, int, int));
30: static void comp_Botline_sub __ARGS((WIN *wp, linenr_t lnum, int done));
31: static void screen_char __ARGS((char_u *, int, int));
32: static void screenclear2 __ARGS((void));
33: static void lineclear __ARGS((char_u *p));
34: static int screen_ins_lines __ARGS((int, int, int, int));
35:
36: /*
37: * updateline() - like updateScreen() but only for cursor line
38: *
39: * Check if the size of the cursor line has changed. If it did change, lines
40: * below the cursor will move up or down and we need to call the routine
41: * updateScreen() to examine the entire screen.
42: */
43: void
44: updateline()
45: {
46: int row;
47: int n;
48:
49: if (!screen_valid(TRUE))
50: return;
51:
52: if (must_redraw) /* must redraw whole screen */
53: {
54: updateScreen(must_redraw);
55: return;
56: }
57:
58: if (RedrawingDisabled)
59: {
60: must_redraw = NOT_VALID; /* remember to update later */
61: return;
62: }
63:
64: cursor_off();
65:
66: (void)set_highlight('v');
67: row = win_line(curwin, curwin->w_cursor.lnum,
68: curwin->w_cline_row, curwin->w_height);
69:
70: if (row == curwin->w_height + 1) /* line too long for window */
71: {
72: /* window needs to be scrolled up to show the cursor line */
73: if (curwin->w_topline < curwin->w_cursor.lnum)
74: ++curwin->w_topline;
75: updateScreen(VALID_TO_CURSCHAR);
76: cursupdate();
77: }
78: else if (!dollar_vcol)
79: {
80: n = row - curwin->w_cline_row;
81: if (n != curwin->w_cline_height) /* line changed size */
82: {
83: if (n < curwin->w_cline_height) /* got smaller: delete lines */
84: win_del_lines(curwin, row,
85: curwin->w_cline_height - n, FALSE, TRUE);
86: else /* got bigger: insert lines */
87: win_ins_lines(curwin,
88: curwin->w_cline_row + curwin->w_cline_height,
89: n - curwin->w_cline_height, FALSE, TRUE);
90: updateScreen(VALID_TO_CURSCHAR);
91: }
92: else if (clear_cmdline || redraw_cmdline)
93: showmode(); /* clear cmdline, show mode and ruler */
94: }
95: }
96:
97: /*
98: * update all windows that are editing the current buffer
99: */
100: void
101: update_curbuf(type)
102: int type;
103: {
104: WIN *wp;
105:
106: for (wp = firstwin; wp; wp = wp->w_next)
107: if (wp->w_buffer == curbuf && wp->w_redr_type < type)
108: wp->w_redr_type = type;
109: updateScreen(type);
110: }
111:
112: /*
113: * updateScreen()
114: *
115: * Based on the current value of curwin->w_topline, transfer a screenfull
116: * of stuff from Filemem to NextScreen, and update curwin->w_botline.
117: */
118:
119: void
120: updateScreen(type)
121: int type;
122: {
123: WIN *wp;
124:
125: if (!screen_valid(TRUE))
126: return;
127:
128: dollar_vcol = 0;
129:
130: if (must_redraw)
131: {
132: if (type < must_redraw) /* use maximal type */
133: type = must_redraw;
134: must_redraw = 0;
135: }
136:
137: if (type == CURSUPD) /* update cursor and then redraw NOT_VALID */
138: {
139: curwin->w_lsize_valid = 0;
140: cursupdate(); /* will call updateScreen() */
141: return;
142: }
143: if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
144: type = NOT_VALID;
145:
146: if (RedrawingDisabled)
147: {
148: must_redraw = type; /* remember type for next time */
149: curwin->w_redr_type = type;
150: curwin->w_lsize_valid = 0; /* don't use w_lsize[] now */
151: return;
152: }
153:
154: /*
155: * if the screen was scrolled up when displaying a message, scroll it down
156: */
157: if (msg_scrolled)
158: {
159: clear_cmdline = TRUE;
160: if (msg_scrolled > Rows - 5) /* clearing is faster */
161: type = CLEAR;
162: else if (type != CLEAR)
163: {
164: if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
165: type = CLEAR;
166: win_rest_invalid(firstwin); /* should do only first/last few */
167: }
168: msg_scrolled = 0;
169: need_wait_return = FALSE;
170: }
171:
172: /*
173: * reset cmdline_row now (may have been changed temporarily)
174: */
175: compute_cmdrow();
176:
177: if (type == CLEAR) /* first clear screen */
178: {
179: screenclear(); /* will reset clear_cmdline */
180: type = NOT_VALID;
181: }
182:
183: if (clear_cmdline) /* first clear cmdline */
184: {
185: if (emsg_on_display)
186: {
187: mch_delay(1000L, TRUE);
188: emsg_on_display = FALSE;
189: }
190: msg_row = cmdline_row;
191: msg_col = 0;
192: msg_clr_eos(); /* will reset clear_cmdline */
193: }
194:
195: /* return if there is nothing to do */
196: if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0]) ||
197: (type == INVERTED &&
198: curwin->w_old_cursor_lnum == curwin->w_cursor.lnum &&
199: curwin->w_old_cursor_vcol == curwin->w_virtcol &&
200: curwin->w_old_curswant == curwin->w_curswant)))
201: {
202: /*
203: * go from top to bottom through the windows, redrawing the ones that
204: * need it
205: */
206: curwin->w_redr_type = type;
207: cursor_off();
208: for (wp = firstwin; wp; wp = wp->w_next)
209: {
210: if (wp->w_redr_type)
211: win_update(wp);
212: if (wp->w_redr_status)
213: win_redr_status(wp);
214: }
215: }
216: if (redraw_cmdline)
217: showmode();
218: }
219:
220: #ifdef USE_GUI
221: /*
222: * Update a single window, its status line and maybe the command line msg.
223: * Used for the GUI scrollbar.
224: */
225: void
226: updateWindow(wp)
227: WIN *wp;
228: {
229: win_update(wp);
230: if (wp->w_redr_status)
231: win_redr_status(wp);
232: if (redraw_cmdline)
233: showmode();
234: }
235: #endif
236:
237: /*
238: * update a single window
239: *
240: * This may cause the windows below it also to be redrawn
241: */
242: void
243: win_update(wp)
244: WIN *wp;
245: {
246: int type = wp->w_redr_type;
247: register int row;
248: register int endrow;
249: linenr_t lnum;
250: linenr_t lastline = 0; /* only valid if endrow != Rows -1 */
251: int done; /* if TRUE, we hit the end of the file */
252: int didline; /* if TRUE, we finished the last line */
253: int srow = 0; /* starting row of the current line */
254: int idx;
255: int i;
256: long j;
257:
258: if (type == NOT_VALID)
259: {
260: wp->w_redr_status = TRUE;
261: wp->w_lsize_valid = 0;
262: }
263:
264: idx = 0;
265: row = 0;
266: lnum = wp->w_topline;
267:
268: /* The number of rows shown is w_height. */
269: /* The default last row is the status/command line. */
270: endrow = wp->w_height;
271:
272: if (type == VALID || type == VALID_TO_CURSCHAR)
273: {
274: /*
275: * We handle two special cases:
276: * 1: we are off the top of the screen by a few lines: scroll down
277: * 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
278: */
279: if (wp->w_topline < wp->w_lsize_lnum[0]) /* may scroll down */
280: {
281: j = wp->w_lsize_lnum[0] - wp->w_topline;
282: if (j < wp->w_height - 2) /* not too far off */
283: {
284: lastline = wp->w_lsize_lnum[0] - 1;
285: i = plines_m_win(wp, wp->w_topline, lastline);
286: if (i < wp->w_height - 2) /* less than a screen off */
287: {
288: /*
289: * Try to insert the correct number of lines.
290: * If not the last window, delete the lines at the bottom.
291: * win_ins_lines may fail.
292: */
293: if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK &&
294: wp->w_lsize_valid)
295: {
296: endrow = i;
297:
298: if ((wp->w_lsize_valid += j) > wp->w_height)
299: wp->w_lsize_valid = wp->w_height;
300: for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
301: {
302: wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
303: wp->w_lsize[idx] = wp->w_lsize[idx - j];
304: }
305: idx = 0;
306: }
307: }
308: else if (lastwin == firstwin)
309: screenclear(); /* far off: clearing the screen is faster */
310: }
311: else if (lastwin == firstwin)
312: screenclear(); /* far off: clearing the screen is faster */
313: }
314: else /* may scroll up */
315: {
316: j = -1;
317: /* try to find wp->w_topline in wp->w_lsize_lnum[] */
318: for (i = 0; i < wp->w_lsize_valid; i++)
319: {
320: if (wp->w_lsize_lnum[i] == wp->w_topline)
321: {
322: j = i;
323: break;
324: }
325: row += wp->w_lsize[i];
326: }
327: if (j == -1) /* wp->w_topline is not in wp->w_lsize_lnum */
328: {
329: row = 0;
330: if (lastwin == firstwin)
331: screenclear(); /* far off: clearing the screen is faster */
332: }
333: else
334: {
335: /*
336: * Try to delete the correct number of lines.
337: * wp->w_topline is at wp->w_lsize_lnum[i].
338: */
339: if ((row == 0 || win_del_lines(wp, 0, row,
340: FALSE, wp == firstwin) == OK) && wp->w_lsize_valid)
341: {
342: srow = row;
343: row = 0;
344: for (;;)
345: {
346: if (type == VALID_TO_CURSCHAR &&
347: lnum == wp->w_cursor.lnum)
348: break;
349: if (row + srow + (int)wp->w_lsize[j] >= wp->w_height)
350: break;
351: wp->w_lsize[idx] = wp->w_lsize[j];
352: wp->w_lsize_lnum[idx] = lnum++;
353:
354: row += wp->w_lsize[idx++];
355: if ((int)++j >= wp->w_lsize_valid)
356: break;
357: }
358: wp->w_lsize_valid = idx;
359: }
360: else
361: row = 0; /* update all lines */
362: }
363: }
364: if (endrow == wp->w_height && idx == 0) /* no scrolling */
365: wp->w_lsize_valid = 0;
366: }
367:
368: done = didline = FALSE;
369:
370: if (VIsual_active) /* check if we are updating the inverted part */
371: {
372: linenr_t from, to;
373:
374: /* find the line numbers that need to be updated */
375: if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
376: {
377: from = curwin->w_cursor.lnum;
378: to = wp->w_old_cursor_lnum;
379: }
380: else
381: {
382: from = wp->w_old_cursor_lnum;
383: to = curwin->w_cursor.lnum;
384: }
385: /* if VIsual changed, update the maximal area */
386: if (VIsual.lnum != wp->w_old_visual_lnum)
387: {
388: if (wp->w_old_visual_lnum < from)
389: from = wp->w_old_visual_lnum;
390: if (wp->w_old_visual_lnum > to)
391: to = wp->w_old_visual_lnum;
392: if (VIsual.lnum < from)
393: from = VIsual.lnum;
394: if (VIsual.lnum > to)
395: to = VIsual.lnum;
396: }
397: /* if in block mode and changed column or wp->w_curswant: update all
398: * lines */
399: if (VIsual_mode == Ctrl('V') &&
400: (curwin->w_virtcol != wp->w_old_cursor_vcol ||
401: wp->w_curswant != wp->w_old_curswant))
402: {
403: if (from > VIsual.lnum)
404: from = VIsual.lnum;
405: if (to < VIsual.lnum)
406: to = VIsual.lnum;
407: }
408:
409: if (from < wp->w_topline)
410: from = wp->w_topline;
411: if (from >= wp->w_botline)
412: from = wp->w_botline - 1;
413: if (to >= wp->w_botline)
414: to = wp->w_botline - 1;
415:
416: /* find the minimal part to be updated */
417: if (type == INVERTED)
418: {
419: while (lnum < from) /* find start */
420: {
421: row += wp->w_lsize[idx++];
422: ++lnum;
423: }
424: srow = row;
425: for (j = idx; j < wp->w_lsize_valid; ++j) /* find end */
426: {
427: if (wp->w_lsize_lnum[j] == to + 1)
428: {
429: endrow = srow;
430: break;
431: }
432: srow += wp->w_lsize[j];
433: }
434: }
435:
436: /* if we update the lines between from and to set old_cursor */
437: if (type == INVERTED || (lnum <= from &&
438: (endrow == wp->w_height || lastline >= to)))
439: {
440: wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
441: wp->w_old_cursor_vcol = curwin->w_virtcol;
442: wp->w_old_visual_lnum = VIsual.lnum;
443: wp->w_old_curswant = wp->w_curswant;
444: }
445: }
446: else
447: {
448: wp->w_old_cursor_lnum = 0;
449: wp->w_old_visual_lnum = 0;
450: }
451:
452: (void)set_highlight('v');
453:
454: /*
455: * Update the screen rows from "row" to "endrow".
456: * Start at line "lnum" which is at wp->w_lsize_lnum[idx].
457: */
458: for (;;)
459: {
460: if (lnum > wp->w_buffer->b_ml.ml_line_count)
461: {
462: done = TRUE; /* hit the end of the file */
463: break;
464: }
465: srow = row;
466: row = win_line(wp, lnum, srow, endrow);
467: if (row > endrow) /* past end of screen */
468: { /* we may need the size of that */
469: wp->w_lsize[idx] = plines_win(wp, lnum);
470: wp->w_lsize_lnum[idx++] = lnum; /* too long line later on */
471: break;
472: }
473:
474: wp->w_lsize[idx] = row - srow;
475: wp->w_lsize_lnum[idx++] = lnum;
476: if (++lnum > wp->w_buffer->b_ml.ml_line_count)
477: {
478: done = TRUE;
479: break;
480: }
481:
482: if (row == endrow)
483: {
484: didline = TRUE;
485: break;
486: }
487: }
488: if (idx > wp->w_lsize_valid)
489: wp->w_lsize_valid = idx;
490:
491: /* Do we have to do off the top of the screen processing ? */
492: if (endrow != wp->w_height)
493: {
494: row = 0;
495: for (idx = 0; idx < wp->w_lsize_valid && row < wp->w_height; idx++)
496: row += wp->w_lsize[idx];
497:
498: if (row < wp->w_height)
499: {
500: done = TRUE;
501: }
502: else if (row > wp->w_height) /* Need to blank out the last line */
503: {
504: lnum = wp->w_lsize_lnum[idx - 1];
505: srow = row - wp->w_lsize[idx - 1];
506: didline = FALSE;
507: }
508: else
509: {
510: lnum = wp->w_lsize_lnum[idx - 1] + 1;
511: didline = TRUE;
512: }
513: }
514:
515: wp->w_empty_rows = 0;
516: /*
517: * If we didn't hit the end of the file, and we didn't finish the last
518: * line we were working on, then the line didn't fit.
519: */
520: if (!done && !didline)
521: {
522: if (lnum == wp->w_topline)
523: {
524: /*
525: * Single line that does not fit!
526: * Fill last line with '@' characters.
527: */
528: screen_fill(wp->w_winpos + wp->w_height - 1,
529: wp->w_winpos + wp->w_height, 0, (int)Columns, '@', '@');
530: wp->w_botline = lnum + 1;
531: }
532: else
533: {
534: /*
535: * Clear the rest of the screen and mark the unused lines.
536: */
537: #ifdef RIGHTLEFT
538: if (wp->w_p_rl)
539: rightleft = 1;
540: #endif
541: screen_fill(wp->w_winpos + srow,
542: wp->w_winpos + wp->w_height, 0, (int)Columns, '@', ' ');
543: #ifdef RIGHTLEFT
544: rightleft = 0;
545: #endif
546: wp->w_botline = lnum;
547: wp->w_empty_rows = wp->w_height - srow;
548: }
549: }
550: else
551: {
552: /* make sure the rest of the screen is blank */
553: /* put '~'s on rows that aren't part of the file. */
554: #ifdef RIGHTLEFT
555: if (wp->w_p_rl)
556: rightleft = 1;
557: #endif
558: screen_fill(wp->w_winpos + row,
559: wp->w_winpos + wp->w_height, 0, (int)Columns, '~', ' ');
560: #ifdef RIGHTLEFT
561: rightleft = 0;
562: #endif
563: wp->w_empty_rows = wp->w_height - row;
564:
565: if (done) /* we hit the end of the file */
566: wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1;
567: else
568: wp->w_botline = lnum;
569: }
570:
571: wp->w_redr_type = 0;
572: }
573:
574: /*
575: * mark all status lines for redraw; used after first :cd
576: */
577: void
578: status_redraw_all()
579: {
580: WIN *wp;
581:
582: for (wp = firstwin; wp; wp = wp->w_next)
583: wp->w_redr_status = TRUE;
584: updateScreen(NOT_VALID);
585: }
586:
587: /*
588: * Redraw the status line of window wp.
589: *
590: * If inversion is possible we use it. Else '=' characters are used.
591: */
592: void
593: win_redr_status(wp)
594: WIN *wp;
595: {
596: int row;
597: char_u *p;
598: int len;
599: int fillchar;
600:
601: if (wp->w_status_height) /* if there is a status line */
602: {
603: if (set_highlight('s') == OK) /* can highlight */
604: {
605: fillchar = ' ';
606: start_highlight();
607: }
608: else /* can't highlight, use '=' */
609: fillchar = '=';
610:
611: p = wp->w_buffer->b_xfilename;
612: if (p == NULL)
613: STRCPY(NameBuff, "[No File]");
614: else
615: {
616: home_replace(wp->w_buffer, p, NameBuff, MAXPATHL);
617: trans_characters(NameBuff, MAXPATHL);
618: }
619: p = NameBuff;
620: len = STRLEN(p);
621:
622: if (wp->w_buffer->b_help || wp->w_buffer->b_changed ||
623: wp->w_buffer->b_p_ro)
624: *(p + len++) = ' ';
625: if (wp->w_buffer->b_help)
626: {
627: STRCPY(p + len, "[help]");
628: len += 6;
629: }
630: if (wp->w_buffer->b_changed)
631: {
632: STRCPY(p + len, "[+]");
633: len += 3;
634: }
635: if (wp->w_buffer->b_p_ro)
636: {
637: STRCPY(p + len, "[RO]");
638: len += 4;
639: }
640:
641: if (len > ru_col - 1)
642: {
643: p += len - (ru_col - 1);
644: *p = '<';
645: len = ru_col - 1;
646: }
647:
648: row = wp->w_winpos + wp->w_height;
649: screen_msg(p, row, 0);
650: screen_fill(row, row + 1, len, ru_col, fillchar, fillchar);
651:
652: stop_highlight();
653: win_redr_ruler(wp, TRUE);
654: }
655: else /* no status line, can only be last window */
656: redraw_cmdline = TRUE;
657: wp->w_redr_status = FALSE;
658: }
659:
660: /*
661: * display line "lnum" of window 'wp' on the screen
662: * Start at row "startrow", stop when "endrow" is reached.
663: * Return the number of last row the line occupies.
664: */
665:
666: static int
667: win_line(wp, lnum, startrow, endrow)
668: WIN *wp;
669: linenr_t lnum;
670: int startrow;
671: int endrow;
672: {
673: char_u *screenp;
674: int c;
675: int col; /* visual column on screen */
676: long vcol; /* visual column for tabs */
677: int row; /* row in the window, excl w_winpos */
678: int screen_row; /* row on the screen, incl w_winpos */
679: char_u *ptr;
680: char_u extra[16]; /* "%ld" must fit in here */
681: char_u *p_extra;
682: char_u *showbreak = NULL;
683: int n_extra;
684: int n_spaces = 0;
685:
686: int fromcol, tocol; /* start/end of inverting */
687: int noinvcur = FALSE; /* don't invert the cursor */
688: FPOS *top, *bot;
689:
690: if (startrow > endrow) /* past the end already! */
691: return startrow;
692:
693: row = startrow;
694: screen_row = row + wp->w_winpos;
695: col = 0;
696: vcol = 0;
697: fromcol = -10;
698: tocol = MAXCOL;
699: canopt = TRUE;
700:
701: /*
702: * handle visual active in this window
703: */
704: if (VIsual_active && wp->w_buffer == curwin->w_buffer)
705: {
706: /* Visual is after curwin->w_cursor */
707: if (ltoreq(curwin->w_cursor, VIsual))
708: {
709: top = &curwin->w_cursor;
710: bot = &VIsual;
711: }
712: else /* Visual is before curwin->w_cursor */
713: {
714: top = &VIsual;
715: bot = &curwin->w_cursor;
716: }
717: if (VIsual_mode == Ctrl('V')) /* block mode */
718: {
719: if (lnum >= top->lnum && lnum <= bot->lnum)
720: {
721: colnr_t from, to;
722:
723: getvcol(wp, top, (colnr_t *)&fromcol, NULL, (colnr_t *)&tocol);
724: getvcol(wp, bot, &from, NULL, &to);
725: if ((int)from < fromcol)
726: fromcol = from;
727: if ((int)to > tocol)
728: tocol = to;
729: ++tocol;
730:
731: if (wp->w_curswant == MAXCOL)
732: tocol = MAXCOL;
733: }
734: }
735: else /* non-block mode */
736: {
737: if (lnum > top->lnum && lnum <= bot->lnum)
738: fromcol = 0;
739: else if (lnum == top->lnum)
740: getvcol(wp, top, (colnr_t *)&fromcol, NULL, NULL);
741: if (lnum == bot->lnum)
742: {
743: getvcol(wp, bot, NULL, NULL, (colnr_t *)&tocol);
744: ++tocol;
745: }
746:
747: if (VIsual_mode == 'V') /* linewise */
748: {
749: if (fromcol > 0)
750: fromcol = 0;
751: tocol = MAXCOL;
752: }
753: }
754: /* if the cursor can't be switched off, don't invert the
755: * character where the cursor is */
756: #ifndef MSDOS
757: if (!highlight_match && *T_VI == NUL &&
758: lnum == curwin->w_cursor.lnum && wp == curwin)
759: noinvcur = TRUE;
760: #endif
761:
762: if (tocol <= (int)wp->w_leftcol) /* inverting is left of screen */
763: fromcol = 0;
764: /* start of invert is left of screen */
765: else if (fromcol >= 0 && fromcol < (int)wp->w_leftcol)
766: fromcol = wp->w_leftcol;
767:
768: /* if inverting in this line, can't optimize cursor positioning */
769: if (fromcol >= 0)
770: canopt = FALSE;
771: }
772: /*
773: * handle incremental search position highlighting
774: */
775: else if (highlight_match && wp == curwin && search_match_len)
776: {
777: if (lnum == curwin->w_cursor.lnum)
778: {
779: getvcol(curwin, &(curwin->w_cursor),
780: (colnr_t *)&fromcol, NULL, NULL);
781: curwin->w_cursor.col += search_match_len;
782: getvcol(curwin, &(curwin->w_cursor),
783: (colnr_t *)&tocol, NULL, NULL);
784: curwin->w_cursor.col -= search_match_len;
785: canopt = FALSE;
786: if (fromcol == tocol) /* do at least one character */
787: tocol = fromcol + 1; /* happens when past end of line */
788: }
789: }
790:
791: ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
792: if (!wp->w_p_wrap) /* advance to first character to be displayed */
793: {
794: while ((colnr_t)vcol < wp->w_leftcol && *ptr)
795: vcol += win_chartabsize(wp, *ptr++, (colnr_t)vcol);
796: if ((colnr_t)vcol > wp->w_leftcol)
797: {
798: n_spaces = vcol - wp->w_leftcol; /* begin with some spaces */
799: vcol = wp->w_leftcol;
800: }
801: }
802: screenp = LinePointers[screen_row];
803: #ifdef RIGHTLEFT
804: if (wp->w_p_rl)
805: {
806: col = Columns - 1; /* col follows screenp here */
807: screenp += Columns - 1;
808: }
809: #endif
810: if (wp->w_p_nu)
811: {
812: #ifdef RIGHTLEFT
813: if (wp->w_p_rl) /* reverse line numbers */
814: {
815: char_u *c1, *c2, t;
816:
817: sprintf((char *)extra, " %-7ld", (long)lnum);
818: for (c1 = extra, c2 = extra + STRLEN(extra) - 1; c1 < c2;
819: c1++, c2--)
820: {
821: t = *c1;
822: *c1 = *c2;
823: *c2 = t;
824: }
825: }
826: else
827: #endif
828: sprintf((char *)extra, "%7ld ", (long)lnum);
829: p_extra = extra;
830: n_extra = 8;
831: vcol -= 8; /* so vcol is 0 when line number has been printed */
832: }
833: else
834: {
835: p_extra = NULL;
836: n_extra = 0;
837: }
838: for (;;)
839: {
840: if (!canopt) /* Visual or match highlighting in this line */
841: {
842: if (((vcol == fromcol && !(noinvcur &&
843: (colnr_t)vcol == wp->w_virtcol)) ||
844: (noinvcur && (colnr_t)vcol == wp->w_virtcol + 1 &&
845: vcol >= fromcol)) && vcol < tocol)
846: start_highlight(); /* start highlighting */
847: else if (attributes && (vcol == tocol ||
848: (noinvcur && (colnr_t)vcol == wp->w_virtcol)))
849: stop_highlight(); /* stop highlighting */
850: }
851:
852: /* Get the next character to put on the screen. */
853:
854: /*
855: * if 'showbreak' is set it contains the characters to put at the
856: * start of each broken line
857: */
858: if (
859: #ifdef RIGHTLEFT
860: (wp->w_p_rl ? col == -1 : col == Columns)
861: #else
862: col == Columns
863: #endif
864: && (*ptr != NUL || (wp->w_p_list && n_extra == 0) ||
865: (n_extra && *p_extra) || n_spaces) &&
866: vcol != 0 && STRLEN(p_sbr) != 0)
867: showbreak = p_sbr;
868: if (showbreak != NULL)
869: {
870: c = *showbreak++;
871: if (*showbreak == NUL)
872: showbreak = NULL;
873: }
874: /*
875: * The 'extra' array contains the extra stuff that is inserted to
876: * represent special characters (non-printable stuff).
877: */
878: else if (n_extra)
879: {
880: c = *p_extra++;
881: n_extra--;
882: }
883: else if (n_spaces)
884: {
885: c = ' ';
886: n_spaces--;
887: }
888: else
889: {
890: c = *ptr++;
891: /*
892: * Found last space before word: check for line break
893: */
894: if (wp->w_p_lbr && isbreak(c) && !isbreak(*ptr) && !wp->w_p_list)
895: {
896: n_spaces = win_lbr_chartabsize(wp, ptr - 1,
897: (colnr_t)vcol, NULL) - 1;
898: if (vim_iswhite(c))
899: c = ' ';
900: }
901: else if (!isprintchar(c))
902: {
903: /*
904: * when getting a character from the file, we may have to turn
905: * it into something else on the way to putting it into
906: * 'NextScreen'.
907: */
908: if (c == TAB && !wp->w_p_list)
909: {
910: /* tab amount depends on current column */
911: n_spaces = (int)wp->w_buffer->b_p_ts -
912: vcol % (int)wp->w_buffer->b_p_ts - 1;
913: c = ' ';
914: }
915: else if (c == NUL && wp->w_p_list)
916: {
917: p_extra = (char_u *)"";
918: n_extra = 1;
919: c = '$';
920: --ptr; /* put it back at the NUL */
921: }
922: else if (c != NUL)
923: {
924: p_extra = transchar(c);
925: n_extra = charsize(c) - 1;
926: c = *p_extra++;
927: }
928: }
929: }
930:
931: if (c == NUL)
932: {
933: if (attributes)
934: {
935: /* invert at least one char, used for Visual and empty line or
936: * highlight match at end of line. If it's beyond the last
937: * char on the screen, just overwrite that one (tricky!) */
938: if (vcol == fromcol)
939: {
940: #ifdef RIGHTLEFT
941: if (wp->w_p_rl)
942: {
943: if (col < 0)
944: {
945: ++screenp;
946: ++col;
947: }
948: }
949: else
950: #endif
951: {
952: if (col >= Columns)
953: {
954: --screenp;
955: --col;
956: }
957: }
958: if (*screenp != ' ' || *(screenp + Columns) != attributes)
959: {
960: *screenp = ' ';
961: *(screenp + Columns) = attributes;
962: screen_char(screenp, screen_row, col);
963: }
964: #ifdef RIGHTLEFT
965: if (wp->w_p_rl)
966: {
967: --screenp;
968: --col;
969: }
970: else
971: #endif
972: {
973: ++screenp;
974: ++col;
975: }
976: }
977: stop_highlight();
978: }
979: /*
980: * blank out the rest of this row, if necessary
981: */
982: #ifdef RIGHTLEFT
983: if (wp->w_p_rl)
984: {
985: while (col >= 0 && *screenp == ' ' &&
986: *(screenp + Columns) == 0)
987: {
988: --screenp;
989: --col;
990: }
991: if (col >= 0)
992: screen_fill(screen_row, screen_row + 1,
993: 0, col + 1, ' ', ' ');
994: }
995: else
996: #endif
997: {
998: while (col < Columns && *screenp == ' ' &&
999: *(screenp + Columns) == 0)
1000: {
1001: ++screenp;
1002: ++col;
1003: }
1004: if (col < Columns)
1005: screen_fill(screen_row, screen_row + 1,
1006: col, (int)Columns, ' ', ' ');
1007: }
1008: row++;
1009: break;
1010: }
1011: if (
1012: #ifdef RIGHTLEFT
1013: wp->w_p_rl ? (col < 0) :
1014: #endif
1015: (col >= Columns)
1016: )
1017: {
1018: col = 0;
1019: ++row;
1020: ++screen_row;
1021: if (!wp->w_p_wrap)
1022: break;
1023: if (row == endrow) /* line got too long for screen */
1024: {
1025: ++row;
1026: break;
1027: }
1028: screenp = LinePointers[screen_row];
1029: #ifdef RIGHTLEFT
1030: if (wp->w_p_rl)
1031: {
1032: col = Columns - 1; /* col is not used if breaking! */
1033: screenp += Columns - 1;
1034: }
1035: #endif
1036: }
1037:
1038: /*
1039: * Store the character in NextScreen.
1040: */
1041: if (*screenp != c || *(screenp + Columns) != attributes)
1042: {
1043: /*
1044: * Special trick to make copy/paste of wrapped lines work with
1045: * xterm/screen:
1046: * If the first column is to be written, write the preceding
1047: * char twice. This will work with all terminal types
1048: * (regardless of the xn,am settings).
1049: * Only do this on a fast tty.
1050: */
1051: if (p_tf && row > startrow && col == 0 &&
1052: LinePointers[screen_row - 1][Columns - 1 + Columns] ==
1053: attributes)
1054: {
1055: if (screen_cur_row != screen_row - 1 ||
1056: screen_cur_col != Columns)
1057: screen_char(LinePointers[screen_row - 1] + Columns - 1,
1058: screen_row - 1, (int)(Columns - 1));
1059: screen_char(LinePointers[screen_row - 1] + Columns - 1,
1060: screen_row - 1, (int)Columns);
1061: screen_start();
1062: }
1063:
1064: *screenp = c;
1065: *(screenp + Columns) = attributes;
1066: screen_char(screenp, screen_row, col);
1067: }
1068: #ifdef RIGHTLEFT
1069: if (wp->w_p_rl)
1070: {
1071: --screenp;
1072: --col;
1073: }
1074: else
1075: #endif
1076: {
1077: ++screenp;
1078: ++col;
1079: }
1080: ++vcol;
1081: /* stop before '$' of change command */
1082: if (wp == curwin && dollar_vcol && vcol >= (long)wp->w_virtcol)
1083: break;
1084: }
1085:
1086: stop_highlight();
1087: return (row);
1088: }
1089:
1090: /*
1091: * Called when p_dollar is set: display a '$' at the end of the changed text
1092: * Only works when cursor is in the line that changes.
1093: */
1094: void
1095: display_dollar(col)
1096: colnr_t col;
1097: {
1098: colnr_t save_col;
1099:
1100: if (RedrawingDisabled)
1101: return;
1102:
1103: cursor_off();
1104: save_col = curwin->w_cursor.col;
1105: curwin->w_cursor.col = col;
1106: curs_columns(FALSE);
1107: if (!curwin->w_p_wrap)
1108: curwin->w_col -= curwin->w_leftcol;
1109: if (curwin->w_col < Columns)
1110: {
1111: screen_msg((char_u *)"$", curwin->w_winpos + curwin->w_row,
1112: #ifdef RIGHTLEFT
1113: curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
1114: #endif
1115: curwin->w_col);
1116: dollar_vcol = curwin->w_virtcol;
1117: }
1118: curwin->w_cursor.col = save_col;
1119: }
1120:
1121: /*
1122: * Call this function before moving the cursor from the normal insert position
1123: * in insert mode.
1124: */
1125: void
1126: undisplay_dollar()
1127: {
1128: if (dollar_vcol)
1129: {
1130: dollar_vcol = 0;
1131: updateline();
1132: }
1133: }
1134:
1135: /*
1136: * output a single character directly to the screen
1137: * update NextScreen
1138: */
1139: void
1140: screen_outchar(c, row, col)
1141: int c;
1142: int row, col;
1143: {
1144: char_u buf[2];
1145:
1146: buf[0] = c;
1147: buf[1] = NUL;
1148: screen_msg(buf, row, col);
1149: }
1150:
1151: /*
1152: * put string '*text' on the screen at position 'row' and 'col'
1153: * update NextScreen
1154: * Note: only outputs within one row, message is truncated at screen boundary!
1155: * Note: if NextScreen, row and/or col is invalid, nothing is done.
1156: */
1157: void
1158: screen_msg(text, row, col)
1159: char_u *text;
1160: int row;
1161: int col;
1162: {
1163: char_u *screenp;
1164:
1165: if (NextScreen != NULL && row < Rows) /* safety check */
1166: {
1167: screenp = LinePointers[row] + col;
1168: while (*text && col < Columns)
1169: {
1170: if (*screenp != *text || *(screenp + Columns) != attributes)
1171: {
1172: *screenp = *text;
1173: *(screenp + Columns) = attributes;
1174: screen_char(screenp, row, col);
1175: }
1176: ++screenp;
1177: ++col;
1178: ++text;
1179: }
1180: }
1181: }
1182:
1183: /*
1184: * Reset cursor position. Use whenever cursor was moved because of outputting
1185: * something directly to the screen (shell commands) or a terminal control
1186: * code.
1187: */
1188: void
1189: screen_start()
1190: {
1191: screen_cur_row = screen_cur_col = 9999;
1192: }
1193:
1194: /*
1195: * set_highlight - set highlight depending on 'highlight' option and context.
1196: *
1197: * return FAIL if highlighting is not possible, OK otherwise
1198: */
1199: int
1200: set_highlight(context)
1201: int context;
1202: {
1203: int i;
1204: int mode;
1205: char_u *p;
1206:
1207: /*
1208: * Try to find the mode in the 'highlight' option.
1209: * If not found, try the default for the 'highlight' option.
1210: * If still not found, use 'r' (should not happen).
1211: */
1212: mode = 'r';
1213: for (i = 0; i < 2; ++i)
1214: {
1215: if (i)
1216: p = get_highlight_default();
1217: else
1218: p = p_hl;
1219: if (p == NULL)
1220: continue;
1221:
1222: while (*p)
1223: {
1224: if (*p == context) /* found what we are looking for */
1225: break;
1226: while (*p && *p != ',') /* skip to comma */
1227: ++p;
1228: p = skip_to_option_part(p); /* skip comma and spaces */
1229: }
1230: if (p[0] && p[1])
1231: {
1232: mode = p[1];
1233: break;
1234: }
1235: }
1236:
1237: switch (mode)
1238: {
1239: case 'b': highlight = T_MD; /* bold */
1240: unhighlight = T_ME;
1241: highlight_attr = CHAR_BOLD;
1242: break;
1243: case 's': highlight = T_SO; /* standout */
1244: unhighlight = T_SE;
1245: highlight_attr = CHAR_STDOUT;
1246: break;
1247: case 'n': highlight = NULL; /* no highlighting */
1248: unhighlight = NULL;
1249: highlight_attr = 0;
1250: break;
1251: case 'u': highlight = T_US; /* underline */
1252: unhighlight = T_UE;
1253: highlight_attr = CHAR_UNDERL;
1254: break;
1255: case 'i': highlight = T_CZH; /* italic */
1256: unhighlight = T_CZR;
1257: highlight_attr = CHAR_ITALIC;
1258: break;
1259: default: highlight = T_MR; /* reverse (invert) */
1260: unhighlight = T_ME;
1261: highlight_attr = CHAR_INVERT;
1262: break;
1263: }
1264: if (highlight == NULL || *highlight == NUL ||
1265: unhighlight == NULL || *unhighlight == NUL)
1266: {
1267: highlight = NULL;
1268: return FAIL;
1269: }
1270: return OK;
1271: }
1272:
1273: void
1274: start_highlight()
1275: {
1276: if (full_screen &&
1277: #ifdef WIN32
1278: termcap_active &&
1279: #endif
1280: highlight != NULL)
1281: {
1282: outstr(highlight);
1283: attributes = highlight_attr;
1284: }
1285: }
1286:
1287: void
1288: stop_highlight()
1289: {
1290: if (attributes)
1291: {
1292: outstr(unhighlight);
1293: attributes = 0;
1294: }
1295: }
1296:
1297: /*
1298: * variables used for one level depth of highlighting
1299: * Used for "-- More --" message.
1300: */
1301:
1302: static char_u *old_highlight = NULL;
1303: static char_u *old_unhighlight = NULL;
1304: static int old_highlight_attr = 0;
1305:
1306: void
1307: remember_highlight()
1308: {
1309: old_highlight = highlight;
1310: old_unhighlight = unhighlight;
1311: old_highlight_attr = highlight_attr;
1312: }
1313:
1314: void
1315: recover_old_highlight()
1316: {
1317: highlight = old_highlight;
1318: unhighlight = old_unhighlight;
1319: highlight_attr = old_highlight_attr;
1320: }
1321:
1322: /*
1323: * put character '*p' on the screen at position 'row' and 'col'
1324: */
1325: static void
1326: screen_char(p, row, col)
1327: char_u *p;
1328: int row;
1329: int col;
1330: {
1331: int c;
1332: int noinvcurs;
1333:
1334: /*
1335: * Outputting the last character on the screen may scrollup the screen.
1336: * Don't to it!
1337: */
1338: if (col == Columns - 1 && row == Rows - 1)
1339: return;
1340: if (screen_cur_col != col || screen_cur_row != row)
1341: {
1342: /* check if no cursor movement is allowed in standout mode */
1343: if (attributes && !p_wiv && *T_MS == NUL)
1344: noinvcurs = 7;
1345: else
1346: noinvcurs = 0;
1347:
1348: /*
1349: * If we're on the same row (which happens a lot!), try to
1350: * avoid a windgoto().
1351: * If we are only a few characters off, output the
1352: * characters. That is faster than cursor positioning.
1353: * This can't be used when switching between inverting and not
1354: * inverting.
1355: */
1356: if (screen_cur_row == row && screen_cur_col < col)
1357: {
1358: register int i;
1359:
1360: i = col - screen_cur_col;
1361: if (i <= 4 + noinvcurs)
1362: {
1363: /* stop at the first character that has different attributes
1364: * from the ones that are active */
1365: while (i && *(p - i + Columns) == attributes)
1366: {
1367: c = *(p - i--);
1368: outchar(c);
1369: }
1370: }
1371: if (i)
1372: {
1373: if (noinvcurs)
1374: stop_highlight();
1375:
1376: if (*T_CRI != NUL) /* use tgoto interface! jw */
1377: OUTSTR(tgoto((char *)T_CRI, 0, i));
1378: else
1379: windgoto(row, col);
1380:
1381: if (noinvcurs)
1382: start_highlight();
1383: }
1384: }
1385: /*
1386: * If the cursor is at the line above where we want to be, use CR LF,
1387: * this is quicker than windgoto().
1388: * Don't do this if the cursor went beyond the last column, the cursor
1389: * position is unknown then (some terminals wrap, some don't )
1390: */
1391: else if (screen_cur_row + 1 == row && col == 0 &&
1392: screen_cur_col < Columns)
1393: {
1394: if (noinvcurs)
1395: stop_highlight();
1396: outchar('\n');
1397: if (noinvcurs)
1398: start_highlight();
1399: }
1400: else
1401: {
1402: if (noinvcurs)
1403: stop_highlight();
1404: windgoto(row, col);
1405: if (noinvcurs)
1406: start_highlight();
1407: }
1408: screen_cur_row = row;
1409: screen_cur_col = col;
1410: }
1411:
1412: /*
1413: * For weird invert mechanism: output (un)highlight before every char
1414: * Lots of extra output, but works.
1415: */
1416: if (p_wiv)
1417: {
1418: if (attributes)
1419: outstr(highlight);
1420: else if (full_screen)
1421: outstr(unhighlight);
1422: }
1423: outchar(*p);
1424: screen_cur_col++;
1425: }
1426:
1427: /*
1428: * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
1429: * with character 'c1' in first column followed by 'c2' in the other columns.
1430: */
1431: void
1432: screen_fill(start_row, end_row, start_col, end_col, c1, c2)
1433: int start_row, end_row;
1434: int start_col, end_col;
1435: int c1, c2;
1436: {
1437: int row;
1438: int col;
1439: char_u *screenp;
1440: char_u *attrp;
1441: int did_delete;
1442: int c;
1443:
1444: if (end_row > Rows) /* safety check */
1445: end_row = Rows;
1446: if (end_col > Columns) /* safety check */
1447: end_col = Columns;
1448: if (NextScreen == NULL ||
1449: start_row >= end_row || start_col >= end_col) /* nothing to do */
1450: return;
1451:
1452: for (row = start_row; row < end_row; ++row)
1453: {
1454: /* try to use delete-line termcap code */
1455: did_delete = FALSE;
1456: if (attributes == 0 && c2 == ' ' && end_col == Columns && *T_CE != NUL
1457: #ifdef RIGHTLEFT
1458: && !rightleft
1459: #endif
1460: )
1461: {
1462: /*
1463: * check if we really need to clear something
1464: */
1465: col = start_col;
1466: screenp = LinePointers[row] + start_col;
1467: if (c1 != ' ') /* don't clear first char */
1468: {
1469: ++col;
1470: ++screenp;
1471: }
1472:
1473: /* skip blanks (used often, keep it fast!) */
1474: attrp = screenp + Columns;
1475: while (col < end_col && *screenp == ' ' && *attrp == 0)
1476: {
1477: ++col;
1478: ++screenp;
1479: ++attrp;
1480: }
1481: if (col < end_col) /* something to be cleared */
1482: {
1483: windgoto(row, col); /* clear rest of this screen line */
1484: outstr(T_CE);
1485: screen_start(); /* don't know where cursor is now */
1486: col = end_col - col;
1487: while (col--) /* clear chars in NextScreen */
1488: {
1489: *attrp++ = 0;
1490: *screenp++ = ' ';
1491: }
1492: }
1493: did_delete = TRUE; /* the chars are cleared now */
1494: }
1495:
1496: screenp = LinePointers[row] +
1497: #ifdef RIGHTLEFT
1498: (rightleft ? (int)Columns - 1 - start_col : start_col);
1499: #else
1500: start_col;
1501: #endif
1502: c = c1;
1503: for (col = start_col; col < end_col; ++col)
1504: {
1505: if (*screenp != c || *(screenp + Columns) != attributes)
1506: {
1507: *screenp = c;
1508: *(screenp + Columns) = attributes;
1509: if (!did_delete || c != ' ')
1510: screen_char(screenp, row,
1511: #ifdef RIGHTLEFT
1512: rightleft ? Columns - 1 - col :
1513: #endif
1514: col);
1515: }
1516: #ifdef RIGHTLEFT
1517: if (rightleft)
1518: --screenp;
1519: else
1520: #endif
1521: ++screenp;
1522: if (col == start_col)
1523: {
1524: if (did_delete)
1525: break;
1526: c = c2;
1527: }
1528: }
1529: if (row == Rows - 1) /* overwritten the command line */
1530: {
1531: redraw_cmdline = TRUE;
1532: if (c1 == ' ' && c2 == ' ')
1533: clear_cmdline = FALSE; /* command line has been cleared */
1534: }
1535: }
1536: }
1537:
1538: /*
1539: * recompute all w_botline's. Called after Rows changed.
1540: */
1541: void
1542: comp_Botline_all()
1543: {
1544: WIN *wp;
1545:
1546: for (wp = firstwin; wp; wp = wp->w_next)
1547: comp_Botline(wp);
1548: }
1549:
1550: /*
1551: * compute wp->w_botline. Can be called after wp->w_topline changed.
1552: */
1553: void
1554: comp_Botline(wp)
1555: WIN *wp;
1556: {
1557: comp_Botline_sub(wp, wp->w_topline, 0);
1558: }
1559:
1560: /*
1561: * Compute wp->w_botline, may have a start at the cursor position.
1562: * Code shared between comp_Botline() and cursupdate().
1563: */
1564: static void
1565: comp_Botline_sub(wp, lnum, done)
1566: WIN *wp;
1567: linenr_t lnum;
1568: int done;
1569: {
1570: int n;
1571:
1572: for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
1573: {
1574: n = plines_win(wp, lnum);
1575: if (done + n > wp->w_height)
1576: break;
1577: done += n;
1578: }
1579:
1580: /* wp->w_botline is the line that is just below the window */
1581: wp->w_botline = lnum;
1582:
1583: /* Also set wp->w_empty_rows, otherwise scroll_cursor_bot() won't work */
1584: if (done == 0)
1585: wp->w_empty_rows = 0; /* single line that doesn't fit */
1586: else
1587: wp->w_empty_rows = wp->w_height - done;
1588: }
1589:
1590: void
1591: screenalloc(clear)
1592: int clear;
1593: {
1594: register int new_row, old_row;
1595: WIN *wp;
1596: int outofmem = FALSE;
1597: int len;
1598: char_u *new_NextScreen;
1599: char_u **new_LinePointers;
1600:
1601: /*
1602: * Allocation of the screen buffers is done only when the size changes
1603: * and when Rows and Columns have been set and we are doing full screen
1604: * stuff.
1605: */
1606: if ((NextScreen != NULL && Rows == screen_Rows && Columns == screen_Columns)
1607: || Rows == 0 || Columns == 0 || !full_screen)
1608: return;
1609:
1610: comp_col(); /* recompute columns for shown command and ruler */
1611:
1612: /*
1613: * We're changing the size of the screen.
1614: * - Allocate new arrays for NextScreen.
1615: * - Move lines from the old arrays into the new arrays, clear extra
1616: * lines (unless the screen is going to be cleared).
1617: * - Free the old arrays.
1618: */
1619: for (wp = firstwin; wp; wp = wp->w_next)
1620: win_free_lsize(wp);
1621:
1622: new_NextScreen = (char_u *)malloc((size_t) (Rows * Columns * 2));
1623: new_LinePointers = (char_u **)malloc(sizeof(char_u *) * Rows);
1624:
1625: for (wp = firstwin; wp; wp = wp->w_next)
1626: {
1627: if (win_alloc_lsize(wp) == FAIL)
1628: {
1629: outofmem = TRUE;
1630: break;
1631: }
1632: }
1633:
1634: if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
1635: {
1636: do_outofmem_msg();
1637: vim_free(new_NextScreen);
1638: new_NextScreen = NULL;
1639: }
1640: else
1641: {
1642: for (new_row = 0; new_row < Rows; ++new_row)
1643: {
1644: new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
1645:
1646: /*
1647: * If the screen is not going to be cleared, copy as much as
1648: * possible from the old screen to the new one and clear the rest
1649: * (used when resizing the window at the "--more--" prompt or when
1650: * executing an external command, for the GUI).
1651: */
1652: if (!clear)
1653: {
1654: lineclear(new_LinePointers[new_row]);
1655: old_row = new_row + (screen_Rows - Rows);
1656: if (old_row >= 0)
1657: {
1658: if (screen_Columns < Columns)
1659: len = screen_Columns;
1660: else
1661: len = Columns;
1662: vim_memmove(new_LinePointers[new_row],
1663: LinePointers[old_row], (size_t)len);
1664: vim_memmove(new_LinePointers[new_row] + Columns,
1665: LinePointers[old_row] + screen_Columns, (size_t)len);
1666: }
1667: }
1668: }
1669: }
1670:
1671: vim_free(NextScreen);
1672: vim_free(LinePointers);
1673: NextScreen = new_NextScreen;
1674: LinePointers = new_LinePointers;
1675:
1676: must_redraw = CLEAR; /* need to clear the screen later */
1677: if (clear)
1678: screenclear2();
1679:
1680: #ifdef USE_GUI
1681: else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
1682: {
1683: gui_redraw_block(0, 0, Rows - 1, Columns - 1);
1684: /*
1685: * Adjust the position of the cursor, for when executing an external
1686: * command.
1687: */
1688: if (msg_row >= Rows) /* Rows got smaller */
1689: msg_row = Rows - 1; /* put cursor at last row */
1690: else if (Rows > screen_Rows) /* Rows got bigger */
1691: msg_row += Rows - screen_Rows; /* put cursor in same place */
1692: if (msg_col >= Columns) /* Columns got smaller */
1693: msg_col = Columns - 1; /* put cursor at last column */
1694: }
1695: #endif
1696:
1697: screen_Rows = Rows;
1698: screen_Columns = Columns;
1699: }
1700:
1701: void
1702: screenclear()
1703: {
1704: if (emsg_on_display)
1705: {
1706: mch_delay(1000L, TRUE);
1707: emsg_on_display = FALSE;
1708: }
1709: screenalloc(FALSE); /* allocate screen buffers if size changed */
1710: screenclear2(); /* clear the screen */
1711: }
1712:
1713: static void
1714: screenclear2()
1715: {
1716: int i;
1717:
1718: if (starting || NextScreen == NULL)
1719: return;
1720:
1721: outstr(T_CL); /* clear the display */
1722:
1723: /* blank out NextScreen */
1724: for (i = 0; i < Rows; ++i)
1725: lineclear(LinePointers[i]);
1726:
1727: screen_cleared = TRUE; /* can use contents of NextScreen now */
1728:
1729: win_rest_invalid(firstwin);
1730: clear_cmdline = FALSE;
1731: redraw_cmdline = TRUE;
1732: if (must_redraw == CLEAR) /* no need to clear again */
1733: must_redraw = NOT_VALID;
1734: compute_cmdrow();
1735: msg_pos((int)Rows - 1, 0); /* put cursor on last line for messages */
1736: screen_start(); /* don't know where cursor is now */
1737: msg_scrolled = 0; /* can't scroll back */
1738: msg_didany = FALSE;
1739: msg_didout = FALSE;
1740: }
1741:
1742: /*
1743: * Clear one line in NextScreen.
1744: */
1745: static void
1746: lineclear(p)
1747: char_u *p;
1748: {
1749: (void)vim_memset(p, ' ', (size_t)Columns);
1750: (void)vim_memset(p + Columns, 0, (size_t)Columns);
1751: }
1752:
1753: /*
1754: * check cursor for a valid lnum
1755: */
1756: void
1757: check_cursor()
1758: {
1759: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1760: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
1761: if (curwin->w_cursor.lnum <= 0)
1762: curwin->w_cursor.lnum = 1;
1763: }
1764:
1765: void
1766: cursupdate()
1767: {
1768: linenr_t lnum;
1769: long line_count;
1770: int sline;
1771: int done;
1772: int temp;
1773:
1774: if (!screen_valid(TRUE))
1775: return;
1776:
1777: /*
1778: * Make sure the cursor is on a valid line number
1779: */
1780: check_cursor();
1781:
1782: /*
1783: * If the buffer is empty, always set topline to 1.
1784: */
1785: if (bufempty()) /* special case - file is empty */
1786: {
1787: curwin->w_topline = 1;
1788: curwin->w_cursor.lnum = 1;
1789: curwin->w_cursor.col = 0;
1790: curwin->w_lsize[0] = 0;
1791: if (curwin->w_lsize_valid == 0) /* don't know about screen contents */
1792: updateScreen(NOT_VALID);
1793: curwin->w_lsize_valid = 1;
1794: }
1795:
1796: /*
1797: * If the cursor is above the top of the window, scroll the window to put
1798: * it at the top of the window.
1799: * If we weren't very close to begin with, we scroll to put the cursor in
1800: * the middle of the window.
1801: */
1802: else if (curwin->w_cursor.lnum < curwin->w_topline + p_so &&
1803: curwin->w_topline > 1)
1804: {
1805: temp = curwin->w_height / 2 - 1;
1806: if (temp < 2)
1807: temp = 2;
1808: /* not very close, put cursor halfway screen */
1809: if (curwin->w_topline + p_so - curwin->w_cursor.lnum >= temp)
1810: scroll_cursor_halfway(FALSE);
1811: else
1812: scroll_cursor_top((int)p_sj, FALSE);
1813: updateScreen(VALID);
1814: }
1815:
1816: /*
1817: * If the cursor is below the bottom of the window, scroll the window
1818: * to put the cursor on the window. If the cursor is less than a
1819: * windowheight down compute the number of lines at the top which have
1820: * the same or more rows than the rows of the lines below the bottom.
1821: * Note: After curwin->w_botline was computed lines may have been
1822: * added or deleted, it may be greater than ml_line_count.
1823: */
1824: else if ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so &&
1825: curwin->w_botline <= curbuf->b_ml.ml_line_count)
1826: {
1827: line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so;
1828: if (line_count <= curwin->w_height + 1)
1829: scroll_cursor_bot((int)p_sj, FALSE);
1830: else
1831: scroll_cursor_halfway(FALSE);
1832: updateScreen(VALID);
1833: }
1834:
1835: /*
1836: * If the window contents is unknown, need to update the screen.
1837: */
1838: else if (curwin->w_lsize_valid == 0)
1839: updateScreen(NOT_VALID);
1840:
1841: /*
1842: * Figure out the row number of the cursor line.
1843: * This is used often, keep it fast!
1844: */
1845: curwin->w_row = sline = 0;
1846: /* curwin->w_lsize[] invalid */
1847: if (RedrawingDisabled || curwin->w_lsize_valid == 0)
1848: {
1849: done = 0;
1850: for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
1851: done += plines(lnum);
1852: curwin->w_row = done;
1853:
1854: /*
1855: * Also need to compute w_botline and w_empty_rows, because
1856: * updateScreen() will not have done that.
1857: */
1858: comp_Botline_sub(curwin, lnum, done);
1859: }
1860: else
1861: {
1862: for (done = curwin->w_cursor.lnum - curwin->w_topline; done > 0; --done)
1863: curwin->w_row += curwin->w_lsize[sline++];
1864: }
1865:
1866: curwin->w_cline_row = curwin->w_row;
1867: curwin->w_col = curwin->w_virtcol = 0;
1868: if (!RedrawingDisabled && sline > curwin->w_lsize_valid)
1869: /* Should only happen with a line that is too */
1870: /* long to fit on the last screen line. */
1871: curwin->w_cline_height = 0;
1872: else
1873: {
1874: /* curwin->w_lsize[] invalid */
1875: if (RedrawingDisabled || curwin->w_lsize_valid == 0)
1876: curwin->w_cline_height = plines(curwin->w_cursor.lnum);
1877: else
1878: curwin->w_cline_height = curwin->w_lsize[sline];
1879: /* compute curwin->w_virtcol and curwin->w_col */
1880: curs_columns(!RedrawingDisabled);
1881: if (must_redraw)
1882: updateScreen(must_redraw);
1883: }
1884:
1885: if (curwin->w_set_curswant)
1886: {
1887: curwin->w_curswant = curwin->w_virtcol;
1888: curwin->w_set_curswant = FALSE;
1889: }
1890: }
1891:
1892: /*
1893: * Recompute topline to put the cursor at the top of the window.
1894: * Scroll at least "min_scroll" lines.
1895: * If "always" is TRUE, always set topline (for "zt").
1896: */
1897: void
1898: scroll_cursor_top(min_scroll, always)
1899: int min_scroll;
1900: int always;
1901: {
1902: int scrolled = 0;
1903: int extra = 0;
1904: int used;
1905: int i;
1906: int sline; /* screen line for cursor */
1907:
1908: /*
1909: * Decrease topline until:
1910: * - it has become 1
1911: * - (part of) the cursor line is moved off the screen or
1912: * - moved at least 'scrolljump' lines and
1913: * - at least 'scrolloff' lines above and below the cursor
1914: */
1915: used = plines(curwin->w_cursor.lnum);
1916: for (sline = 1; sline < curwin->w_cursor.lnum; ++sline)
1917: {
1918: i = plines(curwin->w_cursor.lnum - sline);
1919: used += i;
1920: extra += i;
1921: if (extra <= p_so &&
1922: curwin->w_cursor.lnum + sline < curbuf->b_ml.ml_line_count)
1923: used += plines(curwin->w_cursor.lnum + sline);
1924: if (used > curwin->w_height)
1925: break;
1926: if (curwin->w_cursor.lnum - sline < curwin->w_topline)
1927: scrolled += i;
1928:
1929: /*
1930: * If scrolling is needed, scroll at least 'sj' lines.
1931: */
1932: if ((curwin->w_cursor.lnum - (sline - 1) >= curwin->w_topline ||
1933: scrolled >= min_scroll) && extra > p_so)
1934: break;
1935: }
1936:
1937: /*
1938: * If we don't have enough space, put cursor in the middle.
1939: * This makes sure we get the same position when using "k" and "j"
1940: * in a small window.
1941: */
1942: if (used > curwin->w_height)
1943: scroll_cursor_halfway(FALSE);
1944: else
1945: {
1946: /*
1947: * If "always" is FALSE, only adjust topline to a lower value, higher
1948: * value may happen with wrapping lines
1949: */
1950: if (curwin->w_cursor.lnum - (sline - 1) < curwin->w_topline || always)
1951: curwin->w_topline = curwin->w_cursor.lnum - (sline - 1);
1952: if (curwin->w_topline > curwin->w_cursor.lnum)
1953: curwin->w_topline = curwin->w_cursor.lnum;
1954: }
1955: }
1956:
1957: /*
1958: * Recompute topline to put the cursor at the bottom of the window.
1959: * Scroll at least "min_scroll" lines.
1960: * If "set_topline" is TRUE, set topline and botline first (for "zb").
1961: * This is messy stuff!!!
1962: */
1963: void
1964: scroll_cursor_bot(min_scroll, set_topline)
1965: int min_scroll;
1966: int set_topline;
1967: {
1968: int used;
1969: int scrolled = 0;
1970: int extra = 0;
1971: int sline; /* screen line for cursor from bottom */
1972: int i;
1973: linenr_t lnum;
1974: linenr_t line_count;
1975: linenr_t old_topline = curwin->w_topline;
1976: linenr_t old_botline = curwin->w_botline;
1977: int old_empty_rows = curwin->w_empty_rows;
1978: linenr_t cln; /* Cursor Line Number */
1979:
1980: cln = curwin->w_cursor.lnum;
1981: if (set_topline)
1982: {
1983: used = 0;
1984: curwin->w_botline = cln + 1;
1985: for (curwin->w_topline = curwin->w_botline;
1986: curwin->w_topline != 1;
1987: --curwin->w_topline)
1988: {
1989: i = plines(curwin->w_topline - 1);
1990: if (used + i > curwin->w_height)
1991: break;
1992: used += i;
1993: }
1994: curwin->w_empty_rows = curwin->w_height - used;
1995: }
1996:
1997: used = plines(cln);
1998: if (cln >= curwin->w_botline)
1999: {
2000: scrolled = used;
2001: if (cln == curwin->w_botline)
2002: scrolled -= curwin->w_empty_rows;
2003: }
2004:
2005: /*
2006: * Stop counting lines to scroll when
2007: * - hitting start of the file
2008: * - scrolled nothing or at least 'sj' lines
2009: * - at least 'so' lines below the cursor
2010: * - lines between botline and cursor have been counted
2011: */
2012: for (sline = 1; sline < cln; ++sline)
2013: {
2014: if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= p_so) ||
2015: cln + sline > curbuf->b_ml.ml_line_count) &&
2016: cln - sline < curwin->w_botline)
2017: break;
2018: i = plines(cln - sline);
2019: used += i;
2020: if (used > curwin->w_height)
2021: break;
2022: if (cln - sline >= curwin->w_botline)
2023: {
2024: scrolled += i;
2025: if (cln - sline == curwin->w_botline)
2026: scrolled -= curwin->w_empty_rows;
2027: }
2028: if (cln + sline <= curbuf->b_ml.ml_line_count)
2029: {
2030: i = plines(cln + sline);
2031: used += i;
2032: if (used > curwin->w_height)
2033: break;
2034: if (extra < p_so || scrolled < min_scroll)
2035: {
2036: extra += i;
2037: if (cln + sline >= curwin->w_botline)
2038: {
2039: scrolled += i;
2040: if (cln + sline == curwin->w_botline)
2041: scrolled -= curwin->w_empty_rows;
2042: }
2043: }
2044: }
2045: }
2046: /* curwin->w_empty_rows is larger, no need to scroll */
2047: if (scrolled <= 0)
2048: line_count = 0;
2049: /* more than a screenfull, don't scroll but redraw */
2050: else if (used > curwin->w_height)
2051: line_count = used;
2052: /* scroll minimal number of lines */
2053: else
2054: {
2055: for (i = 0, lnum = curwin->w_topline;
2056: i < scrolled && lnum < curwin->w_botline; ++lnum)
2057: i += plines(lnum);
2058: if (i >= scrolled) /* it's possible to scroll */
2059: line_count = lnum - curwin->w_topline;
2060: else /* below curwin->w_botline, don't scroll */
2061: line_count = 9999;
2062: }
2063:
2064: /*
2065: * Scroll up if the cursor is off the bottom of the screen a bit.
2066: * Otherwise put it at 1/2 of the screen.
2067: */
2068: if (line_count >= curwin->w_height && line_count > min_scroll)
2069: scroll_cursor_halfway(FALSE);
2070: else
2071: scrollup(line_count);
2072:
2073: /*
2074: * If topline didn't change we need to restore w_botline and w_empty_rows
2075: * (we changed them).
2076: * If topline did change, updateScreen() will set botline.
2077: */
2078: if (curwin->w_topline == old_topline && set_topline)
2079: {
2080: curwin->w_botline = old_botline;
2081: curwin->w_empty_rows = old_empty_rows;
2082: }
2083: }
2084:
2085: /*
2086: * Recompute topline to put the cursor halfway the window
2087: * If "atend" is TRUE, also put it halfway at the end of the file.
2088: */
2089: void
2090: scroll_cursor_halfway(atend)
2091: int atend;
2092: {
2093: int above = 0;
2094: linenr_t topline;
2095: int below = 0;
2096: linenr_t botline;
2097: int used;
2098: int i;
2099: linenr_t cln; /* Cursor Line Number */
2100:
2101: topline = botline = cln = curwin->w_cursor.lnum;
2102: used = plines(cln);
2103: while (topline > 1)
2104: {
2105: if (below <= above) /* add a line below the cursor */
2106: {
2107: if (botline + 1 <= curbuf->b_ml.ml_line_count)
2108: {
2109: i = plines(botline + 1);
2110: used += i;
2111: if (used > curwin->w_height)
2112: break;
2113: below += i;
2114: ++botline;
2115: }
2116: else
2117: {
2118: ++below; /* count a "~" line */
2119: if (atend)
2120: ++used;
2121: }
2122: }
2123:
2124: if (below > above) /* add a line above the cursor */
2125: {
2126: i = plines(topline - 1);
2127: used += i;
2128: if (used > curwin->w_height)
2129: break;
2130: above += i;
2131: --topline;
2132: }
2133: }
2134: curwin->w_topline = topline;
2135: }
2136:
2137: /*
2138: * Correct the cursor position so that it is in a part of the screen at least
2139: * 'so' lines from the top and bottom, if possible.
2140: * If not possible, put it at the same position as scroll_cursor_halfway().
2141: * When called topline and botline must be valid!
2142: */
2143: void
2144: cursor_correct()
2145: {
2146: int above = 0; /* screen lines above topline */
2147: linenr_t topline;
2148: int below = 0; /* screen lines below botline */
2149: linenr_t botline;
2150: int above_wanted, below_wanted;
2151: linenr_t cln; /* Cursor Line Number */
2152: int max_off;
2153:
2154: /*
2155: * How many lines we would like to have above/below the cursor depends on
2156: * whether the first/last line of the file is on screen.
2157: */
2158: above_wanted = p_so;
2159: below_wanted = p_so;
2160: if (curwin->w_topline == 1)
2161: {
2162: above_wanted = 0;
2163: max_off = curwin->w_height / 2;
2164: if (below_wanted > max_off)
2165: below_wanted = max_off;
2166: }
2167: if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1)
2168: {
2169: below_wanted = 0;
2170: max_off = (curwin->w_height - 1) / 2;
2171: if (above_wanted > max_off)
2172: above_wanted = max_off;
2173: }
2174:
2175: /*
2176: * If there are sufficient file-lines above and below the cursor, we can
2177: * return now.
2178: */
2179: cln = curwin->w_cursor.lnum;
2180: if (cln >= curwin->w_topline + above_wanted &&
2181: cln < curwin->w_botline - below_wanted)
2182: return;
2183:
2184: /*
2185: * Narrow down the area where the cursor can be put by taking lines from
2186: * the top and the bottom until:
2187: * - the desired context lines are found
2188: * - the lines from the top is past the lines from the bottom
2189: */
2190: topline = curwin->w_topline;
2191: botline = curwin->w_botline - 1;
2192: while ((above < above_wanted || below < below_wanted) && topline < botline)
2193: {
2194: if (below < below_wanted && (below <= above || above >= above_wanted))
2195: {
2196: below += plines(botline);
2197: --botline;
2198: }
2199: if (above < above_wanted && (above < below || below >= below_wanted))
2200: {
2201: above += plines(topline);
2202: ++topline;
2203: }
2204: }
2205: if (topline == botline || botline == 0)
2206: curwin->w_cursor.lnum = topline;
2207: else if (topline > botline)
2208: curwin->w_cursor.lnum = botline;
2209: else
2210: {
2211: if (cln < topline && curwin->w_topline > 1)
2212: curwin->w_cursor.lnum = topline;
2213: if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
2214: curwin->w_cursor.lnum = botline;
2215: }
2216: }
2217:
2218: /*
2219: * Compute curwin->w_row.
2220: * Can be called when topline and botline have not been updated.
2221: * return OK when cursor is in the window, FAIL when it isn't.
2222: */
2223: int
2224: curs_rows()
2225: {
2226: linenr_t lnum;
2227: int i;
2228:
2229: if (curwin->w_cursor.lnum < curwin->w_topline ||
2230: curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count ||
2231: curwin->w_cursor.lnum >= curwin->w_botline)
2232: return FAIL;
2233:
2234: curwin->w_row = i = 0;
2235: for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
2236: if (RedrawingDisabled) /* curwin->w_lsize[] invalid */
2237: curwin->w_row += plines(lnum);
2238: else
2239: curwin->w_row += curwin->w_lsize[i++];
2240: return OK;
2241: }
2242:
2243: /*
2244: * compute curwin->w_col and curwin->w_virtcol
2245: */
2246: void
2247: curs_columns(scroll)
2248: int scroll; /* when TRUE, may scroll horizontally */
2249: {
2250: int diff;
2251: int extra;
2252: int new_leftcol;
2253: colnr_t startcol;
2254: colnr_t endcol;
2255:
2256: getvcol(curwin, &curwin->w_cursor,
2257: &startcol, &(curwin->w_virtcol), &endcol);
2258:
2259: /* remove '$' from change command when cursor moves onto it */
2260: if (startcol > dollar_vcol)
2261: dollar_vcol = 0;
2262:
2263: curwin->w_col = curwin->w_virtcol;
2264: if (curwin->w_p_nu)
2265: {
2266: curwin->w_col += 8;
2267: endcol += 8;
2268: }
2269:
2270: curwin->w_row = curwin->w_cline_row;
2271: if (curwin->w_p_wrap) /* long line wrapping, adjust curwin->w_row */
2272: {
2273: while (curwin->w_col >= Columns)
2274: {
2275: curwin->w_col -= Columns;
2276: curwin->w_row++;
2277: }
2278: }
2279: else if (scroll) /* no line wrapping, compute curwin->w_leftcol if
2280: * scrolling is on. If scrolling is off,
2281: * curwin->w_leftcol is assumed to be 0 */
2282: {
2283: /* If Cursor is left of the screen, scroll rightwards */
2284: /* If Cursor is right of the screen, scroll leftwards */
2285: if ((extra = (int)startcol - (int)curwin->w_leftcol) < 0 ||
2286: (extra = (int)endcol - (int)(curwin->w_leftcol + Columns) + 1) > 0)
2287: {
2288: if (extra < 0)
2289: diff = -extra;
2290: else
2291: diff = extra;
2292:
2293: /* far off, put cursor in middle of window */
2294: if (p_ss == 0 || diff >= Columns / 2)
2295: new_leftcol = curwin->w_col - Columns / 2;
2296: else
2297: {
2298: if (diff < p_ss)
2299: diff = p_ss;
2300: if (extra < 0)
2301: new_leftcol = curwin->w_leftcol - diff;
2302: else
2303: new_leftcol = curwin->w_leftcol + diff;
2304: }
2305: if (new_leftcol < 0)
2306: curwin->w_leftcol = 0;
2307: else
2308: curwin->w_leftcol = new_leftcol;
2309: /* screen has to be redrawn with new curwin->w_leftcol */
2310: redraw_later(NOT_VALID);
2311: }
2312: curwin->w_col -= curwin->w_leftcol;
2313: }
2314: /* Cursor past end of screen */
2315: /* happens with line that does not fit on screen */
2316: if (curwin->w_row > curwin->w_height - 1)
2317: curwin->w_row = curwin->w_height - 1;
2318: }
2319:
2320: void
2321: scrolldown(line_count)
2322: long line_count;
2323: {
2324: register long done = 0; /* total # of physical lines done */
2325:
2326: /* Scroll up 'line_count' lines. */
2327: while (line_count--)
2328: {
2329: if (curwin->w_topline == 1)
2330: break;
2331: done += plines(--curwin->w_topline);
2332: }
2333: /*
2334: * Compute the row number of the last row of the cursor line
2335: * and move it onto the screen.
2336: */
2337: curwin->w_row += done;
2338: if (curwin->w_p_wrap)
2339: curwin->w_row += plines(curwin->w_cursor.lnum) -
2340: 1 - curwin->w_virtcol / Columns;
2341: while (curwin->w_row >= curwin->w_height && curwin->w_cursor.lnum > 1)
2342: curwin->w_row -= plines(curwin->w_cursor.lnum--);
2343: comp_Botline(curwin);
2344: }
2345:
2346: void
2347: scrollup(line_count)
2348: long line_count;
2349: {
2350: curwin->w_topline += line_count;
2351: if (curwin->w_topline > curbuf->b_ml.ml_line_count)
2352: curwin->w_topline = curbuf->b_ml.ml_line_count;
2353: if (curwin->w_cursor.lnum < curwin->w_topline)
2354: curwin->w_cursor.lnum = curwin->w_topline;
2355: comp_Botline(curwin);
2356: }
2357:
2358: /*
2359: * Scroll the screen one line down, but don't do it if it would move the
2360: * cursor off the screen.
2361: */
2362: void
2363: scrolldown_clamp()
2364: {
2365: int end_row;
2366:
2367: if (curwin->w_topline == 1)
2368: return;
2369:
2370: /*
2371: * Compute the row number of the last row of the cursor line
2372: * and make sure it doesn't go off the screen. Make sure the cursor
2373: * doesn't go past 'scrolloff' lines from the screen end.
2374: */
2375: end_row = curwin->w_row + plines(curwin->w_topline - 1);
2376: if (curwin->w_p_wrap)
2377: end_row += plines(curwin->w_cursor.lnum) - 1 -
2378: curwin->w_virtcol / Columns;
2379: if (end_row < curwin->w_height - p_so)
2380: --curwin->w_topline;
2381: }
2382:
2383: /*
2384: * Scroll the screen one line up, but don't do it if it would move the cursor
2385: * off the screen.
2386: */
2387: void
2388: scrollup_clamp()
2389: {
2390: int start_row;
2391:
2392: if (curwin->w_topline == curbuf->b_ml.ml_line_count)
2393: return;
2394:
2395: /*
2396: * Compute the row number of the first row of the cursor line
2397: * and make sure it doesn't go off the screen. Make sure the cursor
2398: * doesn't go before 'scrolloff' lines from the screen start.
2399: */
2400: start_row = curwin->w_row - plines(curwin->w_topline);
2401: if (curwin->w_p_wrap)
2402: start_row -= curwin->w_virtcol / Columns;
2403: if (start_row >= p_so)
2404: ++curwin->w_topline;
2405: }
2406:
2407: /*
2408: * insert 'line_count' lines at 'row' in window 'wp'
2409: * if 'invalid' is TRUE the wp->w_lsize_lnum[] is invalidated.
2410: * if 'mayclear' is TRUE the screen will be cleared if it is faster than
2411: * scrolling.
2412: * Returns FAIL if the lines are not inserted, OK for success.
2413: */
2414: int
2415: win_ins_lines(wp, row, line_count, invalid, mayclear)
2416: WIN *wp;
2417: int row;
2418: int line_count;
2419: int invalid;
2420: int mayclear;
2421: {
2422: int did_delete;
2423: int nextrow;
2424: int lastrow;
2425: int retval;
2426:
2427: if (invalid)
2428: wp->w_lsize_valid = 0;
2429:
2430: if (RedrawingDisabled || line_count <= 0 || wp->w_height < 5)
2431: return FAIL;
2432:
2433: if (line_count > wp->w_height - row)
2434: line_count = wp->w_height - row;
2435:
2436: if (mayclear && Rows - line_count < 5) /* only a few lines left: redraw is faster */
2437: {
2438: screenclear(); /* will set wp->w_lsize_valid to 0 */
2439: return FAIL;
2440: }
2441:
2442: /*
2443: * Delete all remaining lines
2444: */
2445: if (row + line_count >= wp->w_height)
2446: {
2447: screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
2448: 0, (int)Columns, ' ', ' ');
2449: return OK;
2450: }
2451:
2452: /*
2453: * when scrolling, the message on the command line should be cleared,
2454: * otherwise it will stay there forever.
2455: */
2456: clear_cmdline = TRUE;
2457:
2458: /*
2459: * if the terminal can set a scroll region, use that
2460: */
2461: if (scroll_region)
2462: {
2463: scroll_region_set(wp, row);
2464: retval = screen_ins_lines(wp->w_winpos + row, 0, line_count,
2465: wp->w_height - row);
2466: scroll_region_reset();
2467: return retval;
2468: }
2469:
2470: if (wp->w_next && p_tf) /* don't delete/insert on fast terminal */
2471: return FAIL;
2472:
2473: /*
2474: * If there is a next window or a status line, we first try to delete the
2475: * lines at the bottom to avoid messing what is after the window.
2476: * If this fails and there are following windows, don't do anything to avoid
2477: * messing up those windows, better just redraw.
2478: */
2479: did_delete = FALSE;
2480: if (wp->w_next || wp->w_status_height)
2481: {
2482: if (screen_del_lines(0, wp->w_winpos + wp->w_height - line_count,
2483: line_count, (int)Rows, FALSE) == OK)
2484: did_delete = TRUE;
2485: else if (wp->w_next)
2486: return FAIL;
2487: }
2488: /*
2489: * if no lines deleted, blank the lines that will end up below the window
2490: */
2491: if (!did_delete)
2492: {
2493: wp->w_redr_status = TRUE;
2494: redraw_cmdline = TRUE;
2495: nextrow = wp->w_winpos + wp->w_height + wp->w_status_height;
2496: lastrow = nextrow + line_count;
2497: if (lastrow > Rows)
2498: lastrow = Rows;
2499: screen_fill(nextrow - line_count, lastrow - line_count,
2500: 0, (int)Columns, ' ', ' ');
2501: }
2502:
2503: if (screen_ins_lines(0, wp->w_winpos + row, line_count, (int)Rows) == FAIL)
2504: {
2505: /* deletion will have messed up other windows */
2506: if (did_delete)
2507: {
2508: wp->w_redr_status = TRUE;
2509: win_rest_invalid(wp->w_next);
2510: }
2511: return FAIL;
2512: }
2513:
2514: return OK;
2515: }
2516:
2517: /*
2518: * delete 'line_count' lines at 'row' in window 'wp'
2519: * If 'invalid' is TRUE curwin->w_lsize_lnum[] is invalidated.
2520: * If 'mayclear' is TRUE the screen will be cleared if it is faster than
2521: * scrolling
2522: * Return OK for success, FAIL if the lines are not deleted.
2523: */
2524: int
2525: win_del_lines(wp, row, line_count, invalid, mayclear)
2526: WIN *wp;
2527: int row;
2528: int line_count;
2529: int invalid;
2530: int mayclear;
2531: {
2532: int retval;
2533:
2534: if (invalid)
2535: wp->w_lsize_valid = 0;
2536:
2537: if (RedrawingDisabled || line_count <= 0)
2538: return FAIL;
2539:
2540: if (line_count > wp->w_height - row)
2541: line_count = wp->w_height - row;
2542:
2543: /* only a few lines left: redraw is faster */
2544: if (mayclear && Rows - line_count < 5)
2545: {
2546: screenclear(); /* will set wp->w_lsize_valid to 0 */
2547: return FAIL;
2548: }
2549:
2550: /*
2551: * Delete all remaining lines
2552: */
2553: if (row + line_count >= wp->w_height)
2554: {
2555: screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
2556: 0, (int)Columns, ' ', ' ');
2557: return OK;
2558: }
2559:
2560: /*
2561: * when scrolling, the message on the command line should be cleared,
2562: * otherwise it will stay there forever.
2563: */
2564: clear_cmdline = TRUE;
2565:
2566: /*
2567: * if the terminal can set a scroll region, use that
2568: */
2569: if (scroll_region)
2570: {
2571: scroll_region_set(wp, row);
2572: retval = screen_del_lines(wp->w_winpos + row, 0, line_count,
2573: wp->w_height - row, FALSE);
2574: scroll_region_reset();
2575: return retval;
2576: }
2577:
2578: if (wp->w_next && p_tf) /* don't delete/insert on fast terminal */
2579: return FAIL;
2580:
2581: if (screen_del_lines(0, wp->w_winpos + row, line_count,
2582: (int)Rows, FALSE) == FAIL)
2583: return FAIL;
2584:
2585: /*
2586: * If there are windows or status lines below, try to put them at the
2587: * correct place. If we can't do that, they have to be redrawn.
2588: */
2589: if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
2590: {
2591: if (screen_ins_lines(0, wp->w_winpos + wp->w_height - line_count,
2592: line_count, (int)Rows) == FAIL)
2593: {
2594: wp->w_redr_status = TRUE;
2595: win_rest_invalid(wp->w_next);
2596: }
2597: }
2598: /*
2599: * If this is the last window and there is no status line, redraw the
2600: * command line later.
2601: */
2602: else
2603: redraw_cmdline = TRUE;
2604: return OK;
2605: }
2606:
2607: /*
2608: * window 'wp' and everything after it is messed up, mark it for redraw
2609: */
2610: void
2611: win_rest_invalid(wp)
2612: WIN *wp;
2613: {
2614: while (wp)
2615: {
2616: wp->w_lsize_valid = 0;
2617: wp->w_redr_type = NOT_VALID;
2618: wp->w_redr_status = TRUE;
2619: wp = wp->w_next;
2620: }
2621: redraw_cmdline = TRUE;
2622: }
2623:
2624: /*
2625: * The rest of the routines in this file perform screen manipulations. The
2626: * given operation is performed physically on the screen. The corresponding
2627: * change is also made to the internal screen image. In this way, the editor
2628: * anticipates the effect of editing changes on the appearance of the screen.
2629: * That way, when we call screenupdate a complete redraw isn't usually
2630: * necessary. Another advantage is that we can keep adding code to anticipate
2631: * screen changes, and in the meantime, everything still works.
2632: */
2633:
2634: /*
2635: * types for inserting or deleting lines
2636: */
2637: #define USE_T_CAL 1
2638: #define USE_T_CDL 2
2639: #define USE_T_AL 3
2640: #define USE_T_CE 4
2641: #define USE_T_DL 5
2642: #define USE_T_SR 6
2643: #define USE_NL 7
2644: #define USE_T_CD 8
2645:
2646: /*
2647: * insert lines on the screen and update NextScreen
2648: * 'end' is the line after the scrolled part. Normally it is Rows.
2649: * When scrolling region used 'off' is the offset from the top for the region.
2650: * 'row' and 'end' are relative to the start of the region.
2651: *
2652: * return FAIL for failure, OK for success.
2653: */
2654: static int
2655: screen_ins_lines(off, row, line_count, end)
2656: int off;
2657: int row;
2658: int line_count;
2659: int end;
2660: {
2661: int i;
2662: int j;
2663: char_u *temp;
2664: int cursor_row;
2665: int type;
2666: int result_empty;
2667:
2668: /*
2669: * FAIL if
2670: * - there is no valid screen
2671: * - the screen has to be redrawn completely
2672: * - the line count is less than one
2673: * - the line count is more than 'ttyscroll'
2674: */
2675: if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
2676: return FAIL;
2677:
2678: /*
2679: * There are seven ways to insert lines:
2680: * 1. Use T_CD (clear to end of display) if it exists and the result of
2681: * the insert is just empty lines
2682: * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
2683: * present or line_count > 1. It looks better if we do all the inserts
2684: * at once.
2685: * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
2686: * insert is just empty lines and T_CE is not present or line_count >
2687: * 1.
2688: * 4. Use T_AL (insert line) if it exists.
2689: * 5. Use T_CE (erase line) if it exists and the result of the insert is
2690: * just empty lines.
2691: * 6. Use T_DL (delete line) if it exists and the result of the insert is
2692: * just empty lines.
2693: * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
2694: * the 'da' flag is not set or we have clear line capability.
2695: *
2696: * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
2697: * the scrollbar for the window. It does have insert line, use that if it
2698: * exists.
2699: */
2700: result_empty = (row + line_count >= end);
2701: if (*T_CD != NUL && result_empty)
2702: type = USE_T_CD;
2703: else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
2704: type = USE_T_CAL;
2705: else if (*T_CDL != NUL && result_empty && (line_count > 1 || *T_CE == NUL))
2706: type = USE_T_CDL;
2707: else if (*T_AL != NUL)
2708: type = USE_T_AL;
2709: else if (*T_CE != NUL && result_empty)
2710: type = USE_T_CE;
2711: else if (*T_DL != NUL && result_empty)
2712: type = USE_T_DL;
2713: else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || *T_CE))
2714: type = USE_T_SR;
2715: else
2716: return FAIL;
2717:
2718: /*
2719: * For clearing the lines screen_del_lines is used. This will also take
2720: * care of t_db if necessary.
2721: */
2722: if (type == USE_T_CD || type == USE_T_CDL ||
2723: type == USE_T_CE || type == USE_T_DL)
2724: return screen_del_lines(off, row, line_count, end, FALSE);
2725:
2726: /*
2727: * If text is retained below the screen, first clear or delete as many
2728: * lines at the bottom of the window as are about to be inserted so that
2729: * the deleted lines won't later surface during a screen_del_lines.
2730: */
2731: if (*T_DB)
2732: screen_del_lines(off, end - line_count, line_count, end, FALSE);
2733:
2734: if (*T_CSC != NUL) /* cursor relative to region */
2735: cursor_row = row;
2736: else
2737: cursor_row = row + off;
2738:
2739: /*
2740: * Shift LinePointers line_count down to reflect the inserted lines.
2741: * Clear the inserted lines in NextScreen.
2742: */
2743: row += off;
2744: end += off;
2745: for (i = 0; i < line_count; ++i)
2746: {
2747: j = end - 1 - i;
2748: temp = LinePointers[j];
2749: while ((j -= line_count) >= row)
2750: LinePointers[j + line_count] = LinePointers[j];
2751: LinePointers[j + line_count] = temp;
2752: lineclear(temp);
2753: }
2754:
2755: windgoto(cursor_row, 0);
2756: if (type == USE_T_CAL)
2757: {
2758: OUTSTR(tgoto((char *)T_CAL, 0, line_count));
2759: screen_start(); /* don't know where cursor is now */
2760: }
2761: else
2762: {
2763: for (i = 0; i < line_count; i++)
2764: {
2765: if (type == USE_T_AL)
2766: {
2767: if (i && cursor_row != 0)
2768: windgoto(cursor_row, 0);
2769: outstr(T_AL);
2770: }
2771: else /* type == USE_T_SR */
2772: outstr(T_SR);
2773: screen_start(); /* don't know where cursor is now */
2774: }
2775: }
2776:
2777: /*
2778: * With scroll-reverse and 'da' flag set we need to clear the lines that
2779: * have been scrolled down into the region.
2780: */
2781: if (type == USE_T_SR && *T_DA)
2782: {
2783: for (i = 0; i < line_count; ++i)
2784: {
2785: windgoto(off + i, 0);
2786: outstr(T_CE);
2787: screen_start(); /* don't know where cursor is now */
2788: }
2789: }
2790:
2791: return OK;
2792: }
2793:
2794: /*
2795: * delete lines on the screen and update NextScreen
2796: * 'end' is the line after the scrolled part. Normally it is Rows.
2797: * When scrolling region used 'off' is the offset from the top for the region.
2798: * 'row' and 'end' are relative to the start of the region.
2799: *
2800: * Return OK for success, FAIL if the lines are not deleted.
2801: */
2802: int
2803: screen_del_lines(off, row, line_count, end, force)
2804: int off;
2805: int row;
2806: int line_count;
2807: int end;
2808: int force; /* even when line_count > p_ttyscroll */
2809: {
2810: int j;
2811: int i;
2812: char_u *temp;
2813: int cursor_row;
2814: int cursor_end;
2815: int result_empty; /* result is empty until end of region */
2816: int can_delete; /* deleting line codes can be used */
2817: int type;
2818:
2819: /*
2820: * FAIL if
2821: * - there is no valid screen
2822: * - the screen has to be redrawn completely
2823: * - the line count is less than one
2824: * - the line count is more than 'ttyscroll'
2825: */
2826: if (!screen_valid(TRUE) || line_count <= 0 ||
2827: (!force && line_count > p_ttyscroll))
2828: return FAIL;
2829:
2830: /*
2831: * Check if the rest of the current region will become empty.
2832: */
2833: result_empty = row + line_count >= end;
2834:
2835: /*
2836: * We can delete lines only when 'db' flag not set or when 'ce' option
2837: * available.
2838: */
2839: can_delete = (*T_DB == NUL || *T_CE);
2840:
2841: /*
2842: * There are four ways to delete lines:
2843: * 1. Use T_CD if it exists and the result is empty.
2844: * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
2845: * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
2846: * none of the other ways work.
2847: * 4. Use T_CE (erase line) if the result is empty.
2848: * 5. Use T_DL (delete line) if it exists.
2849: */
2850: if (*T_CD != NUL && result_empty)
2851: type = USE_T_CD;
2852: else if (row == 0 && (line_count == 1 || *T_CDL == NUL))
2853: type = USE_NL;
2854: else if (*T_CDL != NUL && line_count > 1 && can_delete)
2855: type = USE_T_CDL;
2856: else if (*T_CE != NUL && result_empty)
2857: type = USE_T_CE;
2858: else if (*T_DL != NUL && can_delete)
2859: type = USE_T_DL;
2860: else if (*T_CDL != NUL && can_delete)
2861: type = USE_T_CDL;
2862: else
2863: return FAIL;
2864:
2865: if (*T_CSC != NUL) /* cursor relative to region */
2866: {
2867: cursor_row = row;
2868: cursor_end = end;
2869: }
2870: else
2871: {
2872: cursor_row = row + off;
2873: cursor_end = end + off;
2874: }
2875:
2876: /*
2877: * Now shift LinePointers line_count up to reflect the deleted lines.
2878: * Clear the inserted lines in NextScreen.
2879: */
2880: row += off;
2881: end += off;
2882: for (i = 0; i < line_count; ++i)
2883: {
2884: j = row + i;
2885: temp = LinePointers[j];
2886: while ((j += line_count) <= end - 1)
2887: LinePointers[j - line_count] = LinePointers[j];
2888: LinePointers[j - line_count] = temp;
2889: lineclear(temp);
2890: }
2891:
2892: /* delete the lines */
2893: if (type == USE_T_CD)
2894: {
2895: windgoto(cursor_row, 0);
2896: outstr(T_CD);
2897: screen_start(); /* don't know where cursor is now */
2898: }
2899: else if (type == USE_T_CDL)
2900: {
2901: windgoto(cursor_row, 0);
2902: OUTSTR(tgoto((char *)T_CDL, 0, line_count));
2903: screen_start(); /* don't know where cursor is now */
2904: }
2905: /*
2906: * Deleting lines at top of the screen or scroll region: Just scroll
2907: * the whole screen (scroll region) up by outputting newlines on the
2908: * last line.
2909: */
2910: else if (type == USE_NL)
2911: {
2912: windgoto(cursor_end - 1, 0);
2913: for (i = line_count; --i >= 0; )
2914: outchar('\n'); /* cursor will remain on same line */
2915: }
2916: else
2917: {
2918: for (i = line_count; --i >= 0; )
2919: {
2920: if (type == USE_T_DL)
2921: {
2922: windgoto(cursor_row, 0);
2923: outstr(T_DL); /* delete a line */
2924: }
2925: else /* type == USE_T_CE */
2926: {
2927: windgoto(cursor_row + i, 0);
2928: outstr(T_CE); /* erase a line */
2929: }
2930: screen_start(); /* don't know where cursor is now */
2931: }
2932: }
2933:
2934: /*
2935: * If the 'db' flag is set, we need to clear the lines that have been
2936: * scrolled up at the bottom of the region.
2937: */
2938: if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
2939: {
2940: for (i = line_count; i > 0; --i)
2941: {
2942: windgoto(cursor_end - i, 0);
2943: outstr(T_CE); /* erase a line */
2944: screen_start(); /* don't know where cursor is now */
2945: }
2946: }
2947: return OK;
2948: }
2949:
2950: /*
2951: * show the current mode and ruler
2952: *
2953: * If clear_cmdline is TRUE, clear the rest of the cmdline.
2954: * If clear_cmdline is FALSE there may be a message there that needs to be
2955: * cleared only if a mode is shown.
1.2 downsj 2956: * Return the lenght of the message (0 if no message).
1.1 downsj 2957: */
1.2 downsj 2958: int
1.1 downsj 2959: showmode()
2960: {
2961: int need_clear = FALSE;
1.2 downsj 2962: int length = 0;
1.1 downsj 2963: int do_mode = (p_smd &&
2964: ((State & INSERT) || restart_edit || VIsual_active));
2965:
2966: if (do_mode || Recording)
2967: {
2968: if (emsg_on_display)
2969: {
2970: mch_delay(1000L, TRUE);
2971: emsg_on_display = FALSE;
2972: }
2973: msg_didout = FALSE; /* never scroll up */
2974: msg_col = 0;
2975: gotocmdline(FALSE);
2976: set_highlight('M'); /* Highlight mode */
2977: if (do_mode)
2978: {
2979: start_highlight();
2980: MSG_OUTSTR("--");
2981: #ifdef INSERT_EXPAND
2982: if (edit_submode != NULL) /* CTRL-X in Insert mode */
2983: {
2984: msg_outstr(edit_submode);
2985: if (edit_submode_extra != NULL)
2986: {
2987: msg_outchar(' '); /* add a space in between */
1.3 ! downsj 2988: if (edit_submode_highl != NUL)
1.1 downsj 2989: {
2990: stop_highlight();
1.3 ! downsj 2991: set_highlight(edit_submode_highl); /* Highlight mode */
1.1 downsj 2992: start_highlight();
2993: }
2994: msg_outstr(edit_submode_extra);
1.3 ! downsj 2995: if (edit_submode_highl != NUL)
1.1 downsj 2996: {
2997: stop_highlight();
2998: set_highlight('M'); /* Highlight mode */
2999: start_highlight();
3000: }
3001: }
3002: }
3003: else
3004: #endif
3005: {
3006: if (State == INSERT)
3007: {
3008: #ifdef RIGHTLEFT
3009: if (p_ri)
3010: MSG_OUTSTR(" REVERSE");
3011: #endif
3012: MSG_OUTSTR(" INSERT");
3013: }
3014: else if (State == REPLACE)
3015: MSG_OUTSTR(" REPLACE");
3016: else if (restart_edit == 'I')
3017: MSG_OUTSTR(" (insert)");
3018: else if (restart_edit == 'R')
3019: MSG_OUTSTR(" (replace)");
3020: #ifdef RIGHTLEFT
3021: if (p_hkmap)
3022: MSG_OUTSTR(" Hebrew");
3023: #endif
3024: if ((State & INSERT) && p_paste)
3025: MSG_OUTSTR(" (paste)");
3026: if (VIsual_active)
3027: {
3028: MSG_OUTSTR(" VISUAL");
3029: if (VIsual_mode == Ctrl('V'))
3030: MSG_OUTSTR(" BLOCK");
3031: else if (VIsual_mode == 'V')
3032: MSG_OUTSTR(" LINE");
3033: }
3034: }
3035: MSG_OUTSTR(" --");
3036: need_clear = TRUE;
3037: }
3038: if (Recording)
3039: {
3040: if (!need_clear)
3041: start_highlight();
3042: MSG_OUTSTR("recording");
3043: need_clear = TRUE;
3044: }
3045: if (need_clear)
3046: stop_highlight();
3047: if (need_clear || clear_cmdline)
3048: msg_clr_eos();
3049: msg_didout = FALSE; /* overwrite this message */
1.2 downsj 3050: length = msg_col;
1.1 downsj 3051: msg_col = 0;
3052: }
3053: else if (clear_cmdline) /* just clear anything */
3054: {
3055: msg_row = cmdline_row;
3056: msg_col = 0;
3057: msg_clr_eos(); /* will reset clear_cmdline */
3058: }
3059: win_redr_ruler(lastwin, TRUE);
3060: redraw_cmdline = FALSE;
1.2 downsj 3061:
3062: return length;
1.1 downsj 3063: }
3064:
3065: /*
3066: * delete mode message
3067: */
3068: void
3069: delmode()
3070: {
3071: if (Recording)
3072: MSG("recording");
3073: else
3074: MSG("");
3075: }
3076:
3077: /*
3078: * if ruler option is set: show current cursor position
3079: * if always is FALSE, only print if position has changed
3080: */
3081: void
3082: showruler(always)
3083: int always;
3084: {
3085: win_redr_ruler(curwin, always);
3086: }
3087:
3088: void
3089: win_redr_ruler(wp, always)
3090: WIN *wp;
3091: int always;
3092: {
3093: static linenr_t old_lnum = 0;
3094: static colnr_t old_col = 0;
3095: char_u buffer[30];
3096: int row;
3097: int fillchar;
3098:
3099: if (p_ru && (redraw_cmdline || always ||
3100: wp->w_cursor.lnum != old_lnum || wp->w_virtcol != old_col))
3101: {
3102: cursor_off();
3103: if (wp->w_status_height)
3104: {
3105: row = wp->w_winpos + wp->w_height;
3106: if (set_highlight('s') == OK) /* can use highlighting */
3107: {
3108: fillchar = ' ';
3109: start_highlight();
3110: }
3111: else
3112: fillchar = '=';
3113: }
3114: else
3115: {
3116: row = Rows - 1;
3117: fillchar = ' ';
3118: }
3119: /*
3120: * Some sprintfs return the length, some return a pointer.
3121: * To avoid portability problems we use strlen() here.
3122: */
3123:
3124: sprintf((char *)buffer, "%ld,",
3125: (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ?
3126: 0L :
3127: (long)(wp->w_cursor.lnum));
3128: /*
3129: * Check if cursor.lnum is valid, since win_redr_ruler() may be called
3130: * after deleting lines, before cursor.lnum is corrected.
3131: */
3132: if (wp->w_cursor.lnum <= wp->w_buffer->b_ml.ml_line_count)
3133: col_print(buffer + STRLEN(buffer),
3134: !(State & INSERT) &&
3135: *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL ?
3136: 0 :
3137: (int)wp->w_cursor.col + 1,
3138: (int)wp->w_virtcol + 1);
3139:
3140: screen_msg(buffer, row, ru_col);
3141: screen_fill(row, row + 1, ru_col + (int)STRLEN(buffer),
3142: (int)Columns, fillchar, fillchar);
3143: old_lnum = wp->w_cursor.lnum;
3144: old_col = wp->w_virtcol;
3145: stop_highlight();
3146: }
3147: }
3148:
3149: /*
3150: * screen_valid - allocate screen buffers if size changed
3151: * If "clear" is TRUE: clear screen if it has been resized.
3152: * Returns TRUE if there is a valid screen to write to.
3153: * Returns FALSE when starting up and screen not initialized yet.
3154: */
3155: int
3156: screen_valid(clear)
3157: int clear;
3158: {
3159: screenalloc(clear); /* allocate screen buffers if size changed */
3160: return (NextScreen != NULL);
3161: }
3162:
3163: #ifdef USE_MOUSE
3164: /*
3165: * Move the cursor to the specified row and column on the screen.
3166: * Change current window if neccesary. Returns an integer with the
3167: * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
3168: *
3169: * If flags has MOUSE_FOCUS, then the current window will not be changed, and
3170: * if the mouse is outside the window then the text will scroll, or if the
3171: * mouse was previously on a status line, then the status line may be dragged.
3172: *
3173: * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
3174: * cursor is moved unless the cursor was on a status line. Ignoring the
3175: * CURSOR_MOVED bit, this function returns one of IN_UNKNOWN, IN_BUFFER, or
3176: * IN_STATUS_LINE depending on where the cursor was clicked.
3177: *
3178: * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
3179: * the last call.
3180: *
3181: * If flags has MOUSE_SETPOS, nothing is done, only the current position is
3182: * remembered.
3183: */
3184: int
3185: jump_to_mouse(flags)
3186: int flags;
3187: {
3188: static int on_status_line = 0; /* #lines below bottom of window */
3189: static int prev_row = -1;
3190: static int prev_col = -1;
3191:
3192: WIN *wp, *old_curwin;
3193: FPOS old_cursor;
3194: int count;
3195: int first;
3196: int row = mouse_row;
3197: int col = mouse_col;
3198:
3199: mouse_past_bottom = FALSE;
3200: mouse_past_eol = FALSE;
3201:
3202: if ((flags & MOUSE_DID_MOVE) && prev_row == mouse_row &&
3203: prev_col == mouse_col)
3204: return IN_BUFFER; /* mouse pointer didn't move */
3205:
3206: prev_row = mouse_row;
3207: prev_col = mouse_col;
3208:
3209: if ((flags & MOUSE_SETPOS))
3210: return IN_BUFFER; /* mouse pointer didn't move */
3211:
3212: old_curwin = curwin;
3213: old_cursor = curwin->w_cursor;
3214:
3215: if (!(flags & MOUSE_FOCUS))
3216: {
3217: if (row < 0 || col < 0) /* check if it makes sense */
3218: return IN_UNKNOWN;
3219:
3220: /* find the window where the row is in */
3221: for (wp = firstwin; wp->w_next; wp = wp->w_next)
3222: if (row < wp->w_next->w_winpos)
3223: break;
3224: /*
3225: * winpos and height may change in win_enter()!
3226: */
3227: row -= wp->w_winpos;
3228: if (row >= wp->w_height) /* In (or below) status line */
3229: on_status_line = row - wp->w_height + 1;
3230: else
3231: on_status_line = 0;
1.2 downsj 3232: win_enter(wp, TRUE); /* can make wp invalid! */
1.1 downsj 3233: if (on_status_line) /* In (or below) status line */
3234: {
3235: /* Don't use start_arrow() if we're in the same window */
3236: if (curwin == old_curwin)
3237: return IN_STATUS_LINE;
3238: else
3239: return IN_STATUS_LINE | CURSOR_MOVED;
3240: }
3241:
3242: curwin->w_cursor.lnum = curwin->w_topline;
3243: }
3244: else if (on_status_line)
3245: {
3246: /* Drag the status line */
3247: count = row - curwin->w_winpos - curwin->w_height + 1 - on_status_line;
3248: win_drag_status_line(count);
3249: return IN_STATUS_LINE; /* Cursor didn't move */
3250: }
3251: else /* keep_window_focus must be TRUE */
3252: {
3253: row -= curwin->w_winpos;
3254:
3255: /*
3256: * When clicking beyond the end of the window, scroll the screen.
3257: * Scroll by however many rows outside the window we are.
3258: */
3259: if (row < 0)
3260: {
3261: count = 0;
3262: for (first = TRUE; curwin->w_topline > 1; --curwin->w_topline)
3263: {
3264: count += plines(curwin->w_topline - 1);
3265: if (!first && count > -row)
3266: break;
3267: first = FALSE;
3268: }
3269: redraw_later(VALID);
3270: row = 0;
3271: }
3272: else if (row >= curwin->w_height)
3273: {
3274: count = 0;
3275: for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count;
3276: ++curwin->w_topline)
3277: {
3278: count += plines(curwin->w_topline);
3279: if (!first && count > row - curwin->w_height + 1)
3280: break;
3281: first = FALSE;
3282: }
3283: redraw_later(VALID);
3284: row = curwin->w_height - 1;
3285: }
3286: curwin->w_cursor.lnum = curwin->w_topline;
3287: }
3288:
3289: #ifdef RIGHTLEFT
3290: if (curwin->w_p_rl)
3291: col = Columns - 1 - col;
3292: #endif
3293:
3294: if (curwin->w_p_wrap) /* lines wrap */
3295: {
3296: while (row)
3297: {
3298: count = plines(curwin->w_cursor.lnum);
3299: if (count > row)
3300: {
3301: col += row * Columns;
3302: break;
3303: }
3304: if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
3305: {
3306: mouse_past_bottom = TRUE;
3307: break;
3308: }
3309: row -= count;
3310: ++curwin->w_cursor.lnum;
3311: }
3312: }
3313: else /* lines don't wrap */
3314: {
3315: curwin->w_cursor.lnum += row;
3316: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
3317: {
3318: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
3319: mouse_past_bottom = TRUE;
3320: }
3321: col += curwin->w_leftcol;
3322: }
1.2 downsj 3323:
3324: if (curwin->w_p_nu) /* skip number in front of the line */
3325: if ((col -= 8) < 0)
3326: col = 0;
3327:
1.1 downsj 3328: curwin->w_curswant = col;
3329: curwin->w_set_curswant = FALSE; /* May still have been TRUE */
3330: if (coladvance(col) == FAIL)
3331: {
3332: /* Mouse click beyond end of line */
3333: op_inclusive = TRUE;
3334: mouse_past_eol = TRUE;
3335: }
3336: else
3337: op_inclusive = FALSE;
3338:
3339: if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
3340: {
3341: start_visual_highlight();
3342: VIsual = old_cursor;
3343: VIsual_active = TRUE;
3344: #ifdef USE_MOUSE
3345: setmouse();
3346: #endif
3347: if (p_smd)
3348: redraw_cmdline = TRUE; /* show visual mode later */
3349: }
3350:
3351: if (curwin == old_curwin && curwin->w_cursor.lnum == old_cursor.lnum &&
3352: curwin->w_cursor.col == old_cursor.col)
3353: return IN_BUFFER; /* Cursor has not moved */
3354: return IN_BUFFER | CURSOR_MOVED; /* Cursor has moved */
3355: }
3356: #endif /* USE_MOUSE */
3357:
3358: /*
3359: * Redraw the screen later, with UpdateScreen(type).
3360: * Set must_redraw only of not already set to a higher value.
3361: * e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
3362: */
3363: void
3364: redraw_later(type)
3365: int type;
3366: {
3367: if (must_redraw < type)
3368: must_redraw = type;
3369: }