📄 xdisp.c
字号:
/* Display generation from window structure and buffer text. Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.This file is part of GNU Emacs.GNU Emacs is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU Emacs is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Emacs; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "config.h"#include <stdio.h>/*#include <ctype.h>*/#undef NULL#include "lisp.h"#include "window.h"#include "termchar.h"#include "dispextern.h"#include "buffer.h"#include "indent.h"#include "commands.h"#include "macros.h"extern int interrupt_input;extern int command_loop_level;/* Nonzero means print newline before next minibuffer message. */int noninteractive_need_newline;#define min(a, b) ((a) < (b) ? (a) : (b))#define max(a, b) ((a) > (b) ? (a) : (b))/* The buffer position of the first character appearing entirely or partially on the current screen line. Or zero, which disables the optimization for the current screen line. */static int this_line_bufpos;/* Number of characters past the end of this line, including the terminating newline */static int this_line_endpos;/* The vertical position of this screen line. */static int this_line_vpos;/* Hpos value for start of display on this screen line. Usually zero, but negative if first character really began on previous line */static int this_line_start_hpos;/* Buffer that this_line variables are describing. */static struct buffer *this_line_buffer;/* Value of echo_area_contents when it was last acted on. If this is nonzero, there is a message on the screen in the minibuffer and it should be erased as soon as it is no longer requested to appear. */char *prev_echo_area_contents;/* Nonzero means truncate lines in all windows less wide than the screen */int truncate_partial_width_windows;Lisp_Object Vglobal_mode_string;/* Marker for where to display an arrow on top of the buffer text. */Lisp_Object Voverlay_arrow_position;/* String to display for the arrow. */Lisp_Object Voverlay_arrow_string;/* Values of those variables at last redisplay. */Lisp_Object last_arrow_position, last_arrow_string;/* If cursor motion alone moves point off screen, Try scrolling this many lines up or down if that will bring it back. */int scroll_step;/* Nonzero means send various TERMCAP strings when screen is cleared. */int reset_terminal_on_clear;/* Nonzero if try_window_id has made blank lines at window bottom since the last redisplay that paused */static int blank_end_of_window;/* Number of windows showing the buffer of the selected window. keyboard.c refers to this. */int buffer_shared;/* display_text_line sets these to the screen position (origin 0) of point, whether the window is selected or not. Set one to -1 first to determine whether point was found afterwards. */static int point_vpos;static int point_hpos;int debug_end_pos;/* Nonzero means display mode line highlighted */int mode_line_inverse_video;struct position *display_text_line ();/* Prompt to display in front of the minibuffer contents */char *minibuf_prompt;/* Width in columns of current minibuffer prompt. */int minibuf_prompt_width;/* Message to display instead of minibuffer contents This is what the functions error and message make, and command echoing uses it as well. It overrides the minibuf_prompt as well as the buffer. */char *echo_area_contents;/* True iff we should redraw the mode lines on the next redisplay */int update_mode_lines;/* Smallest number of characters before the gap at any time since last redisplay that finished. Valid for current buffer when try_window_id can be called. */int beg_unchanged;/* Smallest number of characters after the gap at any time since last redisplay that finished. Valid for current buffer when try_window_id can be called. */int end_unchanged;/* MODIFF as of last redisplay that finished; if it matches MODIFF, beg_unchanged and end_unchanged contain no useful information */int unchanged_modified;/* Nonzero if head_clip or tail_clip of current buffer has changed since last redisplay that finished */int clip_changed;/* Nonzero if window sizes or contents have changed since last redisplay that finished */int windows_or_buffers_changed;char *decode_mode_spec ();DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", "Clear the screen and output again what is supposed to appear on it.") (){ if (screen_height == 0) abort (); /* Some bug zeros some core */ if (reset_terminal_on_clear) set_terminal_modes (); clear_screen (); fflush (stdout); clear_screen_records (); if (screen_height == 0) abort (); /* Some bug zeros some core */ windows_or_buffers_changed++; /* Mark all windows as INaccurate, so that every window will have its redisplay done. */ mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 0); if (screen_height == 0) abort (); /* Some bug zeros some core */ return Qnil;}/* Buffer used for messages formatted by `message'. */char *message_buf;/* dump an informative message to the minibuf *//* VARARGS 1 */message (m, a1, a2, a3) char *m;{ if (noninteractive) { if (noninteractive_need_newline) putchar ('\n'); noninteractive_need_newline = 0; printf (m, a1, a2, a3); printf ("\n"); fflush (stdout); } else if (FROM_KBD) {#ifdef NO_ARG_ARRAY int a[3]; a[0] = a1; a[1] = a2; a[2] = a3; doprnt (message_buf, screen_width, m, 3, a);#else doprnt (message_buf, screen_width, m, 3, &a1);#endif /* NO_ARG_ARRAY */ echo_area_contents = message_buf; do { do_pending_window_change (); display_echo_area_contents (); update_screen (1, 1); do_pending_window_change (); } while (screen_garbaged); }}/* Specify m, a string, as a message in the minibuf. */message1 (m) char *m;{ if (noninteractive) { if (noninteractive_need_newline) putchar ('\n'); noninteractive_need_newline = 0; printf ("%s\n", m); fflush (stdout); } else if (FROM_KBD) { echo_area_contents = m; do { do_pending_window_change (); display_echo_area_contents (); update_screen (1, 1); do_pending_window_change (); } while (screen_garbaged); }}display_echo_area_contents (){ register int vpos; if (screen_garbaged) { Fredraw_display (); screen_garbaged = 0; } if (echo_area_contents || minibuf_level == 0) { vpos = XFASTINT (XWINDOW (minibuf_window)->top); get_display_line (vpos, 0); display_string (XWINDOW (minibuf_window), vpos, echo_area_contents ? echo_area_contents : "", 0, 0, 0, screen_width); /* If desired cursor location is on this line, put it at end of text */ if (cursor_vpos == vpos) cursor_hpos = new_screen->used[vpos]; } else if (!EQ (minibuf_window, selected_window)) windows_or_buffers_changed++; if (EQ (minibuf_window, selected_window)) this_line_bufpos = 0; prev_echo_area_contents = echo_area_contents;}/* Do a screen update, taking possible shortcuts into account. This is the main external entry point for redisplay. If the last redisplay displayed an echo area message and that message is no longer requested, we clear the echo area or bring back the minibuffer if that is in use. Everyone would like to have a hook here to call eval, but that cannot be done safely without a lot of changes elsewhere. This can be called from signal handlers; with alarms set up; or with synchronous processes running. See the function `echo' in keyboard.c. See Fcall_process; if you called it from here, it could be entered recursively. */redisplay (){ register struct window *w = XWINDOW (selected_window); register int pause; int inhibit_hairy_id = 0; int must_finish = 0; int all_windows; register int tlbufpos, tlendpos; struct position pos; extern int input_pending; if (noninteractive) return; /* Notice any pending interrupt request to change screen size. */ do_pending_window_change (); if (screen_garbaged) { Fredraw_display (); screen_garbaged = 0; } /* Initially we have nothing to update on the screen. */ bzero (new_screen->enable, new_screen->height); if (echo_area_contents != 0 || prev_echo_area_contents != 0) { display_echo_area_contents (); must_finish = 1; } if (clip_changed || windows_or_buffers_changed) update_mode_lines++; /* Detect case that we need to write a star in the mode line. */ if (XFASTINT (w->last_modified) < MODIFF && XFASTINT (w->last_modified) <= current_buffer->save_modified) { w->update_mode_line = Qt; if (buffer_shared > 1) update_mode_lines++; } all_windows = update_mode_lines || buffer_shared > 1; /* If specs for an arrow have changed, do thorough redisplay to ensure we remove any arrow that should no longer exist. */ if (Voverlay_arrow_position != last_arrow_position || Voverlay_arrow_string != last_arrow_string) all_windows = 1, clip_changed = 1; tlbufpos = this_line_bufpos; tlendpos = this_line_endpos; if (!all_windows && tlbufpos > 0 && NULL (w->update_mode_line) /* Make sure recorded data applies to current buffer, etc */ && this_line_buffer == current_buffer && current_buffer == XBUFFER (w->buffer) && NULL (w->force_start) /* Point must be on the line that we have info recorded about */ && point >= tlbufpos && point <= Z - tlendpos /* All text outside that line, including its final newline, must be unchanged */ && (XFASTINT (w->last_modified) >= MODIFF || (beg_unchanged >= tlbufpos - 1 && GPT >= tlbufpos && end_unchanged >= tlendpos && Z - GPT >= tlendpos))) { if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n' && (tlbufpos == ZV || FETCH_CHAR (tlbufpos) == '\n')) /* Former continuation line has disappeared by becoming empty */ goto cancel; else if (XFASTINT (w->last_modified) < MODIFF || EQ (selected_window, minibuf_window)) { point_vpos = -1; display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos, pos_tab_offset (w, tlbufpos)); /* If line contains point, is not continued, and ends at same distance from eob as before, we win */ if (point_vpos >= 0 && this_line_bufpos && this_line_endpos == tlendpos) { /* Done by display_text_line cursor_hpos = point_hpos; cursor_vpos = this_line_vpos; */ if (XFASTINT (w->width) != screen_width) preserve_other_columns (w); goto update; } else goto cancel; } else if (point == XFASTINT (w->last_point)) { if (!must_finish) return; goto update; } else { pos = *compute_motion (tlbufpos, 0, XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0, point, 2, - (1 << (SHORTBITS - 1)), XFASTINT (w->width) - 1 - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width), XINT (w->hscroll), 0); if (pos.vpos < 1) { cursor_hpos = max (XFASTINT (w->left), pos.hpos); cursor_vpos = this_line_vpos; goto update; } else goto cancel; } cancel: /* Text changed drastically or point moved off of line */ cancel_line (this_line_vpos); } this_line_bufpos = 0; if (all_windows) redisplay_all_windows (); else { redisplay_window (selected_window, 1); if (XFASTINT (w->width) != screen_width) preserve_other_columns (w); }update: /* Prevent various kinds of signals during display update. stdio is not robust about handling signals, which can cause an apparent I/O error. */ if (interrupt_input) unrequest_sigio (); stop_polling (); pause = update_screen (0, 0); /* If screen does not match, prevent doing single-line-update next time. Also, don't forget to check every line to update the arrow. */ if (pause) { this_line_bufpos = 0; if (!NULL (last_arrow_position)) { last_arrow_position = Qt; last_arrow_string = Qt; } /* If we pause after scrolling, some lines in PhysScreen may be null and then preserve_other_columns won't be able to preserve all the vertical-bar separators. So avoid using it in that case. */ if (XFASTINT (w->width) != screen_width) update_mode_lines = 1; } /* Now text on screen agrees with windows, so put info into the windows for partial redisplay to follow */ if (!pause) { struct buffer *b = XBUFFER (w->buffer); blank_end_of_window = 0; clip_changed = 0; unchanged_modified = BUF_MODIFF (b); beg_unchanged = BUF_GPT (b) - BUF_BEG (b); end_unchanged = BUF_Z (b) - BUF_GPT (b); XFASTINT (w->last_point) = BUF_PT (b); XFASTINT (w->last_point_x) = cursor_hpos; XFASTINT (w->last_point_y) = cursor_vpos; if (all_windows) mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1); else { w->update_mode_line = Qnil; XFASTINT (w->last_modified) = BUF_MODIFF (b); w->window_end_valid = Qt; last_arrow_position = Voverlay_arrow_position; last_arrow_string = Voverlay_arrow_string; } update_mode_lines = 0; windows_or_buffers_changed = 0; } /* Start SIGIO interrupts coming again. Having them off during the code above makes it less likely one will discard output, but not impossible, since there might be stuff in the system buffer here. But it is much hairier to try to do anything about that. */ if (interrupt_input) request_sigio (); start_polling (); do_pending_window_change (); if (screen_garbaged) redisplay ();}/* Redisplay, but leave alone any recent echo area message unless another message has been requested in its place. */redisplay_preserve_echo_area (){ if (echo_area_contents == 0 && prev_echo_area_contents != 0) { echo_area_contents = prev_echo_area_contents; redisplay (); echo_area_contents = 0; } else redisplay ();}mark_window_display_accurate (window, flag) Lisp_Object window; int flag;{ register struct window *w; for (;!NULL (window); window = w->next) { w = XWINDOW (window); if (!NULL (w->buffer))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -