📄 readline.c
字号:
/* Begin defining a keyboard macro. Keystrokes are recorded as they are executed. End the definition with rl_end_kbd_macro (). If a numeric argument was explicitly typed, then append this definition to the end of the existing macro, and start by re-executing the existing macro. */rl_start_kbd_macro (ignore1, ignore2) int ignore1, ignore2;{ if (defining_kbd_macro) rl_abort (); if (rl_explicit_arg) { if (current_macro) with_macro_input (savestring (current_macro)); } else current_macro_index = 0; defining_kbd_macro = 1;}/* Stop defining a keyboard macro. A numeric argument says to execute the macro right now, that many times, counting the definition as the first time. */rl_end_kbd_macro (count, ignore) int count, ignore;{ if (!defining_kbd_macro) rl_abort (); current_macro_index -= (rl_key_sequence_length - 1); current_macro[current_macro_index] = '\0'; defining_kbd_macro = 0; rl_call_last_kbd_macro (--count, 0);}/* Execute the most recently defined keyboard macro. COUNT says how many times to execute it. */rl_call_last_kbd_macro (count, ignore) int count, ignore;{ if (!current_macro) rl_abort (); while (count--) with_macro_input (savestring (current_macro));}/* **************************************************************** *//* *//* Initializations *//* *//* **************************************************************** *//* Initliaze readline (and terminal if not already). */rl_initialize (){ extern char *rl_display_prompt; /* If we have never been called before, initialize the terminal and data structures. */ if (!rl_initialized) { readline_initialize_everything (); rl_initialized++; } /* Initalize the current line information. */ rl_point = rl_end = 0; the_line = rl_line_buffer; the_line[0] = 0; /* We aren't done yet. We haven't even gotten started yet! */ rl_done = 0; /* Tell the history routines what is going on. */ start_using_history (); /* Make the display buffer match the state of the line. */ { extern char *rl_display_prompt; extern int forced_display; rl_on_new_line (); rl_display_prompt = rl_prompt ? rl_prompt : ""; forced_display = 1; } /* No such function typed yet. */ rl_last_func = (Function *)NULL; /* Parsing of key-bindings begins in an enabled state. */ parsing_conditionalized_out = 0;}/* Initialize the entire state of the world. */readline_initialize_everything (){ /* Find out if we are running in Emacs. */ running_in_emacs = getenv ("EMACS"); /* Set up input and output if they aren't already. */ if (!rl_instream) rl_instream = stdin; if (!rl_outstream) rl_outstream = stdout; /* Allocate data structures. */ if (!rl_line_buffer) rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); /* Initialize the terminal interface. */ init_terminal_io ((char *)NULL); /* Bind tty characters to readline functions. */ readline_default_bindings (); /* Initialize the function names. */ rl_initialize_funmap (); /* Read in the init file. */ rl_read_init_file ((char *)NULL); /* If the completion parser's default word break characters haven't been set yet, then do so now. */ { extern char *rl_completer_word_break_characters; extern char *rl_basic_word_break_characters; if (rl_completer_word_break_characters == (char *)NULL) rl_completer_word_break_characters = rl_basic_word_break_characters; }}/* If this system allows us to look at the values of the regular input editing characters, then bind them to their readline equivalents, iff the characters are not bound to keymaps. */readline_default_bindings (){#ifndef __GO32__#if defined (NEW_TTY_DRIVER) struct sgttyb ttybuff; int tty = fileno (rl_instream); if (ioctl (tty, TIOCGETP, &ttybuff) != -1) { int erase, kill; erase = ttybuff.sg_erase; kill = ttybuff.sg_kill; if (erase != -1 && keymap[erase].type == ISFUNC) keymap[erase].function = rl_rubout; if (kill != -1 && keymap[kill].type == ISFUNC) keymap[kill].function = rl_unix_line_discard; }#if defined (TIOCGLTC) { struct ltchars lt; if (ioctl (tty, TIOCGLTC, <) != -1) { int erase, nextc; erase = lt.t_werasc; nextc = lt.t_lnextc; if (erase != -1 && keymap[erase].type == ISFUNC) keymap[erase].function = rl_unix_word_rubout; if (nextc != -1 && keymap[nextc].type == ISFUNC) keymap[nextc].function = rl_quoted_insert; } }#endif /* TIOCGLTC */#else /* not NEW_TTY_DRIVER */#if defined (TERMIOS_TTY_DRIVER) struct termios ttybuff;#else struct termio ttybuff;#endif /* TERMIOS_TTY_DRIVER */ int tty = fileno (rl_instream);#if defined (TERMIOS_TTY_DRIVER) if (tcgetattr (tty, &ttybuff) != -1)#else if (ioctl (tty, TCGETA, &ttybuff) != -1)#endif /* !TERMIOS_TTY_DRIVER */ { int erase, kill; erase = ttybuff.c_cc[VERASE]; kill = ttybuff.c_cc[VKILL]; if (erase != _POSIX_VDISABLE && keymap[(unsigned char)erase].type == ISFUNC) keymap[(unsigned char)erase].function = rl_rubout; if (kill != _POSIX_VDISABLE && keymap[(unsigned char)kill].type == ISFUNC) keymap[(unsigned char)kill].function = rl_unix_line_discard;#if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) { int nextc; nextc = ttybuff.c_cc[VLNEXT]; if (nextc != _POSIX_VDISABLE && keymap[(unsigned char)nextc].type == ISFUNC) keymap[(unsigned char)nextc].function = rl_quoted_insert; }#endif /* VLNEXT && TERMIOS_TTY_DRIVER */#if defined (VWERASE) { int werase; werase = ttybuff.c_cc[VWERASE]; if (werase != _POSIX_VDISABLE && keymap[(unsigned char)werase].type == ISFUNC) keymap[(unsigned char)werase].function = rl_unix_word_rubout; }#endif /* VWERASE */ }#endif /* !NEW_TTY_DRIVER */#endif /* def __GO32__ */}/* **************************************************************** *//* *//* Numeric Arguments *//* *//* **************************************************************** *//* Handle C-u style numeric args, as well as M--, and M-digits. *//* Add the current digit to the argument in progress. */rl_digit_argument (ignore, key) int ignore, key;{ rl_pending_input = key; rl_digit_loop ();}/* What to do when you abort reading an argument. */rl_discard_argument (){ ding (); rl_clear_message (); rl_init_argument ();}/* Create a default argument. */rl_init_argument (){ rl_numeric_arg = rl_arg_sign = 1; rl_explicit_arg = 0;}/* C-u, universal argument. Multiply the current argument by 4. Read a key. If the key has nothing to do with arguments, then dispatch on it. If the key is the abort character then abort. */rl_universal_argument (){ rl_numeric_arg *= 4; rl_digit_loop ();}rl_digit_loop (){ int key, c; while (1) { rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0); key = c = rl_read_key (); if (keymap[c].type == ISFUNC && keymap[c].function == rl_universal_argument) { rl_numeric_arg *= 4; continue; } c = UNMETA (c); if (numeric (c)) { if (rl_explicit_arg) rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); else rl_numeric_arg = (c - '0'); rl_explicit_arg = 1; } else { if (c == '-' && !rl_explicit_arg) { rl_numeric_arg = 1; rl_arg_sign = -1; } else { rl_clear_message (); rl_dispatch (key, keymap); return; } } }}/* **************************************************************** *//* *//* Display stuff *//* *//* **************************************************************** *//* This is the stuff that is hard for me. I never seem to write good display routines in C. Let's see how I do this time. *//* (PWP) Well... Good for a simple line updater, but totally ignores the problems of input lines longer than the screen width. update_line and the code that calls it makes a multiple line, automatically wrapping line update. Carefull attention needs to be paid to the vertical position variables. handling of terminals with autowrap on (incl. DEC braindamage) could be improved a bit. Right now I just cheat and decrement screenwidth by one. *//* Keep two buffers; one which reflects the current contents of the screen, and the other to draw what we think the new contents should be. Then compare the buffers, and make whatever changes to the screen itself that we should. Finally, make the buffer that we just drew into be the one which reflects the current contents of the screen, and place the cursor where it belongs. Commands that want to can fix the display themselves, and then let this function know that the display has been fixed by setting the RL_DISPLAY_FIXED variable. This is good for efficiency. *//* Termcap variables: */extern char *term_up, *term_dc, *term_cr;extern int screenheight, screenwidth, terminal_can_insert;/* What YOU turn on when you have handled all redisplay yourself. */int rl_display_fixed = 0;/* The visible cursor position. If you print some text, adjust this. */int last_c_pos = 0;int last_v_pos = 0;/* The last left edge of text that was displayed. This is used when doing horizontal scrolling. It shifts in thirds of a screenwidth. */static int last_lmargin = 0;/* The line display buffers. One is the line currently displayed on the screen. The other is the line about to be displayed. */static char *visible_line = (char *)NULL;static char *invisible_line = (char *)NULL;/* Number of lines currently on screen minus 1. */int vis_botlin = 0;/* A buffer for `modeline' messages. */char msg_buf[128];/* Non-zero forces the redisplay even if we thought it was unnecessary. */int forced_display = 0;/* The stuff that gets printed out before the actual text of the line. This is usually pointing to rl_prompt. */char *rl_display_prompt = (char *)NULL;/* Default and initial buffer size. Can grow. */static int line_size = 1024;/* Non-zero means to always use horizontal scrolling in line display. */static int horizontal_scroll_mode = 0;/* Non-zero means to display an asterisk at the starts of history lines which have been modified. */static int mark_modified_lines = 0;/* Non-zero means to use a visible bell if one is available rather than simply ringing the terminal bell. */static int prefer_visible_bell = 0;/* I really disagree with this, but my boss (among others) insists that we support compilers that don't work. I don't think we are gaining by doing so; what is the advantage in producing better code if we can't use it? *//* The following two declarations belong inside the function block, not here. */static void move_cursor_relative ();static void output_some_chars ();static void output_character_function ();static int compare_strings ();/* Basic redisplay algorithm. */rl_redisplay (){ register int in, out, c, linenum; register char *line = invisible_line; char *prompt_this_line; int c_pos = 0; int inv_botlin = 0; /* Number of lines in newly drawn buffer. */ extern int readline_echoing_p; if (!readline_echoing_p) return; if (!rl_display_prompt) rl_display_prompt = ""; if (!invisible_line) { visible_line = (char *)xmalloc (line_size); invisible_line = (char *)xmalloc (line_size); line = invisible_line; for (in = 0; in < line_size; in++) { visible_line[in] = 0; invisible_line[in] = 1; } rl_on_new_line (); } /* Draw the line into the buffer. */ c_pos = -1; /* Mark the line as modified or not. We only do this for history lines. */ out = 0; if (mark_modified_lines && current_history () && rl_undo_list) { line[out++] = '*'; line[out] = '\0'; } /* If someone thought that the redisplay was handled, but the currently visible line has a different modification state than the one about to become visible, then correct the callers misconception. */ if (visible_line[0] != invisible_line[0]) rl_display_fixed = 0; prompt_this_line = rindex (rl_display_prompt, '\n'); if (!prompt_this_line) prompt_this_line = rl_display_prompt; else { prompt_this_line++; if (forced_display) output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt); } strncpy (line + out, prompt_this_line, strlen (prompt_this_line)); out += strlen (prompt_this_line); line[out] = '\0'; for (in = 0; in < rl_end; in++) { c = (unsigned char)the_line[in]; if (out + 1 >= line_size) { line_size *= 2; visible_line = (char *)xrealloc (visible_line, line_size); invisible_line = (char *)xrealloc (invisible_line, line_size); line = invisible_line; } if (in == rl_point) c_pos = out; if (c > 127) { line[out++] = 'M'; line[out++] = '-'; line[out++] = c - 128; }#define DISPLAY_TABS#if defined (DISPLAY_TABS) else if (c == '\t') { register int newout = (out | (int)7) + 1; while (out < newout) line[out++] = ' '; }#endif else if (c < 32) { line[out++] = 'C'; line[out++] = '-'; line[out++] = c + 64; } else if (c == 127) { line[out++] = 'C'; line[out++] = '-'; line[out++] = '?'; } else line[out++] = c; } line[out] = '\0'; if (c_pos < 0) c_pos = out; /* PWP: now is when things get a bit hairy. The visible and invisible line buffers are really multiple lines, which would wrap every (screenwidth - 1) characters. Go through each in turn, finding the changed region and updating it. The line order is top to bottom. */ /* If we can move the cursor up and down, then use multiple lines, otherwise, let long lines display in a single terminal line, and horizontally scroll it. */ if (!horizontal_scroll_mode && term_up && *term_up) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -