Conversation
The syntax for interpolated strings in Vim (both Vim9 and pre-Vim9) is
heavily inspired by C# and previous discussions on vim_dev ML.
The interpolated strings are prefixed with the dollar `$` sign and the
inner expression are surrounded with braces `{` `}`.
Codecov Report
@@ Coverage Diff @@
## master #10327 +/- ##
==========================================
- Coverage 81.01% 81.00% -0.01%
==========================================
Files 161 161
Lines 185619 185812 +193
Branches 41972 42003 +31
==========================================
+ Hits 150376 150522 +146
- Misses 22736 22790 +54
+ Partials 12507 12500 -7
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
reverse() doesn't work on strings.
|
How does this relate to #4634 ? |
|
|
> How does this relate to #4634 ?
- Up to date with `master`.
- Simpler implementation.
- The compiler for the interpolated strings is implemented for Vim9.
- Less noisy syntax, `$"{bar}"` reads much better than `$"${bar}"`, this syntax is similar to what's been adopted by Python's f-strings, C#, Typescript and so on.
OK, the reason I had not included the older patch is that I had doubts
about the syntax and the implementation. Looks like you tackled both.
I'll leave this open for a little while for others to comment on.
The help test could say something about the difference between using
double and single quote, probably referring to another part in the help.
…--
From "know your smileys":
(X0||) Double hamburger with lettuce and tomato
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
|
Is there a reason the syntax for interpolated expressions differs from that used with heredocs? |
I mentioned this point in #10129 but got no feedback, the use of backticks was discouraged in #4491 with the following reasoning (which I agree with):
According to this comment the syntax for heredoc placeholders had no objections, but I'd like to see a single style used consistently across heredocs and strings. |
I suggested the backtick equal syntax, because – at the time – it was the closest syntax I could think of. However, if this PR is merged, then the closest syntax would become |
|
> I'd like to see a single style used consistently across heredocs and strings.
I suggested the backtick equal syntax, because – at the time – it was
the closest syntax I could think of. However, if this PR is merged,
then the closest syntax would become `${}`, because backtick equal is
for Ex commands, while `${}` is for strings. So, I definitely agree
that – to be as consistent as possible – we should use `${}` in
heredocs too. I doubt many people would complain considering that the
ability to nest expression inside heredocs was added in patch
[8.2.4770](https://github.com/vim/vim/releases/tag/v8.2.4770), which
is only about 2 weeks old.
Good point. Both are for use inside a string, either a single string or
list of strings. That's a strong connection, thus making them the same
is more important then other reasons.
The "template string" or "interpolated string" is also used in other
languages, thus many users will be more familiar with that then whatever
other things are used in Vim.
Javascript uses `foo ${expr} bar`. They use backticks for the string,
but that looks quite weird (there probably were reasons for this choice
that don't appply to Vim). I have often not spotted the difference
between single quotes and backticks.
Python F-strings use {expr}, without the dollar. If we use $"text"
to indicate a template, it's closer to the Python syntax, thus using
{expr} instead of ${expr} makes sense. It's also easier to include a
curly brace by doubling it. Python does this for both opening and
closing curly braces.
So we would have:
echo $"some {12 + 3} text with {{braces}}"
some 15 text with {braces}
var s =<< eval trim END
some {12 + 3} text
with {{braces}}
END
echo s
['some 15 text', 'with {braces}']
This looks consistent.
…--
I AM THANKFUL...
...for all the complaining I hear about the government
because it means we have freedom of speech.
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
I didn't require the closing braces to be duplicated because it doesn't really matter, once we see an open block the whole expression is parsed according to Vim's rules and we only check if there's a trailing This said, this is not a hill I'd die on, if you feel the double-everywhere rule is better I'll amend the parser. |
|
> Python does this for both opening and closing curly braces.
I didn't require the closing braces to be duplicated because it
doesn't really matter, once we see an open block the whole expression
is parsed according to Vim's rules and we only check if there's a
trailing `}`. It's probably not that consistent but it is documented
and makes the parser simpiler/faster as we don't have to add a whole
other check for `}` and can use a single `strchr`.
This said, this is not a hill I'd die on, if you feel the
double-everywhere rule is better I'll amend the parser.
I think it's a good idea to stick with Python, they must have had a
reason to do it like this. The PEP doesn't mention the reason though:
https://peps.python.org/pep-0498/
Since we are going with $"foo {expr} bar" it's actually more like C#.
It does the same thing to double the closing brace:
https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting#escaping-braces
…--
hundred-and-one symptoms of being an internet addict:
95. Only communication in your household is through email.
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
- Unescape both {{ and }}.
- Skip leading whitespace in the expression.
Address another issue raised during the code review.
|
Done. I also took this chance to change the heredoc markers and simplify a bit the code. Right now the only missing piece are multiline expressions, but let's focus on a MVP for the moment. |
|
I found one problem (which can be fixed later): quotes in the expression need to be escaped. |
|
We might want to update diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 39208e48d..19f3ddd46 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -3253,19 +3253,19 @@ text...
If "eval" is not specified, then each line of text is
used as a |literal-string|. If "eval" is specified,
- then any Vim expression in the form ``={expr}`` is
+ then any Vim expression in the form `{expr}` is
evaluated and the result replaces the expression.
Example where $HOME is expanded: >
let lines =<< trim eval END
some text
- See the file `=$HOME`/.vimrc
+ See the file {$HOME}/.vimrc
more text
END
< There can be multiple Vim expressions in a single line
but an expression cannot span multiple lines. If any
expression evaluation fails, then the assignment fails.
- once the "`=" has been found {expr} and a backtick
- must follow. {expr} cannot be empty.
+ Once the `{` has been found, an expression and a `}`
+ must follow. `expr` cannot be empty.
{endmarker} must not contain white space.
{endmarker} cannot start with a lower case character. |
|
The help was already updated, will go out soon. |
That's by design, interpolated strings are still strings and so the usual rules apply. The expression evaluation happens at a later stage, once the whole string has been parsed and escaped, this makes the parsing (and highlighting) easier, beside making the expression easier to read for the user without having to guess which quote belongs to the string part and which to the expression. |
|
> I found one problem (which can be fixed later): quotes in the
> expression need to be escaped.
That's by design, interpolated strings are still strings and so the
usual rules apply. The expression evaluation happens at a later stage,
once the whole string has been parsed and escaped, this makes the
parsing (and highlighting) easier, beside making the expression easier
to read for the user without having to guess which quote belongs to
the string part and which to the expression.
Well, I understand it's easier, but it goes against my instinct. The
expression between {} should just be an expression, with no special
rules, other than that the "}" terminates the expression. If you would
use a pattern, for example, you might need to use backslashes. With the
current implementation it can be tricky to figure out which ones need to
be escaped.
I was looking at what C# and Python do. Apparently Python doesn't allow
any backslashes in an f-string. That's a bummer.
For C# I could not find a remark about using a backslash in the
expression.
What do others think?
…--
I'm writing a book. I've got the page numbers done.
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
|
C# allows any valid expression as do other languages like JavaScript, Ruby and Dart. I'd much prefer that expressions didn't require any special escaping. I certainly wouldn't find it easier to read. |
Problem: String interpolation only works in heredoc.
Solution: Support interpolated strings. Use syntax for heredoc consistent
with strings, similar to C#. (closes vim/vim#10327)
vim/vim@2eaef10
Cherry-pick Test_Debugger_breakadd_expr() from Vim.
Co-authored-by: LemonBoy <thatlemon@gmail.com>
Problem: String interpolation only works in heredoc.
Solution: Support interpolated strings. Use syntax for heredoc consistent
with strings, similar to C#. (closes vim/vim#10327)
vim/vim@2eaef10
Cherry-pick Test_Debugger_breakadd_expr() from Vim.
Co-authored-by: LemonBoy <thatlemon@gmail.com>
The syntax for interpolated strings in Vim (both Vim9 and pre-Vim9) is
heavily inspired by C# and previous discussions on vim_dev ML.
The interpolated strings are prefixed with the dollar
$sign and theinner expression are surrounded with braces
{}.