# HG changeset patch # User Bram Moolenaar # Date 1642710603 -3600 # Node ID a9f0c1f06c84a915894a2da5711c4755af4cfa65 # Parent 09a65231156f65bcf1da5409986cfcf87e156f98 patch 8.2.4165: the nv_g_cmd() function is too long Commit: https://github.com/vim/vim/commit/05386ca1d4823e5c98c24b8cd038af49aee62577 Author: Yegappan Lakshmanan Date: Thu Jan 20 20:18:27 2022 +0000 patch 8.2.4165: the nv_g_cmd() function is too long Problem: The nv_g_cmd() function is too long. Solution: Move code to separate functions. (Yegappan Lakshmanan, closes #9576) diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -5890,31 +5890,275 @@ nv_suspend(cmdarg_T *cap) } /* + * "gv": Reselect the previous Visual area. If Visual already active, + * exchange previous and current Visual area. + */ + static void +nv_gv_cmd(cmdarg_T *cap) +{ + pos_T tpos; + int i; + + if (checkclearop(cap->oap)) + return; + + if (curbuf->b_visual.vi_start.lnum == 0 + || curbuf->b_visual.vi_start.lnum > curbuf->b_ml.ml_line_count + || curbuf->b_visual.vi_end.lnum == 0) + { + beep_flush(); + return; + } + + // set w_cursor to the start of the Visual area, tpos to the end + if (VIsual_active) + { + i = VIsual_mode; + VIsual_mode = curbuf->b_visual.vi_mode; + curbuf->b_visual.vi_mode = i; +# ifdef FEAT_EVAL + curbuf->b_visual_mode_eval = i; +# endif + i = curwin->w_curswant; + curwin->w_curswant = curbuf->b_visual.vi_curswant; + curbuf->b_visual.vi_curswant = i; + + tpos = curbuf->b_visual.vi_end; + curbuf->b_visual.vi_end = curwin->w_cursor; + curwin->w_cursor = curbuf->b_visual.vi_start; + curbuf->b_visual.vi_start = VIsual; + } + else + { + VIsual_mode = curbuf->b_visual.vi_mode; + curwin->w_curswant = curbuf->b_visual.vi_curswant; + tpos = curbuf->b_visual.vi_end; + curwin->w_cursor = curbuf->b_visual.vi_start; + } + + VIsual_active = TRUE; + VIsual_reselect = TRUE; + + // Set Visual to the start and w_cursor to the end of the Visual + // area. Make sure they are on an existing character. + check_cursor(); + VIsual = curwin->w_cursor; + curwin->w_cursor = tpos; + check_cursor(); + update_topline(); + + // When called from normal "g" command: start Select mode when + // 'selectmode' contains "cmd". When called for K_SELECT, always + // start Select mode. + if (cap->arg) + { + VIsual_select = TRUE; + VIsual_select_reg = 0; + } + else + may_start_select('c'); + setmouse(); +#ifdef FEAT_CLIPBOARD + // Make sure the clipboard gets updated. Needed because start and + // end are still the same, and the selection needs to be owned + clip_star.vmode = NUL; +#endif + redraw_curbuf_later(INVERTED); + showmode(); +} + +/* + * "g0", "g^" : Like "0" and "^" but for screen lines. + * "gm": middle of "g0" and "g$". + */ + static void +nv_g_home_m_cmd(cmdarg_T *cap) +{ + int i; + int flag = FALSE; + + if (cap->nchar == '^') + flag = TRUE; + + cap->oap->motion_type = MCHAR; + cap->oap->inclusive = FALSE; + if (curwin->w_p_wrap && curwin->w_width != 0) + { + int width1 = curwin->w_width - curwin_col_off(); + int width2 = width1 + curwin_col_off2(); + + validate_virtcol(); + i = 0; + if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0) + i = (curwin->w_virtcol - width1) / width2 * width2 + width1; + } + else + i = curwin->w_leftcol; + // Go to the middle of the screen line. When 'number' or + // 'relativenumber' is on and lines are wrapping the middle can be more + // to the left. + if (cap->nchar == 'm') + i += (curwin->w_width - curwin_col_off() + + ((curwin->w_p_wrap && i > 0) + ? curwin_col_off2() : 0)) / 2; + coladvance((colnr_T)i); + if (flag) + { + do + i = gchar_cursor(); + while (VIM_ISWHITE(i) && oneright() == OK); + curwin->w_valid &= ~VALID_WCOL; + } + curwin->w_set_curswant = TRUE; +} + +/* + * "g_": to the last non-blank character in the line or lines + * downward. + */ + static void +nv_g_underscore_cmd(cmdarg_T *cap) +{ + char_u *ptr; + + cap->oap->motion_type = MCHAR; + cap->oap->inclusive = TRUE; + curwin->w_curswant = MAXCOL; + if (cursor_down((long)(cap->count1 - 1), + cap->oap->op_type == OP_NOP) == FAIL) + { + clearopbeep(cap->oap); + return; + } + + ptr = ml_get_curline(); + + // In Visual mode we may end up after the line. + if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL) + --curwin->w_cursor.col; + + // Decrease the cursor column until it's on a non-blank. + while (curwin->w_cursor.col > 0 + && VIM_ISWHITE(ptr[curwin->w_cursor.col])) + --curwin->w_cursor.col; + curwin->w_set_curswant = TRUE; + adjust_for_sel(cap); +} + +/* + * "g$" : Like "$" but for screen lines. + */ + static void +nv_g_dollar_cmd(cmdarg_T *cap) +{ + oparg_T *oap = cap->oap; + int i; + int col_off = curwin_col_off(); + + oap->motion_type = MCHAR; + oap->inclusive = TRUE; + if (curwin->w_p_wrap && curwin->w_width != 0) + { + curwin->w_curswant = MAXCOL; // so we stay at the end + if (cap->count1 == 1) + { + int width1 = curwin->w_width - col_off; + int width2 = width1 + curwin_col_off2(); + + validate_virtcol(); + i = width1 - 1; + if (curwin->w_virtcol >= (colnr_T)width1) + i += ((curwin->w_virtcol - width1) / width2 + 1) + * width2; + coladvance((colnr_T)i); + + // Make sure we stick in this column. + validate_virtcol(); + curwin->w_curswant = curwin->w_virtcol; + curwin->w_set_curswant = FALSE; + if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) + { + // Check for landing on a character that got split at + // the end of the line. We do not want to advance to + // the next screen line. + if (curwin->w_virtcol > (colnr_T)i) + --curwin->w_cursor.col; + } + } + else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == FAIL) + clearopbeep(oap); + } + else + { + if (cap->count1 > 1) + // if it fails, let the cursor still move to the last char + (void)cursor_down(cap->count1 - 1, FALSE); + + i = curwin->w_leftcol + curwin->w_width - col_off - 1; + coladvance((colnr_T)i); + + // if the character doesn't fit move one back + if (curwin->w_cursor.col > 0 + && (*mb_ptr2cells)(ml_get_cursor()) > 1) + { + colnr_T vcol; + + getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol); + if (vcol >= curwin->w_leftcol + curwin->w_width - col_off) + --curwin->w_cursor.col; + } + + // Make sure we stick in this column. + validate_virtcol(); + curwin->w_curswant = curwin->w_virtcol; + curwin->w_set_curswant = FALSE; + } +} + +/* + * "gi": start Insert at the last position. + */ + static void +nv_gi_cmd(cmdarg_T *cap) +{ + int i; + + if (curbuf->b_last_insert.lnum != 0) + { + curwin->w_cursor = curbuf->b_last_insert; + check_cursor_lnum(); + i = (int)STRLEN(ml_get_curline()); + if (curwin->w_cursor.col > (colnr_T)i) + { + if (virtual_active()) + curwin->w_cursor.coladd += curwin->w_cursor.col - i; + curwin->w_cursor.col = i; + } + } + cap->cmdchar = 'i'; + nv_edit(cap); +} + +/* * Commands starting with "g". */ static void nv_g_cmd(cmdarg_T *cap) { oparg_T *oap = cap->oap; - pos_T tpos; int i; - int flag = FALSE; switch (cap->nchar) { case Ctrl_A: case Ctrl_X: #ifdef MEM_PROFILE - /* - * "g^A": dump log of used memory. - */ + // "g^A": dump log of used memory. if (!VIsual_active && cap->nchar == Ctrl_A) vim_mem_profile_dump(); else #endif - /* - * "g^A/g^X": sequentially increment visually selected region - */ + // "g^A/g^X": sequentially increment visually selected region if (VIsual_active) { cap->arg = TRUE; @@ -5926,9 +6170,7 @@ nv_g_cmd(cmdarg_T *cap) clearopbeep(oap); break; - /* - * "gR": Enter virtual replace mode. - */ + // "gR": Enter virtual replace mode. case 'R': cap->arg = TRUE; nv_Replace(cap); @@ -5942,91 +6184,21 @@ nv_g_cmd(cmdarg_T *cap) do_cmdline_cmd((char_u *)"%s//~/&"); break; - /* - * "gv": Reselect the previous Visual area. If Visual already active, - * exchange previous and current Visual area. - */ + // "gv": Reselect the previous Visual area. If Visual already active, + // exchange previous and current Visual area. case 'v': - if (checkclearop(oap)) - break; - - if ( curbuf->b_visual.vi_start.lnum == 0 - || curbuf->b_visual.vi_start.lnum > curbuf->b_ml.ml_line_count - || curbuf->b_visual.vi_end.lnum == 0) - beep_flush(); - else - { - // set w_cursor to the start of the Visual area, tpos to the end - if (VIsual_active) - { - i = VIsual_mode; - VIsual_mode = curbuf->b_visual.vi_mode; - curbuf->b_visual.vi_mode = i; -# ifdef FEAT_EVAL - curbuf->b_visual_mode_eval = i; -# endif - i = curwin->w_curswant; - curwin->w_curswant = curbuf->b_visual.vi_curswant; - curbuf->b_visual.vi_curswant = i; - - tpos = curbuf->b_visual.vi_end; - curbuf->b_visual.vi_end = curwin->w_cursor; - curwin->w_cursor = curbuf->b_visual.vi_start; - curbuf->b_visual.vi_start = VIsual; - } - else - { - VIsual_mode = curbuf->b_visual.vi_mode; - curwin->w_curswant = curbuf->b_visual.vi_curswant; - tpos = curbuf->b_visual.vi_end; - curwin->w_cursor = curbuf->b_visual.vi_start; - } - - VIsual_active = TRUE; - VIsual_reselect = TRUE; - - // Set Visual to the start and w_cursor to the end of the Visual - // area. Make sure they are on an existing character. - check_cursor(); - VIsual = curwin->w_cursor; - curwin->w_cursor = tpos; - check_cursor(); - update_topline(); - /* - * When called from normal "g" command: start Select mode when - * 'selectmode' contains "cmd". When called for K_SELECT, always - * start Select mode. - */ - if (cap->arg) - { - VIsual_select = TRUE; - VIsual_select_reg = 0; - } - else - may_start_select('c'); - setmouse(); -#ifdef FEAT_CLIPBOARD - // Make sure the clipboard gets updated. Needed because start and - // end are still the same, and the selection needs to be owned - clip_star.vmode = NUL; -#endif - redraw_curbuf_later(INVERTED); - showmode(); - } + nv_gv_cmd(cap); break; - /* - * "gV": Don't reselect the previous Visual area after a Select mode - * mapping of menu. - */ + + // "gV": Don't reselect the previous Visual area after a Select mode + // mapping of menu. case 'V': VIsual_reselect = FALSE; break; - /* - * "gh": start Select mode. - * "gH": start Select line mode. - * "g^H": start Select block mode. - */ + // "gh": start Select mode. + // "gH": start Select line mode. + // "g^H": start Select block mode. case K_BS: cap->nchar = Ctrl_H; // FALLTHROUGH @@ -6053,10 +6225,8 @@ nv_g_cmd(cmdarg_T *cap) clearopbeep(oap); break; - /* - * "gj" and "gk" two new funny movement keys -- up and down - * movement based on *screen* line rather than *file* line. - */ + // "gj" and "gk" two new funny movement keys -- up and down + // movement based on *screen* line rather than *file* line. case 'j': case K_DOWN: // with 'nowrap' it works just like the normal "j" command. @@ -6085,55 +6255,19 @@ nv_g_cmd(cmdarg_T *cap) clearopbeep(oap); break; - /* - * "gJ": join two lines without inserting a space. - */ + // "gJ": join two lines without inserting a space. case 'J': nv_join(cap); break; - /* - * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines. - * "gm": middle of "g0" and "g$". - */ + // "g0", "g^" : Like "0" and "^" but for screen lines. + // "gm": middle of "g0" and "g$". case '^': - flag = TRUE; - // FALLTHROUGH - case '0': case 'm': case K_HOME: case K_KHOME: - oap->motion_type = MCHAR; - oap->inclusive = FALSE; - if (curwin->w_p_wrap && curwin->w_width != 0) - { - int width1 = curwin->w_width - curwin_col_off(); - int width2 = width1 + curwin_col_off2(); - - validate_virtcol(); - i = 0; - if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0) - i = (curwin->w_virtcol - width1) / width2 * width2 + width1; - } - else - i = curwin->w_leftcol; - // Go to the middle of the screen line. When 'number' or - // 'relativenumber' is on and lines are wrapping the middle can be more - // to the left. - if (cap->nchar == 'm') - i += (curwin->w_width - curwin_col_off() - + ((curwin->w_p_wrap && i > 0) - ? curwin_col_off2() : 0)) / 2; - coladvance((colnr_T)i); - if (flag) - { - do - i = gchar_cursor(); - while (VIM_ISWHITE(i) && oneright() == OK); - curwin->w_valid &= ~VALID_WCOL; - } - curwin->w_set_curswant = TRUE; + nv_g_home_m_cmd(cap); break; case 'M': @@ -6149,104 +6283,20 @@ nv_g_cmd(cmdarg_T *cap) } break; + // "g_": to the last non-blank character in the line or lines + // downward. case '_': - // "g_": to the last non-blank character in the line or lines - // downward. - cap->oap->motion_type = MCHAR; - cap->oap->inclusive = TRUE; - curwin->w_curswant = MAXCOL; - if (cursor_down((long)(cap->count1 - 1), - cap->oap->op_type == OP_NOP) == FAIL) - clearopbeep(cap->oap); - else - { - char_u *ptr = ml_get_curline(); - - // In Visual mode we may end up after the line. - if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL) - --curwin->w_cursor.col; - - // Decrease the cursor column until it's on a non-blank. - while (curwin->w_cursor.col > 0 - && VIM_ISWHITE(ptr[curwin->w_cursor.col])) - --curwin->w_cursor.col; - curwin->w_set_curswant = TRUE; - adjust_for_sel(cap); - } + nv_g_underscore_cmd(cap); break; + // "g$" : Like "$" but for screen lines. case '$': case K_END: case K_KEND: - { - int col_off = curwin_col_off(); - - oap->motion_type = MCHAR; - oap->inclusive = TRUE; - if (curwin->w_p_wrap && curwin->w_width != 0) - { - curwin->w_curswant = MAXCOL; // so we stay at the end - if (cap->count1 == 1) - { - int width1 = curwin->w_width - col_off; - int width2 = width1 + curwin_col_off2(); - - validate_virtcol(); - i = width1 - 1; - if (curwin->w_virtcol >= (colnr_T)width1) - i += ((curwin->w_virtcol - width1) / width2 + 1) - * width2; - coladvance((colnr_T)i); - - // Make sure we stick in this column. - validate_virtcol(); - curwin->w_curswant = curwin->w_virtcol; - curwin->w_set_curswant = FALSE; - if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) - { - /* - * Check for landing on a character that got split at - * the end of the line. We do not want to advance to - * the next screen line. - */ - if (curwin->w_virtcol > (colnr_T)i) - --curwin->w_cursor.col; - } - } - else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == FAIL) - clearopbeep(oap); - } - else - { - if (cap->count1 > 1) - // if it fails, let the cursor still move to the last char - (void)cursor_down(cap->count1 - 1, FALSE); - - i = curwin->w_leftcol + curwin->w_width - col_off - 1; - coladvance((colnr_T)i); - - // if the character doesn't fit move one back - if (curwin->w_cursor.col > 0 - && (*mb_ptr2cells)(ml_get_cursor()) > 1) - { - colnr_T vcol; - - getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol); - if (vcol >= curwin->w_leftcol + curwin->w_width - col_off) - --curwin->w_cursor.col; - } - - // Make sure we stick in this column. - validate_virtcol(); - curwin->w_curswant = curwin->w_virtcol; - curwin->w_set_curswant = FALSE; - } - } + nv_g_dollar_cmd(cap); break; - /* - * "g*" and "g#", like "*" and "#" but without using "\<" and "\>" - */ + // "g*" and "g#", like "*" and "#" but without using "\<" and "\>" case '*': case '#': #if POUND != '#' @@ -6257,9 +6307,7 @@ nv_g_cmd(cmdarg_T *cap) nv_ident(cap); break; - /* - * ge and gE: go back to end of word - */ + // ge and gE: go back to end of word case 'e': case 'E': oap->motion_type = MCHAR; @@ -6269,36 +6317,17 @@ nv_g_cmd(cmdarg_T *cap) clearopbeep(oap); break; - /* - * "g CTRL-G": display info about cursor position - */ + // "g CTRL-G": display info about cursor position case Ctrl_G: cursor_pos_info(NULL); break; - /* - * "gi": start Insert at the last position. - */ + // "gi": start Insert at the last position. case 'i': - if (curbuf->b_last_insert.lnum != 0) - { - curwin->w_cursor = curbuf->b_last_insert; - check_cursor_lnum(); - i = (int)STRLEN(ml_get_curline()); - if (curwin->w_cursor.col > (colnr_T)i) - { - if (virtual_active()) - curwin->w_cursor.coladd += curwin->w_cursor.col - i; - curwin->w_cursor.col = i; - } - } - cap->cmdchar = 'i'; - nv_edit(cap); + nv_gi_cmd(cap); break; - /* - * "gI": Start insert in column 1. - */ + // "gI": Start insert in column 1. case 'I': beginline(0); if (!checkclearopq(oap)) @@ -6306,17 +6335,15 @@ nv_g_cmd(cmdarg_T *cap) break; #ifdef FEAT_SEARCHPATH - /* - * "gf": goto file, edit file under cursor - * "]f" and "[f": can also be used. - */ + // "gf": goto file, edit file under cursor + // "]f" and "[f": can also be used. case 'f': case 'F': nv_gotofile(cap); break; #endif - // "g'm" and "g`m": jump to mark without setting pcmark + // "g'm" and "g`m": jump to mark without setting pcmark case '\'': cap->arg = TRUE; // FALLTHROUGH @@ -6324,26 +6351,20 @@ nv_g_cmd(cmdarg_T *cap) nv_gomark(cap); break; - /* - * "gs": Goto sleep. - */ + // "gs": Goto sleep. case 's': do_sleep(cap->count1 * 1000L, FALSE); break; - /* - * "ga": Display the ascii value of the character under the - * cursor. It is displayed in decimal, hex, and octal. -- webb - */ + // "ga": Display the ascii value of the character under the + // cursor. It is displayed in decimal, hex, and octal. -- webb case 'a': do_ascii(NULL); break; - /* - * "g8": Display the bytes used for the UTF-8 character under the - * cursor. It is displayed in hex. - * "8g8" finds illegal byte sequence. - */ + // "g8": Display the bytes used for the UTF-8 character under the + // cursor. It is displayed in hex. + // "8g8" finds illegal byte sequence. case '8': if (cap->count0 == 8) utf_find_illegal(); @@ -6356,25 +6377,21 @@ nv_g_cmd(cmdarg_T *cap) show_sb_text(); break; - /* - * "gg": Goto the first line in file. With a count it goes to - * that line number like for "G". -- webb - */ + // "gg": Goto the first line in file. With a count it goes to + // that line number like for "G". -- webb case 'g': cap->arg = FALSE; nv_goto(cap); break; - /* - * Two-character operators: - * "gq" Format text - * "gw" Format text and keep cursor position - * "g~" Toggle the case of the text. - * "gu" Change text to lower case. - * "gU" Change text to upper case. - * "g?" rot13 encoding - * "g@" call 'operatorfunc' - */ + // Two-character operators: + // "gq" Format text + // "gw" Format text and keep cursor position + // "g~" Toggle the case of the text. + // "gu" Change text to lower case. + // "gU" Change text to upper case. + // "g?" rot13 encoding + // "g@" call 'operatorfunc' case 'q': case 'w': oap->cursor_start = curwin->w_cursor; @@ -6387,19 +6404,15 @@ nv_g_cmd(cmdarg_T *cap) nv_operator(cap); break; - /* - * "gd": Find first occurrence of pattern under the cursor in the - * current function - * "gD": idem, but in the current file. - */ + // "gd": Find first occurrence of pattern under the cursor in the + // current function + // "gD": idem, but in the current file. case 'd': case 'D': nv_gd(oap, cap->nchar, (int)cap->count0); break; - /* - * g<*Mouse> : - */ + // g<*Mouse> : case K_MIDDLEMOUSE: case K_MIDDLEDRAG: case K_MIDDLERELEASE: @@ -6423,9 +6436,7 @@ nv_g_cmd(cmdarg_T *cap) case K_IGNORE: break; - /* - * "gP" and "gp": same as "P" and "p" but leave cursor just after new text - */ + // "gP" and "gp": same as "P" and "p" but leave cursor just after new text case 'p': case 'P': nv_put(cap); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4165, +/**/ 4164, /**/ 4163,