Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
October 03, 2018 Template/mixin ideas? | ||||
---|---|---|---|---|
| ||||
I've got this simple task but I'm trying to perfect it as best I can to learn something in the process. I have Linux terminal ASCII codes for coloring terminal output. string red(string) { /* ... */ } "Hello world".red => "\033[31mHello World\033[0m" which translates to "[red]Hello World[reset to normal text]". I have to do some slight trickery so I can chain them. But it all works fine. __The function is the same__ no matter what kind of color, bold, etc attribute I want. The only difference is the tag/prefix string. So I have a table (or enum): enum colors{ reset = "\033[0m", red = "\033[31m", bold = "\033[1m" //... } Absolute perfection would be some way to add a single line to that enum (or table) and magically get a new function. I add "blue" with its prefix code to the enum and immediately I can do: "hello world".blue Add yellow = "\033..." and I can do: "hello world".bold.yellow It's an interesting problem. Right now, I made a generic version that accepts the prefix code string directly called "color()" and red() translates to a call to color with the red string. blue() does the same. And so on. But it's still plenty of boiler plate. I do that so I don't have 80+ functions all a half-page long--which would be a nightmare to verify. It's surely nothing mission critical. But I wonder if I can distill this simple problem down further, I may be able to learn some tricks for later problems. Thanks. |
October 03, 2018 Re: Template/mixin ideas? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Katko | On Wednesday, 3 October 2018 at 11:01:53 UTC, Chris Katko wrote:
> I've got this simple task but I'm trying to perfect it as best I can to learn something in the process.
>
> I have Linux terminal ASCII codes for coloring terminal output.
>
> string red(string) { /* ... */ }
>
> "Hello world".red => "\033[31mHello World\033[0m"
>
> which translates to "[red]Hello World[reset to normal text]".
>
> I have to do some slight trickery so I can chain them. But it all works fine. __The function is the same__ no matter what kind of color, bold, etc attribute I want. The only difference is the tag/prefix string.
>
> So I have a table (or enum):
> enum colors{
> reset = "\033[0m",
> red = "\033[31m",
> bold = "\033[1m" //...
> }
>
> Absolute perfection would be some way to add a single line to that enum (or table) and magically get a new function. I add "blue" with its prefix code to the enum and immediately I can do:
>
> "hello world".blue
>
> Add yellow = "\033..." and I can do:
>
> "hello world".bold.yellow
>
> It's an interesting problem. Right now, I made a generic version that accepts the prefix code string directly called "color()" and red() translates to a call to color with the red string. blue() does the same. And so on. But it's still plenty of boiler plate. I do that so I don't have 80+ functions all a half-page long--which would be a nightmare to verify.
>
> It's surely nothing mission critical. But I wonder if I can distill this simple problem down further, I may be able to learn some tricks for later problems.
>
> Thanks.
A combination of static introspection with string mixins does the trick:
---
enum colors {
reset = "\033[0m",
red = "\033[31m"
}
auto GenerateColorFuncs() {
string result;
static foreach(c; __traits(allMembers, colors))
result ~= "auto "~c~"(string str) { return colors."~c~" ~ str ~ colors.reset; }";
return result;
}
mixin(GenerateColorFuncs());
void main()
{
import std.stdio;
writeln("bla".red);
}
---
Although you might want to replace the string concatenation with something more performant if used a lot.
|
October 04, 2018 Re: Template/mixin ideas? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sebastiaan Koppe | On Wednesday, 3 October 2018 at 11:51:01 UTC, Sebastiaan Koppe wrote:
> On Wednesday, 3 October 2018 at 11:01:53 UTC, Chris Katko wrote:
>> [...]
>
> A combination of static introspection with string mixins does the trick:
>
> ---
> enum colors {
> reset = "\033[0m",
> red = "\033[31m"
> }
>
> auto GenerateColorFuncs() {
> string result;
> static foreach(c; __traits(allMembers, colors))
> result ~= "auto "~c~"(string str) { return colors."~c~" ~ str ~ colors.reset; }";
> return result;
> }
>
> mixin(GenerateColorFuncs());
>
> void main()
> {
> import std.stdio;
> writeln("bla".red);
> }
> ---
>
> Although you might want to replace the string concatenation with something more performant if used a lot.
The mixin part wouldn't be slowed by strings, right? So the "slowness" is the invokation part which changes strings and forces GC allocations, I guess?
What's the alternative to using strings... for strings?
|
October 05, 2018 Re: Template/mixin ideas? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Katko | On Thursday, 4 October 2018 at 01:12:04 UTC, Chris Katko wrote: > The mixin part wouldn't be slowed by strings, right? So the "slowness" is the invokation part which changes strings and forces GC allocations, I guess? Yep, that is right. > What's the alternative to using strings... for strings? During the concatenation phase you'll use an Appender. Afterwards you retrieve the resulting string from the appender. It is very similar to a StringBuilder in other languages. See std.array.appender |
October 05, 2018 Re: Template/mixin ideas? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Katko | On Wednesday, 3 October 2018 at 11:01:53 UTC, Chris Katko wrote: > I've got this simple task but I'm trying to perfect it as best I can to learn something in the process. > > I have Linux terminal ASCII codes for coloring terminal output. > > string red(string) { /* ... */ } > > "Hello world".red => "\033[31mHello World\033[0m" > > which translates to "[red]Hello World[reset to normal text]". > > I have to do some slight trickery so I can chain them. But it all works fine. __The function is the same__ no matter what kind of color, bold, etc attribute I want. The only difference is the tag/prefix string. > > So I have a table (or enum): > enum colors{ > reset = "\033[0m", > red = "\033[31m", > bold = "\033[1m" //... > } > > Absolute perfection would be some way to add a single line to that enum (or table) and magically get a new function. I add "blue" with its prefix code to the enum and immediately I can do: > > "hello world".blue > > Add yellow = "\033..." and I can do: > > "hello world".bold.yellow https://run.dlang.io/gist/run-dlang/e0d0bcebe6c4edcc3cd0c2858183357d?compiler=dmd https://issues.dlang.org/show_bug.cgi?id=19286 prevents us from using static foreaches to declare the aliases. |
October 05, 2018 Re: Template/mixin ideas? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Katko | On Thursday, 4 October 2018 at 01:12:04 UTC, Chris Katko wrote: > What's the alternative to using strings... for strings? Since the purpose is terminal output, you could just make a custom formatter, something like this: https://run.dlang.io/is/F51UCZ |
Copyright © 1999-2021 by the D Language Foundation