📄 dispnew.c
字号:
current_screen->used[vpos] - end); new_screen->used[vpos] = current_screen->used[vpos]; } } }}/* On discovering that the redisplay for a window was no good, cancel the columns of that window, so that when the window is displayed over again get_display_line will not complain. */cancel_my_columns (w) struct window *w;{ register int vpos; register int start = XFASTINT (w->left); register int bot = XFASTINT (w->top) + XFASTINT (w->height); for (vpos = XFASTINT (w->top); vpos < bot; vpos++) if (new_screen->enable[vpos] && new_screen->used[vpos] >= start) new_screen->used[vpos] = start;}/* These functions try to perform directly and immediately on the screen the necessary output for one change in the buffer. They may return 0 meaning nothing was done if anything is difficult, or 1 meaning the output was performed properly. They assume that the screen was up to date before the buffer change being displayed. THey make various other assumptions too; see command_loop_1 where these are called. */intdirect_output_for_insert (c) int c;{#ifndef COMPILER_REGISTER_BUG register#endif COMPILER_REGISTER_BUG struct window *w = XWINDOW (selected_window);#ifndef COMPILER_REGISTER_BUG register#endif COMPILER_REGISTER_BUG int hpos = cursor_hpos;#ifndef COMPILER_REGISTER_BUG register#endif COMPILER_REGISTER_BUG int vpos = cursor_vpos; /* Give up if about to continue line */ if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width) /* Avoid losing if cursor is in invisible text off left margin */ || XINT (w->hscroll) && hpos == XFASTINT (w->left) /* Give up if cursor outside window (in minibuf, probably) */ || cursor_vpos < XFASTINT (w->top) || cursor_vpos >= XFASTINT (w->top) + XFASTINT (w->height) /* Give up if cursor not really at cursor_hpos, cursor_vpos */ || !display_completed /* Give up if w is minibuffer and a message is being displayed there */ || EQ (selected_window, minibuf_window) && echo_area_contents) return 0; current_screen->contents[vpos][hpos] = c; unchanged_modified = MODIFF; beg_unchanged = GPT - BEG; XFASTINT (w->last_point) = point; XFASTINT (w->last_point_x) = cursor_hpos; XFASTINT (w->last_modified) = MODIFF; reassert_line_highlight (0, cursor_vpos); output_chars (¤t_screen->contents[vpos][hpos], 1); fflush (stdout); ++cursor_hpos; if (hpos == current_screen->used[vpos]) { current_screen->used[vpos] = hpos + 1; current_screen->contents[vpos][hpos + 1] = 0; } return 1;}intdirect_output_forward_char (n) int n;{ register struct window *w = XWINDOW (selected_window); /* Avoid losing if cursor is in invisible text off left margin */ if (XINT (w->hscroll) && cursor_hpos == XFASTINT (w->left)) return 0; cursor_hpos += n; XFASTINT (w->last_point_x) = cursor_hpos; XFASTINT (w->last_point) = point; move_cursor (cursor_vpos, cursor_hpos); fflush (stdout); return 1;}/* Update the actual terminal screen based on the data in new_screen. Value is nonzero if redisplay stopped due to pending input. FORCE nonzero means do not stop for pending input. */update_screen (force, inhibit_hairy_id) int force; int inhibit_hairy_id;{ register struct display_line **p; register struct display_line *l, *lnew; register int i; int pause; int preempt_count = baud_rate / 2400 + 1; extern input_pending; if (screen_height == 0) abort (); /* Some bug zeros some core */ detect_input_pending (); if (!force && ((num_input_chars == debug_preemption_char_count && debug_preemption_vpos == screen_height - 1) || input_pending)) { pause = screen_height; goto do_pause; } update_begin (); if (!line_ins_del_ok) inhibit_hairy_id = 1; /* Don't compute for i/d line if just want cursor motion. */ for (i = 0; i < screen_height; i++) if (new_screen->enable) break; /* Try doing i/d line, if not yet inhibited. */ if (!inhibit_hairy_id && i < screen_height) force |= scrolling (); /* Update the individual lines as needed. Do bottom line first. */ if (new_screen->enable[screen_height - 1]) update_line (screen_height - 1); for (i = 0; i < screen_height - 1 && (force || !input_pending); i++) { if (!force && num_input_chars == debug_preemption_char_count && debug_preemption_vpos == i) break; if (new_screen->enable[i]) { /* Flush out every so many lines. Also flush out if likely to have more than 1k buffered otherwise. I'm told that telnet connections get really screwed by more than 1k output at once. */ int outq = PENDING_OUTPUT_COUNT (stdout); if (outq > 900 || (outq > 20 && ((i - 1) % preempt_count == 0))) { fflush (stdout); if (preempt_count == 1) {#ifdef TIOCOUTQ if (ioctl (0, TIOCOUTQ, &outq) < 0) /* Probably not a tty. Ignore the error and reset * the outq count. */ outq = PENDING_OUTPUT_COUNT (stdout);#endif outq *= 10; sleep (outq / baud_rate); } } if ((i - 1) % preempt_count == 0) detect_input_pending (); /* Now update this line. */ update_line (i); } } pause = (i < screen_height - 1) ? i + 1 : 0; /* Now just clean up termcap drivers and set cursor, etc. */ if (!pause) { if (cursor_in_echo_area < 0) move_cursor (screen_height - 1, 0); else if (cursor_in_echo_area > 0 && !current_screen->enable[screen_height - 1]) move_cursor (screen_height - 1, 0); else if (cursor_in_echo_area) move_cursor (screen_height - 1, min (screen_width - 1, current_screen->used[screen_height - 1])); else move_cursor (cursor_vpos, max (min (cursor_hpos, screen_width - 1), 0)); } update_end (); if (termscript) fflush (termscript); fflush (stdout); /* Here if output is preempted because input is detected. */ do_pause: if (screen_height == 0) abort (); /* Some bug zeros some core */ display_completed = !pause; if (pause) { preemptions[preemption_index].vpos = pause - 1; preemptions[preemption_index].keyboard_char_count = num_input_chars; preemption_index++; if (preemption_index == N_PREEMPTIONS) preemption_index = 0; } bzero (new_screen->enable, screen_height); return pause;}/* Called when about to quit, to check for doing so at an improper time. */voidquit_error_check (){ if (new_screen == 0) return; if (new_screen->enable[0]) abort (); if (new_screen->enable[screen_height - 1]) abort ();}/* Decide what insert/delete line to do, and do it */scrolling (){ int unchanged_at_top, unchanged_at_bottom; int window_size; int changed_lines; int *old_hash = (int *) alloca (screen_height * sizeof (int)); int *new_hash = (int *) alloca (screen_height * sizeof (int)); int *draw_cost = (int *) alloca (screen_height * sizeof (int)); register int i; int free_at_end_vpos = screen_height; /* Compute hash codes of all the lines. Also calculate number of changed lines, number of unchanged lines at the beginning, and number of unchanged lines at the end. */ changed_lines = 0; unchanged_at_top = 0; unchanged_at_bottom = screen_height; for (i = 0; i < screen_height; i++) { /* Give up on this scrolling if some old lines are not enabled. */ if (!current_screen->enable[i]) return 0; old_hash[i] = line_hash_code (current_screen, i); if (!new_screen->enable[i]) new_hash[i] = old_hash[i]; else new_hash[i] = line_hash_code (new_screen, i); if (old_hash[i] != new_hash[i]) { changed_lines++; unchanged_at_bottom = screen_height - i - 1; } else if (i == unchanged_at_top) unchanged_at_top++; /* If line is not changing, its redraw cost is infinite, since we can't redraw it. */ if (!new_screen->enable[i]) draw_cost[i] = INFINITY; else draw_cost[i] = line_draw_cost (new_screen, i); } /* If changed lines are few, don't allow preemption, don't scroll. */ if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height) return 1; window_size = screen_height - unchanged_at_top - unchanged_at_bottom; if (scroll_region_ok) free_at_end_vpos -= unchanged_at_bottom; else if (memory_below_screen) free_at_end_vpos = -1; /* If large window, fast terminal and few lines in common between current_screen and new_screen, don't bother with i/d calc. */ if (window_size >= 18 && baud_rate > 2400 && (window_size >= 10 * scrolling_max_lines_saved (unchanged_at_top, screen_height - unchanged_at_bottom, old_hash, new_hash, draw_cost))) return 0; scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom, draw_cost + unchanged_at_top - 1, old_hash + unchanged_at_top - 1, new_hash + unchanged_at_top - 1, free_at_end_vpos - unchanged_at_top); return 0;}update_line (vpos) int vpos;{ register unsigned char *obody, *nbody, *op1, *op2, *np1; int tem; int osp, nsp, begmatch, endmatch, olen, nlen; int save; unsigned char *temp; /* Check for highlighting change. */ if (new_screen->highlight[vpos] != (current_screen->enable[vpos] && current_screen->highlight[vpos])) { change_line_highlight (new_screen->highlight[vpos], vpos, (current_screen->enable[vpos] ? current_screen->used[vpos] : 0)); current_screen->enable[vpos] = 0; } else reassert_line_highlight (new_screen->highlight[vpos], vpos); /* ??? */ if (! current_screen->enable[vpos]) { olen = 0; } else { obody = current_screen->contents[vpos]; olen = current_screen->used[vpos]; if (! current_screen->highlight[vpos]) { /* Note obody[-1] is always 0. */ if (!must_write_spaces) while (obody[olen - 1] == ' ') olen--; } else { /* For an inverse-video line, remember we gave it spaces all the way to the screen edge so that the reverse video extends all the way across. */ while (olen < screen_width - 1) obody[olen++] = ' '; } } /* One way or another, this will enable the line being updated. */ current_screen->enable[vpos] = 1; current_screen->used[vpos] = new_screen->used[vpos]; current_screen->highlight[vpos] = new_screen->highlight[vpos]; if (!new_screen->enable[vpos]) { nlen = 0; goto just_erase; } nbody = new_screen->contents[vpos]; nlen = new_screen->used[vpos]; /* Pretend trailing spaces are not there at all, unless for one reason or another we must write all spaces. */ /* We know that the previous character byte contains 0. */ if (! new_screen->highlight[vpos]) { if (!must_write_spaces) while (nbody[nlen - 1] == ' ') nlen--; } else { /* For an inverse-video line, give it extra trailing spaces all the way to the screen edge so that the reverse video extends all the way across. */ while (nlen < screen_width - 1) nbody[nlen++] = ' '; } /* If there's no i/d char, quickly do the best we can without it. */ if (!char_ins_del_ok) { int i,j; for (i = 0; i < nlen; i++) { if (i >= olen || nbody[i] != obody[i]) { /* We found a non-matching char. */ move_cursor (vpos, i); for (j = 1; (i + j < nlen && (i + j >= olen || nbody[i+j] != obody[i+j])); j++); /* Output this run of non-matching chars. */ output_chars (nbody + i, j); i += j - 1; /* Now find the next non-match. */ } } /* Clear the rest of the line, or the non-clear part of it. */ if (olen > nlen) { move_cursor (vpos, nlen); clear_end_of_line (olen); } /* Exchange contents between current_screen and new_screen. */ temp = new_screen->contents[vpos]; new_screen->contents[vpos] = current_screen->contents[vpos]; current_screen->contents[vpos] = temp; return; } if (!olen) { nsp = (must_write_spaces || new_screen->highlight[vpos]) ? 0 : count_blanks (nbody); if (nlen > nsp) { move_cursor (vpos, nsp); output_chars (nbody + nsp, nlen - nsp); } /* Exchange contents between current_screen and new_screen. */ temp = new_screen->contents[vpos]; new_screen->contents[vpos] = current_screen->contents[vpos]; current_screen->contents[vpos] = temp; return; } obody[olen] = 1; save = nbody[nlen]; nbody[nlen] = 0; /* Compute number of leading blanks in old and new contents. */ osp = count_blanks (obody); if (!new_screen->highlight[vpos]) nsp = count_blanks (nbody); else nsp = 0; /* Compute number of matching chars starting with first nonblank. */ begmatch = count_match (obody + osp, nbody + nsp); /* Spaces in new match implicit space past the end of old. */ /* A bug causing this to be a no-op was fixed in 18.29. */ if (!must_write_spaces && osp + begmatch == olen) { np1 = nbody + nsp; while (np1[begmatch] == ' ') begmatch++; } /* Avoid doing insert/delete char just cause number of leading spaces differs when the following text does not match. */ if (begmatch == 0 && osp != nsp) osp = nsp = min (osp, nsp); /* Find matching characters at end of line */ op1 = obody + olen; np1 = nbody + nlen; op2 = op1 + begmatch - min (olen - osp, nlen - nsp); while (op1 > op2 && op1[-1] == np1[-1]) { op1--; np1--; } endmatch = obody + olen - op1; /* Put correct value back in nbody[nlen]. This is important because direct_output_for_insert can write into the line at a later point. */ nbody[nlen] = save; /* tem gets the distance to insert or delete. endmatch is how many characters we save by doing so. Is it worth it? */ tem = (nlen - nsp) - (olen - osp); if (endmatch && tem && endmatch <= DCICcost[tem]) endmatch = 0; /* nsp - osp is the distance to insert or delete. begmatch + endmatch is how much we save by doing so. Is it worth it? */ if (begmatch + endmatch > 0 && nsp != osp && begmatch + endmatch <= DCICcost[nsp - osp]) { begmatch = 0; endmatch = 0; osp = nsp = min (osp, nsp); } /* Now go through the line, inserting, writing and deleting as appropriate. */ if (osp > nsp) { move_cursor (vpos, nsp); delete_chars (osp - nsp); } else if (nsp > osp) { /* If going to delete chars later in line and insert earlier in the line,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -