Re: [vim/vim] `expand()` and `expandcmd()` behave differently on `%:~` (Issue #20793)

h_east (Vim Github Repository) <[email protected]>
Newsgroups gmane.editors.vim.devel
Message-ID <vim/vim/issues/20793/[email protected]>
h-east left a comment (vim/vim#20793)

@dkearns is right, `%:~` is not a special case. Here is the code for the two
steps.

`expandcmd()` is a thin wrapper around `expand_filename()` (see `f_expandcmd()`
in `src/evalfunc.c`), and `expand_filename()` in `src/ex_docmd.c` does this:

1. `eval_vars()` evaluates the cmdline-special item, so `%:~` becomes
   `~/file`.

2. The replacement text is then run through `expand_env_save()`:

```c
	// Wildcards won't be expanded below, the replacement is taken
	// literally.  But do expand "~/file", "~user/file" and "$HOME/file".
	if (vim_strchr(repl, '$') != NULL || vim_strchr(repl, '~') != NULL)
	{
	    char_u *l = repl;

	    repl = expand_env_save(repl);
	    vim_free(l);
	}
```

So the `~` produced by step 1 is expanded in step 2, just like it is when you
type the command. `expand()` stops after step 1, which is why it keeps the
`~`.

A literal `~/path` in the string is handled by the same mechanism at the end
of `expand_filename()`: `mch_has_wildcard()` returns TRUE for a `~` that is
followed by another character, and the argument is then passed to
`expand_env_esc()`, which expands `~` only at the start of a name.

So the behaviour is correct and I do not intend to change it. What is missing
is that the help never mentions the second step. I would rather document that
order than describe `%:~` as an exception, since it is not one:

```diff
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -3099,6 +3099,10 @@ expandcmd({string} [, {options}])			*expandcmd()*
 		like with |expand()|, and environment variables, anywhere in
 		{string}.  "~user" and "~/path" are only expanded at the
 		start.
+		The expansion is done in two steps: the special keywords are
+		evaluated first, then "~" and environment variables are
+		expanded in the result.  Thus `expand('%:~')` keeps the "~",
+		while `expandcmd('%:~')` returns the full path.
 
 		The following items are supported in the {options} Dict
 		argument:
```

The patch only writes down what @dkearns already described.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/vim/vim/issues/20793#issuecomment-5078933065
You are receiving this because you are subscribed to this thread.

Message ID: <vim/vim/issues/20793/[email protected]>

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/vim/vim/issues/20793/5078933065%40github.com.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.