forked from lix-project/lix
Merge pull request #9754 from 9999years/print-value-when-coercion-fails
Print the value in `error: cannot coerce` messages
This commit is contained in:
commit
5b7bfd2d6b
24
doc/manual/rl-next/print-value-in-coercion-error.md
Normal file
24
doc/manual/rl-next/print-value-in-coercion-error.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
synopsis: Coercion errors include the failing value
|
||||||
|
issues: #561
|
||||||
|
prs: #9754
|
||||||
|
---
|
||||||
|
|
||||||
|
The `error: cannot coerce a <TYPE> to a string` message now includes the value
|
||||||
|
which caused the error.
|
||||||
|
|
||||||
|
Before:
|
||||||
|
|
||||||
|
```
|
||||||
|
error: cannot coerce a set to a string
|
||||||
|
```
|
||||||
|
|
||||||
|
After:
|
||||||
|
|
||||||
|
```
|
||||||
|
error: cannot coerce a set to a string: { aesSupport = «thunk»;
|
||||||
|
avx2Support = «thunk»; avx512Support = «thunk»; avxSupport = «thunk»;
|
||||||
|
canExecute = «thunk»; config = «thunk»; darwinArch = «thunk»; darwinMinVersion
|
||||||
|
= «thunk»; darwinMinVersionVariable = «thunk»; darwinPlatform = «thunk»; «84
|
||||||
|
attributes elided»}
|
||||||
|
```
|
|
@ -189,7 +189,7 @@ If neither is present, an error is thrown.
|
||||||
> "${a}"
|
> "${a}"
|
||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> error: cannot coerce a set to a string
|
> error: cannot coerce a set to a string: { }
|
||||||
>
|
>
|
||||||
> at «string»:4:2:
|
> at «string»:4:2:
|
||||||
>
|
>
|
||||||
|
|
|
@ -2259,7 +2259,9 @@ BackedStringView EvalState::coerceToString(
|
||||||
return std::move(*maybeString);
|
return std::move(*maybeString);
|
||||||
auto i = v.attrs->find(sOutPath);
|
auto i = v.attrs->find(sOutPath);
|
||||||
if (i == v.attrs->end()) {
|
if (i == v.attrs->end()) {
|
||||||
error("cannot coerce %1% to a string", showType(v))
|
error("cannot coerce %1% to a string: %2%",
|
||||||
|
showType(v),
|
||||||
|
ValuePrinter(*this, v, errorPrintOptions))
|
||||||
.withTrace(pos, errorCtx)
|
.withTrace(pos, errorCtx)
|
||||||
.debugThrow<TypeError>();
|
.debugThrow<TypeError>();
|
||||||
}
|
}
|
||||||
|
@ -2305,7 +2307,9 @@ BackedStringView EvalState::coerceToString(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error("cannot coerce %1% to a string", showType(v))
|
error("cannot coerce %1% to a string: %2%",
|
||||||
|
showType(v),
|
||||||
|
ValuePrinter(*this, v, errorPrintOptions))
|
||||||
.withTrace(pos, errorCtx)
|
.withTrace(pos, errorCtx)
|
||||||
.debugThrow<TypeError>();
|
.debugThrow<TypeError>();
|
||||||
}
|
}
|
||||||
|
@ -2665,7 +2669,7 @@ void EvalState::printStatistics()
|
||||||
std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
|
std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
|
||||||
{
|
{
|
||||||
throw TypeError({
|
throw TypeError({
|
||||||
.msg = hintfmt("cannot coerce %1% to a string", showType())
|
.msg = hintfmt("cannot coerce %1% to a string: %2%", showType(), *this)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,17 @@ struct PrintOptions
|
||||||
*/
|
*/
|
||||||
size_t maxDepth = std::numeric_limits<size_t>::max();
|
size_t maxDepth = std::numeric_limits<size_t>::max();
|
||||||
/**
|
/**
|
||||||
* Maximum number of attributes in an attribute set to print.
|
* Maximum number of attributes in attribute sets to print.
|
||||||
|
*
|
||||||
|
* Note that this is a limit for the entire print invocation, not for each
|
||||||
|
* attribute set encountered.
|
||||||
*/
|
*/
|
||||||
size_t maxAttrs = std::numeric_limits<size_t>::max();
|
size_t maxAttrs = std::numeric_limits<size_t>::max();
|
||||||
/**
|
/**
|
||||||
* Maximum number of list items to print.
|
* Maximum number of list items to print.
|
||||||
|
*
|
||||||
|
* Note that this is a limit for the entire print invocation, not for each
|
||||||
|
* list encountered.
|
||||||
*/
|
*/
|
||||||
size_t maxListItems = std::numeric_limits<size_t>::max();
|
size_t maxListItems = std::numeric_limits<size_t>::max();
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,7 @@ void printElided(
|
||||||
{
|
{
|
||||||
if (ansiColors)
|
if (ansiColors)
|
||||||
output << ANSI_FAINT;
|
output << ANSI_FAINT;
|
||||||
output << " «";
|
output << "«";
|
||||||
pluralize(output, value, single, plural);
|
pluralize(output, value, single, plural);
|
||||||
output << " elided»";
|
output << " elided»";
|
||||||
if (ansiColors)
|
if (ansiColors)
|
||||||
|
@ -37,7 +37,7 @@ printLiteralString(std::ostream & str, const std::string_view string, size_t max
|
||||||
str << "\"";
|
str << "\"";
|
||||||
for (auto i = string.begin(); i != string.end(); ++i) {
|
for (auto i = string.begin(); i != string.end(); ++i) {
|
||||||
if (charsPrinted >= maxLength) {
|
if (charsPrinted >= maxLength) {
|
||||||
str << "\"";
|
str << "\" ";
|
||||||
printElided(str, string.length() - charsPrinted, "byte", "bytes", ansiColors);
|
printElided(str, string.length() - charsPrinted, "byte", "bytes", ansiColors);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,8 @@ private:
|
||||||
EvalState & state;
|
EvalState & state;
|
||||||
PrintOptions options;
|
PrintOptions options;
|
||||||
std::optional<ValuesSeen> seen;
|
std::optional<ValuesSeen> seen;
|
||||||
|
size_t attrsPrinted = 0;
|
||||||
|
size_t listItemsPrinted = 0;
|
||||||
|
|
||||||
void printRepeated()
|
void printRepeated()
|
||||||
{
|
{
|
||||||
|
@ -279,7 +281,6 @@ private:
|
||||||
else
|
else
|
||||||
std::sort(sorted.begin(), sorted.end(), ImportantFirstAttrNameCmp());
|
std::sort(sorted.begin(), sorted.end(), ImportantFirstAttrNameCmp());
|
||||||
|
|
||||||
size_t attrsPrinted = 0;
|
|
||||||
for (auto & i : sorted) {
|
for (auto & i : sorted) {
|
||||||
if (attrsPrinted >= options.maxAttrs) {
|
if (attrsPrinted >= options.maxAttrs) {
|
||||||
printElided(sorted.size() - attrsPrinted, "attribute", "attributes");
|
printElided(sorted.size() - attrsPrinted, "attribute", "attributes");
|
||||||
|
@ -307,7 +308,6 @@ private:
|
||||||
|
|
||||||
output << "[ ";
|
output << "[ ";
|
||||||
if (depth < options.maxDepth) {
|
if (depth < options.maxDepth) {
|
||||||
size_t listItemsPrinted = 0;
|
|
||||||
for (auto elem : v.listItems()) {
|
for (auto elem : v.listItems()) {
|
||||||
if (listItemsPrinted >= options.maxListItems) {
|
if (listItemsPrinted >= options.maxListItems) {
|
||||||
printElided(v.listSize() - listItemsPrinted, "item", "items");
|
printElided(v.listSize() - listItemsPrinted, "item", "items");
|
||||||
|
@ -486,6 +486,9 @@ public:
|
||||||
|
|
||||||
void print(Value & v)
|
void print(Value & v)
|
||||||
{
|
{
|
||||||
|
attrsPrinted = 0;
|
||||||
|
listItemsPrinted = 0;
|
||||||
|
|
||||||
if (options.trackRepeated) {
|
if (options.trackRepeated) {
|
||||||
seen.emplace();
|
seen.emplace();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,4 +5,4 @@ error:
|
||||||
| ^
|
| ^
|
||||||
2|
|
2|
|
||||||
|
|
||||||
error: cannot coerce a function to a string
|
error: cannot coerce a function to a string: «lambda @ /pwd/lang/eval-fail-bad-string-interpolation-1.nix:1:4»
|
||||||
|
|
|
@ -5,4 +5,4 @@ error:
|
||||||
| ^
|
| ^
|
||||||
2|
|
2|
|
||||||
|
|
||||||
error: cannot coerce a function to a string
|
error: cannot coerce a function to a string: «lambda @ /pwd/lang/eval-fail-bad-string-interpolation-3.nix:1:5»
|
||||||
|
|
|
@ -6,4 +6,4 @@ error:
|
||||||
| ^
|
| ^
|
||||||
10|
|
10|
|
||||||
|
|
||||||
error: cannot coerce a set to a string
|
error: cannot coerce a set to a string: { a = { a = { a = { a = "ha"; b = "ha"; c = "ha"; d = "ha"; e = "ha"; f = "ha"; g = "ha"; h = "ha"; j = "ha"; }; «4294967295 attributes elided»}; «4294967294 attributes elided»}; «4294967293 attributes elided»}
|
||||||
|
|
|
@ -295,7 +295,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, toPath) {
|
TEST_F(ErrorTraceTest, toPath) {
|
||||||
ASSERT_TRACE2("toPath []",
|
ASSERT_TRACE2("toPath []",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a list"),
|
hintfmt("cannot coerce %s to a string: %s", "a list", "[ ]"),
|
||||||
hintfmt("while evaluating the first argument passed to builtins.toPath"));
|
hintfmt("while evaluating the first argument passed to builtins.toPath"));
|
||||||
|
|
||||||
ASSERT_TRACE2("toPath \"foo\"",
|
ASSERT_TRACE2("toPath \"foo\"",
|
||||||
|
@ -309,7 +309,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, storePath) {
|
TEST_F(ErrorTraceTest, storePath) {
|
||||||
ASSERT_TRACE2("storePath true",
|
ASSERT_TRACE2("storePath true",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a Boolean"),
|
hintfmt("cannot coerce %s to a string: %s", "a Boolean", ANSI_CYAN "true" ANSI_NORMAL),
|
||||||
hintfmt("while evaluating the first argument passed to 'builtins.storePath'"));
|
hintfmt("while evaluating the first argument passed to 'builtins.storePath'"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, pathExists) {
|
TEST_F(ErrorTraceTest, pathExists) {
|
||||||
ASSERT_TRACE2("pathExists []",
|
ASSERT_TRACE2("pathExists []",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a list"),
|
hintfmt("cannot coerce %s to a string: %s", "a list", "[ ]"),
|
||||||
hintfmt("while realising the context of a path"));
|
hintfmt("while realising the context of a path"));
|
||||||
|
|
||||||
ASSERT_TRACE2("pathExists \"zorglub\"",
|
ASSERT_TRACE2("pathExists \"zorglub\"",
|
||||||
|
@ -332,7 +332,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, baseNameOf) {
|
TEST_F(ErrorTraceTest, baseNameOf) {
|
||||||
ASSERT_TRACE2("baseNameOf []",
|
ASSERT_TRACE2("baseNameOf []",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a list"),
|
hintfmt("cannot coerce %s to a string: %s", "a list", "[ ]"),
|
||||||
hintfmt("while evaluating the first argument passed to builtins.baseNameOf"));
|
hintfmt("while evaluating the first argument passed to builtins.baseNameOf"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, filterSource) {
|
TEST_F(ErrorTraceTest, filterSource) {
|
||||||
ASSERT_TRACE2("filterSource [] []",
|
ASSERT_TRACE2("filterSource [] []",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a list"),
|
hintfmt("cannot coerce %s to a string: %s", "a list", "[ ]"),
|
||||||
hintfmt("while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'"));
|
hintfmt("while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'"));
|
||||||
|
|
||||||
ASSERT_TRACE2("filterSource [] \"foo\"",
|
ASSERT_TRACE2("filterSource [] \"foo\"",
|
||||||
|
@ -1038,7 +1038,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, toString) {
|
TEST_F(ErrorTraceTest, toString) {
|
||||||
ASSERT_TRACE2("toString { a = 1; }",
|
ASSERT_TRACE2("toString { a = 1; }",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ a = " ANSI_CYAN "1" ANSI_NORMAL "; }"),
|
||||||
hintfmt("while evaluating the first argument passed to builtins.toString"));
|
hintfmt("while evaluating the first argument passed to builtins.toString"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1057,7 +1057,7 @@ namespace nix {
|
||||||
|
|
||||||
ASSERT_TRACE2("substring 0 3 {}",
|
ASSERT_TRACE2("substring 0 3 {}",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating the third argument (the string) passed to builtins.substring"));
|
hintfmt("while evaluating the third argument (the string) passed to builtins.substring"));
|
||||||
|
|
||||||
ASSERT_TRACE1("substring (-3) 3 \"sometext\"",
|
ASSERT_TRACE1("substring (-3) 3 \"sometext\"",
|
||||||
|
@ -1070,7 +1070,7 @@ namespace nix {
|
||||||
TEST_F(ErrorTraceTest, stringLength) {
|
TEST_F(ErrorTraceTest, stringLength) {
|
||||||
ASSERT_TRACE2("stringLength {} # TODO: context is missing ???",
|
ASSERT_TRACE2("stringLength {} # TODO: context is missing ???",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating the argument passed to builtins.stringLength"));
|
hintfmt("while evaluating the argument passed to builtins.stringLength"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1143,7 @@ namespace nix {
|
||||||
|
|
||||||
ASSERT_TRACE2("concatStringsSep \"foo\" [ 1 2 {} ] # TODO: coerce to string is buggy",
|
ASSERT_TRACE2("concatStringsSep \"foo\" [ 1 2 {} ] # TODO: coerce to string is buggy",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "an integer"),
|
hintfmt("cannot coerce %s to a string: %s", "an integer", ANSI_CYAN "1" ANSI_NORMAL),
|
||||||
hintfmt("while evaluating one element of the list of strings to concat passed to builtins.concatStringsSep"));
|
hintfmt("while evaluating one element of the list of strings to concat passed to builtins.concatStringsSep"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1229,12 +1229,12 @@ namespace nix {
|
||||||
|
|
||||||
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = {}; }",
|
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = {}; }",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating the attribute 'system' of derivation 'foo'"));
|
hintfmt("while evaluating the attribute 'system' of derivation 'foo'"));
|
||||||
|
|
||||||
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = {}; }",
|
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = {}; }",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'"));
|
hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'"));
|
||||||
|
|
||||||
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"drv\"; }",
|
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"drv\"; }",
|
||||||
|
@ -1279,17 +1279,17 @@ namespace nix {
|
||||||
|
|
||||||
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ {} ]; }",
|
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ {} ]; }",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating an element of the argument list"));
|
hintfmt("while evaluating an element of the argument list"));
|
||||||
|
|
||||||
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ \"a\" {} ]; }",
|
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ \"a\" {} ]; }",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating an element of the argument list"));
|
hintfmt("while evaluating an element of the argument list"));
|
||||||
|
|
||||||
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; FOO = {}; }",
|
ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; FOO = {}; }",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("cannot coerce %s to a string", "a set"),
|
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
|
||||||
hintfmt("while evaluating the attribute 'FOO' of derivation 'foo'"));
|
hintfmt("while evaluating the attribute 'FOO' of derivation 'foo'"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@ TEST_F(ValuePrintingTests, ansiColorsStringElided)
|
||||||
v.mkString("puppy");
|
v.mkString("puppy");
|
||||||
|
|
||||||
test(v,
|
test(v,
|
||||||
ANSI_MAGENTA "\"pup\"" ANSI_FAINT " «2 bytes elided»" ANSI_NORMAL,
|
ANSI_MAGENTA "\"pup\" " ANSI_FAINT "«2 bytes elided»" ANSI_NORMAL,
|
||||||
PrintOptions {
|
PrintOptions {
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.maxStringLength = 3
|
.maxStringLength = 3
|
||||||
|
@ -756,7 +756,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||||
vAttrs.mkAttrs(builder.finish());
|
vAttrs.mkAttrs(builder.finish());
|
||||||
|
|
||||||
test(vAttrs,
|
test(vAttrs,
|
||||||
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT " «1 attribute elided»" ANSI_NORMAL "}",
|
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«1 attribute elided»" ANSI_NORMAL "}",
|
||||||
PrintOptions {
|
PrintOptions {
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.maxAttrs = 1
|
.maxAttrs = 1
|
||||||
|
@ -769,7 +769,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||||
vAttrs.mkAttrs(builder.finish());
|
vAttrs.mkAttrs(builder.finish());
|
||||||
|
|
||||||
test(vAttrs,
|
test(vAttrs,
|
||||||
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT " «2 attributes elided»" ANSI_NORMAL "}",
|
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«2 attributes elided»" ANSI_NORMAL "}",
|
||||||
PrintOptions {
|
PrintOptions {
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.maxAttrs = 1
|
.maxAttrs = 1
|
||||||
|
@ -793,7 +793,7 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||||
vList.bigList.size = 2;
|
vList.bigList.size = 2;
|
||||||
|
|
||||||
test(vList,
|
test(vList,
|
||||||
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT " «1 item elided»" ANSI_NORMAL "]",
|
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«1 item elided»" ANSI_NORMAL "]",
|
||||||
PrintOptions {
|
PrintOptions {
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.maxListItems = 1
|
.maxListItems = 1
|
||||||
|
@ -806,7 +806,7 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||||
vList.bigList.size = 3;
|
vList.bigList.size = 3;
|
||||||
|
|
||||||
test(vList,
|
test(vList,
|
||||||
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT " «2 items elided»" ANSI_NORMAL "]",
|
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«2 items elided»" ANSI_NORMAL "]",
|
||||||
PrintOptions {
|
PrintOptions {
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.maxListItems = 1
|
.maxListItems = 1
|
||||||
|
|
Loading…
Reference in a new issue