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