display.c revision 47563
121308Sache/* display.c -- readline redisplay facility. */ 221308Sache 321308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. 421308Sache 521308Sache This file is part of the GNU Readline Library, a library for 621308Sache reading lines of text with interactive input and history editing. 721308Sache 821308Sache The GNU Readline Library is free software; you can redistribute it 921308Sache and/or modify it under the terms of the GNU General Public License 1021308Sache as published by the Free Software Foundation; either version 1, or 1121308Sache (at your option) any later version. 1221308Sache 1321308Sache The GNU Readline Library is distributed in the hope that it will be 1421308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1521308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1621308Sache GNU General Public License for more details. 1721308Sache 1821308Sache The GNU General Public License is often shipped with GNU software, and 1921308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2021308Sache have a copy of the license, write to the Free Software Foundation, 2121308Sache 675 Mass Ave, Cambridge, MA 02139, USA. */ 2221308Sache#define READLINE_LIBRARY 2321308Sache 2421308Sache#if defined (HAVE_CONFIG_H) 2521308Sache# include <config.h> 2621308Sache#endif 2721308Sache 2821308Sache#include <sys/types.h> 2921308Sache 3021308Sache#if defined (HAVE_UNISTD_H) 3121308Sache# include <unistd.h> 3221308Sache#endif /* HAVE_UNISTD_H */ 3321308Sache 3426497Sache#include "posixstat.h" 3526497Sache 3621308Sache#if defined (HAVE_STDLIB_H) 3721308Sache# include <stdlib.h> 3821308Sache#else 3921308Sache# include "ansi_stdlib.h" 4021308Sache#endif /* HAVE_STDLIB_H */ 4121308Sache 4226497Sache#include <stdio.h> 4321308Sache 4426497Sache#if defined (__GO32__) 4526497Sache# include <go32.h> 4626497Sache# include <pc.h> 4726497Sache#endif /* __GO32__ */ 4826497Sache 4921308Sache/* System-specific feature definitions and include files. */ 5021308Sache#include "rldefs.h" 5121308Sache 5221308Sache/* Termcap library stuff. */ 5321308Sache#include "tcap.h" 5421308Sache 5521308Sache/* Some standard library routines. */ 5621308Sache#include "readline.h" 5721308Sache#include "history.h" 5821308Sache 5921308Sache#if !defined (strchr) && !defined (__STDC__) 6021308Sacheextern char *strchr (), *strrchr (); 6121308Sache#endif /* !strchr && !__STDC__ */ 6221308Sache 6321308Sache/* Global and pseudo-global variables and functions 6421308Sache imported from readline.c. */ 6521308Sacheextern char *rl_prompt; 6621308Sacheextern int readline_echoing_p; 6721308Sache 6821308Sacheextern int _rl_output_meta_chars; 6921308Sacheextern int _rl_horizontal_scroll_mode; 7021308Sacheextern int _rl_mark_modified_lines; 7121308Sacheextern int _rl_prefer_visible_bell; 7221308Sache 7321308Sache/* Variables and functions imported from terminal.c */ 7421308Sacheextern void _rl_output_some_chars (); 7535486Sache#ifdef _MINIX 7635486Sacheextern void _rl_output_character_function (); 7735486Sache#else 7821308Sacheextern int _rl_output_character_function (); 7935486Sache#endif 8021308Sacheextern int _rl_backspace (); 8121308Sache 8226497Sacheextern char *term_clreol, *term_clrpag; 8326497Sacheextern char *term_im, *term_ic, *term_ei, *term_DC; 8421308Sacheextern char *term_up, *term_dc, *term_cr, *term_IC; 8521308Sacheextern int screenheight, screenwidth, screenchars; 8621308Sacheextern int terminal_can_insert, _rl_term_autowrap; 8721308Sache 8821308Sache/* Pseudo-global functions (local to the readline library) exported 8921308Sache by this file. */ 9021308Sachevoid _rl_move_cursor_relative (), _rl_output_some_chars (); 9121308Sachevoid _rl_move_vert (); 9226497Sachevoid _rl_clear_to_eol (), _rl_clear_screen (); 9321308Sache 9426497Sachestatic void update_line (), space_to_eol (); 9521308Sachestatic void delete_chars (), insert_some_chars (); 9621308Sachestatic void cr (); 9721308Sache 9821308Sachestatic int *inv_lbreaks, *vis_lbreaks; 9921308Sache 10021308Sacheextern char *xmalloc (), *xrealloc (); 10121308Sache 10221308Sache/* Heuristic used to decide whether it is faster to move from CUR to NEW 10321308Sache by backing up or outputting a carriage return and moving forward. */ 10421308Sache#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) 10521308Sache 10621308Sache/* **************************************************************** */ 10721308Sache/* */ 10821308Sache/* Display stuff */ 10921308Sache/* */ 11021308Sache/* **************************************************************** */ 11121308Sache 11221308Sache/* This is the stuff that is hard for me. I never seem to write good 11321308Sache display routines in C. Let's see how I do this time. */ 11421308Sache 11521308Sache/* (PWP) Well... Good for a simple line updater, but totally ignores 11621308Sache the problems of input lines longer than the screen width. 11721308Sache 11821308Sache update_line and the code that calls it makes a multiple line, 11921308Sache automatically wrapping line update. Careful attention needs 12021308Sache to be paid to the vertical position variables. */ 12121308Sache 12221308Sache/* Keep two buffers; one which reflects the current contents of the 12321308Sache screen, and the other to draw what we think the new contents should 12421308Sache be. Then compare the buffers, and make whatever changes to the 12521308Sache screen itself that we should. Finally, make the buffer that we 12621308Sache just drew into be the one which reflects the current contents of the 12721308Sache screen, and place the cursor where it belongs. 12821308Sache 12921308Sache Commands that want to can fix the display themselves, and then let 13021308Sache this function know that the display has been fixed by setting the 13121308Sache RL_DISPLAY_FIXED variable. This is good for efficiency. */ 13221308Sache 13321308Sache/* Application-specific redisplay function. */ 13421308SacheVFunction *rl_redisplay_function = rl_redisplay; 13521308Sache 13621308Sache/* Global variables declared here. */ 13721308Sache/* What YOU turn on when you have handled all redisplay yourself. */ 13821308Sacheint rl_display_fixed = 0; 13921308Sache 14021308Sacheint _rl_suppress_redisplay = 0; 14121308Sache 14221308Sache/* The stuff that gets printed out before the actual text of the line. 14321308Sache This is usually pointing to rl_prompt. */ 14421308Sachechar *rl_display_prompt = (char *)NULL; 14521308Sache 14621308Sache/* Pseudo-global variables declared here. */ 14721308Sache/* The visible cursor position. If you print some text, adjust this. */ 14821308Sacheint _rl_last_c_pos = 0; 14921308Sacheint _rl_last_v_pos = 0; 15021308Sache 15121308Sache/* Number of lines currently on screen minus 1. */ 15221308Sacheint _rl_vis_botlin = 0; 15321308Sache 15421308Sache/* Variables used only in this file. */ 15521308Sache/* The last left edge of text that was displayed. This is used when 15621308Sache doing horizontal scrolling. It shifts in thirds of a screenwidth. */ 15721308Sachestatic int last_lmargin; 15821308Sache 15921308Sache/* The line display buffers. One is the line currently displayed on 16021308Sache the screen. The other is the line about to be displayed. */ 16121308Sachestatic char *visible_line = (char *)NULL; 16221308Sachestatic char *invisible_line = (char *)NULL; 16321308Sache 16421308Sache/* A buffer for `modeline' messages. */ 16521308Sachestatic char msg_buf[128]; 16621308Sache 16721308Sache/* Non-zero forces the redisplay even if we thought it was unnecessary. */ 16821308Sachestatic int forced_display; 16921308Sache 17021308Sache/* Default and initial buffer size. Can grow. */ 17121308Sachestatic int line_size = 1024; 17221308Sache 17321308Sachestatic char *local_prompt, *local_prompt_prefix; 17421308Sachestatic int visible_length, prefix_length; 17521308Sache 17621308Sache/* The number of invisible characters in the line currently being 17721308Sache displayed on the screen. */ 17821308Sachestatic int visible_wrap_offset; 17921308Sache 18021308Sache/* static so it can be shared between rl_redisplay and update_line */ 18121308Sachestatic int wrap_offset; 18221308Sache 18321308Sache/* The index of the last invisible_character in the prompt string. */ 18421308Sachestatic int last_invisible; 18521308Sache 18621308Sache/* The length (buffer offset) of the first line of the last (possibly 18721308Sache multi-line) buffer displayed on the screen. */ 18821308Sachestatic int visible_first_line_len; 18921308Sache 19021308Sache/* Expand the prompt string S and return the number of visible 19121308Sache characters in *LP, if LP is not null. This is currently more-or-less 19221308Sache a placeholder for expansion. LIP, if non-null is a place to store the 19321308Sache index of the last invisible character in ther eturned string. */ 19421308Sache 19521308Sache/* Current implementation: 19621308Sache \001 (^A) start non-visible characters 19721308Sache \002 (^B) end non-visible characters 19821308Sache all characters except \001 and \002 (following a \001) are copied to 19921308Sache the returned string; all characters except those between \001 and 20021308Sache \002 are assumed to be `visible'. */ 20121308Sache 20221308Sachestatic char * 20321308Sacheexpand_prompt (pmt, lp, lip) 20421308Sache char *pmt; 20521308Sache int *lp, *lip; 20621308Sache{ 20721308Sache char *r, *ret, *p; 20821308Sache int l, rl, last, ignoring; 20921308Sache 21021308Sache /* Short-circuit if we can. */ 21121308Sache if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0) 21221308Sache { 21321308Sache r = savestring (pmt); 21421308Sache if (lp) 21521308Sache *lp = strlen (r); 21621308Sache return r; 21721308Sache } 21821308Sache 21921308Sache l = strlen (pmt); 22021308Sache r = ret = xmalloc (l + 1); 22121308Sache 22221308Sache for (rl = ignoring = last = 0, p = pmt; p && *p; p++) 22321308Sache { 22421308Sache /* This code strips the invisible character string markers 22521308Sache RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ 22621308Sache if (*p == RL_PROMPT_START_IGNORE) 22721308Sache { 22821308Sache ignoring++; 22921308Sache continue; 23021308Sache } 23121308Sache else if (ignoring && *p == RL_PROMPT_END_IGNORE) 23221308Sache { 23321308Sache ignoring = 0; 23421308Sache last = r - ret - 1; 23521308Sache continue; 23621308Sache } 23721308Sache else 23821308Sache { 23921308Sache *r++ = *p; 24021308Sache if (!ignoring) 24121308Sache rl++; 24221308Sache } 24321308Sache } 24421308Sache 24521308Sache *r = '\0'; 24621308Sache if (lp) 24721308Sache *lp = rl; 24821308Sache if (lip) 24921308Sache *lip = last; 25021308Sache return ret; 25121308Sache} 25221308Sache 25321308Sache/* 25421308Sache * Expand the prompt string into the various display components, if 25521308Sache * necessary. 25621308Sache * 25721308Sache * local_prompt = expanded last line of string in rl_display_prompt 25821308Sache * (portion after the final newline) 25921308Sache * local_prompt_prefix = portion before last newline of rl_display_prompt, 26021308Sache * expanded via expand_prompt 26121308Sache * visible_length = number of visible characters in local_prompt 26221308Sache * prefix_length = number of visible characters in local_prompt_prefix 26321308Sache * 26421308Sache * This function is called once per call to readline(). It may also be 26521308Sache * called arbitrarily to expand the primary prompt. 26621308Sache * 26721308Sache * The return value is the number of visible characters on the last line 26821308Sache * of the (possibly multi-line) prompt. 26921308Sache */ 27021308Sacheint 27121308Sacherl_expand_prompt (prompt) 27221308Sache char *prompt; 27321308Sache{ 27421308Sache char *p, *t; 27521308Sache int c; 27621308Sache 27721308Sache /* Clear out any saved values. */ 27821308Sache if (local_prompt) 27921308Sache free (local_prompt); 28021308Sache if (local_prompt_prefix) 28121308Sache free (local_prompt_prefix); 28221308Sache local_prompt = local_prompt_prefix = (char *)0; 28347563Sache last_invisible = visible_length = 0; 28421308Sache 28521308Sache if (prompt == 0 || *prompt == 0) 28621308Sache return (0); 28721308Sache 28821308Sache p = strrchr (prompt, '\n'); 28921308Sache if (!p) 29021308Sache { 29121308Sache /* The prompt is only one line. */ 29221308Sache local_prompt = expand_prompt (prompt, &visible_length, &last_invisible); 29321308Sache local_prompt_prefix = (char *)0; 29421308Sache return (visible_length); 29521308Sache } 29621308Sache else 29721308Sache { 29821308Sache /* The prompt spans multiple lines. */ 29921308Sache t = ++p; 30021308Sache local_prompt = expand_prompt (p, &visible_length, &last_invisible); 30121308Sache c = *t; *t = '\0'; 30221308Sache /* The portion of the prompt string up to and including the 30321308Sache final newline is now null-terminated. */ 30421308Sache local_prompt_prefix = expand_prompt (prompt, &prefix_length, (int *)NULL); 30521308Sache *t = c; 30621308Sache return (prefix_length); 30721308Sache } 30821308Sache} 30921308Sache 31021308Sache/* Basic redisplay algorithm. */ 31121308Sachevoid 31221308Sacherl_redisplay () 31321308Sache{ 31421308Sache register int in, out, c, linenum, cursor_linenum; 31521308Sache register char *line; 31621308Sache int c_pos, inv_botlin, lb_botlin, lb_linenum; 31726497Sache int newlines, lpos, temp; 31821308Sache char *prompt_this_line; 31921308Sache 32021308Sache if (!readline_echoing_p) 32121308Sache return; 32221308Sache 32321308Sache if (!rl_display_prompt) 32421308Sache rl_display_prompt = ""; 32521308Sache 32621308Sache if (invisible_line == 0) 32721308Sache { 32821308Sache visible_line = xmalloc (line_size); 32921308Sache invisible_line = xmalloc (line_size); 33021308Sache for (in = 0; in < line_size; in++) 33121308Sache { 33221308Sache visible_line[in] = 0; 33321308Sache invisible_line[in] = 1; 33421308Sache } 33521308Sache 33621308Sache /* should be enough, but then again, this is just for testing. */ 33721308Sache inv_lbreaks = (int *)malloc (256 * sizeof (int)); 33821308Sache vis_lbreaks = (int *)malloc (256 * sizeof (int)); 33921308Sache inv_lbreaks[0] = vis_lbreaks[0] = 0; 34021308Sache 34121308Sache rl_on_new_line (); 34221308Sache } 34321308Sache 34421308Sache /* Draw the line into the buffer. */ 34521308Sache c_pos = -1; 34621308Sache 34721308Sache line = invisible_line; 34821308Sache out = inv_botlin = 0; 34921308Sache 35021308Sache /* Mark the line as modified or not. We only do this for history 35121308Sache lines. */ 35221308Sache if (_rl_mark_modified_lines && current_history () && rl_undo_list) 35321308Sache { 35421308Sache line[out++] = '*'; 35521308Sache line[out] = '\0'; 35621308Sache } 35721308Sache 35821308Sache /* If someone thought that the redisplay was handled, but the currently 35921308Sache visible line has a different modification state than the one about 36021308Sache to become visible, then correct the caller's misconception. */ 36121308Sache if (visible_line[0] != invisible_line[0]) 36221308Sache rl_display_fixed = 0; 36321308Sache 36421308Sache /* If the prompt to be displayed is the `primary' readline prompt (the 36521308Sache one passed to readline()), use the values we have already expanded. 36621308Sache If not, use what's already in rl_display_prompt. WRAP_OFFSET is the 36721308Sache number of non-visible characters in the prompt string. */ 36821308Sache if (rl_display_prompt == rl_prompt || local_prompt) 36921308Sache { 37021308Sache int local_len = local_prompt ? strlen (local_prompt) : 0; 37121308Sache if (local_prompt_prefix && forced_display) 37221308Sache _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); 37321308Sache 37421308Sache if (local_len > 0) 37521308Sache { 37647563Sache temp = local_len + out + 2; 37747563Sache if (temp >= line_size) 37847563Sache { 37947563Sache line_size = (temp + 1024) - (temp % 1024); 38047563Sache visible_line = xrealloc (visible_line, line_size); 38147563Sache line = invisible_line = xrealloc (invisible_line, line_size); 38247563Sache } 38321308Sache strncpy (line + out, local_prompt, local_len); 38421308Sache out += local_len; 38521308Sache } 38621308Sache line[out] = '\0'; 38721308Sache wrap_offset = local_len - visible_length; 38821308Sache } 38921308Sache else 39021308Sache { 39121308Sache int pmtlen; 39221308Sache prompt_this_line = strrchr (rl_display_prompt, '\n'); 39321308Sache if (!prompt_this_line) 39421308Sache prompt_this_line = rl_display_prompt; 39521308Sache else 39621308Sache { 39721308Sache prompt_this_line++; 39821308Sache if (forced_display) 39921308Sache { 40021308Sache _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt); 40121308Sache /* Make sure we are at column zero even after a newline, 40221308Sache regardless of the state of terminal output processing. */ 40321308Sache if (prompt_this_line[-2] != '\r') 40421308Sache cr (); 40521308Sache } 40621308Sache } 40721308Sache 40821308Sache pmtlen = strlen (prompt_this_line); 40947563Sache temp = pmtlen + out + 2; 41047563Sache if (temp >= line_size) 41147563Sache { 41247563Sache line_size = (temp + 1024) - (temp % 1024); 41347563Sache visible_line = xrealloc (visible_line, line_size); 41447563Sache line = invisible_line = xrealloc (invisible_line, line_size); 41547563Sache } 41621308Sache strncpy (line + out, prompt_this_line, pmtlen); 41721308Sache out += pmtlen; 41821308Sache line[out] = '\0'; 41921308Sache wrap_offset = 0; 42021308Sache } 42121308Sache 42221308Sache#define CHECK_LPOS() \ 42321308Sache do { \ 42447563Sache lpos++; \ 42547563Sache if (lpos >= screenwidth) \ 42647563Sache { \ 42747563Sache inv_lbreaks[++newlines] = out; \ 42847563Sache lpos = 0; \ 42947563Sache } \ 43021308Sache } while (0) 43121308Sache 43221308Sache /* inv_lbreaks[i] is where line i starts in the buffer. */ 43321308Sache inv_lbreaks[newlines = 0] = 0; 43426497Sache lpos = out - wrap_offset; 43521308Sache 43626497Sache /* XXX - what if lpos is already >= screenwidth before we start drawing the 43726497Sache contents of the command line? */ 43826497Sache while (lpos >= screenwidth) 43921308Sache { 44036328Sdes#if 0 44126497Sache temp = ((newlines + 1) * screenwidth) - ((newlines == 0) ? wrap_offset : 0); 44236328Sdes#else 44336328Sdes /* XXX - possible fix from Darin Johnson <darin@acuson.com> for prompt 44447563Sache string with invisible characters that is longer than the screen 44547563Sache width. */ 44636328Sdes temp = ((newlines + 1) * screenwidth) + ((newlines == 0) ? wrap_offset : 0); 44736328Sdes#endif 44826497Sache inv_lbreaks[++newlines] = temp; 44926497Sache lpos -= screenwidth; 45026497Sache } 45126497Sache 45226497Sache lb_linenum = 0; 45326497Sache for (in = 0; in < rl_end; in++) 45426497Sache { 45521308Sache c = (unsigned char)rl_line_buffer[in]; 45621308Sache 45721308Sache if (out + 8 >= line_size) /* XXX - 8 for \t */ 45821308Sache { 45921308Sache line_size *= 2; 46021308Sache visible_line = xrealloc (visible_line, line_size); 46121308Sache invisible_line = xrealloc (invisible_line, line_size); 46221308Sache line = invisible_line; 46321308Sache } 46421308Sache 46521308Sache if (in == rl_point) 46621308Sache { 46721308Sache c_pos = out; 46821308Sache lb_linenum = newlines; 46921308Sache } 47021308Sache 47121308Sache if (META_CHAR (c)) 47221308Sache { 47321308Sache if (_rl_output_meta_chars == 0) 47421308Sache { 47521308Sache sprintf (line + out, "\\%o", c); 47621308Sache 47721308Sache if (lpos + 4 >= screenwidth) 47821308Sache { 47921308Sache temp = screenwidth - lpos; 48021308Sache inv_lbreaks[++newlines] = out + temp; 48121308Sache lpos = 4 - temp; 48221308Sache } 48321308Sache else 48421308Sache lpos += 4; 48521308Sache 48621308Sache out += 4; 48721308Sache } 48821308Sache else 48921308Sache { 49021308Sache line[out++] = c; 49121308Sache CHECK_LPOS(); 49221308Sache } 49321308Sache } 49421308Sache#if defined (DISPLAY_TABS) 49521308Sache else if (c == '\t') 49621308Sache { 49721308Sache register int temp, newout; 49847563Sache 49947563Sache#if 0 50021308Sache newout = (out | (int)7) + 1; 50147563Sache#else 50247563Sache newout = out + 8 - lpos % 8; 50347563Sache#endif 50421308Sache temp = newout - out; 50521308Sache if (lpos + temp >= screenwidth) 50621308Sache { 50721308Sache register int temp2; 50821308Sache temp2 = screenwidth - lpos; 50921308Sache inv_lbreaks[++newlines] = out + temp2; 51021308Sache lpos = temp - temp2; 51121308Sache while (out < newout) 51221308Sache line[out++] = ' '; 51321308Sache } 51421308Sache else 51521308Sache { 51621308Sache while (out < newout) 51721308Sache line[out++] = ' '; 51821308Sache lpos += temp; 51921308Sache } 52021308Sache } 52121308Sache#endif 52221308Sache else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && term_up && *term_up) 52347563Sache { 52447563Sache line[out++] = '\0'; /* XXX - sentinel */ 52547563Sache inv_lbreaks[++newlines] = out; 52647563Sache lpos = 0; 52747563Sache } 52821308Sache else if (CTRL_CHAR (c) || c == RUBOUT) 52921308Sache { 53021308Sache line[out++] = '^'; 53121308Sache CHECK_LPOS(); 53221308Sache line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; 53321308Sache CHECK_LPOS(); 53421308Sache } 53521308Sache else 53621308Sache { 53721308Sache line[out++] = c; 53821308Sache CHECK_LPOS(); 53921308Sache } 54021308Sache } 54121308Sache line[out] = '\0'; 54221308Sache if (c_pos < 0) 54321308Sache { 54421308Sache c_pos = out; 54521308Sache lb_linenum = newlines; 54621308Sache } 54721308Sache 54821308Sache inv_botlin = lb_botlin = newlines; 54921308Sache inv_lbreaks[newlines+1] = out; 55021308Sache cursor_linenum = lb_linenum; 55121308Sache 55221308Sache /* C_POS == position in buffer where cursor should be placed. */ 55321308Sache 55421308Sache /* PWP: now is when things get a bit hairy. The visible and invisible 55521308Sache line buffers are really multiple lines, which would wrap every 55621308Sache (screenwidth - 1) characters. Go through each in turn, finding 55721308Sache the changed region and updating it. The line order is top to bottom. */ 55821308Sache 55921308Sache /* If we can move the cursor up and down, then use multiple lines, 56021308Sache otherwise, let long lines display in a single terminal line, and 56121308Sache horizontally scroll it. */ 56221308Sache 56321308Sache if (_rl_horizontal_scroll_mode == 0 && term_up && *term_up) 56421308Sache { 56521308Sache int nleft, pos, changed_screen_line; 56621308Sache 56721308Sache if (!rl_display_fixed || forced_display) 56821308Sache { 56921308Sache forced_display = 0; 57021308Sache 57121308Sache /* If we have more than a screenful of material to display, then 57221308Sache only display a screenful. We should display the last screen, 57321308Sache not the first. */ 57421308Sache if (out >= screenchars) 57521308Sache out = screenchars - 1; 57621308Sache 57721308Sache /* The first line is at character position 0 in the buffer. The 57821308Sache second and subsequent lines start at inv_lbreaks[N], offset by 57921308Sache OFFSET (which has already been calculated above). */ 58021308Sache 58121308Sache#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0) 58221308Sache#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) 58321308Sache#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) 58421308Sache#define VIS_CHARS(line) (visible_line + vis_lbreaks[line]) 58521308Sache#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) 58621308Sache#define INV_LINE(line) (invisible_line + inv_lbreaks[line]) 58721308Sache 58821308Sache /* For each line in the buffer, do the updating display. */ 58921308Sache for (linenum = 0; linenum <= inv_botlin; linenum++) 59021308Sache { 59121308Sache update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, 59221308Sache VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); 59321308Sache 59421308Sache /* If this is the line with the prompt, we might need to 59521308Sache compensate for invisible characters in the new line. Do 59621308Sache this only if there is not more than one new line (which 59721308Sache implies that we completely overwrite the old visible line) 59821308Sache and the new line is shorter than the old. Make sure we are 59921308Sache at the end of the new line before clearing. */ 60021308Sache if (linenum == 0 && 60121308Sache inv_botlin == 0 && _rl_last_c_pos == out && 60221308Sache (wrap_offset > visible_wrap_offset) && 60321308Sache (_rl_last_c_pos < visible_first_line_len)) 60421308Sache { 60521308Sache nleft = screenwidth + wrap_offset - _rl_last_c_pos; 60621308Sache if (nleft) 60726497Sache _rl_clear_to_eol (nleft); 60821308Sache } 60921308Sache 61021308Sache /* Since the new first line is now visible, save its length. */ 61121308Sache if (linenum == 0) 61221308Sache visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset; 61321308Sache } 61421308Sache 61521308Sache /* We may have deleted some lines. If so, clear the left over 61621308Sache blank ones at the bottom out. */ 61721308Sache if (_rl_vis_botlin > inv_botlin) 61821308Sache { 61921308Sache char *tt; 62021308Sache for (; linenum <= _rl_vis_botlin; linenum++) 62121308Sache { 62221308Sache tt = VIS_CHARS (linenum); 62321308Sache _rl_move_vert (linenum); 62421308Sache _rl_move_cursor_relative (0, tt); 62526497Sache _rl_clear_to_eol 62621308Sache ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth); 62721308Sache } 62821308Sache } 62921308Sache _rl_vis_botlin = inv_botlin; 63021308Sache 63121308Sache /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a 63221308Sache different screen line during this redisplay. */ 63321308Sache changed_screen_line = _rl_last_v_pos != cursor_linenum; 63421308Sache if (changed_screen_line) 63521308Sache { 63621308Sache _rl_move_vert (cursor_linenum); 63721308Sache /* If we moved up to the line with the prompt using term_up, 63847563Sache the physical cursor position on the screen stays the same, 63947563Sache but the buffer position needs to be adjusted to account 64047563Sache for invisible characters. */ 64121308Sache if (cursor_linenum == 0 && wrap_offset) 64247563Sache _rl_last_c_pos += wrap_offset; 64321308Sache } 64421308Sache 64521308Sache /* We have to reprint the prompt if it contains invisible 64621308Sache characters, since it's not generally OK to just reprint 64721308Sache the characters from the current cursor position. But we 64821308Sache only need to reprint it if the cursor is before the last 64921308Sache invisible character in the prompt string. */ 65021308Sache nleft = visible_length + wrap_offset; 65121308Sache if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && 65221308Sache _rl_last_c_pos <= last_invisible && local_prompt) 65321308Sache { 65421308Sache if (term_cr) 65521308Sache tputs (term_cr, 1, _rl_output_character_function); 65621308Sache _rl_output_some_chars (local_prompt, nleft); 65721308Sache _rl_last_c_pos = nleft; 65821308Sache } 65921308Sache 66021308Sache /* Where on that line? And where does that line start 66121308Sache in the buffer? */ 66221308Sache pos = inv_lbreaks[cursor_linenum]; 66321308Sache /* nleft == number of characters in the line buffer between the 66421308Sache start of the line and the cursor position. */ 66521308Sache nleft = c_pos - pos; 66621308Sache 66721308Sache /* Since _rl_backspace() doesn't know about invisible characters in the 66821308Sache prompt, and there's no good way to tell it, we compensate for 66921308Sache those characters here and call _rl_backspace() directly. */ 67021308Sache if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) 67121308Sache { 67221308Sache _rl_backspace (_rl_last_c_pos - nleft); 67321308Sache _rl_last_c_pos = nleft; 67421308Sache } 67521308Sache 67621308Sache if (nleft != _rl_last_c_pos) 67721308Sache _rl_move_cursor_relative (nleft, &invisible_line[pos]); 67821308Sache } 67921308Sache } 68021308Sache else /* Do horizontal scrolling. */ 68121308Sache { 68221308Sache#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0) 68321308Sache int lmargin, ndisp, nleft, phys_c_pos, t; 68421308Sache 68521308Sache /* Always at top line. */ 68621308Sache _rl_last_v_pos = 0; 68721308Sache 68821308Sache /* Compute where in the buffer the displayed line should start. This 68921308Sache will be LMARGIN. */ 69021308Sache 69121308Sache /* The number of characters that will be displayed before the cursor. */ 69221308Sache ndisp = c_pos - wrap_offset; 69321308Sache nleft = visible_length + wrap_offset; 69421308Sache /* Where the new cursor position will be on the screen. This can be 69547563Sache longer than SCREENWIDTH; if it is, lmargin will be adjusted. */ 69621308Sache phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset); 69721308Sache t = screenwidth / 3; 69821308Sache 69921308Sache /* If the number of characters had already exceeded the screenwidth, 70047563Sache last_lmargin will be > 0. */ 70121308Sache 70221308Sache /* If the number of characters to be displayed is more than the screen 70347563Sache width, compute the starting offset so that the cursor is about 70447563Sache two-thirds of the way across the screen. */ 70521308Sache if (phys_c_pos > screenwidth - 2) 70621308Sache { 70721308Sache lmargin = c_pos - (2 * t); 70821308Sache if (lmargin < 0) 70921308Sache lmargin = 0; 71021308Sache /* If the left margin would be in the middle of a prompt with 71121308Sache invisible characters, don't display the prompt at all. */ 71221308Sache if (wrap_offset && lmargin > 0 && lmargin < nleft) 71321308Sache lmargin = nleft; 71421308Sache } 71521308Sache else if (ndisp < screenwidth - 2) /* XXX - was -1 */ 71647563Sache lmargin = 0; 71721308Sache else if (phys_c_pos < 1) 71821308Sache { 71921308Sache /* If we are moving back towards the beginning of the line and 72021308Sache the last margin is no longer correct, compute a new one. */ 72121308Sache lmargin = ((c_pos - 1) / t) * t; /* XXX */ 72221308Sache if (wrap_offset && lmargin > 0 && lmargin < nleft) 72321308Sache lmargin = nleft; 72421308Sache } 72521308Sache else 72647563Sache lmargin = last_lmargin; 72721308Sache 72821308Sache /* If the first character on the screen isn't the first character 72921308Sache in the display line, indicate this with a special character. */ 73021308Sache if (lmargin > 0) 73121308Sache line[lmargin] = '<'; 73221308Sache 73321308Sache /* If SCREENWIDTH characters starting at LMARGIN do not encompass 73447563Sache the whole line, indicate that with a special character at the 73547563Sache right edge of the screen. If LMARGIN is 0, we need to take the 73647563Sache wrap offset into account. */ 73721308Sache t = lmargin + M_OFFSET (lmargin, wrap_offset) + screenwidth; 73821308Sache if (t < out) 73947563Sache line[t - 1] = '>'; 74021308Sache 74121308Sache if (!rl_display_fixed || forced_display || lmargin != last_lmargin) 74221308Sache { 74321308Sache forced_display = 0; 74421308Sache update_line (&visible_line[last_lmargin], 74521308Sache &invisible_line[lmargin], 74621308Sache 0, 74721308Sache screenwidth + visible_wrap_offset, 74821308Sache screenwidth + (lmargin ? 0 : wrap_offset), 74921308Sache 0); 75021308Sache 75121308Sache /* If the visible new line is shorter than the old, but the number 75221308Sache of invisible characters is greater, and we are at the end of 75321308Sache the new line, we need to clear to eol. */ 75421308Sache t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset); 75521308Sache if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) && 75621308Sache (_rl_last_c_pos == out) && 75721308Sache t < visible_first_line_len) 75821308Sache { 75921308Sache nleft = screenwidth - t; 76026497Sache _rl_clear_to_eol (nleft); 76121308Sache } 76221308Sache visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset); 76321308Sache if (visible_first_line_len > screenwidth) 76421308Sache visible_first_line_len = screenwidth; 76521308Sache 76621308Sache _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); 76721308Sache last_lmargin = lmargin; 76821308Sache } 76921308Sache } 77021308Sache fflush (rl_outstream); 77121308Sache 77221308Sache /* Swap visible and non-visible lines. */ 77321308Sache { 77421308Sache char *temp = visible_line; 77521308Sache int *itemp = vis_lbreaks; 77621308Sache visible_line = invisible_line; 77721308Sache invisible_line = temp; 77821308Sache vis_lbreaks = inv_lbreaks; 77921308Sache inv_lbreaks = itemp; 78021308Sache rl_display_fixed = 0; 78121308Sache /* If we are displaying on a single line, and last_lmargin is > 0, we 78221308Sache are not displaying any invisible characters, so set visible_wrap_offset 78321308Sache to 0. */ 78421308Sache if (_rl_horizontal_scroll_mode && last_lmargin) 78521308Sache visible_wrap_offset = 0; 78621308Sache else 78721308Sache visible_wrap_offset = wrap_offset; 78821308Sache } 78921308Sache} 79021308Sache 79121308Sache/* PWP: update_line() is based on finding the middle difference of each 79221308Sache line on the screen; vis: 79321308Sache 79421308Sache /old first difference 79521308Sache /beginning of line | /old last same /old EOL 79621308Sache v v v v 79721308Sacheold: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 79821308Sachenew: eddie> Oh, my little buggy says to me, as lurgid as 79921308Sache ^ ^ ^ ^ 80021308Sache \beginning of line | \new last same \new end of line 80121308Sache \new first difference 80221308Sache 80321308Sache All are character pointers for the sake of speed. Special cases for 80447563Sache no differences, as well as for end of line additions must be handled. 80521308Sache 80621308Sache Could be made even smarter, but this works well enough */ 80721308Sachestatic void 80821308Sacheupdate_line (old, new, current_line, omax, nmax, inv_botlin) 80921308Sache register char *old, *new; 81021308Sache int current_line, omax, nmax, inv_botlin; 81121308Sache{ 81221308Sache register char *ofd, *ols, *oe, *nfd, *nls, *ne; 81321308Sache int temp, lendiff, wsatend, od, nd; 81421308Sache int current_invis_chars; 81521308Sache 81621308Sache /* If we're at the right edge of a terminal that supports xn, we're 81721308Sache ready to wrap around, so do so. This fixes problems with knowing 81821308Sache the exact cursor position and cut-and-paste with certain terminal 81921308Sache emulators. In this calculation, TEMP is the physical screen 82021308Sache position of the cursor. */ 82121308Sache temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); 82221308Sache if (temp == screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode 82321308Sache && _rl_last_v_pos == current_line - 1) 82421308Sache { 82521308Sache if (new[0]) 82621308Sache putc (new[0], rl_outstream); 82721308Sache else 82821308Sache putc (' ', rl_outstream); 82921308Sache _rl_last_c_pos = 1; /* XXX */ 83021308Sache _rl_last_v_pos++; 83121308Sache if (old[0] && new[0]) 83247563Sache old[0] = new[0]; 83321308Sache } 83421308Sache 83521308Sache /* Find first difference. */ 83621308Sache for (ofd = old, nfd = new; 83721308Sache (ofd - old < omax) && *ofd && (*ofd == *nfd); 83821308Sache ofd++, nfd++) 83921308Sache ; 84021308Sache 84121308Sache /* Move to the end of the screen line. ND and OD are used to keep track 84221308Sache of the distance between ne and new and oe and old, respectively, to 84321308Sache move a subtraction out of each loop. */ 84421308Sache for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++); 84521308Sache for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++); 84621308Sache 84721308Sache /* If no difference, continue to next line. */ 84821308Sache if (ofd == oe && nfd == ne) 84921308Sache return; 85021308Sache 85121308Sache wsatend = 1; /* flag for trailing whitespace */ 85221308Sache ols = oe - 1; /* find last same */ 85321308Sache nls = ne - 1; 85421308Sache while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) 85521308Sache { 85621308Sache if (*ols != ' ') 85721308Sache wsatend = 0; 85821308Sache ols--; 85921308Sache nls--; 86021308Sache } 86121308Sache 86221308Sache if (wsatend) 86321308Sache { 86421308Sache ols = oe; 86521308Sache nls = ne; 86621308Sache } 86721308Sache else if (*ols != *nls) 86821308Sache { 86921308Sache if (*ols) /* don't step past the NUL */ 87021308Sache ols++; 87121308Sache if (*nls) 87221308Sache nls++; 87321308Sache } 87421308Sache 87521308Sache /* count of invisible characters in the current invisible line. */ 87621308Sache current_invis_chars = W_OFFSET (current_line, wrap_offset); 87721308Sache if (_rl_last_v_pos != current_line) 87821308Sache { 87921308Sache _rl_move_vert (current_line); 88021308Sache if (current_line == 0 && visible_wrap_offset) 88121308Sache _rl_last_c_pos += visible_wrap_offset; 88221308Sache } 88321308Sache 88421308Sache /* If this is the first line and there are invisible characters in the 88521308Sache prompt string, and the prompt string has not changed, and the current 88621308Sache cursor position is before the last invisible character in the prompt, 88721308Sache and the index of the character to move to is past the end of the prompt 88821308Sache string, then redraw the entire prompt string. We can only do this 88921308Sache reliably if the terminal supports a `cr' capability. 89021308Sache 89121308Sache This is not an efficiency hack -- there is a problem with redrawing 89221308Sache portions of the prompt string if they contain terminal escape 89321308Sache sequences (like drawing the `unbold' sequence without a corresponding 89421308Sache `bold') that manifests itself on certain terminals. */ 89521308Sache 89621308Sache lendiff = local_prompt ? strlen (local_prompt) : 0; 89721308Sache od = ofd - old; /* index of first difference in visible line */ 89821308Sache if (current_line == 0 && !_rl_horizontal_scroll_mode && 89921308Sache term_cr && lendiff > visible_length && _rl_last_c_pos > 0 && 90021308Sache od > lendiff && _rl_last_c_pos < last_invisible) 90121308Sache { 90221308Sache tputs (term_cr, 1, _rl_output_character_function); 90321308Sache _rl_output_some_chars (local_prompt, lendiff); 90421308Sache _rl_last_c_pos = lendiff; 90521308Sache } 90621308Sache 90721308Sache _rl_move_cursor_relative (od, old); 90821308Sache 90921308Sache /* if (len (new) > len (old)) */ 91021308Sache lendiff = (nls - nfd) - (ols - ofd); 91121308Sache 91221308Sache /* If we are changing the number of invisible characters in a line, and 91321308Sache the spot of first difference is before the end of the invisible chars, 91421308Sache lendiff needs to be adjusted. */ 91521308Sache if (current_line == 0 && !_rl_horizontal_scroll_mode && 91621308Sache current_invis_chars != visible_wrap_offset) 91747563Sache lendiff += visible_wrap_offset - current_invis_chars; 91821308Sache 91921308Sache /* Insert (diff (len (old), len (new)) ch. */ 92021308Sache temp = ne - nfd; 92121308Sache if (lendiff > 0) 92221308Sache { 92321308Sache /* Non-zero if we're increasing the number of lines. */ 92421308Sache int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin; 92521308Sache /* Sometimes it is cheaper to print the characters rather than 92621308Sache use the terminal's capabilities. If we're growing the number 92721308Sache of lines, make sure we actually cause the new line to wrap 92821308Sache around on auto-wrapping terminals. */ 92921308Sache if (terminal_can_insert && ((2 * temp) >= lendiff || term_IC) && (!_rl_term_autowrap || !gl)) 93021308Sache { 93121308Sache /* If lendiff > visible_length and _rl_last_c_pos == 0 and 93221308Sache _rl_horizontal_scroll_mode == 1, inserting the characters with 93321308Sache term_IC or term_ic will screw up the screen because of the 93421308Sache invisible characters. We need to just draw them. */ 93521308Sache if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 || 93621308Sache lendiff <= visible_length || !current_invis_chars)) 93721308Sache { 93821308Sache insert_some_chars (nfd, lendiff); 93921308Sache _rl_last_c_pos += lendiff; 94021308Sache } 94121308Sache else if (*ols == 0) 94221308Sache { 94321308Sache /* At the end of a line the characters do not have to 94421308Sache be "inserted". They can just be placed on the screen. */ 94521308Sache /* However, this screws up the rest of this block, which 94647563Sache assumes you've done the insert because you can. */ 94721308Sache _rl_output_some_chars (nfd, lendiff); 94821308Sache _rl_last_c_pos += lendiff; 94921308Sache } 95021308Sache else 95121308Sache { 95221308Sache /* We have horizontal scrolling and we are not inserting at 95321308Sache the end. We have invisible characters in this line. This 95421308Sache is a dumb update. */ 95521308Sache _rl_output_some_chars (nfd, temp); 95621308Sache _rl_last_c_pos += temp; 95721308Sache return; 95821308Sache } 95921308Sache /* Copy (new) chars to screen from first diff to last match. */ 96021308Sache temp = nls - nfd; 96121308Sache if ((temp - lendiff) > 0) 96221308Sache { 96321308Sache _rl_output_some_chars (nfd + lendiff, temp - lendiff); 96421308Sache _rl_last_c_pos += temp - lendiff; 96521308Sache } 96621308Sache } 96721308Sache else 96821308Sache { 96921308Sache /* cannot insert chars, write to EOL */ 97021308Sache _rl_output_some_chars (nfd, temp); 97121308Sache _rl_last_c_pos += temp; 97221308Sache } 97321308Sache } 97421308Sache else /* Delete characters from line. */ 97521308Sache { 97621308Sache /* If possible and inexpensive to use terminal deletion, then do so. */ 97721308Sache if (term_dc && (2 * temp) >= -lendiff) 97821308Sache { 97921308Sache /* If all we're doing is erasing the invisible characters in the 98021308Sache prompt string, don't bother. It screws up the assumptions 98121308Sache about what's on the screen. */ 98221308Sache if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 && 98321308Sache -lendiff == visible_wrap_offset) 98421308Sache lendiff = 0; 98521308Sache 98621308Sache if (lendiff) 98721308Sache delete_chars (-lendiff); /* delete (diff) characters */ 98821308Sache 98921308Sache /* Copy (new) chars to screen from first diff to last match */ 99021308Sache temp = nls - nfd; 99121308Sache if (temp > 0) 99221308Sache { 99321308Sache _rl_output_some_chars (nfd, temp); 99421308Sache _rl_last_c_pos += temp; 99521308Sache } 99621308Sache } 99721308Sache /* Otherwise, print over the existing material. */ 99821308Sache else 99921308Sache { 100021308Sache if (temp > 0) 100121308Sache { 100221308Sache _rl_output_some_chars (nfd, temp); 100321308Sache _rl_last_c_pos += temp; 100421308Sache } 100521308Sache lendiff = (oe - old) - (ne - new); 100647563Sache if (lendiff) 100747563Sache { 100847563Sache if (_rl_term_autowrap && current_line < inv_botlin) 100947563Sache space_to_eol (lendiff); 101047563Sache else 101147563Sache _rl_clear_to_eol (lendiff); 101247563Sache } 101321308Sache } 101421308Sache } 101521308Sache} 101621308Sache 101721308Sache/* Tell the update routines that we have moved onto a new (empty) line. */ 101821308Sacheint 101921308Sacherl_on_new_line () 102021308Sache{ 102121308Sache if (visible_line) 102221308Sache visible_line[0] = '\0'; 102321308Sache 102421308Sache _rl_last_c_pos = _rl_last_v_pos = 0; 102521308Sache _rl_vis_botlin = last_lmargin = 0; 102621308Sache if (vis_lbreaks) 102721308Sache vis_lbreaks[0] = vis_lbreaks[1] = 0; 102821308Sache visible_wrap_offset = 0; 102921308Sache return 0; 103021308Sache} 103121308Sache 103221308Sache/* Actually update the display, period. */ 103321308Sacheint 103421308Sacherl_forced_update_display () 103521308Sache{ 103621308Sache if (visible_line) 103721308Sache { 103821308Sache register char *temp = visible_line; 103921308Sache 104021308Sache while (*temp) 104147563Sache *temp++ = '\0'; 104221308Sache } 104321308Sache rl_on_new_line (); 104421308Sache forced_display++; 104521308Sache (*rl_redisplay_function) (); 104621308Sache return 0; 104721308Sache} 104821308Sache 104921308Sache/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices. 105021308Sache DATA is the contents of the screen line of interest; i.e., where 105121308Sache the movement is being done. */ 105221308Sachevoid 105321308Sache_rl_move_cursor_relative (new, data) 105421308Sache int new; 105521308Sache char *data; 105621308Sache{ 105721308Sache register int i; 105821308Sache 105921308Sache /* If we don't have to do anything, then return. */ 106021308Sache if (_rl_last_c_pos == new) return; 106121308Sache 106221308Sache /* It may be faster to output a CR, and then move forwards instead 106321308Sache of moving backwards. */ 106421308Sache /* i == current physical cursor position. */ 106521308Sache i = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); 106621308Sache if (new == 0 || CR_FASTER (new, _rl_last_c_pos) || 106721308Sache (_rl_term_autowrap && i == screenwidth)) 106821308Sache { 106921308Sache#if defined (__MSDOS__) 107021308Sache putc ('\r', rl_outstream); 107121308Sache#else 107221308Sache tputs (term_cr, 1, _rl_output_character_function); 107321308Sache#endif /* !__MSDOS__ */ 107421308Sache _rl_last_c_pos = 0; 107521308Sache } 107621308Sache 107721308Sache if (_rl_last_c_pos < new) 107821308Sache { 107921308Sache /* Move the cursor forward. We do it by printing the command 108021308Sache to move the cursor forward if there is one, else print that 108121308Sache portion of the output buffer again. Which is cheaper? */ 108221308Sache 108321308Sache /* The above comment is left here for posterity. It is faster 108421308Sache to print one character (non-control) than to print a control 108521308Sache sequence telling the terminal to move forward one character. 108621308Sache That kind of control is for people who don't know what the 108721308Sache data is underneath the cursor. */ 108821308Sache#if defined (HACK_TERMCAP_MOTION) 108921308Sache extern char *term_forward_char; 109021308Sache 109121308Sache if (term_forward_char) 109221308Sache for (i = _rl_last_c_pos; i < new; i++) 109321308Sache tputs (term_forward_char, 1, _rl_output_character_function); 109421308Sache else 109521308Sache for (i = _rl_last_c_pos; i < new; i++) 109621308Sache putc (data[i], rl_outstream); 109721308Sache#else 109821308Sache for (i = _rl_last_c_pos; i < new; i++) 109921308Sache putc (data[i], rl_outstream); 110021308Sache#endif /* HACK_TERMCAP_MOTION */ 110121308Sache } 110247563Sache else if (_rl_last_c_pos > new) 110321308Sache _rl_backspace (_rl_last_c_pos - new); 110421308Sache _rl_last_c_pos = new; 110521308Sache} 110621308Sache 110721308Sache/* PWP: move the cursor up or down. */ 110821308Sachevoid 110921308Sache_rl_move_vert (to) 111021308Sache int to; 111121308Sache{ 111221308Sache register int delta, i; 111321308Sache 111421308Sache if (_rl_last_v_pos == to || to > screenheight) 111521308Sache return; 111621308Sache 111721308Sache#if defined (__GO32__) 111821308Sache { 111921308Sache int row, col; 112021308Sache 112121308Sache ScreenGetCursor (&row, &col); 112221308Sache ScreenSetCursor ((row + to - _rl_last_v_pos), col); 112321308Sache } 112421308Sache#else /* !__GO32__ */ 112521308Sache 112621308Sache if ((delta = to - _rl_last_v_pos) > 0) 112721308Sache { 112821308Sache for (i = 0; i < delta; i++) 112921308Sache putc ('\n', rl_outstream); 113021308Sache tputs (term_cr, 1, _rl_output_character_function); 113121308Sache _rl_last_c_pos = 0; 113221308Sache } 113321308Sache else 113421308Sache { /* delta < 0 */ 113521308Sache if (term_up && *term_up) 113621308Sache for (i = 0; i < -delta; i++) 113721308Sache tputs (term_up, 1, _rl_output_character_function); 113821308Sache } 113921308Sache#endif /* !__GO32__ */ 114021308Sache _rl_last_v_pos = to; /* Now TO is here */ 114121308Sache} 114221308Sache 114321308Sache/* Physically print C on rl_outstream. This is for functions which know 114421308Sache how to optimize the display. Return the number of characters output. */ 114521308Sacheint 114621308Sacherl_show_char (c) 114721308Sache int c; 114821308Sache{ 114921308Sache int n = 1; 115021308Sache if (META_CHAR (c) && (_rl_output_meta_chars == 0)) 115121308Sache { 115221308Sache fprintf (rl_outstream, "M-"); 115321308Sache n += 2; 115421308Sache c = UNMETA (c); 115521308Sache } 115621308Sache 115721308Sache#if defined (DISPLAY_TABS) 115821308Sache if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT) 115921308Sache#else 116021308Sache if (CTRL_CHAR (c) || c == RUBOUT) 116121308Sache#endif /* !DISPLAY_TABS */ 116221308Sache { 116321308Sache fprintf (rl_outstream, "C-"); 116421308Sache n += 2; 116521308Sache c = CTRL_CHAR (c) ? UNCTRL (c) : '?'; 116621308Sache } 116721308Sache 116821308Sache putc (c, rl_outstream); 116921308Sache fflush (rl_outstream); 117021308Sache return n; 117121308Sache} 117221308Sache 117321308Sacheint 117421308Sacherl_character_len (c, pos) 117521308Sache register int c, pos; 117621308Sache{ 117721308Sache unsigned char uc; 117821308Sache 117921308Sache uc = (unsigned char)c; 118021308Sache 118121308Sache if (META_CHAR (uc)) 118221308Sache return ((_rl_output_meta_chars == 0) ? 4 : 1); 118321308Sache 118421308Sache if (uc == '\t') 118521308Sache { 118621308Sache#if defined (DISPLAY_TABS) 118721308Sache return (((pos | 7) + 1) - pos); 118821308Sache#else 118921308Sache return (2); 119021308Sache#endif /* !DISPLAY_TABS */ 119121308Sache } 119221308Sache 119321308Sache if (CTRL_CHAR (c) || c == RUBOUT) 119421308Sache return (2); 119521308Sache 119621308Sache return ((isprint (uc)) ? 1 : 2); 119721308Sache} 119821308Sache 119921308Sache/* How to print things in the "echo-area". The prompt is treated as a 120021308Sache mini-modeline. */ 120121308Sache 120221308Sache#if defined (USE_VARARGS) 120321308Sacheint 120421308Sache#if defined (PREFER_STDARG) 120521308Sacherl_message (const char *format, ...) 120621308Sache#else 120721308Sacherl_message (va_alist) 120821308Sache va_dcl 120921308Sache#endif 121021308Sache{ 121121308Sache va_list args; 121221308Sache#if defined (PREFER_VARARGS) 121321308Sache char *format; 121421308Sache#endif 121521308Sache 121621308Sache#if defined (PREFER_STDARG) 121721308Sache va_start (args, format); 121821308Sache#else 121921308Sache va_start (args); 122021308Sache format = va_arg (args, char *); 122121308Sache#endif 122221308Sache 122321308Sache vsprintf (msg_buf, format, args); 122421308Sache va_end (args); 122521308Sache 122621308Sache rl_display_prompt = msg_buf; 122721308Sache (*rl_redisplay_function) (); 122821308Sache return 0; 122921308Sache} 123021308Sache#else /* !USE_VARARGS */ 123121308Sacheint 123221308Sacherl_message (format, arg1, arg2) 123321308Sache char *format; 123421308Sache{ 123521308Sache sprintf (msg_buf, format, arg1, arg2); 123621308Sache rl_display_prompt = msg_buf; 123721308Sache (*rl_redisplay_function) (); 123821308Sache return 0; 123921308Sache} 124021308Sache#endif /* !USE_VARARGS */ 124121308Sache 124221308Sache/* How to clear things from the "echo-area". */ 124321308Sacheint 124421308Sacherl_clear_message () 124521308Sache{ 124621308Sache rl_display_prompt = rl_prompt; 124721308Sache (*rl_redisplay_function) (); 124821308Sache return 0; 124921308Sache} 125021308Sache 125121308Sacheint 125221308Sacherl_reset_line_state () 125321308Sache{ 125421308Sache rl_on_new_line (); 125521308Sache 125621308Sache rl_display_prompt = rl_prompt ? rl_prompt : ""; 125721308Sache forced_display = 1; 125821308Sache return 0; 125921308Sache} 126021308Sache 126121308Sachestatic char *saved_local_prompt; 126221308Sachestatic char *saved_local_prefix; 126321308Sachestatic int saved_last_invisible; 126421308Sachestatic int saved_visible_length; 126521308Sache 126621308Sachevoid 126747563Sacherl_save_prompt () 126821308Sache{ 126921308Sache saved_local_prompt = local_prompt; 127021308Sache saved_local_prefix = local_prompt_prefix; 127121308Sache saved_last_invisible = last_invisible; 127221308Sache saved_visible_length = visible_length; 127321308Sache 127421308Sache local_prompt = local_prompt_prefix = (char *)0; 127521308Sache last_invisible = visible_length = 0; 127621308Sache} 127721308Sache 127821308Sachevoid 127947563Sacherl_restore_prompt () 128021308Sache{ 128121308Sache if (local_prompt) 128221308Sache free (local_prompt); 128321308Sache if (local_prompt_prefix) 128421308Sache free (local_prompt_prefix); 128521308Sache 128621308Sache local_prompt = saved_local_prompt; 128721308Sache local_prompt_prefix = saved_local_prefix; 128821308Sache last_invisible = saved_last_invisible; 128921308Sache visible_length = saved_visible_length; 129021308Sache} 129121308Sache 129221308Sachechar * 129321308Sache_rl_make_prompt_for_search (pchar) 129421308Sache int pchar; 129521308Sache{ 129621308Sache int len; 129721308Sache char *pmt; 129821308Sache 129947563Sache rl_save_prompt (); 130021308Sache 130121308Sache if (saved_local_prompt == 0) 130221308Sache { 130321308Sache len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; 130421308Sache pmt = xmalloc (len + 2); 130521308Sache if (len) 130647563Sache strcpy (pmt, rl_prompt); 130721308Sache pmt[len] = pchar; 130821308Sache pmt[len+1] = '\0'; 130921308Sache } 131021308Sache else 131121308Sache { 131221308Sache len = *saved_local_prompt ? strlen (saved_local_prompt) : 0; 131321308Sache pmt = xmalloc (len + 2); 131421308Sache if (len) 131547563Sache strcpy (pmt, saved_local_prompt); 131621308Sache pmt[len] = pchar; 131721308Sache pmt[len+1] = '\0'; 131821308Sache local_prompt = savestring (pmt); 131921308Sache last_invisible = saved_last_invisible; 132021308Sache visible_length = saved_visible_length + 1; 132121308Sache } 132221308Sache return pmt; 132321308Sache} 132421308Sache 132521308Sache/* Quick redisplay hack when erasing characters at the end of the line. */ 132621308Sachevoid 132721308Sache_rl_erase_at_end_of_line (l) 132821308Sache int l; 132921308Sache{ 133021308Sache register int i; 133121308Sache 133221308Sache _rl_backspace (l); 133321308Sache for (i = 0; i < l; i++) 133421308Sache putc (' ', rl_outstream); 133521308Sache _rl_backspace (l); 133621308Sache for (i = 0; i < l; i++) 133721308Sache visible_line[--_rl_last_c_pos] = '\0'; 133821308Sache rl_display_fixed++; 133921308Sache} 134021308Sache 134121308Sache/* Clear to the end of the line. COUNT is the minimum 134221308Sache number of character spaces to clear, */ 134326497Sachevoid 134426497Sache_rl_clear_to_eol (count) 134521308Sache int count; 134621308Sache{ 134721308Sache#if !defined (__GO32__) 134821308Sache if (term_clreol) 134926497Sache tputs (term_clreol, 1, _rl_output_character_function); 135026497Sache else if (count) 135121308Sache#endif /* !__GO32__ */ 135221308Sache space_to_eol (count); 135321308Sache} 135421308Sache 135521308Sache/* Clear to the end of the line using spaces. COUNT is the minimum 135621308Sache number of character spaces to clear, */ 135721308Sachestatic void 135821308Sachespace_to_eol (count) 135921308Sache int count; 136021308Sache{ 136121308Sache register int i; 136221308Sache 136321308Sache for (i = 0; i < count; i++) 136421308Sache putc (' ', rl_outstream); 136521308Sache 136621308Sache _rl_last_c_pos += count; 136721308Sache} 136821308Sache 136926497Sachevoid 137026497Sache_rl_clear_screen () 137126497Sache{ 137226497Sache#if !defined (__GO32__) 137326497Sache if (term_clrpag) 137426497Sache tputs (term_clrpag, 1, _rl_output_character_function); 137526497Sache else 137626497Sache#endif /* !__GO32__ */ 137726497Sache crlf (); 137826497Sache} 137926497Sache 138021308Sache/* Insert COUNT characters from STRING to the output stream. */ 138121308Sachestatic void 138221308Sacheinsert_some_chars (string, count) 138321308Sache char *string; 138421308Sache int count; 138521308Sache{ 138621308Sache#if defined (__GO32__) 138721308Sache int row, col, width; 138821308Sache char *row_start; 138921308Sache 139021308Sache ScreenGetCursor (&row, &col); 139121308Sache width = ScreenCols (); 139221308Sache row_start = ScreenPrimary + (row * width); 139321308Sache 139421308Sache memcpy (row_start + col + count, row_start + col, width - col - count); 139521308Sache 139621308Sache /* Place the text on the screen. */ 139721308Sache _rl_output_some_chars (string, count); 139821308Sache#else /* !_GO32 */ 139921308Sache 140021308Sache /* If IC is defined, then we do not have to "enter" insert mode. */ 140121308Sache if (term_IC) 140221308Sache { 140321308Sache char *buffer; 140421308Sache buffer = tgoto (term_IC, 0, count); 140521308Sache tputs (buffer, 1, _rl_output_character_function); 140621308Sache _rl_output_some_chars (string, count); 140721308Sache } 140821308Sache else 140921308Sache { 141021308Sache register int i; 141121308Sache 141221308Sache /* If we have to turn on insert-mode, then do so. */ 141321308Sache if (term_im && *term_im) 141421308Sache tputs (term_im, 1, _rl_output_character_function); 141521308Sache 141621308Sache /* If there is a special command for inserting characters, then 141721308Sache use that first to open up the space. */ 141821308Sache if (term_ic && *term_ic) 141921308Sache { 142021308Sache for (i = count; i--; ) 142121308Sache tputs (term_ic, 1, _rl_output_character_function); 142221308Sache } 142321308Sache 142421308Sache /* Print the text. */ 142521308Sache _rl_output_some_chars (string, count); 142621308Sache 142721308Sache /* If there is a string to turn off insert mode, we had best use 142821308Sache it now. */ 142921308Sache if (term_ei && *term_ei) 143021308Sache tputs (term_ei, 1, _rl_output_character_function); 143121308Sache } 143221308Sache#endif /* !__GO32__ */ 143321308Sache} 143421308Sache 143521308Sache/* Delete COUNT characters from the display line. */ 143621308Sachestatic void 143721308Sachedelete_chars (count) 143821308Sache int count; 143921308Sache{ 144021308Sache#if defined (__GO32__) 144121308Sache int row, col, width; 144221308Sache char *row_start; 144321308Sache 144421308Sache ScreenGetCursor (&row, &col); 144521308Sache width = ScreenCols (); 144621308Sache row_start = ScreenPrimary + (row * width); 144721308Sache 144821308Sache memcpy (row_start + col, row_start + col + count, width - col - count); 144921308Sache memset (row_start + width - count, 0, count * 2); 145021308Sache#else /* !_GO32 */ 145121308Sache 145221308Sache if (count > screenwidth) /* XXX */ 145321308Sache return; 145421308Sache 145521308Sache if (term_DC && *term_DC) 145621308Sache { 145721308Sache char *buffer; 145821308Sache buffer = tgoto (term_DC, count, count); 145921308Sache tputs (buffer, count, _rl_output_character_function); 146021308Sache } 146121308Sache else 146221308Sache { 146321308Sache if (term_dc && *term_dc) 146421308Sache while (count--) 146521308Sache tputs (term_dc, 1, _rl_output_character_function); 146621308Sache } 146721308Sache#endif /* !__GO32__ */ 146821308Sache} 146921308Sache 147021308Sachevoid 147121308Sache_rl_update_final () 147221308Sache{ 147321308Sache int full_lines; 147421308Sache 147521308Sache full_lines = 0; 147621308Sache /* If the cursor is the only thing on an otherwise-blank last line, 147721308Sache compensate so we don't print an extra CRLF. */ 147821308Sache if (_rl_vis_botlin && _rl_last_c_pos == 0 && 147926497Sache visible_line[vis_lbreaks[_rl_vis_botlin]] == 0) 148021308Sache { 148121308Sache _rl_vis_botlin--; 148221308Sache full_lines = 1; 148321308Sache } 148421308Sache _rl_move_vert (_rl_vis_botlin); 148521308Sache /* If we've wrapped lines, remove the final xterm line-wrap flag. */ 148621308Sache if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == screenwidth)) 148721308Sache { 148821308Sache char *last_line; 148921308Sache last_line = &visible_line[inv_lbreaks[_rl_vis_botlin]]; 149021308Sache _rl_move_cursor_relative (screenwidth - 1, last_line); 149126497Sache _rl_clear_to_eol (0); 149221308Sache putc (last_line[screenwidth - 1], rl_outstream); 149321308Sache } 149421308Sache _rl_vis_botlin = 0; 149521308Sache crlf (); 149621308Sache fflush (rl_outstream); 149721308Sache rl_display_fixed++; 149821308Sache} 149921308Sache 150021308Sache/* Move to the start of the current line. */ 150121308Sachestatic void 150221308Sachecr () 150321308Sache{ 150421308Sache if (term_cr) 150521308Sache { 150621308Sache tputs (term_cr, 1, _rl_output_character_function); 150721308Sache _rl_last_c_pos = 0; 150821308Sache } 150921308Sache} 151021308Sache 151121308Sache/* Redisplay the current line after a SIGWINCH is received. */ 151221308Sachevoid 151321308Sache_rl_redisplay_after_sigwinch () 151421308Sache{ 151530971Sache char *t, *oldp, *oldl, *oldlprefix; 151621308Sache 151721308Sache /* Clear the current line and put the cursor at column 0. Make sure 151821308Sache the right thing happens if we have wrapped to a new screen line. */ 151921308Sache if (term_cr) 152021308Sache { 152121308Sache tputs (term_cr, 1, _rl_output_character_function); 152221308Sache _rl_last_c_pos = 0; 152321308Sache if (term_clreol) 152421308Sache tputs (term_clreol, 1, _rl_output_character_function); 152521308Sache else 152621308Sache { 152721308Sache space_to_eol (screenwidth); 152821308Sache tputs (term_cr, 1, _rl_output_character_function); 152921308Sache } 153021308Sache if (_rl_last_v_pos > 0) 153121308Sache _rl_move_vert (0); 153221308Sache } 153321308Sache else 153421308Sache crlf (); 153521308Sache 153621308Sache /* Redraw only the last line of a multi-line prompt. */ 153721308Sache t = strrchr (rl_display_prompt, '\n'); 153821308Sache if (t) 153921308Sache { 154021308Sache oldp = rl_display_prompt; 154130971Sache oldl = local_prompt; 154230971Sache oldlprefix = local_prompt_prefix; 154321308Sache rl_display_prompt = ++t; 154430971Sache local_prompt = local_prompt_prefix = (char *)NULL; 154521308Sache rl_forced_update_display (); 154621308Sache rl_display_prompt = oldp; 154730971Sache local_prompt = oldl; 154830971Sache local_prompt_prefix = oldlprefix; 154921308Sache } 155021308Sache else 155121308Sache rl_forced_update_display (); 155221308Sache} 155321308Sache 155421308Sachevoid 155521308Sache_rl_clean_up_for_exit () 155621308Sache{ 155721308Sache if (readline_echoing_p) 155821308Sache { 155921308Sache _rl_move_vert (_rl_vis_botlin); 156021308Sache _rl_vis_botlin = 0; 156121308Sache fflush (rl_outstream); 156247563Sache rl_restart_output (1, 0); 156321308Sache } 156421308Sache} 156547563Sache 156647563Sachevoid 156747563Sache_rl_erase_entire_line () 156847563Sache{ 156947563Sache cr (); 157047563Sache _rl_clear_to_eol (0); 157147563Sache cr (); 157247563Sache fflush (rl_outstream); 157347563Sache} 1574