📄 lib_mvcur.c
字号:
NCURSES_EXPORT(void)_nc_mvcur_wrap(void)/* wrap up cursor-addressing mode */{ /* leave cursor at screen bottom */ mvcur(-1, -1, screen_lines - 1, 0); /* set cursor to normal mode */ if (SP->_cursor != -1) curs_set(1); if (exit_ca_mode) { TPUTS_TRACE("exit_ca_mode"); putp(exit_ca_mode); } /* * Reset terminal's tab counter. There's a long-time bug that * if you exit a "curses" program such as vi or more, tab * forward, and then backspace, the cursor doesn't go to the * right place. The problem is that the kernel counts the * escape sequences that reset things as column positions. * Utter a \r to reset this invisibly. */ _nc_outch('\r');}/**************************************************************************** * * Optimized cursor movement * ****************************************************************************//* * Perform repeated-append, returning cost */static inline intrepeated_append(string_desc * target, int total, int num, int repeat, const char *src){ size_t need = repeat * strlen(src); if (need < target->s_size) { while (repeat-- > 0) { if (_nc_safe_strcat(target, src)) { total += num; } else { total = INFINITY; break; } } } else { total = INFINITY; } return total;}#ifndef NO_OPTIMIZE#define NEXTTAB(fr) (fr + init_tabs - (fr % init_tabs))/* * Assume back_tab (CBT) does not wrap backwards at the left margin, return * a negative value at that point to simplify the loop. */#define LASTTAB(fr) ((fr > 0) ? ((fr - 1) / init_tabs) * init_tabs : -1)static intrelative_move(string_desc * target, int from_y, int from_x, int to_y, int to_x, bool ovw)/* move via local motions (cuu/cuu1/cud/cud1/cub1/cub/cuf1/cuf/vpa/hpa) */{ string_desc save; int n, vcost = 0, hcost = 0; (void) _nc_str_copy(&save, target); if (to_y != from_y) { vcost = INFINITY; if (row_address != 0 && _nc_safe_strcat(target, tparm(row_address, to_y))) { vcost = SP->_vpa_cost; } if (to_y > from_y) { n = (to_y - from_y); if (parm_down_cursor && SP->_cud_cost < vcost && _nc_safe_strcat(_nc_str_copy(target, &save), tparm(parm_down_cursor, n))) { vcost = SP->_cud_cost; } if (cursor_down && (*cursor_down != '\n' || SP->_nl) && (n * SP->_cud1_cost < vcost)) { vcost = repeated_append(_nc_str_copy(target, &save), 0, SP->_cud1_cost, n, cursor_down); } } else { /* (to_y < from_y) */ n = (from_y - to_y); if (parm_up_cursor && SP->_cuu_cost < vcost && _nc_safe_strcat(_nc_str_copy(target, &save), tparm(parm_up_cursor, n))) { vcost = SP->_cuu_cost; } if (cursor_up && (n * SP->_cuu1_cost < vcost)) { vcost = repeated_append(_nc_str_copy(target, &save), 0, SP->_cuu1_cost, n, cursor_up); } } if (vcost == INFINITY) return (INFINITY); } save = *target; if (to_x != from_x) { char str[OPT_SIZE]; string_desc check; hcost = INFINITY; if (column_address && _nc_safe_strcat(_nc_str_copy(target, &save), tparm(column_address, to_x))) { hcost = SP->_hpa_cost; } if (to_x > from_x) { n = to_x - from_x; if (parm_right_cursor && SP->_cuf_cost < hcost && _nc_safe_strcat(_nc_str_copy(target, &save), tparm(parm_right_cursor, n))) { hcost = SP->_cuf_cost; } if (cursor_right) { int lhcost = 0; (void) _nc_str_init(&check, str, sizeof(str));#if USE_HARD_TABS /* use hard tabs, if we have them, to do as much as possible */ if (init_tabs > 0 && tab) { int nxt, fr; for (fr = from_x; (nxt = NEXTTAB(fr)) <= to_x; fr = nxt) { lhcost = repeated_append(&check, lhcost, SP->_ht_cost, 1, tab); if (lhcost == INFINITY) break; } n = to_x - fr; from_x = fr; }#endif /* USE_HARD_TABS */ if (n <= 0 || n >= (int) check.s_size) ovw = FALSE;#if BSD_TPUTS /* * If we're allowing BSD-style padding in tputs, don't generate * a string with a leading digit. Otherwise, that will be * interpreted as a padding value rather than sent to the * screen. */ if (ovw && n > 0 && n < (int) check.s_size && vcost == 0 && str[0] == '\0') { int wanted = CharOf(WANT_CHAR(to_y, from_x)); if (is8bits(wanted) && isdigit(wanted)) ovw = FALSE; }#endif /* * If we have no attribute changes, overwrite is cheaper. * Note: must suppress this by passing in ovw = FALSE whenever * WANT_CHAR would return invalid data. In particular, this * is true between the time a hardware scroll has been done * and the time the structure WANT_CHAR would access has been * updated. */ if (ovw) { int i; for (i = 0; i < n; i++) { NCURSES_CH_T ch = WANT_CHAR(to_y, from_x + i); if (!SameAttrOf(ch, SCREEN_ATTRS(SP))#if USE_WIDEC_SUPPORT || !Charable(ch)#endif ) { ovw = FALSE; break; } } } if (ovw) { int i; for (i = 0; i < n; i++) *check.s_tail++ = CharOf(WANT_CHAR(to_y, from_x + i)); *check.s_tail = '\0'; check.s_size -= n; lhcost += n * SP->_char_padding; } else { lhcost = repeated_append(&check, lhcost, SP->_cuf1_cost, n, cursor_right); } if (lhcost < hcost && _nc_safe_strcat(_nc_str_copy(target, &save), str)) { hcost = lhcost; } } } else { /* (to_x < from_x) */ n = from_x - to_x; if (parm_left_cursor && SP->_cub_cost < hcost && _nc_safe_strcat(_nc_str_copy(target, &save), tparm(parm_left_cursor, n))) { hcost = SP->_cub_cost; } if (cursor_left) { int lhcost = 0; (void) _nc_str_init(&check, str, sizeof(str));#if USE_HARD_TABS if (init_tabs > 0 && back_tab) { int nxt, fr; for (fr = from_x; (nxt = LASTTAB(fr)) >= to_x; fr = nxt) { lhcost = repeated_append(&check, lhcost, SP->_cbt_cost, 1, back_tab); if (lhcost == INFINITY) break; } n = fr - to_x; }#endif /* USE_HARD_TABS */ lhcost = repeated_append(&check, lhcost, SP->_cub1_cost, n, cursor_left); if (lhcost < hcost && _nc_safe_strcat(_nc_str_copy(target, &save), str)) { hcost = lhcost; } } } if (hcost == INFINITY) return (INFINITY); } return (vcost + hcost);}#endif /* !NO_OPTIMIZE *//* * With the machinery set up above, it's conceivable that * onscreen_mvcur could be modified into a recursive function that does * an alpha-beta search of motion space, as though it were a chess * move tree, with the weight function being boolean and the search * depth equated to length of string. However, this would jack up the * computation cost a lot, especially on terminals without a cup * capability constraining the search tree depth. So we settle for * the simpler method below. */static inline intonscreen_mvcur(int yold, int xold, int ynew, int xnew, bool ovw)/* onscreen move from (yold, xold) to (ynew, xnew) */{ string_desc result; char buffer[OPT_SIZE]; int tactic = 0, newcost, usecost = INFINITY; int t5_cr_cost;#if defined(MAIN) || defined(NCURSES_TEST) struct timeval before, after; gettimeofday(&before, NULL);#endif /* MAIN */#define NullResult _nc_str_null(&result, sizeof(buffer))#define InitResult _nc_str_init(&result, buffer, sizeof(buffer)) /* tactic #0: use direct cursor addressing */ if (_nc_safe_strcpy(InitResult, tparm(SP->_address_cursor, ynew, xnew))) { tactic = 0; usecost = SP->_cup_cost;#if defined(TRACE) || defined(NCURSES_TEST) if (!(_nc_optimize_enable & OPTIMIZE_MVCUR)) goto nonlocal;#endif /* TRACE */ /* * We may be able to tell in advance that the full optimization * will probably not be worth its overhead. Also, don't try to * use local movement if the current attribute is anything but * A_NORMAL...there are just too many ways this can screw up * (like, say, local-movement \n getting mapped to some obscure * character because A_ALTCHARSET is on). */ if (yold == -1 || xold == -1 || NOT_LOCAL(yold, xold, ynew, xnew)) {#if defined(MAIN) || defined(NCURSES_TEST) if (!profiling) { (void) fputs("nonlocal\n", stderr); goto nonlocal; /* always run the optimizer if profiling */ }#else goto nonlocal;#endif /* MAIN */ } }#ifndef NO_OPTIMIZE /* tactic #1: use local movement */ if (yold != -1 && xold != -1 && ((newcost = relative_move(NullResult, yold, xold, ynew, xnew, ovw)) != INFINITY) && newcost < usecost) { tactic = 1; usecost = newcost; } /* tactic #2: use carriage-return + local movement */ if (yold != -1 && carriage_return && ((newcost = relative_move(NullResult, yold, 0, ynew, xnew, ovw)) != INFINITY) && SP->_cr_cost + newcost < usecost) { tactic = 2; usecost = SP->_cr_cost + newcost; } /* tactic #3: use home-cursor + local movement */ if (cursor_home && ((newcost = relative_move(NullResult, 0, 0, ynew, xnew, ovw)) != INFINITY) && SP->_home_cost + newcost < usecost) { tactic = 3; usecost = SP->_home_cost + newcost; } /* tactic #4: use home-down + local movement */ if (cursor_to_ll && ((newcost = relative_move(NullResult, screen_lines - 1, 0, ynew, xnew, ovw)) != INFINITY) && SP->_ll_cost + newcost < usecost) { tactic = 4; usecost = SP->_ll_cost + newcost; } /* * tactic #5: use left margin for wrap to right-hand side, * unless strange wrap behavior indicated by xenl might hose us. */ t5_cr_cost = (xold > 0 ? SP->_cr_cost : 0); if (auto_left_margin && !eat_newline_glitch && yold > 0 && cursor_left && ((newcost = relative_move(NullResult, yold - 1, screen_columns - 1, ynew, xnew, ovw)) != INFINITY) && t5_cr_cost + SP->_cub1_cost + newcost < usecost) { tactic = 5; usecost = t5_cr_cost + SP->_cub1_cost + newcost; } /* * These cases are ordered by estimated relative frequency. */ if (tactic) InitResult; switch (tactic) { case 1: (void) relative_move(&result, yold, xold, ynew, xnew, ovw); break; case 2: (void) _nc_safe_strcpy(&result, carriage_return); (void) relative_move(&result, yold, 0, ynew, xnew, ovw); break; case 3: (void) _nc_safe_strcpy(&result, cursor_home); (void) relative_move(&result, 0, 0, ynew, xnew, ovw); break; case 4: (void) _nc_safe_strcpy(&result, cursor_to_ll); (void) relative_move(&result, screen_lines - 1, 0, ynew, xnew, ovw); break; case 5: if (xold > 0) (void) _nc_safe_strcat(&result, carriage_return); (void) _nc_safe_strcat(&result, cursor_left); (void) relative_move(&result, yold - 1, screen_columns - 1, ynew, xnew, ovw); break; }#endif /* !NO_OPTIMIZE */ nonlocal:#if defined(MAIN) || defined(NCURSES_TEST) gettimeofday(&after, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -