changeset 27273:a9f0c1f06c84 v8.2.4165

patch 8.2.4165: the nv_g_cmd() function is too long Commit: https://github.com/vim/vim/commit/05386ca1d4823e5c98c24b8cd038af49aee62577 Author: Yegappan Lakshmanan <yegappan@yahoo.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Thu, 20 Jan 2022 21:30:03 +0100
parents 09a65231156f
children 34e3b99f045d
files src/normal.c src/version.c
diffstat 2 files changed, 305 insertions(+), 292 deletions(-) [+]
line wrap: on
line diff
--- 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 <count> 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 <count> lines
+    // downward.
     case '_':
-	// "g_": to the last non-blank character in the line or <count> 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> : <C-*mouse>
-     */
+    // g<*Mouse> : <C-*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);
--- 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,