|
|
1.1 root 1: /* Display generation from window structure and buffer text.
2: Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 1, or (at your option)
9: any later version.
10:
11: GNU Emacs is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU Emacs; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20:
21: #include "config.h"
22: #include <stdio.h>
23: /*#include <ctype.h>*/
24: #undef NULL
25: #include "lisp.h"
26: #include "window.h"
27: #include "termchar.h"
28: #include "dispextern.h"
29: #include "buffer.h"
30: #include "indent.h"
31: #include "commands.h"
32: #include "macros.h"
33:
34: extern int interrupt_input;
35: extern int command_loop_level;
36:
37: /* Nonzero means print newline before next minibuffer message. */
38:
39: int noninteractive_need_newline;
40:
41: #define min(a, b) ((a) < (b) ? (a) : (b))
42: #define max(a, b) ((a) > (b) ? (a) : (b))
43:
44: /* The buffer position of the first character appearing
45: entirely or partially on the current screen line.
46: Or zero, which disables the optimization for the current screen line. */
47: static int this_line_bufpos;
48:
49: /* Number of characters past the end of this line,
50: including the terminating newline */
51: static int this_line_endpos;
52:
53: /* The vertical position of this screen line. */
54: static int this_line_vpos;
55:
56: /* Hpos value for start of display on this screen line.
57: Usually zero, but negative if first character really began
58: on previous line */
59: static int this_line_start_hpos;
60:
61: /* Buffer that this_line variables are describing. */
62: static struct buffer *this_line_buffer;
63:
64: /* Value of echo_area_contents when it was last acted on.
65: If this is nonzero, there is a message on the screen
66: in the minibuffer and it should be erased as soon
67: as it is no longer requested to appear. */
68: char *prev_echo_area_contents;
69:
70: /* Nonzero means truncate lines in all windows less wide than the screen */
71: int truncate_partial_width_windows;
72:
73: Lisp_Object Vglobal_mode_string;
74:
75: /* Marker for where to display an arrow on top of the buffer text. */
76: Lisp_Object Voverlay_arrow_position;
77:
78: /* String to display for the arrow. */
79: Lisp_Object Voverlay_arrow_string;
80:
81: /* Values of those variables at last redisplay. */
82: Lisp_Object last_arrow_position, last_arrow_string;
83:
84: /* If cursor motion alone moves point off screen,
85: Try scrolling this many lines up or down if that will bring it back. */
86: int scroll_step;
87:
88: /* Nonzero means send various TERMCAP strings when screen is cleared. */
89: int reset_terminal_on_clear;
90:
91: /* Nonzero if try_window_id has made blank lines at window bottom
92: since the last redisplay that paused */
93: static int blank_end_of_window;
94:
95: /* Number of windows showing the buffer of the selected window.
96: keyboard.c refers to this. */
97: int buffer_shared;
98:
99: /* display_text_line sets these to the screen position (origin 0) of point,
100: whether the window is selected or not.
101: Set one to -1 first to determine whether point was found afterwards. */
102:
103: static int point_vpos;
104: static int point_hpos;
105:
106: int debug_end_pos;
107:
108: /* Nonzero means display mode line highlighted */
109: int mode_line_inverse_video;
110:
111: struct position *display_text_line ();
112:
113: /* Prompt to display in front of the minibuffer contents */
114: char *minibuf_prompt;
115:
116: /* Width in columns of current minibuffer prompt. */
117: int minibuf_prompt_width;
118:
119: /* Message to display instead of minibuffer contents
120: This is what the functions error and message make,
121: and command echoing uses it as well.
122: It overrides the minibuf_prompt as well as the buffer. */
123: char *echo_area_contents;
124:
125: /* True iff we should redraw the mode lines on the next redisplay */
126: int update_mode_lines;
127:
128: /* Smallest number of characters before the gap
129: at any time since last redisplay that finished.
130: Valid for current buffer when try_window_id can be called. */
131: int beg_unchanged;
132:
133: /* Smallest number of characters after the gap
134: at any time since last redisplay that finished.
135: Valid for current buffer when try_window_id can be called. */
136: int end_unchanged;
137:
138: /* MODIFF as of last redisplay that finished;
139: if it matches MODIFF, beg_unchanged and end_unchanged
140: contain no useful information */
141: int unchanged_modified;
142:
143: /* Nonzero if head_clip or tail_clip of current buffer has changed
144: since last redisplay that finished */
145: int clip_changed;
146:
147: /* Nonzero if window sizes or contents have changed
148: since last redisplay that finished */
149: int windows_or_buffers_changed;
150:
151: char *decode_mode_spec ();
152:
153: DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
154: "Clear the screen and output again what is supposed to appear on it.")
155: ()
156: {
157: if (screen_height == 0) abort (); /* Some bug zeros some core */
158: if (reset_terminal_on_clear)
159: set_terminal_modes ();
160: clear_screen ();
161: fflush (stdout);
162: clear_screen_records ();
163: if (screen_height == 0) abort (); /* Some bug zeros some core */
164: windows_or_buffers_changed++;
165: /* Mark all windows as INaccurate,
166: so that every window will have its redisplay done. */
167: mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 0);
168: if (screen_height == 0) abort (); /* Some bug zeros some core */
169: return Qnil;
170: }
171:
172: /* Buffer used for messages formatted by `message', and by print. */
173: char *message_buf;
174:
175: /* Nonzero if message_buf is being used by print;
176: zero if being used by message. */
177: int message_buf_print;
178:
179: /* dump an informative message to the minibuf */
180: /* VARARGS 1 */
181: message (m, a1, a2, a3)
182: char *m;
183: {
184: if (noninteractive)
185: {
186: if (noninteractive_need_newline)
187: putchar ('\n');
188: noninteractive_need_newline = 0;
189: printf (m, a1, a2, a3);
190: printf ("\n");
191: fflush (stdout);
192: }
193: else if (FROM_KBD)
194: {
195: #ifdef NO_ARG_ARRAY
196: int a[3];
197: a[0] = a1;
198: a[1] = a2;
199: a[2] = a3;
200:
201: doprnt (message_buf, screen_width, m, 3, a);
202: #else
203: doprnt (message_buf, screen_width, m, 3, &a1);
204: #endif /* NO_ARG_ARRAY */
205: echo_area_contents = message_buf;
206: message_buf_print = 0;
207: do {
208: do_pending_window_change ();
209: display_echo_area_contents ();
210: update_screen (1, 1);
211: do_pending_window_change ();
212: } while (screen_garbaged);
213: }
214: }
215:
216: /* Specify m, a string, as a message in the minibuf. */
217: message1 (m)
218: char *m;
219: {
220: if (noninteractive)
221: {
222: if (noninteractive_need_newline)
223: putchar ('\n');
224: noninteractive_need_newline = 0;
225: printf ("%s\n", m);
226: fflush (stdout);
227: }
228: else if (FROM_KBD)
229: {
230: echo_area_contents = m;
231: do {
232: do_pending_window_change ();
233: display_echo_area_contents ();
234: update_screen (1, 1);
235: do_pending_window_change ();
236: } while (screen_garbaged);
237: }
238: }
239:
240: display_echo_area_contents ()
241: {
242: register int vpos;
243:
244: if (screen_garbaged)
245: {
246: Fredraw_display ();
247: screen_garbaged = 0;
248: }
249:
250: if (echo_area_contents || minibuf_level == 0)
251: {
252: vpos = XFASTINT (XWINDOW (minibuf_window)->top);
253: get_display_line (vpos, 0);
254: display_string (XWINDOW (minibuf_window), vpos,
255: echo_area_contents ? echo_area_contents : "",
256: 0, 0, 0, screen_width);
257:
258: /* If desired cursor location is on this line, put it at end of text */
259: if (cursor_vpos == vpos)
260: cursor_hpos = new_screen->used[vpos];
261:
262: /* Fill the rest of the minibuffer window with blank lines. */
263: {
264: int i;
265:
266: for (i = vpos + 1; i < vpos + XWINDOW (minibuf_window)->height; i++)
267: {
268: get_display_line (i, 0);
269: display_string (XWINDOW (minibuf_window), vpos,
270: "", 0, 0, 0, screen_width);
271: }
272: }
273: }
274: else if (!EQ (minibuf_window, selected_window))
275: windows_or_buffers_changed++;
276:
277: if (EQ (minibuf_window, selected_window))
278: this_line_bufpos = 0;
279:
280: prev_echo_area_contents = echo_area_contents;
281: }
282:
283: /* Do a screen update, taking possible shortcuts into account.
284: This is the main external entry point for redisplay.
285:
286: If the last redisplay displayed an echo area message and that
287: message is no longer requested, we clear the echo area
288: or bring back the minibuffer if that is in use.
289:
290: Everyone would like to have a hook here to call eval,
291: but that cannot be done safely without a lot of changes elsewhere.
292: This can be called from signal handlers; with alarms set up;
293: or with synchronous processes running.
294: See the function `echo' in keyboard.c.
295: See Fcall_process; if you called it from here, it could be
296: entered recursively. */
297:
298: redisplay ()
299: {
300: register struct window *w = XWINDOW (selected_window);
301: register int pause;
302: int inhibit_hairy_id = 0;
303: int must_finish = 0;
304: int all_windows;
305: register int tlbufpos, tlendpos;
306: struct position pos;
307: extern int input_pending;
308:
309: if (noninteractive)
310: return;
311:
312: /* Notice any pending interrupt request to change screen size. */
313: do_pending_window_change ();
314:
315: if (screen_garbaged)
316: {
317: Fredraw_display ();
318: screen_garbaged = 0;
319: }
320:
321: /* Initially we have nothing to update on the screen. */
322: bzero (new_screen->enable, new_screen->height);
323:
324: if (echo_area_contents != 0 || prev_echo_area_contents != 0)
325: {
326: display_echo_area_contents ();
327: must_finish = 1;
328: }
329:
330: if (clip_changed || windows_or_buffers_changed)
331: update_mode_lines++;
332:
333: /* Detect case that we need to write a star in the mode line. */
334: if (XFASTINT (w->last_modified) < MODIFF
335: && XFASTINT (w->last_modified) <= current_buffer->save_modified)
336: {
337: w->update_mode_line = Qt;
338: if (buffer_shared > 1)
339: update_mode_lines++;
340: }
341:
342: all_windows = update_mode_lines || buffer_shared > 1;
343:
344: /* If specs for an arrow have changed, do thorough redisplay
345: to ensure we remove any arrow that should no longer exist. */
346: if (Voverlay_arrow_position != last_arrow_position
347: || Voverlay_arrow_string != last_arrow_string)
348: all_windows = 1, clip_changed = 1;
349:
350: tlbufpos = this_line_bufpos;
351: tlendpos = this_line_endpos;
352: if (!all_windows && tlbufpos > 0 && NULL (w->update_mode_line)
353: /* Make sure recorded data applies to current buffer, etc */
354: && this_line_buffer == current_buffer
355: && current_buffer == XBUFFER (w->buffer)
356: && NULL (w->force_start)
357: /* Point must be on the line that we have info recorded about */
358: && point >= tlbufpos
359: && point <= Z - tlendpos
360: /* All text outside that line, including its final newline,
361: must be unchanged */
362: && (XFASTINT (w->last_modified) >= MODIFF
363: || (beg_unchanged >= tlbufpos - 1
364: && GPT >= tlbufpos
365: /* If selective display, can't optimize
366: if the changes start at the beginning of the line. */
367: && ((XTYPE (current_buffer->selective_display) == Lisp_Int
368: && XINT (current_buffer->selective_display) > 0
369: ? (beg_unchanged >= tlbufpos
370: && GPT > tlbufpos)
371: : 1))
372: && end_unchanged >= tlendpos
373: && Z - GPT >= tlendpos)))
374: {
375: if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
376: && (tlbufpos == ZV
377: || FETCH_CHAR (tlbufpos) == '\n'))
378: /* Former continuation line has disappeared by becoming empty */
379: goto cancel;
380: else if (XFASTINT (w->last_modified) < MODIFF
381: || EQ (selected_window, minibuf_window))
382: {
383: point_vpos = -1;
384: display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
385: pos_tab_offset (w, tlbufpos));
386: /* If line contains point, is not continued,
387: and ends at same distance from eob as before, we win */
388: if (point_vpos >= 0 && this_line_bufpos
389: && this_line_endpos == tlendpos)
390: {
391: /* Done by display_text_line
392: cursor_hpos = point_hpos;
393: cursor_vpos = this_line_vpos;
394: */
395: if (XFASTINT (w->width) != screen_width)
396: preserve_other_columns (w);
397: goto update;
398: }
399: else
400: goto cancel;
401: }
402: else if (point == XFASTINT (w->last_point))
403: {
404: if (!must_finish)
405: return;
406: goto update;
407: }
408: else
409: {
410: pos = *compute_motion (tlbufpos, 0,
411: XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
412: point, 2, - (1 << (SHORTBITS - 1)),
413: XFASTINT (w->width) - 1
414: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width),
415: XINT (w->hscroll),
416: pos_tab_offset (w, tlbufpos));
417: if (pos.vpos < 1)
418: {
419: cursor_hpos = max (XFASTINT (w->left), pos.hpos);
420: cursor_vpos = this_line_vpos;
421: goto update;
422: }
423: else
424: goto cancel;
425: }
426: cancel:
427: /* Text changed drastically or point moved off of line */
428: cancel_line (this_line_vpos);
429: }
430:
431: this_line_bufpos = 0;
432:
433: if (all_windows)
434: redisplay_all_windows ();
435: else
436: {
437: redisplay_window (selected_window, 1);
438: if (XFASTINT (w->width) != screen_width)
439: preserve_other_columns (w);
440: }
441:
442: update:
443: /* Prevent various kinds of signals during display update.
444: stdio is not robust about handling signals,
445: which can cause an apparent I/O error. */
446: if (interrupt_input)
447: unrequest_sigio ();
448: stop_polling ();
449:
450: pause = update_screen (0, 0);
451:
452: /* If screen does not match, prevent doing single-line-update next time.
453: Also, don't forget to check every line to update the arrow. */
454: if (pause)
455: {
456: this_line_bufpos = 0;
457: if (!NULL (last_arrow_position))
458: {
459: last_arrow_position = Qt;
460: last_arrow_string = Qt;
461: }
462: /* If we pause after scrolling, some lines in PhysScreen may be null
463: and then preserve_other_columns won't be able to preserve all
464: the vertical-bar separators. So avoid using it in that case. */
465: if (XFASTINT (w->width) != screen_width)
466: update_mode_lines = 1;
467: }
468:
469: /* Now text on screen agrees with windows, so
470: put info into the windows for partial redisplay to follow */
471:
472: if (!pause)
473: {
474: struct buffer *b = XBUFFER (w->buffer);
475:
476: blank_end_of_window = 0;
477: clip_changed = 0;
478: unchanged_modified = BUF_MODIFF (b);
479: beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
480: end_unchanged = BUF_Z (b) - BUF_GPT (b);
481:
482: XFASTINT (w->last_point) = BUF_PT (b);
483: XFASTINT (w->last_point_x) = cursor_hpos;
484: XFASTINT (w->last_point_y) = cursor_vpos;
485:
486: if (all_windows)
487: mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1);
488: else
489: {
490: w->update_mode_line = Qnil;
491: XFASTINT (w->last_modified) = BUF_MODIFF (b);
492: w->window_end_valid = Qt;
493: last_arrow_position = Voverlay_arrow_position;
494: last_arrow_string = Voverlay_arrow_string;
495: }
496: update_mode_lines = 0;
497: windows_or_buffers_changed = 0;
498: }
499:
500: /* Start SIGIO interrupts coming again.
501: Having them off during the code above
502: makes it less likely one will discard output,
503: but not impossible, since there might be stuff
504: in the system buffer here.
505: But it is much hairier to try to do anything about that. */
506:
507: if (interrupt_input)
508: request_sigio ();
509: start_polling ();
510:
511: do_pending_window_change ();
512:
513: if (screen_garbaged)
514: redisplay ();
515: }
516:
517: /* Redisplay, but leave alone any recent echo area message
518: unless another message has been requested in its place. */
519:
520: redisplay_preserve_echo_area ()
521: {
522: if (echo_area_contents == 0 && prev_echo_area_contents != 0)
523: {
524: echo_area_contents = prev_echo_area_contents;
525: redisplay ();
526: echo_area_contents = 0;
527: }
528: else
529: redisplay ();
530: }
531:
532: mark_window_display_accurate (window, flag)
533: Lisp_Object window;
534: int flag;
535: {
536: register struct window *w;
537:
538: for (;!NULL (window); window = w->next)
539: {
540: w = XWINDOW (window);
541:
542: if (!NULL (w->buffer))
543: XFASTINT (w->last_modified)
544: = !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer));
545: w->window_end_valid = Qt;
546: w->update_mode_line = Qnil;
547:
548: if (!NULL (w->vchild))
549: mark_window_display_accurate (w->vchild, flag);
550: if (!NULL (w->hchild))
551: mark_window_display_accurate (w->hchild, flag);
552: }
553:
554: if (flag)
555: {
556: last_arrow_position = Voverlay_arrow_position;
557: last_arrow_string = Voverlay_arrow_string;
558: }
559: else
560: {
561: /* t is unequal to any useful value of Voverlay_arrow_... */
562: last_arrow_position = Qt;
563: last_arrow_string = Qt;
564: }
565: }
566:
567: int do_id = 1;
568:
569: /* Do full redisplay of one or all windows.
570: This does not include updating the screen;
571: just generating lines to pass to update_screen. */
572:
573: /* Entry point to redisplay all windows */
574:
575: redisplay_all_windows ()
576: {
577: buffer_shared = 0;
578:
579: redisplay_windows (XWINDOW (minibuf_window)->prev);
580: }
581:
582: redisplay_windows (window)
583: Lisp_Object window;
584: {
585: for (; !NULL (window); window = XWINDOW (window)->next)
586: redisplay_window (window, 0);
587: }
588:
589: redisplay_window (window, just_this_one)
590: Lisp_Object window;
591: int just_this_one;
592: {
593: register struct window *w = XWINDOW (window);
594: int height;
595: struct buffer *old = current_buffer;
596: register int width = XFASTINT (w->width) - 1
597: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
598: register int startp;
599: register int hscroll = XINT (w->hscroll);
600: struct position pos;
601: int opoint;
602: int tem;
603:
604: if (screen_height == 0) abort (); /* Some bug zeros some core */
605:
606: /* If this is a combination window, do its children; that's all. */
607:
608: if (!NULL (w->vchild))
609: {
610: redisplay_windows (w->vchild);
611: return;
612: }
613: if (!NULL (w->hchild))
614: {
615: redisplay_windows (w->hchild);
616: return;
617: }
618: if (NULL (w->buffer))
619: abort ();
620:
621: if (update_mode_lines)
622: w->update_mode_line = Qt;
623:
624: /* Otherwise set up data on this window; select its buffer and point value */
625:
626: height = XFASTINT (w->height);
627: if (w != XWINDOW (minibuf_window))
628: height--;
629: else if (echo_area_contents)
630: return 0;
631:
632: current_buffer = XBUFFER (w->buffer);
633:
634: if (!just_this_one
635: && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
636: buffer_shared++;
637:
638: /* Go temporarily to where point is in the window being displayed.
639: We will restore point at the end. */
640: opoint = point;
641: if (!EQ (window, selected_window))
642: {
643: SET_PT (marker_position (w->pointm));
644: if (point < BEGV)
645: point = BEGV;
646: else if (point > ZV)
647: point = ZV;
648: }
649:
650: /* If window-start is screwed up, choose a new one. */
651:
652: if (XMARKER (w->start)->buffer != current_buffer)
653: goto recenter;
654:
655: startp = marker_position (w->start);
656:
657: /* Handle case where place to start displaying has been specified */
658:
659: if (!NULL (w->force_start))
660: {
661: w->update_mode_line = Qt;
662: w->force_start = Qnil;
663: XFASTINT (w->last_modified) = 0;
664:
665: /* Constrain the starting position to be within the visible range. */
666: startp = clip_to_bounds (BEGV, startp, ZV);
667:
668: try_window (window, startp);
669: if (point_vpos < 0)
670: {
671: /* If point does not appear, move point so it does appear */
672: pos = *compute_motion (startp, 0,
673: ((EQ (window, minibuf_window) && startp == 1)
674: ? minibuf_prompt_width : 0)
675: +
676: (hscroll ? 1 - hscroll : 0),
677: ZV, height / 2,
678: - (1 << (SHORTBITS - 1)),
679: width, hscroll, pos_tab_offset (w, startp));
680: SET_PT (pos.bufpos);
681: if (w != XWINDOW (selected_window))
682: Fset_marker (w->pointm, make_number (point), Qnil);
683: else
684: /* We want to change point permanently,
685: so don't restore the old value. */
686: opoint = point;
687:
688: if (EQ (window, selected_window))
689: {
690: cursor_hpos = max (0, pos.hpos) + XFASTINT (w->left);
691: cursor_vpos = pos.vpos + XFASTINT (w->top);
692: }
693: }
694: goto done;
695: }
696:
697: /* Handle case where text has not changed, only point,
698: and it has not moved off the screen */
699:
700: /* This code is not used for minibuffer for the sake of
701: the case of redisplaying to replace an echo area message;
702: since in that case the minibuffer contents per se are usually unchanged.
703: This code is of no real use in the minibuffer since
704: the handling of this_line_bufpos, etc.,
705: in redisplay handles the same cases. */
706:
707: if (XFASTINT (w->last_modified) >= MODIFF
708: && point >= startp && !clip_changed
709: && (just_this_one || XFASTINT (w->width) == screen_width)
710: && !EQ (window, minibuf_window))
711: {
712: pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
713: point, height + 1, 10000, width, hscroll,
714: pos_tab_offset (w, startp));
715:
716: if (pos.vpos < height)
717: {
718: /* Ok, point is still on screen */
719: if (w == XWINDOW (selected_window))
720: {
721: /* These variables are supposed to be origin 1 */
722: cursor_hpos = max (0, pos.hpos) + XFASTINT (w->left);
723: cursor_vpos = pos.vpos + XFASTINT (w->top);
724: }
725: /* This doesn't do the trick, because if a window to the right of
726: this one must be redisplayed, this does nothing because there
727: is nothing in DesiredScreen yet, and then the other window is
728: redisplayed, making likes that are empty in this window's columns.
729: if (XFASTINT (w->width) != screen_width)
730: preserve_my_columns (w);
731: */
732: goto done;
733: }
734: /* Don't bother trying redisplay with same start;
735: we already know it will lose */
736: }
737: /* If current starting point was originally the beginning of a line
738: but no longer is, find a new starting point. */
739: else if (!NULL (w->start_at_line_beg)
740: && !(startp == BEGV
741: || FETCH_CHAR (startp - 1) == '\n'))
742: {
743: goto recenter;
744: }
745: else if (just_this_one && !EQ (window, minibuf_window)
746: && point >= startp
747: && XFASTINT (w->last_modified)
748: && ! EQ (w->window_end_valid, Qnil)
749: && do_id && !clip_changed
750: && !blank_end_of_window
751: && XFASTINT (w->width) == screen_width
752: && EQ (last_arrow_position, Voverlay_arrow_position)
753: && EQ (last_arrow_string, Voverlay_arrow_string)
754: && (tem = try_window_id (selected_window))
755: && tem != -2)
756: {
757: /* tem > 0 means success. tem == -1 means choose new start.
758: tem == -2 means try again with same start,
759: and nothing but whitespace follows the changed stuff.
760: tem == 0 means try again with same start. */
761: if (tem > 0)
762: {
763: goto done;
764: }
765: }
766: else if (startp >= BEGV && startp <= ZV
767: /* Avoid starting display at end of buffer! */
768: && (startp < ZV || startp == BEGV
769: || (XFASTINT (w->last_modified) >= MODIFF)))
770: {
771: /* Try to redisplay starting at same place as before */
772: /* If point has not moved off screen, accept the results */
773: try_window (window, startp);
774: if (point_vpos >= 0)
775: goto done;
776: else
777: cancel_my_columns (w);
778: }
779:
780: XFASTINT (w->last_modified) = 0;
781: w->update_mode_line = Qt;
782:
783: /* Try to scroll by specified few lines */
784:
785: if (scroll_step && !clip_changed)
786: {
787: if (point > startp)
788: {
789: pos = *vmotion (Z - XFASTINT (w->window_end_pos),
790: scroll_step, width, hscroll, window);
791: if (pos.vpos >= height)
792: goto scroll_fail;
793: }
794:
795: pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
796: width, hscroll, window);
797:
798: if (point >= pos.bufpos)
799: {
800: try_window (window, pos.bufpos);
801: if (point_vpos >= 0)
802: goto done;
803: else
804: cancel_my_columns (w);
805: }
806: scroll_fail: ;
807: }
808:
809: /* Finally, just choose place to start which centers point */
810:
811: recenter:
812: pos = *vmotion (point, - height / 2, width, hscroll, window);
813: try_window (window, pos.bufpos);
814:
815: startp = marker_position (w->start);
816: w->start_at_line_beg =
817: (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
818:
819: done:
820: /* If window not full width, must redo its mode line
821: if the window to its side is being redone */
822: if ((!NULL (w->update_mode_line)
823: || (!just_this_one && width < screen_width - 1))
824: && !EQ (window, minibuf_window))
825: display_mode_line (w);
826:
827: SET_PT (opoint);
828: current_buffer = old;
829: }
830:
831: /* Do full redisplay on one window,
832: starting at position `pos'. */
833:
834: try_window (window, pos)
835: Lisp_Object window;
836: register int pos;
837: {
838: register struct window *w = XWINDOW (window);
839: register int height = XFASTINT (w->height) - !EQ (window, minibuf_window);
840: register int vpos = XFASTINT (w->top);
841: register int last_text_vpos = vpos;
842: int tab_offset = pos_tab_offset (w, pos);
843:
844: struct position val;
845:
846: Fset_marker (w->start, make_number (pos), Qnil);
847:
848: point_vpos = -1;
849: val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
850:
851: while (--height >= 0)
852: {
853: val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
854: tab_offset += (XFASTINT (w->width) - 1
855: - (XFASTINT (w->width) + XFASTINT (w->left)
856: != screen_width));
857: if (val.vpos) tab_offset = 0;
858: vpos++;
859: if (pos != val.bufpos)
860: last_text_vpos
861: /* Next line, unless prev line ended in end of buffer with no cr */
862: = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
863: pos = val.bufpos;
864: }
865:
866: /* If last line is continued in middle of character,
867: include the split character in the text considered on the screen */
868: if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
869: pos++;
870:
871: /* Say where last char on screen will be, once redisplay is finished. */
872: XFASTINT (w->window_end_pos) = Z - pos;
873: XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
874: /* But that is not valid info until redisplay finishes. */
875: w->window_end_valid = Qnil;
876: }
877:
878: /* Try to redisplay when buffer is modified locally,
879: computing insert/delete line to preserve text outside
880: the bounds of the changes.
881: Return 1 if successful, 0 if if cannot tell what to do,
882: or -1 to tell caller to find a new window start,
883: or -2 to tell caller to do normal redisplay with same window start. */
884:
885: static struct position debug_bp, debug_ep, debug_xp, debug_pp;
886: static int debug_start_vpos, debug_stop_vpos, debug_scroll_amount;
887: static int debug_dont_scroll;
888:
889: try_window_id (window)
890: Lisp_Object window;
891: {
892: int pos;
893: register struct window *w = XWINDOW (window);
894: register int height = XFASTINT (w->height) - !EQ (window, minibuf_window);
895: int top = XFASTINT (w->top);
896: int start = marker_position (w->start);
897: int width = XFASTINT (w->width) - 1
898: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
899: int hscroll = XINT (w->hscroll);
900: int lmargin = hscroll > 0 ? 1 - hscroll : 0;
901: register int vpos;
902: register int i, tem;
903: int last_text_vpos = 0;
904: int stop_vpos;
905:
906: struct position val, bp, ep, xp, pp;
907: int scroll_amount = 0;
908: int delta;
909: int tab_offset, epto;
910:
911: if (GPT - BEG < beg_unchanged)
912: beg_unchanged = GPT - BEG;
913: if (Z - GPT < end_unchanged)
914: end_unchanged = Z - GPT;
915:
916: if (beg_unchanged + 1 < start)
917: return 0; /* Give up if changes go above top of window */
918:
919: /* Find position before which nothing is changed. */
920: bp = *compute_motion (start, 0, lmargin,
921: beg_unchanged + 1, height + 1, 0, width, hscroll,
922: pos_tab_offset (w, start));
923: if (bp.vpos >= height)
924: {
925: if (point < bp.bufpos && !bp.contin)
926: {
927: /* All changes are below the screen, and point is on the screen.
928: We don't need to change the screen at all.
929: But we need to update window_end_pos to account for
930: any change in buffer size. */
931: bp = *compute_motion (start, 0, lmargin,
932: Z, height, 0,
933: width, hscroll, pos_tab_offset (w, start));
934: XFASTINT (w->window_end_vpos) = height;
935: XFASTINT (w->window_end_pos) = Z - bp.bufpos;
936: return 1;
937: }
938: return 0;
939: }
940:
941: vpos = bp.vpos;
942:
943: /* Find beginning of that screen line. Must display from there. */
944: bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
945:
946: pos = bp.bufpos;
947: val.hpos = lmargin;
948: if (pos < start)
949: return -1;
950:
951: /* If about to start displaying at the beginning of a continuation line,
952: really start with previous screen line, in case it was not
953: continued when last redisplayed */
954: if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
955: ||
956: /* Likewise if we have to worry about selective display. */
957: (XTYPE (current_buffer->selective_display) == Lisp_Int
958: && XINT (current_buffer->selective_display) > 0
959: && bp.bufpos - 1 == beg_unchanged && vpos > 0))
960: {
961: bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
962: --vpos;
963: pos = bp.bufpos;
964: }
965:
966: if (bp.contin && bp.hpos != lmargin)
967: {
968: val.hpos = bp.prevhpos - width + lmargin;
969: pos--;
970: }
971:
972: bp.vpos = vpos;
973:
974: /* Find first visible newline after which no more is changed. */
975: tem = find_next_newline (Z - max (end_unchanged, Z - ZV),
976: 1);
977: if (XTYPE (current_buffer->selective_display) == Lisp_Int
978: && XINT (current_buffer->selective_display) > 0)
979: while (tem < ZV - 1
980: && (position_indentation (tem)
981: >= XINT (current_buffer->selective_display)))
982: tem = find_next_newline (tem, 1);
983:
984: /* Compute the cursor position after that newline. */
985: ep = *compute_motion (pos, vpos, val.hpos, tem,
986: height, - (1 << (SHORTBITS - 1)),
987: width, hscroll, pos_tab_offset (w, bp.bufpos));
988:
989: /* If changes reach past the text available on the screen,
990: just display rest of screen. */
991: if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
992: stop_vpos = height;
993: else
994: stop_vpos = ep.vpos;
995:
996: /* If no newline before ep, the line ep is on includes some changes
997: that must be displayed. Make sure we don't stop before it. */
998: /* Also, if changes reach all the way until ep.bufpos,
999: it is possible that something was deleted after the
1000: newline before it, so the following line must be redrawn. */
1001: if (stop_vpos == ep.vpos
1002: && (ep.bufpos == BEGV
1003: || FETCH_CHAR (ep.bufpos - 1) != '\n'
1004: || ep.bufpos == Z - end_unchanged))
1005: stop_vpos = ep.vpos + 1;
1006:
1007: point_vpos = -1;
1008: debug_dont_scroll = 0;
1009:
1010: /* If changes do not reach to bottom of window,
1011: figure out how much to scroll the rest of the window */
1012: if (stop_vpos < height)
1013: {
1014: /* Now determine how far up or down the rest of the window has moved */
1015: epto = pos_tab_offset (w, ep.bufpos);
1016: xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1017: Z - XFASTINT (w->window_end_pos),
1018: 10000, 0, width, hscroll, epto);
1019: scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1020:
1021: /* Is everything on screen below the changes whitespace?
1022: If so, no scrolling is really necessary. */
1023: for (i = ep.bufpos; i < xp.bufpos; i++)
1024: {
1025: tem = FETCH_CHAR (i);
1026: if (tem != ' ' && tem != '\n' && tem != '\t')
1027: break;
1028: }
1029: if (i == xp.bufpos)
1030: return -2;
1031:
1032: XFASTINT (w->window_end_vpos) += scroll_amount;
1033:
1034: /* Before doing any scrolling, verify that point will be on screen. */
1035: if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
1036: {
1037: if (point <= xp.bufpos)
1038: {
1039: pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1040: point, height, - (1 << (SHORTBITS - 1)),
1041: width, hscroll, epto);
1042: }
1043: else
1044: {
1045: pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
1046: point, height, - (1 << (SHORTBITS - 1)),
1047: width, hscroll, pos_tab_offset (w, xp.bufpos));
1048: }
1049: if (pp.bufpos < point || pp.vpos == height)
1050: return 0;
1051: point_vpos = pp.vpos + top;
1052: point_hpos = pp.hpos + XFASTINT (w->left);
1053: }
1054:
1055: if (stop_vpos - scroll_amount >= height
1056: || ep.bufpos == xp.bufpos)
1057: {
1058: if (scroll_amount < 0)
1059: stop_vpos -= scroll_amount;
1060: scroll_amount = 0;
1061: debug_dont_scroll = 1;
1062: /* In this path, we have altered window_end_vpos
1063: and not left it negative.
1064: We must make sure that, in case display is preempted
1065: before the screen changes to reflect what we do here,
1066: further updates will not come to try_window_id
1067: and assume the screen and window_end_vpos match. */
1068: blank_end_of_window = 1;
1069: }
1070: else if (!scroll_amount)
1071: {}
1072: else if (bp.bufpos == Z - end_unchanged)
1073: {
1074: /* If reprinting everything is nearly as fast as scrolling,
1075: don't bother scrolling. Can happen if lines are short. */
1076: if (scroll_cost (bp.vpos + top - scroll_amount,
1077: top + height - max (0, scroll_amount),
1078: scroll_amount)
1079: > xp.bufpos - bp.bufpos - 20)
1080: /* Return "try normal display with same window-start."
1081: Too bad we can't prevent further scroll-thinking. */
1082: return -2;
1083: /* If pure deletion, scroll up as many lines as possible.
1084: In common case of killing a line, this can save the
1085: following line from being overwritten by scrolling
1086: and therefore having to be redrawn. */
1087: tem = scroll_screen_lines (bp.vpos + top - scroll_amount,
1088: top + height - max (0, scroll_amount),
1089: scroll_amount);
1090: if (!tem) stop_vpos = height;
1091: }
1092: else if (scroll_amount)
1093: {
1094: /* If reprinting everything is nearly as fast as scrolling,
1095: don't bother scrolling. Can happen if lines are short. */
1096: /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1097: overestimate of cost of reprinting, since xp.bufpos
1098: would end up below the bottom of the window. */
1099: if (scroll_cost (ep.vpos + top - scroll_amount,
1100: top + height - max (0, scroll_amount),
1101: scroll_amount)
1102: > xp.bufpos - ep.bufpos - 20)
1103: /* Return "try normal display with same window-start."
1104: Too bad we can't prevent further scroll-thinking. */
1105: return -2;
1106: tem = scroll_screen_lines (ep.vpos + top - scroll_amount,
1107: top + height - max (0, scroll_amount),
1108: scroll_amount);
1109: if (!tem) stop_vpos = height;
1110: }
1111: }
1112:
1113: debug_scroll_amount = scroll_amount;
1114: debug_bp = bp;
1115: debug_ep = ep;
1116: debug_xp = xp;
1117: debug_pp = pp;
1118:
1119: /* In any case, do not display past bottom of window */
1120: if (stop_vpos >= height)
1121: {
1122: stop_vpos = height;
1123: scroll_amount = 0;
1124: }
1125:
1126: debug_stop_vpos = stop_vpos;
1127: debug_start_vpos = vpos;
1128:
1129: /* Handle case where pos is before w->start --
1130: can happen if part of line had been clipped and is not clipped now */
1131: if (vpos == 0 && pos < marker_position (w->start))
1132: Fset_marker (w->start, make_number (pos), Qnil);
1133:
1134: /* Redisplay the lines where the text was changed */
1135: last_text_vpos = vpos;
1136: tab_offset = pos_tab_offset (w, pos);
1137: if (val.hpos + hscroll - (hscroll > 0) < 0)
1138: tab_offset += (XFASTINT (w->width) - 1
1139: - (XFASTINT (w->width) + XFASTINT (w->left)
1140: != screen_width));
1141: while (vpos < stop_vpos)
1142: {
1143: val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1144: tab_offset += (XFASTINT (w->width) - 1
1145: - (XFASTINT (w->width) + XFASTINT (w->left)
1146: != screen_width));
1147: if (val.vpos) tab_offset = 0;
1148: if (pos != val.bufpos)
1149: last_text_vpos
1150: /* Next line, unless prev line ended in end of buffer with no cr */
1151: = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1152: pos = val.bufpos;
1153: }
1154:
1155: /* There are two cases:
1156: 1) we have displayed down to the bottom of the window
1157: 2) we have scrolled lines below stop_vpos by scroll_amount */
1158:
1159: if (vpos == height)
1160: {
1161: /* If last line is continued in middle of character,
1162: include the split character in the text considered on the screen */
1163: if (val.hpos < lmargin)
1164: val.bufpos++;
1165: XFASTINT (w->window_end_vpos) = last_text_vpos;
1166: XFASTINT (w->window_end_pos) = Z - val.bufpos;
1167: }
1168:
1169: /* If scrolling made blank lines at window bottom,
1170: redisplay to fill those lines */
1171: if (scroll_amount < 0)
1172: {
1173: vpos = xp.vpos;
1174: pos = xp.bufpos;
1175: val.hpos = lmargin;
1176: if (pos == ZV)
1177: vpos = height + scroll_amount;
1178: else if (xp.contin && xp.hpos != lmargin)
1179: {
1180: val.hpos = xp.prevhpos - width + lmargin;
1181: pos--;
1182: }
1183:
1184: blank_end_of_window = 1;
1185: tab_offset = pos_tab_offset (w, pos);
1186: if (val.hpos < 0)
1187: tab_offset += (XFASTINT (w->width) - 1
1188: - (XFASTINT (w->width) + XFASTINT (w->left)
1189: != screen_width));
1190:
1191: while (vpos < height)
1192: {
1193: val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1194: tab_offset += (XFASTINT (w->width) - 1
1195: - (XFASTINT (w->width) + XFASTINT (w->left)
1196: != screen_width));
1197: if (val.vpos) tab_offset = 0;
1198: pos = val.bufpos;
1199: }
1200:
1201: /* Here is a case where display_text_line sets point_vpos wrong.
1202: Make it be fixed up, below. */
1203: if (xp.bufpos == ZV
1204: && xp.bufpos == point)
1205: point_vpos = -1;
1206: }
1207:
1208: /* Attempt to adjust end-of-text positions to new bottom line */
1209: if (scroll_amount)
1210: {
1211: delta = height - xp.vpos;
1212: if (delta < 0
1213: || (delta > 0 && xp.bufpos < ZV)
1214: || (delta == 0 && xp.hpos))
1215: {
1216: val = *vmotion (Z - XFASTINT (w->window_end_pos),
1217: delta, width, hscroll, window);
1218: XFASTINT (w->window_end_pos) = Z - val.bufpos;
1219: XFASTINT (w->window_end_vpos) += val.vpos;
1220: }
1221: }
1222:
1223: w->window_end_valid = Qnil;
1224:
1225: /* If point was not in a line that was displayed, find it */
1226: if (point_vpos < 0)
1227: {
1228: val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1229: width, hscroll, pos_tab_offset (w, start));
1230: /* Admit failure if point is off screen now */
1231: if (val.vpos >= height)
1232: {
1233: for (vpos = 0; vpos < height; vpos++)
1234: cancel_line (vpos + top);
1235: return 0;
1236: }
1237: point_vpos = val.vpos + top;
1238: point_hpos = val.hpos + XFASTINT (w->left);
1239: }
1240:
1241: cursor_hpos = max (0, point_hpos);
1242: cursor_vpos = point_vpos;
1243:
1244: if (debug_end_pos)
1245: {
1246: val = *compute_motion (start, 0, lmargin, ZV,
1247: height, - (1 << (SHORTBITS - 1)),
1248: width, hscroll, pos_tab_offset (w, start));
1249: if (val.vpos != XFASTINT (w->window_end_vpos))
1250: abort ();
1251: if (XFASTINT (w->window_end_pos) != Z - val.bufpos)
1252: abort ();
1253: }
1254:
1255: return 1;
1256: }
1257:
1258: /* Display one line of window w, starting at position `start' in w's buffer.
1259: Display starting at horizontal position `hpos',
1260: which is normally zero or negative.
1261: A negative value causes output up to hpos = 0 to be discarded.
1262: This is done for negative hscroll, or when this is a continuation line
1263: and the continuation occurred in the middle of a multi-column character.
1264:
1265: `taboffset' is an offset for ostensible hpos, used in tab stop calculations.
1266:
1267: Display on position `vpos' on the screen. (origin 0).
1268:
1269: Returns a `struct position' giving character to start next line with
1270: and where to display it, including a zero or negative hpos.
1271: The vpos field is not really a vpos; it is 1 unless the line is continued */
1272:
1273: struct position val_display_text_line;
1274:
1275: struct position *
1276: display_text_line (w, start, vpos, hpos, taboffset)
1277: struct window *w;
1278: int start;
1279: int vpos;
1280: int hpos;
1281: int taboffset;
1282: {
1283: register int pos = start;
1284: register int c;
1285: register unsigned char *p1;
1286: int end;
1287: register int pause;
1288: register unsigned char *p;
1289: unsigned char *endp;
1290: register unsigned char *startp;
1291: register unsigned char *p1prev = 0;
1292: int tab_width = XINT (current_buffer->tab_width);
1293: int ctl_arrow = !NULL (current_buffer->ctl_arrow);
1294: int width = XFASTINT (w->width) - 1
1295: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width);
1296: struct position val;
1297: int lastpos;
1298: int invis;
1299: int hscroll = XINT (w->hscroll);
1300: int truncate = hscroll
1301: || (truncate_partial_width_windows
1302: && XFASTINT (w->width) < screen_width)
1303: || !NULL (current_buffer->truncate_lines);
1304: int selective
1305: = XTYPE (current_buffer->selective_display) == Lisp_Int
1306: ? XINT (current_buffer->selective_display)
1307: : !NULL (current_buffer->selective_display) ? -1 : 0;
1308: int selective_e = selective && !NULL (current_buffer->selective_display_ellipses);
1309:
1310: hpos += XFASTINT (w->left);
1311: get_display_line (vpos, XFASTINT (w->left));
1312: if (tab_width <= 0 || tab_width > 20) tab_width = 8;
1313:
1314: if (w == XWINDOW (minibuf_window) && start == 1
1315: && vpos == XFASTINT (w->top))
1316: {
1317: if (minibuf_prompt)
1318: hpos = display_string (w, vpos, minibuf_prompt, hpos,
1319: !truncate ? '\\' : '$', -1, -1);
1320: minibuf_prompt_width = hpos;
1321: }
1322:
1323: p1 = new_screen->contents[vpos] + hpos;
1324:
1325: end = ZV;
1326:
1327: startp = new_screen->contents[vpos] + XFASTINT (w->left);
1328: endp = startp + width;
1329:
1330: /* Loop generating characters.
1331: Stop at end of buffer, before newline,
1332: or if reach or pass continuation column. */
1333:
1334: pause = pos;
1335: while (p1 < endp)
1336: {
1337: p1prev = p1;
1338: if (pos == pause)
1339: {
1340: if (pos == end)
1341: break;
1342: if (pos == point && point_vpos < 0)
1343: {
1344: point_vpos = vpos;
1345: point_hpos = p1 - startp;
1346: }
1347:
1348: pause = end;
1349: if (pos < point && point < pause)
1350: pause = point;
1351: if (pos < GPT && GPT < pause)
1352: pause = GPT;
1353:
1354: p = &FETCH_CHAR (pos);
1355: }
1356: c = *p++;
1357: if (c >= 040 && c < 0177)
1358: {
1359: if (p1 >= startp)
1360: *p1 = c;
1361: p1++;
1362: }
1363: else if (c == '\n')
1364: {
1365: invis = 0;
1366: while (pos < end
1367: && selective > 0
1368: && position_indentation (pos + 1) >= selective)
1369: {
1370: invis = 1;
1371: pos = find_next_newline (pos + 1, 1);
1372: if (FETCH_CHAR (pos - 1) == '\n')
1373: pos--;
1374: }
1375: if (invis && selective_e)
1376: {
1377: p1 += 4;
1378: if (p1 - startp > width)
1379: p1 = endp;
1380: if (p1prev >= startp)
1381: strncpy (p1prev, " ...", p1 - p1prev);
1382: }
1383: break;
1384: }
1385: else if (c == '\t')
1386: {
1387: do
1388: {
1389: if (p1 >= startp && p1 < endp)
1390: *p1 = ' ';
1391: p1++;
1392: }
1393: while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1394: % tab_width);
1395: }
1396: else if (c == Ctl ('M') && selective == -1)
1397: {
1398: pos = find_next_newline (pos, 1);
1399: if (FETCH_CHAR (pos - 1) == '\n')
1400: pos--;
1401: if (selective_e)
1402: {
1403: p1 += 4;
1404: if (p1 - startp > width)
1405: p1 = endp;
1406: if (p1prev >= startp)
1407: strncpy (p1prev, " ...", p1 - p1prev);
1408: }
1409: break;
1410: }
1411: else if (c < 0200 && ctl_arrow)
1412: {
1413: if (p1 >= startp)
1414: *p1 = '^';
1415: p1++;
1416: if (p1 >= startp && p1 < endp)
1417: *p1 = c ^ 0100;
1418: p1++;
1419: }
1420: else
1421: {
1422: if (p1 >= startp)
1423: *p1 = '\\';
1424: p1++;
1425: if (p1 >= startp && p1 < endp)
1426: *p1 = (c >> 6) + '0';
1427: p1++;
1428: if (p1 >= startp && p1 < endp)
1429: *p1 = (7 & (c >> 3)) + '0';
1430: p1++;
1431: if (p1 >= startp && p1 < endp)
1432: *p1 = (7 & c) + '0';
1433: p1++;
1434: }
1435: pos++;
1436: }
1437:
1438: val.hpos = - XINT (w->hscroll);
1439: if (val.hpos)
1440: val.hpos++;
1441:
1442: val.vpos = 1;
1443:
1444: lastpos = pos;
1445:
1446: /* Handle continuation in middle of a character */
1447: /* by backing up over it */
1448: if (p1 > endp)
1449: {
1450: if (p1prev)
1451: {
1452: /* Start the next line with that same character */
1453: pos--;
1454: /* but at negative hpos, to skip the columns output on this line. */
1455: val.hpos += p1prev - endp;
1456: }
1457:
1458: /* Keep in this line everything up to the continuation column. */
1459: p1 = endp;
1460: }
1461:
1462: /* Finish deciding which character to start the next line on,
1463: and what hpos to start it at.
1464: Also set `lastpos' to the last position which counts as "on this line"
1465: for cursor-positioning. */
1466:
1467: if (pos < ZV)
1468: {
1469: if (FETCH_CHAR (pos) == '\n')
1470: /* If stopped due to a newline, start next line after it */
1471: pos++;
1472: else
1473: /* Stopped due to right margin of window */
1474: {
1475: if (truncate)
1476: {
1477: *p1++ = '$';
1478: /* Truncating => start next line after next newline,
1479: and point is on this line if it is before the newline,
1480: and skip none of first char of next line */
1481: pos = find_next_newline (pos, 1);
1482: val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1483:
1484: lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
1485: }
1486: else
1487: {
1488: *p1++ = '\\';
1489: val.vpos = 0;
1490: lastpos--;
1491: }
1492: }
1493: }
1494:
1495: /* If point is at eol or in invisible text at eol,
1496: record its screen location now. */
1497:
1498: if (start <= point && point <= lastpos && point_vpos < 0)
1499: {
1500: point_vpos = vpos;
1501: point_hpos = p1 - startp;
1502: }
1503:
1504: if (point_vpos == vpos)
1505: {
1506: if (point_hpos < 0) point_hpos = 0;
1507: if (point_hpos > width) point_hpos = width;
1508: point_hpos += XFASTINT (w->left);
1509: if (w == XWINDOW (selected_window))
1510: {
1511: cursor_vpos = point_vpos;
1512: cursor_hpos = point_hpos;
1513:
1514: /* Line is not continued and did not start in middle of character */
1515: if (hpos == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0)
1516: && val.vpos)
1517: {
1518: this_line_bufpos = start;
1519: this_line_buffer = current_buffer;
1520: this_line_vpos = point_vpos;
1521: this_line_start_hpos = hpos;
1522: this_line_endpos = Z - lastpos;
1523: }
1524: else
1525: this_line_bufpos = 0;
1526: }
1527: }
1528:
1529: /* If hscroll and line not empty, insert truncation-at-left marker */
1530: if (hscroll && lastpos != start)
1531: {
1532: *startp = '$';
1533: if (p1 <= startp)
1534: p1 = startp + 1;
1535: }
1536:
1537: if (XFASTINT (w->width) + XFASTINT (w->left) != screen_width)
1538: {
1539: endp++;
1540: if (p1 < startp) p1 = startp;
1541: while (p1 < endp) *p1++ = ' ';
1542: *p1++ = '|';
1543: }
1544: new_screen->used[vpos] = max (new_screen->used[vpos],
1545: p1 - new_screen->contents[vpos]);
1546: new_screen->contents[vpos][new_screen->used[vpos]] = 0;
1547:
1548: /* If the start of this line is the overlay arrow-position,
1549: then put the arrow string into the display-line. */
1550:
1551: if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
1552: && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
1553: && start == marker_position (Voverlay_arrow_position)
1554: && XTYPE (Voverlay_arrow_string) == Lisp_String)
1555: {
1556: unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
1557: int len = XSTRING (Voverlay_arrow_string)->size;
1558: int minlen = (XFASTINT (w->width) - 1
1559: - (XFASTINT (w->width) + XFASTINT (w->left)
1560: != screen_width));
1561:
1562: if (len > minlen)
1563: len = minlen;
1564: bcopy (p, startp, len);
1565: if (new_screen->used[vpos] < len + startp - new_screen->contents[vpos])
1566: new_screen->used[vpos] = len + startp - new_screen->contents[vpos];
1567: }
1568:
1569: val.bufpos = pos;
1570: val_display_text_line = val;
1571: return &val_display_text_line;
1572: }
1573:
1574: /* Display the mode line for window w */
1575:
1576: display_mode_line (w)
1577: struct window *w;
1578: {
1579: register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
1580: register int left = XFASTINT (w->left);
1581: register int right = XFASTINT (w->width) + left;
1582: get_display_line (vpos, left);
1583:
1584: display_mode_element (w, vpos, left, 0, right, right,
1585: current_buffer->mode_line_format);
1586:
1587: /* Make the mode line inverse video if the entire line
1588: is made of mode lines.
1589: I.e. if this window is full width,
1590: or if it is the child of a full width window
1591: (which implies that that window is split side-by-side
1592: and the rest of this line is mode lines of the sibling windows). */
1593: if (XFASTINT (w->width) == screen_width ||
1594: XFASTINT (XWINDOW (w->parent)->width) == screen_width)
1595: new_screen->highlight[vpos] = mode_line_inverse_video;
1596:
1597: }
1598:
1599: /* Contribute ELT to the mode line for window W.
1600: How it translates into text depends on its data type.
1601:
1602: LINE is the display-line that the mode line is being displayed in.
1603:
1604: HPOS is the position (absolute on screen) where this element's text
1605: should start. The output is truncated automatically at the right
1606: edge of window W.
1607:
1608: DEPTH is the depth in recursion. It is used to prevent
1609: infinite recursion here.
1610:
1611: MINENDCOL is the hpos before which the element may not end.
1612: The element is padded at the right with spaces if nec
1613: to reach this column.
1614:
1615: MAXENDCOL is the hpos past which this element may not extend.
1616: If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
1617: (This is necessary to make nested padding and truncation work.)
1618:
1619: Returns the hpos of the end of the text generated by ELT.
1620: The next element will receive that value as its HPOS arg,
1621: so as to concatenate the elements. */
1622:
1623: int
1624: display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
1625: struct window *w;
1626: int vpos;
1627: register int hpos;
1628: int depth;
1629: int minendcol;
1630: register int maxendcol;
1631: register Lisp_Object elt;
1632: {
1633: tail_recurse:
1634: if (depth > 10)
1635: goto invalid;
1636:
1637: depth++;
1638:
1639: #ifdef SWITCH_ENUM_BUG
1640: switch ((int) XTYPE (elt))
1641: #else
1642: switch (XTYPE (elt))
1643: #endif
1644: {
1645: case Lisp_String:
1646: {
1647: /* A string: output it and check for %-constructs within it. */
1648: register unsigned char c;
1649: register unsigned char *this = XSTRING (elt)->data;
1650:
1651: while (hpos < maxendcol && *this)
1652: {
1653: unsigned char *last = this;
1654: while ((c = *this++) != '\0' && c != '%')
1655: ;
1656: if (this - 1 != last)
1657: {
1658: register int lim = --this - last + hpos;
1659: hpos = display_string (w, vpos, last, hpos, 0, hpos,
1660: min (lim, maxendcol));
1661: }
1662: else /* c == '%' */
1663: {
1664: register int spec_width = 0;
1665:
1666: /* We can't allow -ve args due to the "%-" construct */
1667: /* Argument specifies minwidth but not maxwidth
1668: (maxwidth can be specified by
1669: (<negative-number> . <stuff>) mode-line elements) */
1670:
1671: while ((c = *this++) >= '0' && c <= '9')
1672: {
1673: spec_width = spec_width * 10 + (c - '0');
1674: }
1675:
1676: spec_width += hpos;
1677: if (spec_width > maxendcol)
1678: spec_width = maxendcol;
1679:
1680: if (c == 'M')
1681: hpos = display_mode_element (w, vpos, hpos, depth,
1682: spec_width, maxendcol,
1683: Vglobal_mode_string);
1684: else if (c != 0)
1685: hpos = display_string (w, vpos,
1686: decode_mode_spec (w, c,
1687: spec_width - hpos),
1688: hpos, 0, spec_width, maxendcol);
1689: }
1690: }
1691: }
1692: break;
1693:
1694: case Lisp_Symbol:
1695: /* A symbol: process the value of the symbol recursively
1696: as if it appeared here directly. Avoid error if symbol void.
1697: Special case: if value of symbol is a string, output the string
1698: literally. */
1699: {
1700: register Lisp_Object tem;
1701: tem = Fboundp (elt);
1702: if (!NULL (tem))
1703: {
1704: tem = Fsymbol_value (elt);
1705: /* If value is a string, output that string literally:
1706: don't check for % within it. */
1707: if (XTYPE (tem) == Lisp_String)
1708: hpos = display_string (w, vpos, XSTRING (tem)->data,
1709: hpos, 0, minendcol, maxendcol);
1710: /* Give up right away for nil or t. */
1711: else if (!EQ (tem, elt))
1712: { elt = tem; goto tail_recurse; }
1713: }
1714: }
1715: break;
1716:
1717: case Lisp_Cons:
1718: {
1719: register Lisp_Object car, tem;
1720:
1721: /* A cons cell: three distinct cases.
1722: If first element is a string or a cons, process all the elements
1723: and effectively concatenate them.
1724: If first element is a negative number, truncate displaying cdr to
1725: at most that many characters. If positive, pad (with spaces)
1726: to at least that many characters.
1727: If first element is a symbol, process the cadr or caddr recursively
1728: according to whether the symbol's value is non-nil or nil. */
1729: car = XCONS (elt)->car;
1730: if (XTYPE (car) == Lisp_Symbol)
1731: {
1732: tem = Fboundp (car);
1733: elt = XCONS (elt)->cdr;
1734: if (XTYPE (elt) != Lisp_Cons)
1735: goto invalid;
1736: /* elt is now the cdr, and we know it is a cons cell.
1737: Use its car if CAR has a non-nil value. */
1738: if (!NULL (tem))
1739: {
1740: tem = Fsymbol_value (car);
1741: if (!NULL (tem))
1742: { elt = XCONS (elt)->car; goto tail_recurse; }
1743: }
1744: /* Symbol's value is nil (or symbol is unbound)
1745: Get the cddr of the original list
1746: and if possible find the caddr and use that. */
1747: elt = XCONS (elt)->cdr;
1748: if (NULL (elt))
1749: break;
1750: else if (XTYPE (elt) != Lisp_Cons)
1751: goto invalid;
1752: elt = XCONS (elt)->car;
1753: goto tail_recurse;
1754: }
1755: else if (XTYPE (car) == Lisp_Int)
1756: {
1757: register int lim = XINT (car);
1758: elt = XCONS (elt)->cdr;
1759: if (lim < 0)
1760: /* Negative int means reduce maximum width.
1761: DO NOT change MINENDCOL here!
1762: (20 -10 . foo) should truncate foo to 10 col
1763: and then pad to 20. */
1764: maxendcol = min (maxendcol, hpos - lim);
1765: else if (lim > 0)
1766: {
1767: /* Padding specified. Don't let it be more than
1768: current maximum. */
1769: lim += hpos;
1770: if (lim > maxendcol)
1771: lim = maxendcol;
1772: /* If that's more padding than already wanted, queue it.
1773: But don't reduce padding already specified even if
1774: that is beyond the current truncation point. */
1775: if (lim > minendcol)
1776: minendcol = lim;
1777: }
1778: goto tail_recurse;
1779: }
1780: else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
1781: {
1782: register int limit = 50;
1783: /* LIMIT is to protect against circular lists. */
1784: while (XTYPE (elt) == Lisp_Cons && --limit > 0
1785: && hpos < maxendcol)
1786: {
1787: hpos = display_mode_element (w, vpos, hpos, depth,
1788: hpos, maxendcol,
1789: XCONS (elt)->car);
1790: elt = XCONS (elt)->cdr;
1791: }
1792: }
1793: }
1794: break;
1795:
1796: default:
1797: invalid:
1798: return (display_string (w, vpos, "*invalid*", hpos, 0,
1799: minendcol, maxendcol));
1800: }
1801:
1802: end:
1803: if (minendcol > hpos)
1804: hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
1805: return hpos;
1806: }
1807:
1808: /* Return a string for the output of a mode line %-spec
1809: for window W, generated by character C and width MAXWIDTH. */
1810:
1811: char *
1812: decode_mode_spec (w, c, maxwidth)
1813: struct window *w;
1814: register char c;
1815: register int maxwidth;
1816: {
1817: Lisp_Object obj = Qnil;
1818: char *decode_mode_spec_buf = (char *) temp_screen->total_contents;
1819:
1820: switch (c)
1821: {
1822: case 'b':
1823: obj = current_buffer->name;
1824: #if 0
1825: if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
1826: {
1827: bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
1828: decode_mode_spec_buf[maxwidth - 1] = '\\';
1829: decode_mode_spec_buf[maxwidth] = '\0';
1830: return decode_mode_spec_buf;
1831: }
1832: #endif
1833: break;
1834:
1835: case 'f':
1836: obj = current_buffer->filename;
1837: #if 0
1838: if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
1839: {
1840: bcopy ("...", decode_mode_spec_buf, 3);
1841: bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
1842: decode_mode_spec_buf + 3, maxwidth - 3);
1843: return decode_mode_spec_buf;
1844: }
1845: #endif
1846: break;
1847:
1848: case 'm':
1849: obj = current_buffer->mode_name;
1850: break;
1851:
1852: case 'n':
1853: if (BEGV > BEG || ZV < Z)
1854: return " Narrow";
1855: break;
1856:
1857: case '*':
1858: if (!NULL (current_buffer->read_only))
1859: return "%";
1860: if (MODIFF > current_buffer->save_modified)
1861: return "*";
1862: return "-";
1863:
1864: case 's':
1865: /* status of process */
1866: #ifdef subprocesses
1867: obj = Fget_buffer_process (Fcurrent_buffer ());
1868: if (NULL (obj))
1869: return "no process";
1870: obj = Fsymbol_name (Fprocess_status (obj));
1871: break;
1872: #else
1873: return "no processes";
1874: #endif /* subprocesses */
1875:
1876: case 'p':
1877: {
1878: int pos = marker_position (w->start);
1879: int total = ZV - BEGV;
1880:
1881: if (XFASTINT (w->window_end_pos) <= Z - ZV)
1882: {
1883: if (pos <= BEGV)
1884: return "All";
1885: else
1886: return "Bottom";
1887: }
1888: else if (pos <= BEGV)
1889: return "Top";
1890: else
1891: {
1892: total = ((pos - BEGV) * 100 + total - 1) / total;
1893: /* We can't normally display a 3-digit number,
1894: so get us a 2-digit number that is close. */
1895: if (total == 100)
1896: total = 99;
1897: sprintf (decode_mode_spec_buf, "%2d%%", total);
1898: return decode_mode_spec_buf;
1899: }
1900: }
1901:
1902: case '[':
1903: {
1904: int i;
1905: char *p;
1906: if (command_loop_level > 5)
1907: return "[[[... ";
1908: p = decode_mode_spec_buf;
1909: for (i = 0; i < command_loop_level; i++)
1910: *p++ = '[';
1911: *p = 0;
1912: return decode_mode_spec_buf;
1913: }
1914:
1915: case '%':
1916: return "%";
1917:
1918: case ']':
1919: {
1920: int i;
1921: char *p;
1922: if (command_loop_level > 5)
1923: return " ...]]]";
1924: p = decode_mode_spec_buf;
1925: for (i = 0; i < command_loop_level; i++)
1926: *p++ = ']';
1927: *p = 0;
1928: return decode_mode_spec_buf;
1929: }
1930:
1931: case '-':
1932: {
1933: int i;
1934: if (maxwidth < 140)
1935: return "--------------------------------------------------------------------------------------------------------------------------------------------";
1936: for (i = 0; i < maxwidth; i++)
1937: decode_mode_spec_buf[i] = '-';
1938: return decode_mode_spec_buf;
1939: }
1940: }
1941:
1942: if (XTYPE (obj) == Lisp_String)
1943: return (char *) XSTRING (obj)->data;
1944: else
1945: return "";
1946: }
1947:
1948: /* Display STRING on one line of window W, starting at HPOS.
1949: Display at position VPOS. Caller should do get_display_line first.
1950:
1951: TRUNCATE is character to display at end if truncated. Zero for none.
1952:
1953: MINCOL is the first column ok to end at. (Pad with spaces to this col.)
1954: MAXCOL is the last column ok to end at. Truncate here.
1955: -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
1956: Both count from the left edge of the screen, as does HPOS.
1957: The right edge of W is an implicit maximum.
1958: If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
1959:
1960: Returns ending hpos */
1961:
1962: display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
1963: struct window *w;
1964: int vpos;
1965: unsigned char *string;
1966: int hpos;
1967: char truncate;
1968: int mincol, maxcol;
1969: {
1970: register int c;
1971: register unsigned char *p1;
1972: int hscroll = XINT (w->hscroll);
1973: int tab_width = XINT (current_buffer->tab_width);
1974: register unsigned char *start;
1975: register unsigned char *end;
1976: unsigned char *p1start = new_screen->contents[vpos] + hpos;
1977: int window_width = XFASTINT (w->width);
1978:
1979: if (tab_width <= 0 || tab_width > 20) tab_width = 8;
1980:
1981: p1 = p1start;
1982: start = new_screen->contents[vpos] + XFASTINT (w->left);
1983: end = start + window_width - (truncate != 0);
1984:
1985: if ((window_width + XFASTINT (w->left)) != screen_width)
1986: *end-- = '|';
1987:
1988: if (maxcol >= 0 && end - new_screen->contents[vpos] > maxcol)
1989: end = new_screen->contents[vpos] + maxcol;
1990: if (maxcol >= 0 && mincol > maxcol)
1991: mincol = maxcol;
1992:
1993: while (p1 < end)
1994: {
1995: c = *string++;
1996: if (!c) break;
1997: if (c >= 040 && c < 0177)
1998: {
1999: if (p1 >= start)
2000: *p1 = c;
2001: p1++;
2002: }
2003: else if (c == '\t')
2004: {
2005: do
2006: {
2007: if (p1 >= start && p1 < end)
2008: *p1 = ' ';
2009: p1++;
2010: }
2011: while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
2012: }
2013: else if (c < 0200 && buffer_defaults.ctl_arrow)
2014: {
2015: if (p1 >= start)
2016: *p1 = '^';
2017: p1++;
2018: if (p1 >= start && p1 < end)
2019: *p1 = c ^ 0100;
2020: p1++;
2021: }
2022: else
2023: {
2024: if (p1 >= start)
2025: *p1 = '\\';
2026: p1++;
2027: if (p1 >= start && p1 < end)
2028: *p1 = (c >> 6) + '0';
2029: p1++;
2030: if (p1 >= start && p1 < end)
2031: *p1 = (7 & (c >> 3)) + '0';
2032: p1++;
2033: if (p1 >= start && p1 < end)
2034: *p1 = (7 & c) + '0';
2035: p1++;
2036: }
2037: }
2038:
2039: if (c)
2040: {
2041: p1 = end;
2042: if (truncate) *p1++ = truncate;
2043: }
2044: else if (mincol >= 0)
2045: {
2046: end = new_screen->contents[vpos] + mincol;
2047: while (p1 < end)
2048: *p1++ = ' ';
2049: }
2050:
2051: {
2052: register int len = p1 - new_screen->contents[vpos];
2053: if (len > new_screen->used[vpos])
2054: new_screen->used[vpos] = len;
2055: new_screen->contents[vpos][new_screen->used[vpos]] = 0;
2056: return len;
2057: }
2058: }
2059:
2060: syms_of_xdisp ()
2061: {
2062: staticpro (&last_arrow_position);
2063: staticpro (&last_arrow_string);
2064: last_arrow_position = Qnil;
2065: last_arrow_string = Qnil;
2066:
2067: DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
2068: "String displayed by mode-line-format's \"%m\" specifiation.");
2069: Vglobal_mode_string = Qnil;
2070:
2071: DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
2072: "Marker for where to display an arrow on top of the buffer text.\n\
2073: This must be the beginning of a line in order to work.\n\
2074: See also overlay-arrow-string.");
2075: Voverlay_arrow_position = Qnil;
2076:
2077: DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
2078: "String to display as an arrow. See also overlay-arrow-position.");
2079: Voverlay_arrow_string = Qnil;
2080:
2081: DEFVAR_INT ("scroll-step", &scroll_step,
2082: "*The number of lines to try scrolling a window by when point moves out.\n\
2083: If that fails to bring point back on screen, point is centered instead.\n\
2084: If this is zero, point is always centered after it moves off screen.");
2085:
2086: DEFVAR_BOOL ("reset-terminal-on-clear", &reset_terminal_on_clear,
2087: "Non-nil means re-init terminal modes for clear screen as on entry to Emacs.");
2088: reset_terminal_on_clear = 1;
2089:
2090: DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
2091:
2092: DEFVAR_BOOL ("truncate-partial-width-windows",
2093: &truncate_partial_width_windows,
2094: "*Non-nil means truncate lines in all windows less than full screen wide.");
2095: truncate_partial_width_windows = 1;
2096:
2097: DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
2098: "*Non-nil means use inverse video, or other suitable display mode, for the mode line.");
2099: mode_line_inverse_video = 1;
2100:
2101: defsubr (&Sredraw_display);
2102: }
2103:
2104: /* initialize the window system */
2105: init_xdisp ()
2106: {
2107: Lisp_Object root_window;
2108: #ifndef COMPILER_REGISTER_BUG
2109: register
2110: #endif COMPILER_REGISTER_BUG
2111: struct window *mini_w;
2112:
2113: this_line_bufpos = 0;
2114:
2115: mini_w = XWINDOW (minibuf_window);
2116: root_window = mini_w->prev;
2117:
2118: echo_area_contents = 0;
2119: prev_echo_area_contents = 0;
2120:
2121: if (!noninteractive)
2122: {
2123: XFASTINT (XWINDOW (root_window)->top) = 0;
2124: set_window_height (root_window, screen_height - 1, 0);
2125: XFASTINT (mini_w->top) = screen_height - 1;
2126: set_window_height (minibuf_window, 1, 0);
2127:
2128: XFASTINT (XWINDOW (root_window)->width) = screen_width;
2129: XFASTINT (mini_w->width) = screen_width;
2130: }
2131: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.