In prompts implicitly coerce float64 to string

Including the float64 data type in the prompt value stream causes an error.
This causes those values to be implicitly converted to a string as happens
everywhere else in Elvish.

I initially intended to modify the code to do the implicit string coercion
for any type not otherwise explicitly handled by the pkg/ui `Concat`
methods. I decided against that approach because doing so doesn't make
sense for some types that might appear in the value stream; e.g., Elvish
exceptions.

Fixes #1186
This commit is contained in:
Kurtis Rader 2020-11-26 19:53:03 -08:00 committed by Qi Xiao
parent 2bf7a5d8d1
commit d52aa03764
5 changed files with 27 additions and 5 deletions

View File

@ -12,11 +12,11 @@ import (
)
func TestPrompt_ValueOutput(t *testing.T) {
f := setup(rc(`edit:prompt = { put 'val'; styled '> ' red }`))
f := setup(rc(`edit:prompt = { put '#'; float64 13; styled '> ' red }`))
defer f.Cleanup()
f.TestTTY(t,
"val> ", Styles,
"#13> ", Styles,
" !!", term.DotHere)
}

View File

@ -75,6 +75,10 @@ func TestStyledConcat(t *testing.T) {
That("print abc(styled abc blink)").Prints("abc\033[5mabc\033[m"),
// text+string
That("print (styled abc blink)abc").Prints("\033[5mabc\033[mabc"),
// float64+text
That("print (float64 13)(styled abc blink)").Prints("13\033[5mabc\033[m"),
// text+float64
That("print (styled abc blink)(float64 13)").Prints("\033[5mabc\033[m13"),
// text+segment
That("print (styled abc inverse)(styled-segment abc &bg-color=white)").Prints("\033[7mabc\033[m\033[47mabc\033[m"),
// text+text

View File

@ -61,11 +61,15 @@ func (t Text) Index(k interface{}) (interface{}, error) {
}
}
// Concat implements Text+string, Text+Segment and Text+Text.
// Concat implements Text+string, Text+Segment and Text+Text. Where "string"
// refers to strings and data types, such as float64, where it is reasonable
// to implicitly convert the type to a string.
func (t Text) Concat(rhs interface{}) (interface{}, error) {
switch rhs := rhs.(type) {
case string:
return Concat(t, T(rhs)), nil
case float64:
return Concat(t, T(vals.ToString(rhs))), nil
case *Segment:
return Concat(t, Text{rhs}), nil
case Text:
@ -75,11 +79,15 @@ func (t Text) Concat(rhs interface{}) (interface{}, error) {
return nil, vals.ErrConcatNotImplemented
}
// RConcat implements string+Text.
// RConcat implements string+Text. Where "string" refers to strings and data
// types, such as float64, where it is reasonable to implicitly convert the
// type to a string.
func (t Text) RConcat(lhs interface{}) (interface{}, error) {
switch lhs := lhs.(type) {
case string:
return Concat(T(lhs), t), nil
case float64:
return Concat(T(vals.ToString(lhs)), t), nil
}
return nil, vals.ErrConcatNotImplemented

View File

@ -95,6 +95,11 @@ func (s *Segment) Concat(v interface{}) (interface{}, error) {
s,
&Segment{Text: rhs},
}, nil
case float64:
return Text{
s,
&Segment{Text: vals.ToString(rhs)},
}, nil
case *Segment:
return Text{s, rhs}, nil
case Text:
@ -112,6 +117,11 @@ func (s *Segment) RConcat(v interface{}) (interface{}, error) {
&Segment{Text: lhs},
s,
}, nil
case float64:
return Text{
&Segment{Text: vals.ToString(lhs)},
s,
}, nil
}
return nil, vals.ErrConcatNotImplemented
}

View File

@ -102,7 +102,7 @@ To see the transformer in action, try the following example (assuming default
```elvish
n = 0
edit:prompt = { sleep 2; to-string $n; n = (+ $n 1); put ': ' }
edit:prompt = { sleep 2; put $n; n = (+ $n 1); put ': ' }
edit:-prompt-eagerness = 10 # update prompt on each keystroke
edit:prompt-stale-threshold = 0.5
```