📄 xdisp.c
字号:
XFASTINT (w->last_modified) = !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)); w->window_end_valid = Qt; w->update_mode_line = Qnil; if (!NULL (w->vchild)) mark_window_display_accurate (w->vchild, flag); if (!NULL (w->hchild)) mark_window_display_accurate (w->hchild, flag); } if (flag) { last_arrow_position = Voverlay_arrow_position; last_arrow_string = Voverlay_arrow_string; } else { /* t is unequal to any useful value of Voverlay_arrow_... */ last_arrow_position = Qt; last_arrow_string = Qt; }}int do_id = 1;/* Do full redisplay of one or all windows. This does not include updating the screen; just generating lines to pass to update_screen. *//* Entry point to redisplay all windows */redisplay_all_windows (){ buffer_shared = 0; redisplay_windows (XWINDOW (minibuf_window)->prev);}redisplay_windows (window) Lisp_Object window;{ for (; !NULL (window); window = XWINDOW (window)->next) redisplay_window (window, 0);}redisplay_window (window, just_this_one) Lisp_Object window; int just_this_one;{ register struct window *w = XWINDOW (window); int height; struct buffer *old = current_buffer; register int width = XFASTINT (w->width) - 1 - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width); register int startp; register int hscroll = XINT (w->hscroll); struct position pos; int opoint; int tem; if (screen_height == 0) abort (); /* Some bug zeros some core */ /* If this is a combination window, do its children; that's all. */ if (!NULL (w->vchild)) { redisplay_windows (w->vchild); return; } if (!NULL (w->hchild)) { redisplay_windows (w->hchild); return; } if (NULL (w->buffer)) abort (); if (update_mode_lines) w->update_mode_line = Qt; /* Otherwise set up data on this window; select its buffer and point value */ height = XFASTINT (w->height); if (w != XWINDOW (minibuf_window)) height--; else if (echo_area_contents) return 0; current_buffer = XBUFFER (w->buffer); if (!just_this_one && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer)) buffer_shared++; /* Go temporarily to where point is in the window being displayed. We will restore point at the end. */ opoint = point; if (!EQ (window, selected_window)) { SET_PT (marker_position (w->pointm)); if (point < BEGV) point = BEGV; else if (point > ZV) point = ZV; } /* If window-start is screwed up, choose a new one. */ if (XMARKER (w->start)->buffer != current_buffer) goto recenter; startp = marker_position (w->start); /* Handle case where place to start displaying has been specified */ if (!NULL (w->force_start)) { w->update_mode_line = Qt; w->force_start = Qnil; XFASTINT (w->last_modified) = 0; try_window (window, startp); if (point_vpos < 0) { /* If point does not appear, move point so it does appear */ pos = *compute_motion (startp, 0, ((EQ (window, minibuf_window) && startp == 1) ? minibuf_prompt_width : 0) + (hscroll ? 1 - hscroll : 0), ZV, height / 2, - (1 << (SHORTBITS - 1)), width, hscroll, pos_tab_offset (w, startp)); SET_PT (pos.bufpos); if (w != XWINDOW (selected_window)) Fset_marker (w->pointm, make_number (point), Qnil); else /* We want to change point permanently, so don't restore the old value. */ opoint = point; if (EQ (window, selected_window)) { cursor_hpos = max (0, pos.hpos) + XFASTINT (w->left); cursor_vpos = pos.vpos + XFASTINT (w->top); } } goto done; } /* Handle case where text has not changed, only point, and it has not moved off the screen */ /* This code is not used for minibuffer for the sake of the case of redisplaying to replace an echo area message; since in that case the minibuffer contents per se are usually unchanged. This code is of no real use in the minibuffer since the handling of this_line_bufpos, etc., in redisplay handles the same cases. */ if (XFASTINT (w->last_modified) >= MODIFF && point >= startp && !clip_changed && (just_this_one || XFASTINT (w->width) == screen_width) && !EQ (window, minibuf_window)) { pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), point, height + 1, 10000, width, hscroll, pos_tab_offset (w, startp)); if (pos.vpos < height) { /* Ok, point is still on screen */ if (w == XWINDOW (selected_window)) { /* These variables are supposed to be origin 1 */ cursor_hpos = max (0, pos.hpos) + XFASTINT (w->left); cursor_vpos = pos.vpos + XFASTINT (w->top); }/* This doesn't do the trick, because if a window to the right of this one must be redisplayed, this does nothing because there is nothing in DesiredScreen yet, and then the other window is redisplayed, making likes that are empty in this window's columns. if (XFASTINT (w->width) != screen_width) preserve_my_columns (w);*/ goto done; } /* Don't bother trying redisplay with same start; we already know it will lose */ } /* If current starting point was originally the beginning of a line but no longer is, find a new starting point. */ else if (!NULL (w->start_at_line_beg) && !(startp == BEGV || FETCH_CHAR (startp - 1) == '\n')) { goto recenter; } else if (just_this_one && !EQ (window, minibuf_window) && point >= startp && XFASTINT (w->last_modified) && ! EQ (w->window_end_valid, Qnil) && do_id && !clip_changed && !blank_end_of_window && XFASTINT (w->width) == screen_width && EQ (last_arrow_position, Voverlay_arrow_position) && EQ (last_arrow_string, Voverlay_arrow_string) && (tem = try_window_id (selected_window)) && tem != -2) { /* tem > 0 means success. tem == -1 means choose new start. tem == -2 means try again with same start, and nothing but whitespace follows the changed stuff. tem == 0 means try again with same start. */ if (tem > 0) { goto done; } } else if (startp >= BEGV && startp <= ZV /* Avoid starting display at end of buffer! */ && (startp < ZV || startp == BEGV || (XFASTINT (w->last_modified) >= MODIFF))) { /* Try to redisplay starting at same place as before */ /* If point has not moved off screen, accept the results */ try_window (window, startp); if (point_vpos >= 0) goto done; else cancel_my_columns (w); } XFASTINT (w->last_modified) = 0; w->update_mode_line = Qt; /* Try to scroll by specified few lines */ if (scroll_step && !clip_changed) { if (point > startp) { pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, width, hscroll, window); if (pos.vpos >= height) goto scroll_fail; } pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step, width, hscroll, window); if (point >= pos.bufpos) { try_window (window, pos.bufpos); if (point_vpos >= 0) goto done; else cancel_my_columns (w); } scroll_fail: ; } /* Finally, just choose place to start which centers point */recenter: pos = *vmotion (point, - height / 2, width, hscroll, window); try_window (window, pos.bufpos); startp = marker_position (w->start); w->start_at_line_beg = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;done: /* If window not full width, must redo its mode line if the window to its side is being redone */ if ((!NULL (w->update_mode_line) || (!just_this_one && width < screen_width - 1)) && !EQ (window, minibuf_window)) display_mode_line (w); SET_PT (opoint); current_buffer = old;}/* Do full redisplay on one window, starting at position `pos'. */try_window (window, pos) Lisp_Object window; register int pos;{ register struct window *w = XWINDOW (window); register int height = XFASTINT (w->height) - !EQ (window, minibuf_window); register int vpos = XFASTINT (w->top); register int last_text_vpos = vpos; int tab_offset = pos_tab_offset (w, pos); struct position val; Fset_marker (w->start, make_number (pos), Qnil); point_vpos = -1; val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0; while (--height >= 0) { val = *display_text_line (w, pos, vpos, val.hpos, tab_offset); tab_offset += XFASTINT (w->width) - 1; if (val.vpos) tab_offset = 0; vpos++; if (pos != val.bufpos) last_text_vpos /* Next line, unless prev line ended in end of buffer with no cr */ = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n'); pos = val.bufpos; } /* If last line is continued in middle of character, include the split character in the text considered on the screen */ if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0)) pos++; /* Say where last char on screen will be, once redisplay is finished. */ XFASTINT (w->window_end_pos) = Z - pos; XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top); /* But that is not valid info until redisplay finishes. */ w->window_end_valid = Qnil;}/* Try to redisplay when buffer is modified locally, computing insert/delete line to preserve text outside the bounds of the changes. Return 1 if successful, 0 if if cannot tell what to do, or -1 to tell caller to find a new window start, or -2 to tell caller to do normal redisplay with same window start. */static struct position debug_bp, debug_ep, debug_xp, debug_pp;static int debug_start_vpos, debug_stop_vpos, debug_scroll_amount;static int debug_dont_scroll;try_window_id (window) Lisp_Object window;{ int pos; register struct window *w = XWINDOW (window); register int height = XFASTINT (w->height) - !EQ (window, minibuf_window); int top = XFASTINT (w->top); int start = marker_position (w->start); int width = XFASTINT (w->width) - 1 - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width); int hscroll = XINT (w->hscroll); int lmargin = hscroll > 0 ? 1 - hscroll : 0; register int vpos; register int i, tem; int last_text_vpos = 0; int stop_vpos; struct position val, bp, ep, xp, pp; int scroll_amount = 0; int delta; int tab_offset, epto; if (GPT - BEG < beg_unchanged) beg_unchanged = GPT - BEG; if (Z - GPT < end_unchanged) end_unchanged = Z - GPT; if (beg_unchanged + 1 < start) return 0; /* Give up if changes go above top of window */ /* Find position before which nothing is changed. */ bp = *compute_motion (start, 0, lmargin, beg_unchanged + 1, 10000, 10000, width, hscroll, pos_tab_offset (w, start)); if (bp.vpos >= height) return point < bp.bufpos && !bp.contin; vpos = bp.vpos; /* Find beginning of that screen line. Must display from there. */ bp = *vmotion (bp.bufpos, 0, width, hscroll, window); pos = bp.bufpos; val.hpos = lmargin; if (pos < start) return -1; /* If about to start displaying at the beginning of a continuation line, really start with previous screen line, in case it was not continued when last redisplayed */ if (bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0) { bp = *vmotion (bp.bufpos, -1, width, hscroll, window); --vpos; pos = bp.bufpos; } if (bp.contin && bp.hpos != lmargin) { val.hpos = bp.prevhpos - width + lmargin; pos--; } bp.vpos = vpos; /* Find first visible newline after which no more is changed. */ tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1); if (XTYPE (current_buffer->selective_display) == Lisp_Int && XINT (current_buffer->selective_display) > 0) while (tem < ZV - 1 && (position_indentation (tem) >= XINT (current_buffer->selective_display))) tem = find_next_newline (tem, 1); /* Compute the cursor position after that newline. */ ep = *compute_motion (pos, vpos, val.hpos, tem, height, - (1 << (SHORTBITS - 1)), width, hscroll, pos_tab_offset (w, bp.bufpos)); /* If changes reach past the text available on the screen, just display rest of screen. */ if (ep.bufpos > Z - XFASTINT (w->window_end_pos)) stop_vpos = height; else stop_vpos = ep.vpos; /* If no newline before ep, the line ep is on includes some changes that must be displayed. Make sure we don't stop before it. */ /* Also, if changes reach all the way until ep.bufpos, it is possible that something was deleted after the newline before it, so the following line must be redrawn. */ if (stop_vpos == ep.vpos && (ep.bufpos == BEGV || FETCH_CHAR (ep.bufpos - 1) != '\n' || ep.bufpos == Z - end_unchanged)) stop_vpos = ep.vpos + 1; point_vpos = -1; debug_dont_scroll = 0; /* If changes do not reach to bottom of window, figure out how much to scroll the rest of the window */ if (stop_vpos < height) { /* Now determine how far up or down the rest of the window has moved */ epto = pos_tab_offset (w, ep.bufpos); xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, Z - XFASTINT (w->window_end_pos), 10000, 0, width, hscroll, epto); scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos); /* Is everything on screen below the changes whitespace? If so, no scrolling is really necessary. */ for (i = ep.bufpos; i < xp.bufpos; i++) { tem = FETCH_CHAR (i); if (tem != ' ' && tem != '\n' && tem != '\t') break; } if (i == xp.bufpos) return -2; XFASTINT (w->window_end_vpos) += scroll_amount; /* Before doing any scrolling, verify that point will be on screen. */ if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height)) { if (point <= xp.bufpos) { pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, point, height, - (1 << (SHORTBITS - 1)), width, hscroll, epto); } else { pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, point, height, - (1 << (SHORTBITS - 1)), width, hscroll, pos_tab_offset (w, xp.bufpos)); } if (pp.bufpos < point || pp.vpos == height) return 0; point_vpos = pp.vpos + top; point_hpos = pp.hpos + XFASTINT (w->left); } if (stop_vpos - scroll_amount >= height || ep.bufpos == xp.bufpos) { if (scroll_amount < 0) stop_vpos -= scroll_amount; scroll_amount = 0; debug_dont_scroll = 1; /* In this path, we have altered window_end_vpos and not left it negative. We must make sure that, in case display is preempted before the screen changes to reflect what we do here, further updates will not come to try_window_id and assume the screen and window_end_vpos match. */ blank_end_of_window = 1; } else if (!scroll_amount) {} else if (bp.bufpos == Z - end_unchanged) { /* If reprinting everything is nearly as fast as scrolling, don't bother scrolling. Can happen if lines are short. */ if (scroll_cost (bp.vpos + top - scroll_amount, top + height - max (0, scroll_amount), scroll_amount) > xp.bufpos - bp.bufpos - 20) /* Return "try normal display with same window-start." Too bad we can't prevent further scroll-thinking. */ return -2; /* If pure deletion, scroll up as many lines as possible. In common case of killing a line, this can save the following line from being overwritten by scrolling
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -