1 /* display.c -- readline redisplay facility. */
3 /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
5 This file is part of the GNU Readline Library, a library for
6 reading lines of text with interactive input and history editing.
8 The GNU Readline Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 1, or
11 (at your option) any later version.
13 The GNU Readline Library is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 The GNU General Public License is often shipped with GNU software, and
19 is generally kept in a file called COPYING or LICENSE. If you do not
20 have a copy of the license, write to the Free Software Foundation,
21 675 Mass Ave, Cambridge, MA 02139, USA. */
24 #include <sys/types.h>
26 /* System-specific feature definitions and include files. */
29 /* Some standard library routines. */
33 #if !defined (strrchr)
34 extern char *strrchr ();
37 /* Global and pseudo-global variables and functions
38 imported from readline.c. */
39 extern char *rl_prompt
;
40 extern int readline_echoing_p
;
41 extern char *term_clreol
, *term_im
, *term_ic
, *term_ei
, *term_DC
;
42 /* Termcap variables. */
43 extern char *term_up
, *term_dc
, *term_cr
, *term_IC
;
44 extern int screenheight
, screenwidth
, terminal_can_insert
;
46 extern void _rl_output_some_chars ();
47 extern void _rl_output_character_function ();
49 extern int _rl_convert_meta_chars_to_ascii
;
50 extern int _rl_horizontal_scroll_mode
;
51 extern int _rl_mark_modified_lines
;
52 extern int _rl_prefer_visible_bell
;
54 /* Pseudo-global functions (local to the readline library) exported
56 void _rl_move_cursor_relative (), _rl_output_some_chars ();
57 void _rl_move_vert ();
59 static void update_line (), clear_to_eol ();
60 static void delete_chars (), insert_some_chars ();
62 extern char *xmalloc (), *xrealloc ();
64 /* **************************************************************** */
68 /* **************************************************************** */
70 /* This is the stuff that is hard for me. I never seem to write good
71 display routines in C. Let's see how I do this time. */
73 /* (PWP) Well... Good for a simple line updater, but totally ignores
74 the problems of input lines longer than the screen width.
76 update_line and the code that calls it makes a multiple line,
77 automatically wrapping line update. Carefull attention needs
78 to be paid to the vertical position variables.
80 handling of terminals with autowrap on (incl. DEC braindamage)
81 could be improved a bit. Right now I just cheat and decrement
82 screenwidth by one. */
84 /* Keep two buffers; one which reflects the current contents of the
85 screen, and the other to draw what we think the new contents should
86 be. Then compare the buffers, and make whatever changes to the
87 screen itself that we should. Finally, make the buffer that we
88 just drew into be the one which reflects the current contents of the
89 screen, and place the cursor where it belongs.
91 Commands that want to can fix the display themselves, and then let
92 this function know that the display has been fixed by setting the
93 RL_DISPLAY_FIXED variable. This is good for efficiency. */
95 /* What YOU turn on when you have handled all redisplay yourself. */
96 int rl_display_fixed
= 0;
98 /* The stuff that gets printed out before the actual text of the line.
99 This is usually pointing to rl_prompt. */
100 char *rl_display_prompt
= (char *)NULL
;
102 /* Pseudo-global variables declared here. */
103 /* The visible cursor position. If you print some text, adjust this. */
104 int _rl_last_c_pos
= 0;
105 int _rl_last_v_pos
= 0;
107 /* Number of lines currently on screen minus 1. */
108 int _rl_vis_botlin
= 0;
110 /* Variables used only in this file. */
111 /* The last left edge of text that was displayed. This is used when
112 doing horizontal scrolling. It shifts in thirds of a screenwidth. */
113 static int last_lmargin
= 0;
115 /* The line display buffers. One is the line currently displayed on
116 the screen. The other is the line about to be displayed. */
117 static char *visible_line
= (char *)NULL
;
118 static char *invisible_line
= (char *)NULL
;
120 /* A buffer for `modeline' messages. */
121 static char msg_buf
[128];
123 /* Non-zero forces the redisplay even if we thought it was unnecessary. */
124 static int forced_display
= 0;
126 /* Default and initial buffer size. Can grow. */
127 static int line_size
= 1024;
129 /* Basic redisplay algorithm. */
132 register int in
, out
, c
, linenum
;
133 register char *line
= invisible_line
;
134 char *prompt_this_line
;
136 int inv_botlin
= 0; /* Number of lines in newly drawn buffer. */
138 if (!readline_echoing_p
)
141 if (!rl_display_prompt
)
142 rl_display_prompt
= "";
146 visible_line
= (char *)xmalloc (line_size
);
147 invisible_line
= (char *)xmalloc (line_size
);
148 line
= invisible_line
;
149 for (in
= 0; in
< line_size
; in
++)
151 visible_line
[in
] = 0;
152 invisible_line
[in
] = 1;
157 /* Draw the line into the buffer. */
160 /* Mark the line as modified or not. We only do this for history
163 if (_rl_mark_modified_lines
&& current_history () && rl_undo_list
)
169 /* If someone thought that the redisplay was handled, but the currently
170 visible line has a different modification state than the one about
171 to become visible, then correct the caller's misconception. */
172 if (visible_line
[0] != invisible_line
[0])
173 rl_display_fixed
= 0;
175 prompt_this_line
= strrchr (rl_display_prompt
, '\n');
176 if (!prompt_this_line
)
177 prompt_this_line
= rl_display_prompt
;
182 _rl_output_some_chars
183 (rl_display_prompt
, prompt_this_line
- rl_display_prompt
);
186 strncpy (line
+ out
, prompt_this_line
, strlen (prompt_this_line
));
187 out
+= strlen (prompt_this_line
);
190 for (in
= 0; in
< rl_end
; in
++)
192 c
= (unsigned char)rl_line_buffer
[in
];
194 if (out
+ 8 >= line_size
) /* XXX - 8 for \t */
197 visible_line
= (char *)xrealloc (visible_line
, line_size
);
198 invisible_line
= (char *)xrealloc (invisible_line
, line_size
);
199 line
= invisible_line
;
207 if (_rl_convert_meta_chars_to_ascii
)
209 sprintf (line
+ out
, "\\%o", c
);
216 #if defined (DISPLAY_TABS)
219 register int newout
= (out
| (int)7) + 1;
227 line
[out
++] = UNCTRL (c
); /* XXX was c ^ 0x40 */
241 /* PWP: now is when things get a bit hairy. The visible and invisible
242 line buffers are really multiple lines, which would wrap every
243 (screenwidth - 1) characters. Go through each in turn, finding
244 the changed region and updating it. The line order is top to bottom. */
246 /* If we can move the cursor up and down, then use multiple lines,
247 otherwise, let long lines display in a single terminal line, and
248 horizontally scroll it. */
250 if (!_rl_horizontal_scroll_mode
&& term_up
&& *term_up
)
252 int total_screen_chars
= (screenwidth
* screenheight
);
254 if (!rl_display_fixed
|| forced_display
)
258 /* If we have more than a screenful of material to display, then
259 only display a screenful. We should display the last screen,
260 not the first. I'll fix this in a minute. */
261 if (out
>= total_screen_chars
)
262 out
= total_screen_chars
- 1;
264 /* Number of screen lines to display. */
265 inv_botlin
= out
/ screenwidth
;
267 /* For each line in the buffer, do the updating display. */
268 for (linenum
= 0; linenum
<= inv_botlin
; linenum
++)
269 update_line (linenum
> _rl_vis_botlin
? ""
270 : &visible_line
[linenum
* screenwidth
],
271 &invisible_line
[linenum
* screenwidth
],
274 /* We may have deleted some lines. If so, clear the left over
275 blank ones at the bottom out. */
276 if (_rl_vis_botlin
> inv_botlin
)
279 for (; linenum
<= _rl_vis_botlin
; linenum
++)
281 tt
= &visible_line
[linenum
* screenwidth
];
282 _rl_move_vert (linenum
);
283 _rl_move_cursor_relative (0, tt
);
285 ((linenum
== _rl_vis_botlin
) ? strlen (tt
) : screenwidth
);
288 _rl_vis_botlin
= inv_botlin
;
290 /* Move the cursor where it should be. */
291 _rl_move_vert (c_pos
/ screenwidth
);
292 _rl_move_cursor_relative (c_pos
% screenwidth
,
293 &invisible_line
[(c_pos
/ screenwidth
) * screenwidth
]);
296 else /* Do horizontal scrolling. */
300 /* Always at top line. */
303 /* If the display position of the cursor would be off the edge
304 of the screen, start the display of this line at an offset that
305 leaves the cursor on the screen. */
306 if (c_pos
- last_lmargin
> screenwidth
- 2)
307 lmargin
= (c_pos
/ (screenwidth
/ 3) - 2) * (screenwidth
/ 3);
308 else if (c_pos
- last_lmargin
< 1)
309 lmargin
= ((c_pos
- 1) / (screenwidth
/ 3)) * (screenwidth
/ 3);
311 lmargin
= last_lmargin
;
313 /* If the first character on the screen isn't the first character
314 in the display line, indicate this with a special character. */
318 if (lmargin
+ screenwidth
< out
)
319 line
[lmargin
+ screenwidth
- 1] = '>';
321 if (!rl_display_fixed
|| forced_display
|| lmargin
!= last_lmargin
)
324 update_line (&visible_line
[last_lmargin
],
325 &invisible_line
[lmargin
], 0);
327 _rl_move_cursor_relative (c_pos
- lmargin
, &invisible_line
[lmargin
]);
328 last_lmargin
= lmargin
;
331 fflush (rl_outstream
);
333 /* Swap visible and non-visible lines. */
335 char *temp
= visible_line
;
336 visible_line
= invisible_line
;
337 invisible_line
= temp
;
338 rl_display_fixed
= 0;
342 /* PWP: update_line() is based on finding the middle difference of each
343 line on the screen; vis:
345 /old first difference
346 /beginning of line | /old last same /old EOL
348 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
349 new: eddie> Oh, my little buggy says to me, as lurgid as
351 \beginning of line | \new last same \new end of line
352 \new first difference
354 All are character pointers for the sake of speed. Special cases for
355 no differences, as well as for end of line additions must be handeled.
357 Could be made even smarter, but this works well enough */
359 update_line (old
, new, current_line
)
360 register char *old
, *new;
363 register char *ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
364 int lendiff
, wsatend
;
366 /* Find first difference. */
367 for (ofd
= old
, nfd
= new;
368 (ofd
- old
< screenwidth
) && *ofd
&& (*ofd
== *nfd
);
372 /* Move to the end of the screen line. */
373 for (oe
= ofd
; ((oe
- old
) < screenwidth
) && *oe
; oe
++);
374 for (ne
= nfd
; ((ne
- new) < screenwidth
) && *ne
; ne
++);
376 /* If no difference, continue to next line. */
377 if (ofd
== oe
&& nfd
== ne
)
380 wsatend
= 1; /* flag for trailing whitespace */
381 ols
= oe
- 1; /* find last same */
383 while ((ols
> ofd
) && (nls
> nfd
) && (*ols
== *nls
))
396 else if (*ols
!= *nls
)
398 if (*ols
) /* don't step past the NUL */
404 _rl_move_vert (current_line
);
405 _rl_move_cursor_relative (ofd
- old
, old
);
407 /* if (len (new) > len (old)) */
408 lendiff
= (nls
- nfd
) - (ols
- ofd
);
410 /* Insert (diff (len (old), len (new)) ch. */
413 if (terminal_can_insert
)
415 /* Sometimes it is cheaper to print the characters rather than
416 use the terminal's capabilities. */
417 if ((2 * (ne
- nfd
)) < lendiff
&& !term_IC
)
419 _rl_output_some_chars (nfd
, (ne
- nfd
));
420 _rl_last_c_pos
+= (ne
- nfd
);
426 insert_some_chars (nfd
, lendiff
);
427 _rl_last_c_pos
+= lendiff
;
431 /* At the end of a line the characters do not have to
432 be "inserted". They can just be placed on the screen. */
433 _rl_output_some_chars (nfd
, lendiff
);
434 _rl_last_c_pos
+= lendiff
;
436 /* Copy (new) chars to screen from first diff to last match. */
437 if (((nls
- nfd
) - lendiff
) > 0)
439 _rl_output_some_chars (&nfd
[lendiff
], ((nls
- nfd
) - lendiff
));
440 _rl_last_c_pos
+= ((nls
- nfd
) - lendiff
);
445 { /* cannot insert chars, write to EOL */
446 _rl_output_some_chars (nfd
, (ne
- nfd
));
447 _rl_last_c_pos
+= (ne
- nfd
);
450 else /* Delete characters from line. */
452 /* If possible and inexpensive to use terminal deletion, then do so. */
453 if (term_dc
&& (2 * (ne
- nfd
)) >= (-lendiff
))
456 delete_chars (-lendiff
); /* delete (diff) characters */
458 /* Copy (new) chars to screen from first diff to last match */
461 _rl_output_some_chars (nfd
, (nls
- nfd
));
462 _rl_last_c_pos
+= (nls
- nfd
);
465 /* Otherwise, print over the existing material. */
468 _rl_output_some_chars (nfd
, (ne
- nfd
));
469 _rl_last_c_pos
+= (ne
- nfd
);
470 clear_to_eol ((oe
- old
) - (ne
- new));
475 /* Tell the update routines that we have moved onto a new (empty) line. */
479 visible_line
[0] = '\0';
481 _rl_last_c_pos
= _rl_last_v_pos
= 0;
482 _rl_vis_botlin
= last_lmargin
= 0;
485 /* Actually update the display, period. */
486 rl_forced_update_display ()
490 register char *temp
= visible_line
;
492 while (*temp
) *temp
++ = '\0';
499 /* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
500 DATA is the contents of the screen line of interest; i.e., where
501 the movement is being done. */
503 _rl_move_cursor_relative (new, data
)
509 /* It may be faster to output a CR, and then move forwards instead
510 of moving backwards. */
511 if (new + 1 < _rl_last_c_pos
- new)
514 putc('\r', rl_outstream
);
516 tputs (term_cr
, 1, _rl_output_character_function
);
521 if (_rl_last_c_pos
== new) return;
523 if (_rl_last_c_pos
< new)
525 /* Move the cursor forward. We do it by printing the command
526 to move the cursor forward if there is one, else print that
527 portion of the output buffer again. Which is cheaper? */
529 /* The above comment is left here for posterity. It is faster
530 to print one character (non-control) than to print a control
531 sequence telling the terminal to move forward one character.
532 That kind of control is for people who don't know what the
533 data is underneath the cursor. */
534 #if defined (HACK_TERMCAP_MOTION)
535 extern char *term_forward_char
;
537 if (term_forward_char
)
538 for (i
= _rl_last_c_pos
; i
< new; i
++)
539 tputs (term_forward_char
, 1, _rl_output_character_function
);
541 for (i
= _rl_last_c_pos
; i
< new; i
++)
542 putc (data
[i
], rl_outstream
);
544 for (i
= _rl_last_c_pos
; i
< new; i
++)
545 putc (data
[i
], rl_outstream
);
546 #endif /* HACK_TERMCAP_MOTION */
549 backspace (_rl_last_c_pos
- new);
550 _rl_last_c_pos
= new;
553 /* PWP: move the cursor up or down. */
558 register int delta
, i
;
560 if (_rl_last_v_pos
== to
|| to
> screenheight
)
566 ScreenGetCursor (&row
, &col
);
567 ScreenSetCursor ((row
+ to
- _rl_last_v_pos
), col
);
570 if ((delta
= to
- _rl_last_v_pos
) > 0)
572 for (i
= 0; i
< delta
; i
++)
573 putc ('\n', rl_outstream
);
574 tputs (term_cr
, 1, _rl_output_character_function
);
579 if (term_up
&& *term_up
)
580 for (i
= 0; i
< -delta
; i
++)
581 tputs (term_up
, 1, _rl_output_character_function
);
583 #endif /* !__GO32__ */
584 _rl_last_v_pos
= to
; /* Now TO is here */
587 /* Physically print C on rl_outstream. This is for functions which know
588 how to optimize the display. */
592 if (META_CHAR (c
) && _rl_convert_meta_chars_to_ascii
)
594 fprintf (rl_outstream
, "M-");
598 #if defined (DISPLAY_TABS)
599 if (c
< 32 && c
!= '\t')
602 #endif /* !DISPLAY_TABS */
608 putc (c
, rl_outstream
);
609 fflush (rl_outstream
);
613 rl_character_len (c
, pos
)
617 return (_rl_convert_meta_chars_to_ascii
? 4 : 1);
621 #if defined (DISPLAY_TABS)
622 return (((pos
| (int)7) + 1) - pos
);
625 #endif /* !DISPLAY_TABS */
634 /* How to print things in the "echo-area". The prompt is treated as a
637 #if defined (HAVE_VARARGS_H)
638 rl_message (va_alist
)
645 format
= va_arg (args
, char *);
646 vsprintf (msg_buf
, format
, args
);
649 rl_display_prompt
= msg_buf
;
652 #else /* !HAVE_VARARGS_H */
653 rl_message (format
, arg1
, arg2
)
656 sprintf (msg_buf
, format
, arg1
, arg2
);
657 rl_display_prompt
= msg_buf
;
660 #endif /* !HAVE_VARARGS_H */
662 /* How to clear things from the "echo-area". */
665 rl_display_prompt
= rl_prompt
;
669 rl_reset_line_state ()
673 rl_display_prompt
= rl_prompt
? rl_prompt
: "";
677 /* Quick redisplay hack when erasing characters at the end of the line. */
679 _rl_erase_at_end_of_line (l
)
685 for (i
= 0; i
< l
; i
++)
686 putc (' ', rl_outstream
);
688 for (i
= 0; i
< l
; i
++)
689 visible_line
[--_rl_last_c_pos
] = '\0';
693 /* Clear to the end of the line. COUNT is the minimum
694 number of character spaces to clear, */
702 tputs (term_clreol
, 1, _rl_output_character_function
);
705 #endif /* !__GO32__ */
709 /* Do one more character space. */
712 for (i
= 0; i
< count
; i
++)
713 putc (' ', rl_outstream
);
718 /* Insert COUNT characters from STRING to the output stream. */
720 insert_some_chars (string
, count
)
728 ScreenGetCursor (&row
, &col
);
729 width
= ScreenCols ();
730 row_start
= ScreenPrimary
+ (row
* width
);
731 memcpy (row_start
+ col
+ count
, row_start
+ col
, width
- col
- count
);
732 /* Place the text on the screen. */
733 _rl_output_some_chars (string
, count
);
735 /* If IC is defined, then we do not have to "enter" insert mode. */
738 char *tgoto (), *buffer
;
739 buffer
= tgoto (term_IC
, 0, count
);
740 tputs (buffer
, 1, _rl_output_character_function
);
741 _rl_output_some_chars (string
, count
);
747 /* If we have to turn on insert-mode, then do so. */
748 if (term_im
&& *term_im
)
749 tputs (term_im
, 1, _rl_output_character_function
);
751 /* If there is a special command for inserting characters, then
752 use that first to open up the space. */
753 if (term_ic
&& *term_ic
)
755 for (i
= count
; i
--; )
756 tputs (term_ic
, 1, _rl_output_character_function
);
759 /* Print the text. */
760 _rl_output_some_chars (string
, count
);
762 /* If there is a string to turn off insert mode, we had best use
764 if (term_ei
&& *term_ei
)
765 tputs (term_ei
, 1, _rl_output_character_function
);
767 #endif /* __GO32__ */
770 /* Delete COUNT characters from the display line. */
775 #if defined (__GO32__)
779 ScreenGetCursor (&row
, &col
);
780 width
= ScreenCols ();
781 row_start
= ScreenPrimary
+ (row
* width
);
782 memcpy (row_start
+ col
, row_start
+ col
+ count
, width
- col
- count
);
783 memset (row_start
+ width
- count
, 0, count
* 2);
784 #else /* !__GO32__ */
785 if (count
> screenwidth
)
788 if (term_DC
&& *term_DC
)
790 char *tgoto (), *buffer
;
791 buffer
= tgoto (term_DC
, 0, count
);
792 tputs (buffer
, 1, _rl_output_character_function
);
796 if (term_dc
&& *term_dc
)
798 tputs (term_dc
, 1, _rl_output_character_function
);
800 #endif /* !__GO32__ */