October 22, 2012
On 10/22/12 8:24 AM, Jens Mueller wrote:
> Andrei Alexandrescu wrote:
>> On 10/22/12 9:47 AM, Jens Mueller wrote:
>>> This is probably interesting for Phobos. But I'm not the one to make a
>>> decision. The core Phobos developers should decide.
>>> Hopefully somebody is reading this.
>>
>> Off the top of my head something that is specific for only certain
>> systems (Unixen in this case) is decidedly of less Phobos interest.
>> We could, nevertheless, put such functionality in system-specific
>> modules.
>
> It also works on Windows. Even already implemented. The situation is
> similar to the file abstraction which has a different API in the Unix
> world and the Windows world.
>
> Jens

Cool. Do all systems implement color as escape sequences?

Andrei
October 22, 2012
Andrei Alexandrescu wrote:
> On 10/22/12 8:24 AM, Jens Mueller wrote:
> >Andrei Alexandrescu wrote:
> >>On 10/22/12 9:47 AM, Jens Mueller wrote:
> >>>This is probably interesting for Phobos. But I'm not the one to make a
> >>>decision. The core Phobos developers should decide.
> >>>Hopefully somebody is reading this.
> >>
> >>Off the top of my head something that is specific for only certain systems (Unixen in this case) is decidedly of less Phobos interest. We could, nevertheless, put such functionality in system-specific modules.
> >
> >It also works on Windows. Even already implemented. The situation is similar to the file abstraction which has a different API in the Unix world and the Windows world.
> >
> >Jens
> 
> Cool. Do all systems implement color as escape sequences?

No. On Windows you have to explicitly call a function. http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047%28v=vs.85%29.aspx

Jens
October 22, 2012
On Monday, 22 October 2012 at 12:26:29 UTC, Jens Mueller wrote:
> It also works on Windows.

It's still more of a linux tradition. Implementing it as a separate package will be also a good exercise of writing a layer over Phobos I/O system.
October 22, 2012
On Mon, 22 Oct 2012 06:04:51 -0500, Dejan Lekic <dejan.lekic@gmail.com> wrote:

> On Sunday, 21 October 2012 at 19:28:21 UTC, Robik wrote:
>> Hello,
>>
>> I would like to introduce ColorD, small library that allows to simply manipulate console output colors, both on Windows and Posix operating systems. It also supports font styles such as underline and strikethrough(Posix feature only).
>>
>>
>> Simple example:
>>
>> import std.stdio, colord;
>> void main()
>> {
>>     setConsoleColors(Fg.red, Bg.blue);
>>     writeln("Red text on blue background.");
>>     resetConsoleColors(); // Bring back initial state
>> }
>>
>>
>> Feedback welcome.
>>
>> GitHub: https://github.com/robik/ColorD
>>
>> Regards.
>
> This is very much related to the ycurses and dcurses projects, and I strongly suggest you work with people behind those projects and come up with a nice/flexible/robust "console" API/package for D.

I had some trouble getting in touch with ylixir last time, and pardon me if I'm wrong,
but *you* are the 'people behind' dcurses.  =P

I would be willing to chip in for something like this though.

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
October 23, 2012
On 10/22/2012 03:47 AM, Jens Mueller wrote:
> Chad J wrote:
>> There is no weakness to this.  The only shred of a counterargument I
>> can think of is that it makes the format strings more difficult to
>> learn. Other than that, it is possible to detect the destination of
>> the formatter, so color codes will never end up in places where they
>> shouldn't.  A conservative approach to this should handle most
>> desires and never interfere with all the people with no interest in
>> color.
>>
>> On the upshot are the things I've mentioned:
>> - A format specifier is potentially more discoverable.
>> - A format specifier is more concise.  This keeps your lines from
>> wrapping.  They are probably too long already.
>
> Do you consider this
> writecf(Color.red, "something %s", "here")
> concise as well?
>

The case is too easy.  You're formatting an entire line.

>> - To cement the previous point: nesting requires a few extra
>> characters with a format specifier, rather than a couple extra
>> /lines/ for extra function calls.
>
> Don't understand this point. Can you give an example?
>

Option A:

    auto save = getConsoleState();
    scope (exit) setConsoleState(save);
    setConsoleColors(Fg.red, Bg.blue);
    writeln("Red text on blue background.");

Option B:

    writefln("%CFredBblu(Red text on blue background.%)");

>> - Calls to stateful console functions allow people to write bugs
>> like saving console state and then forgetting to restore it (or
>> throwing an exception and neglecting to restore from within a scope
>> guard).  Format specifiers do not have this problem.
>
> The same holds for
> writecf(Color.red, "something %s", "here")
>

See my above example.  In that case the formatter no longer requires even using the scope feature because there are no resources to clean up.  The library handles that mess.

Also statefulness is a pain to deal with.  Stack-like operation with push/pop or bracketing constructs is usually much less troublesome for this sort of thing.

>> - etc (I'm sure I'm forgetting one or two.)
>>
>> These are the reasons why my ideal language has color formatting
>> built into its I/O routines.
>
> Just wanted to point out that instead of that you can add writec*
> functions. I think the only thing is that these are less discoverable
> but they also work without formatting, e.g.
> writec(Color.red, "my text");
>

The thing I found very difficult with other color formatting APIs was formatting individual words or characters.  Entire lines are easy-peasy stuff in any API.  Solving the entire-lines case won't impress me. ;)

Here's my more typical use case:

writefln("The %CFred(widgetometer%) is a device for measuring");
writefln("widget effectiveness.  It is possible to ");
writefln("reconcile transcendental properties by hitting");
writefln("%CFblu(B%) for blue coefficients, %CFgrn(G%) for green");
writefln("coefficients, or %CFyel(Y%) for yellow coefficients.");
writefln("Here is a correspondence table:");
writefln("  %CFnue( %) | %CFblu( B %) %CFgrn( G %) %CFyel( Y %) ");
writefln("  %CFnue(-%)-+-%CFnue(---%)-%CFnue(---%)-%CFnue(---%)-");
writefln("  %CFblu(B%) | %CFblu(200%) %CFwht(330%) %CFwht(303%) ");
writefln("  %CFgrn(G%) | %CFwht(110%) %CFgrn(020%) %CFwht(033%) ");
writefln("  %CFyel(Y%) | %CFwht(101%) %CFwht(011%) %CFyel(002%) ");

I realized that I wanted a "nue" color that has no effect but allows me to align things effectively ;)

Anyhow, please try to write the above example using any other style. Interleaved function calls are particularly "fun" <g>


October 23, 2012
Chad J wrote:
> On 10/22/2012 03:47 AM, Jens Mueller wrote:
> >Chad J wrote:
> >>There is no weakness to this.  The only shred of a counterargument I can think of is that it makes the format strings more difficult to learn. Other than that, it is possible to detect the destination of the formatter, so color codes will never end up in places where they shouldn't.  A conservative approach to this should handle most desires and never interfere with all the people with no interest in color.
> >>
> >>On the upshot are the things I've mentioned:
> >>- A format specifier is potentially more discoverable.
> >>- A format specifier is more concise.  This keeps your lines from
> >>wrapping.  They are probably too long already.
> >
> >Do you consider this
> >writecf(Color.red, "something %s", "here")
> >concise as well?
> >
> 
> The case is too easy.  You're formatting an entire line.

Am I? I think it's not a line. But I see your point.
You mean something like
writec(Color.red, "red")
writec(Color.blue, "blue")
writec(Color.green, "green")
is too verbose.
You want something like
writef("%CFred(red%)%CFblue(blue%)%CFgreeng(reen%)");
Right?

> >>- To cement the previous point: nesting requires a few extra characters with a format specifier, rather than a couple extra /lines/ for extra function calls.
> >
> >Don't understand this point. Can you give an example?
> >
> 
> Option A:
> 
>     auto save = getConsoleState();
>     scope (exit) setConsoleState(save);
>     setConsoleColors(Fg.red, Bg.blue);
>     writeln("Red text on blue background.");
> 
> Option B:
> 
>     writefln("%CFredBblu(Red text on blue background.%)");

I see. Though I find the last line difficult to decipher (because there
are no spaces).

> >>- Calls to stateful console functions allow people to write bugs like saving console state and then forgetting to restore it (or throwing an exception and neglecting to restore from within a scope guard).  Format specifiers do not have this problem.
> >
> >The same holds for
> >writecf(Color.red, "something %s", "here")
> >
> 
> See my above example.  In that case the formatter no longer requires even using the scope feature because there are no resources to clean up.  The library handles that mess.
> 
> Also statefulness is a pain to deal with.  Stack-like operation with push/pop or bracketing constructs is usually much less troublesome for this sort of thing.

It'll be nice then if you can built something using format specifiers on top of a basic library.

> >>- etc (I'm sure I'm forgetting one or two.)
> >>
> >>These are the reasons why my ideal language has color formatting built into its I/O routines.
> >
> >Just wanted to point out that instead of that you can add writec*
> >functions. I think the only thing is that these are less discoverable
> >but they also work without formatting, e.g.
> >writec(Color.red, "my text");
> >
> 
> The thing I found very difficult with other color formatting APIs was formatting individual words or characters.  Entire lines are easy-peasy stuff in any API.  Solving the entire-lines case won't impress me. ;)

I see your point now. But we should keep it simple.

> Here's my more typical use case:
> 
> writefln("The %CFred(widgetometer%) is a device for measuring");
> writefln("widget effectiveness.  It is possible to ");
> writefln("reconcile transcendental properties by hitting");
> writefln("%CFblu(B%) for blue coefficients, %CFgrn(G%) for green");
> writefln("coefficients, or %CFyel(Y%) for yellow coefficients.");
> writefln("Here is a correspondence table:");
> writefln("  %CFnue( %) | %CFblu( B %) %CFgrn( G %) %CFyel( Y %) ");
> writefln("  %CFnue(-%)-+-%CFnue(---%)-%CFnue(---%)-%CFnue(---%)-");
> writefln("  %CFblu(B%) | %CFblu(200%) %CFwht(330%) %CFwht(303%) ");
> writefln("  %CFgrn(G%) | %CFwht(110%) %CFgrn(020%) %CFwht(033%) ");
> writefln("  %CFyel(Y%) | %CFwht(101%) %CFwht(011%) %CFyel(002%) ");
> 
> I realized that I wanted a "nue" color that has no effect but allows me to align things effectively ;)
> 
> Anyhow, please try to write the above example using any other style. Interleaved function calls are particularly "fun" <g>

I'm convinced. But I find that it difficult to read. Though that's a problem I usually have with format strings. Can these format strings be made easier to read. I mean

writefln("The %CF(red)(widgetometer) is a device for measuring");
or
writefln("The %c(red,white)(widgetometer) is a device for measuring"); // for writing red on white

is already easier to my eyes.
I'd be happy to see it built on top.

Jens
October 23, 2012
On 10/23/2012 03:51 AM, Jens Mueller wrote:
> Chad J wrote:
>> On 10/22/2012 03:47 AM, Jens Mueller wrote:
>>> Chad J wrote:
>>>> There is no weakness to this.  The only shred of a counterargument I
>>>> can think of is that it makes the format strings more difficult to
>>>> learn. Other than that, it is possible to detect the destination of
>>>> the formatter, so color codes will never end up in places where they
>>>> shouldn't.  A conservative approach to this should handle most
>>>> desires and never interfere with all the people with no interest in
>>>> color.
>>>>
>>>> On the upshot are the things I've mentioned:
>>>> - A format specifier is potentially more discoverable.
>>>> - A format specifier is more concise.  This keeps your lines from
>>>> wrapping.  They are probably too long already.
>>>
>>> Do you consider this
>>> writecf(Color.red, "something %s", "here")
>>> concise as well?
>>>
>>
>> The case is too easy.  You're formatting an entire line.
>
> Am I? I think it's not a line. But I see your point.
> You mean something like
> writec(Color.red, "red")
> writec(Color.blue, "blue")
> writec(Color.green, "green")
> is too verbose.
> You want something like
> writef("%CFred(red%)%CFblue(blue%)%CFgreeng(reen%)");
> Right?
>
>>>> - To cement the previous point: nesting requires a few extra
>>>> characters with a format specifier, rather than a couple extra
>>>> /lines/ for extra function calls.
>>>
>>> Don't understand this point. Can you give an example?
>>>
>>
>> Option A:
>>
>>      auto save = getConsoleState();
>>      scope (exit) setConsoleState(save);
>>      setConsoleColors(Fg.red, Bg.blue);
>>      writeln("Red text on blue background.");
>>
>> Option B:
>>
>>      writefln("%CFredBblu(Red text on blue background.%)");
>
> I see. Though I find the last line difficult to decipher (because there
> are no spaces).
>
>>>> - Calls to stateful console functions allow people to write bugs
>>>> like saving console state and then forgetting to restore it (or
>>>> throwing an exception and neglecting to restore from within a scope
>>>> guard).  Format specifiers do not have this problem.
>>>
>>> The same holds for
>>> writecf(Color.red, "something %s", "here")
>>>
>>
>> See my above example.  In that case the formatter no longer requires
>> even using the scope feature because there are no resources to clean
>> up.  The library handles that mess.
>>
>> Also statefulness is a pain to deal with.  Stack-like operation with
>> push/pop or bracketing constructs is usually much less troublesome
>> for this sort of thing.
>
> It'll be nice then if you can built something using format specifiers on
> top of a basic library.
>
>>>> - etc (I'm sure I'm forgetting one or two.)
>>>>
>>>> These are the reasons why my ideal language has color formatting
>>>> built into its I/O routines.
>>>
>>> Just wanted to point out that instead of that you can add writec*
>>> functions. I think the only thing is that these are less discoverable
>>> but they also work without formatting, e.g.
>>> writec(Color.red, "my text");
>>>
>>
>> The thing I found very difficult with other color formatting APIs
>> was formatting individual words or characters.  Entire lines are
>> easy-peasy stuff in any API.  Solving the entire-lines case won't
>> impress me. ;)
>
> I see your point now. But we should keep it simple.
>
>> Here's my more typical use case:
>>
>> writefln("The %CFred(widgetometer%) is a device for measuring");
>> writefln("widget effectiveness.  It is possible to ");
>> writefln("reconcile transcendental properties by hitting");
>> writefln("%CFblu(B%) for blue coefficients, %CFgrn(G%) for green");
>> writefln("coefficients, or %CFyel(Y%) for yellow coefficients.");
>> writefln("Here is a correspondence table:");
>> writefln("  %CFnue( %) | %CFblu( B %) %CFgrn( G %) %CFyel( Y %) ");
>> writefln("  %CFnue(-%)-+-%CFnue(---%)-%CFnue(---%)-%CFnue(---%)-");
>> writefln("  %CFblu(B%) | %CFblu(200%) %CFwht(330%) %CFwht(303%) ");
>> writefln("  %CFgrn(G%) | %CFwht(110%) %CFgrn(020%) %CFwht(033%) ");
>> writefln("  %CFyel(Y%) | %CFwht(101%) %CFwht(011%) %CFyel(002%) ");
>>
>> I realized that I wanted a "nue" color that has no effect but allows
>> me to align things effectively ;)
>>
>> Anyhow, please try to write the above example using any other style.
>> Interleaved function calls are particularly "fun"<g>
>
> I'm convinced. But I find that it difficult to read. Though that's a
> problem I usually have with format strings. Can these format strings be
> made easier to read. I mean
>
> writefln("The %CF(red)(widgetometer) is a device for measuring");
> or
> writefln("The %c(red,white)(widgetometer) is a device for measuring"); // for writing red on white
>
> is already easier to my eyes.
> I'd be happy to see it built on top.
>
> Jens

That's a reasonable suggestion.  The only thing that can't be solved is the trailing ) enclosing the text to be formatted.  That needs a % before it to prevent ambiguity with parentheses in the text itself.  So I could make your example:

> writefln("The %c(red,white)(widgetometer%) is a device formeasuring"); // for writing red on white

I was also considering the possibility of separating layout and style by allowing some kind of style specification before the printing, with a limited formatting spec for using the styles:

stdout.addTermTextStyle("id=myStyle, fg=red, bg=white, dark, underline");

writefln("The %c(myStyle)(widgetometer%) is a device for measuring");
October 23, 2012
>> writefln("The %c(red,white)(widgetometer%) is a device formeasuring"); //
>> for writing red on white

Would something like the following be possible?

// col is a string-accepting function that returns a correctly formatted string
// red and white are from a general Color enum
alias col!(Color.red, Color.white) rw;

writeln("The ", rw("widgetometer"), " is a device for measuring...");
October 23, 2012
On 10/23/2012 03:56 PM, Philippe Sigaud wrote:
>>> writefln("The %c(red,white)(widgetometer%) is a device formeasuring"); //
>>> for writing red on white
>
> Would something like the following be possible?
>
> // col is a string-accepting function that returns a correctly formatted string
> // red and white are from a general Color enum
> alias col!(Color.red, Color.white) rw;
>
> writeln("The ", rw("widgetometer"), " is a device for measuring...");

Nope.  Windows requires function calls to do color formatting.  It does not use escape sequences.

That said, it is always possible to scan all text about to be sent off to Windows and look for escape sequences, then reinterpret them as WinAPI coloring calls.  The difficulty then is getting the "rw" construct above to know if it should emit escape sequences or not: the text it creates might eventually be bound for a file, a network socket, or some buffer in memory, but not a terminal.  If it's heading for a terminal it has to know which one because they might use different escape sequences.  So there always has to be some way of contextualizing the color formatting to its destination so that it can select the right form of output, including no formatting if its inappropriate for the destination.

Also, it doesn't nest.  It should be possible to push/pop terminal attributes in mid-string.
October 23, 2012
Chad J wrote:
> On 10/23/2012 03:51 AM, Jens Mueller wrote:
> >Chad J wrote:
> >>On 10/22/2012 03:47 AM, Jens Mueller wrote:
> >>>Chad J wrote:
> >>>>There is no weakness to this.  The only shred of a counterargument I can think of is that it makes the format strings more difficult to learn. Other than that, it is possible to detect the destination of the formatter, so color codes will never end up in places where they shouldn't.  A conservative approach to this should handle most desires and never interfere with all the people with no interest in color.
> >>>>
> >>>>On the upshot are the things I've mentioned:
> >>>>- A format specifier is potentially more discoverable.
> >>>>- A format specifier is more concise.  This keeps your lines from
> >>>>wrapping.  They are probably too long already.
> >>>
> >>>Do you consider this
> >>>writecf(Color.red, "something %s", "here")
> >>>concise as well?
> >>>
> >>
> >>The case is too easy.  You're formatting an entire line.
> >
> >Am I? I think it's not a line. But I see your point.
> >You mean something like
> >writec(Color.red, "red")
> >writec(Color.blue, "blue")
> >writec(Color.green, "green")
> >is too verbose.
> >You want something like
> >writef("%CFred(red%)%CFblue(blue%)%CFgreeng(reen%)");
> >Right?
> >
> >>>>- To cement the previous point: nesting requires a few extra characters with a format specifier, rather than a couple extra /lines/ for extra function calls.
> >>>
> >>>Don't understand this point. Can you give an example?
> >>>
> >>
> >>Option A:
> >>
> >>     auto save = getConsoleState();
> >>     scope (exit) setConsoleState(save);
> >>     setConsoleColors(Fg.red, Bg.blue);
> >>     writeln("Red text on blue background.");
> >>
> >>Option B:
> >>
> >>     writefln("%CFredBblu(Red text on blue background.%)");
> >
> >I see. Though I find the last line difficult to decipher (because there
> >are no spaces).
> >
> >>>>- Calls to stateful console functions allow people to write bugs like saving console state and then forgetting to restore it (or throwing an exception and neglecting to restore from within a scope guard).  Format specifiers do not have this problem.
> >>>
> >>>The same holds for
> >>>writecf(Color.red, "something %s", "here")
> >>>
> >>
> >>See my above example.  In that case the formatter no longer requires even using the scope feature because there are no resources to clean up.  The library handles that mess.
> >>
> >>Also statefulness is a pain to deal with.  Stack-like operation with push/pop or bracketing constructs is usually much less troublesome for this sort of thing.
> >
> >It'll be nice then if you can built something using format specifiers on top of a basic library.
> >
> >>>>- etc (I'm sure I'm forgetting one or two.)
> >>>>
> >>>>These are the reasons why my ideal language has color formatting built into its I/O routines.
> >>>
> >>>Just wanted to point out that instead of that you can add writec*
> >>>functions. I think the only thing is that these are less discoverable
> >>>but they also work without formatting, e.g.
> >>>writec(Color.red, "my text");
> >>>
> >>
> >>The thing I found very difficult with other color formatting APIs was formatting individual words or characters.  Entire lines are easy-peasy stuff in any API.  Solving the entire-lines case won't impress me. ;)
> >
> >I see your point now. But we should keep it simple.
> >
> >>Here's my more typical use case:
> >>
> >>writefln("The %CFred(widgetometer%) is a device for measuring");
> >>writefln("widget effectiveness.  It is possible to ");
> >>writefln("reconcile transcendental properties by hitting");
> >>writefln("%CFblu(B%) for blue coefficients, %CFgrn(G%) for green");
> >>writefln("coefficients, or %CFyel(Y%) for yellow coefficients.");
> >>writefln("Here is a correspondence table:");
> >>writefln("  %CFnue( %) | %CFblu( B %) %CFgrn( G %) %CFyel( Y %) ");
> >>writefln("  %CFnue(-%)-+-%CFnue(---%)-%CFnue(---%)-%CFnue(---%)-");
> >>writefln("  %CFblu(B%) | %CFblu(200%) %CFwht(330%) %CFwht(303%) ");
> >>writefln("  %CFgrn(G%) | %CFwht(110%) %CFgrn(020%) %CFwht(033%) ");
> >>writefln("  %CFyel(Y%) | %CFwht(101%) %CFwht(011%) %CFyel(002%) ");
> >>
> >>I realized that I wanted a "nue" color that has no effect but allows me to align things effectively ;)
> >>
> >>Anyhow, please try to write the above example using any other style. Interleaved function calls are particularly "fun"<g>
> >
> >I'm convinced. But I find that it difficult to read. Though that's a problem I usually have with format strings. Can these format strings be made easier to read. I mean
> >
> >writefln("The %CF(red)(widgetometer) is a device for measuring");
> >or
> >writefln("The %c(red,white)(widgetometer) is a device for measuring"); // for writing red on white
> >
> >is already easier to my eyes.
> >I'd be happy to see it built on top.
> >
> >Jens
> 
> That's a reasonable suggestion.  The only thing that can't be solved is the trailing ) enclosing the text to be formatted.  That needs a % before it to prevent ambiguity with parentheses in the text itself.  So I could make your example:
> 
> > writefln("The %c(red,white)(widgetometer%) is a device
> formeasuring"); // for writing red on white
> 
> I was also considering the possibility of separating layout and style by allowing some kind of style specification before the printing, with a limited formatting spec for using the styles:
> 
> stdout.addTermTextStyle("id=myStyle, fg=red, bg=white, dark, underline");
> 
> writefln("The %c(myStyle)(widgetometer%) is a device for measuring");

Ideally, we get some users and ask them what they find easy to read. Or
look how other languages solve this.
Because I myself don't color my terminals that much I find it hard to
imagine.
I searched for some ruby libraries. I find ruby syntax often very easy.
We could use UFCS, e.g.
"some string".red
or
"some string".foreground(Color.red)

What do you think?
I find this way easier than format strings.

Jens