From aa5341477c9f3840d63f709de3b9e5d0266f93d7 Mon Sep 17 00:00:00 2001
From: Bram Moolenaar <Bram@vim.org>
Date: Thu, 15 Sep 2022 21:46:02 +0100
Subject: [PATCH] patch 9.0.0473: fullcommand() only works for the current
 script version

Problem:    fullcommand() only works for the current script version.
Solution:   Add an optional argument for the script version.
---
 runtime/doc/builtin.txt           | 14 ++++++++++----
 src/ex_docmd.c                    | 30 +++++++++++++++++++++++-------
 src/testdir/test_cmdline.vim      |  3 +++
 src/testdir/test_vim9_builtin.vim |  7 +++++++
 4 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index fb8b116010095..53179ca85aba6 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -195,7 +195,7 @@ foldlevel({lnum})		Number	fold level at {lnum}
 foldtext()			String	line displayed for closed fold
 foldtextresult({lnum})		String	text for closed fold at {lnum}
 foreground()			Number	bring the Vim window to the foreground
-fullcommand({name})		String	get full command from {name}
+fullcommand({name} [, {vim9}])	String	get full command from {name}
 funcref({name} [, {arglist}] [, {dict}])
 				Funcref	reference to function {name}
 function({name} [, {arglist}] [, {dict}])
@@ -2954,14 +2954,20 @@ foreground()	Move the Vim window to the foreground.  Useful when sent from
 		{only in the Win32, Motif and GTK GUI versions and the
 		Win32 console version}
 
-fullcommand({name})						*fullcommand()*
+fullcommand({name} [, {vim9}])				*fullcommand()*
 		Get the full command name from a short abbreviated command
 		name; see |20.2| for details on command abbreviations.
 
 		The string argument {name} may start with a `:` and can
 		include a [range], these are skipped and not returned.
-		Returns an empty string if a command doesn't exist or if it's
-		ambiguous (for user-defined commands).
+		Returns an empty string if a command doesn't exist, if it's
+		ambiguous (for user-defined commands) or cannot be shortened
+		this way. |vim9-no-shorten|
+
+		Without the {vim9} argument uses the current script version.
+		If {vim9} is present and FALSE then legacy script rules are
+		used.  When {vim9} is present and TRUE then Vim9 rules are
+		used, e.g. "en" is not a short form of "endif".
 
 		For example `fullcommand('s')`, `fullcommand('sub')`,
 		`fullcommand(':%substitute')` all return "substitute".
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 0e5e1db5ecd87..814f1b6f8a5a8 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -4033,20 +4033,31 @@ cmd_exists(char_u *name)
     void
 f_fullcommand(typval_T *argvars, typval_T *rettv)
 {
-    exarg_T  ea;
-    char_u   *name;
-    char_u   *p;
+    exarg_T	ea;
+    char_u	*name;
+    char_u	*p;
+    int		vim9script = in_vim9script();
+    int		save_cmod_flags = cmdmod.cmod_flags;
 
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
 
-    if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
+    if (in_vim9script()
+	    && (check_for_string_arg(argvars, 0) == FAIL
+		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
 	return;
 
     name = argvars[0].vval.v_string;
     if (name == NULL)
 	return;
 
+    if (argvars[1].v_type != VAR_UNKNOWN)
+    {
+	vim9script = tv_get_bool(&argvars[1]);
+	cmdmod.cmod_flags &= ~(CMOD_VIM9CMD | CMOD_LEGACY);
+	cmdmod.cmod_flags |= vim9script ? CMOD_VIM9CMD : CMOD_LEGACY;
+    }
+
     while (*name == ':')
 	name++;
     name = skip_range(name, TRUE, NULL);
@@ -4054,10 +4065,13 @@ f_fullcommand(typval_T *argvars, typval_T *rettv)
     ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name;
     ea.cmdidx = (cmdidx_T)0;
     ea.addr_count = 0;
+    ++emsg_silent;  // don't complain about using "en" in Vim9 script
     p = find_ex_command(&ea, NULL, NULL, NULL);
+    --emsg_silent;
     if (p == NULL || ea.cmdidx == CMD_SIZE)
-	return;
-    if (in_vim9script())
+	goto theend;
+
+    if (vim9script)
     {
 	int	     res;
 
@@ -4066,12 +4080,14 @@ f_fullcommand(typval_T *argvars, typval_T *rettv)
 	--emsg_silent;
 
 	if (res == FAIL)
-	    return;
+	    goto theend;
     }
 
     rettv->vval.v_string = vim_strsave(IS_USER_CMDIDX(ea.cmdidx)
 				 ? get_user_command_name(ea.useridx, ea.cmdidx)
 				 : cmdnames[ea.cmdidx].cmd_name);
+theend:
+    cmdmod.cmod_flags = save_cmod_flags;
 }
 #endif
 
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 7febc12269953..27ca8bf841b5c 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -648,6 +648,9 @@ func Test_fullcommand()
         \ '3match':     'match',
         \ 'aboveleft':  'aboveleft',
         \ 'abo':        'aboveleft',
+        \ 'en':         'endif',
+        \ 'end':        'endif',
+        \ 'endi':        'endif',
         \ 's':          'substitute',
         \ '5s':         'substitute',
         \ ':5s':        'substitute',
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 109cb35af6877..dccd99bb321ca 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -1529,6 +1529,13 @@ def Test_fullcommand()
   assert_equal('scriptnames', fullcommand('scr'))
   assert_equal('', fullcommand('scg'))
   fullcommand('')->assert_equal('')
+
+  assert_equal('', fullcommand('en'))
+  legacy call assert_equal('endif', fullcommand('en'))
+  assert_equal('endif', fullcommand('en', 0))
+  legacy call assert_equal('endif', fullcommand('en', 0))
+  assert_equal('', fullcommand('en', 1))
+  legacy call assert_equal('', fullcommand('en', 1))
 enddef
 
 def Test_funcref()
