[nodejs] [ANN] colors.js - get colors in your node.js console like what

763 views
Skip to first unread message

Marak Squires

unread,
Jun 11, 2010, 8:13:24 AM6/11/10
to nod...@googlegroups.com, ny...@googlegroups.com
hello internet friends!

i've released a new library for node.js that adds really easy color support for the console

works something like ,  sys.puts("this is a green string".green);

check out the example on the ReadMe


Scott Taylor

unread,
Jun 11, 2010, 8:45:13 AM6/11/10
to nod...@googlegroups.com
Cool.  Have you also looked at:


Scott



--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.

Marak Squires

unread,
Jun 11, 2010, 8:48:45 AM6/11/10
to nod...@googlegroups.com
Yeah, the API for botanicus's version is crap and the code from chrislloyd's is crap. 

if you dig into both libs you'll see what im talking about >.<

many ways to achieve this. i think my approach (really cloudhead's) is very clean

Bradley Meck

unread,
Jun 11, 2010, 9:02:16 AM6/11/10
to nodejs
feel free to steal node-terminal's junk if you want some other stuff,
its going to be largely unmaintained for quite a bit prolly.
> > nodejs+un...@googlegroups.com<nodejs%2Bunsu...@googlegroups.com>
> > .

TooTallNate

unread,
Jun 11, 2010, 1:01:19 PM6/11/10
to nodejs
Yeah! Nice! I'm digging the API honestly.

Without looking at your source.... I'm guessing you augment
String.prototype with your colors as properties via
Object.defineProperty, and specifically defining a getter function
that returns 'this' (the String) with the color prefix/suffix (I don't
actually know how the coloring in the terminal is done).

So how'd I do :p

Marak Squires

unread,
Jun 11, 2010, 1:07:28 PM6/11/10
to nod...@googlegroups.com
Something like that ya. All I did was wrap up the package nicely, the code is mostly cloudhead's.

Debacker

unread,
Jun 11, 2010, 4:05:10 PM6/11/10
to nod...@googlegroups.com
You are adding many properties to string... and from an OO point-of-view it looks strange because what if another guy like you says "hey I just came up with 'text in green'.green returning <a style="color: green">text in green</a>" ? Then both of your libraries are clashing each other. I agree that the syntax is short and easy to use, but from an OO pov it is no good. TTY.greenText('text in green') is not that annoying to use, and a better citizen. I guess it depends on your priorities.

Laurent Debacker

anders conbere

unread,
Jun 11, 2010, 4:40:09 PM6/11/10
to nod...@googlegroups.com
Yeah... I'm not too comfortable applying a bunch of random methods to string :-/

~ Anders

Marak Squires

unread,
Jun 11, 2010, 4:46:41 PM6/11/10
to nod...@googlegroups.com
Not being OO? 

Scared of prototyping String?

lol you guys, good joke

anders conbere

unread,
Jun 11, 2010, 4:51:28 PM6/11/10
to nod...@googlegroups.com
Even namespacing these methods properly would help

"my string".tty.green

On Fri, Jun 11, 2010 at 1:46 PM, Marak Squires <marak....@gmail.com> wrote:
> Not being OO?
> Scared of prototyping String?
> lol you guys, good joke

You can take the comments or leave them, but don't be surprised when
people respond to an email you send to a list.

Marak Squires

unread,
Jun 11, 2010, 4:55:23 PM6/11/10
to nod...@googlegroups.com
:p the internet is serious bidness!

your namespacing suggestion isnt that bad. in my general coding practices the only thing i would allow to prototype String is a helper library. i'm almost never going to be prototyping String in my applications code.

with that being said, you do have a point. i think the best compromise here would be to introduce a noconflict mode or something along the lines of that? this way a developer could specify an optional namespace like "tty" if they wanted?

Debacker

unread,
Jun 11, 2010, 5:07:51 PM6/11/10
to nod...@googlegroups.com
Okay, I meant good "OO practice", it's not because you are using methods, properties, and prototypes that you are doing good OO ;-) If I wanted to make a joke, I would say that the API had a bad smell.

'green text'.tty.green is indeed interesting.

Laurent

Isaac Schlueter

unread,
Jun 11, 2010, 5:17:58 PM6/11/10
to nod...@googlegroups.com
The "good OO practice" would be to use String#green(getter)
everywhere, and then set that to a TTY wrapper when you're in TTY
mode, and an HTML wrapper when you're in an HTML mode, or a null
pass-through if it doesn't make sense to apply colors. Your
application code shouldn't care how it's being colored, only *that*
it's being colored.

Polymorphism and encapsulation are the *point* of OOP.

--i

Debacker

unread,
Jun 11, 2010, 6:20:15 PM6/11/10
to nod...@googlegroups.com
Isaac, in most OO languages, you will make use of polymorphism by derivating a base class, then depending on the type of your object, one implement or another will be used. Since I'm no JS guru, could you show me how you would implement polymorphism for string coloring please ? 'foo'.tty and 'foo'.html would makes sense to me if you want polymorphism because these functions could return another string object, but with another prototype so that the color getters would have a different implementation. Is it what you are refereeing to? In that case, for "good OO practice", 'foo'.green should the same object (default implementation), but 'foo'.html and 'foo'.tty would offer different implementations, so I would not see any contradicting with what has been said earlier. Or maybe you mean, modifying the prototype of string depending on the module, problem is for modules which outputs both to terminal and HTTP clients.

Laurent

Marak Squires

unread,
Jun 11, 2010, 6:28:40 PM6/11/10
to nod...@googlegroups.com
I'm glad we have a really easy example of object prototyping in JavaScript that everyone can understand and apply their own knowledge and experience to. Surely this collaborative discussion will yield a fruitful bounty of information in which we can all benefit from.

Dean Landolt

unread,
Jun 11, 2010, 6:29:39 PM6/11/10
to nod...@googlegroups.com
On Fri, Jun 11, 2010 at 4:55 PM, Marak Squires <marak....@gmail.com> wrote:
:p the internet is serious bidness!

your namespacing suggestion isnt that bad. in my general coding practices the only thing i would allow to prototype String is a helper library. i'm almost never going to be prototyping String in my applications code.

with that being said, you do have a point. i think the best compromise here would be to introduce a noconflict mode or something along the lines of that? this way a developer could specify an optional namespace like "tty" if they wanted?


Your idea of noconflict sounds more like oneconflict. 

Ryan Gahl

unread,
Jun 11, 2010, 6:35:56 PM6/11/10
to nod...@googlegroups.com
On Fri, Jun 11, 2010 at 5:28 PM, Marak Squires <marak....@gmail.com> wrote:
I'm glad we have a really easy example of object prototyping in JavaScript that everyone can understand and apply their own knowledge and experience to. Surely this collaborative discussion will yield a fruitful bounty of information in which we can all benefit from.


Who are you and what have you done with Marak?

(or: ohhhh I see what you did there...)

Isaac Schlueter

unread,
Jun 11, 2010, 6:56:06 PM6/11/10
to nod...@googlegroups.com
> On Fri, Jun 11, 2010 at 6:20 PM, Debacker <deba...@gmail.com> wrote:
>>
>> Isaac, in most OO languages, you will make use of polymorphism by
>> derivating a base class, then depending on the type of your object, one
>> implement or another will be used.

JavaScript isn't most OO languages. There are no classes, no
interfaces, etc. It's just objects and functions all the way down.

The purpose of polymorphism – not the implementation or syntax, mind
you – is to abstract out functionality away from where it doesn't
matter, while preserving a consistent interface. Since the interface
remains constant, consumers can just use it, and trust that it will
work appropriately.

The idea is that you'd have some consumer code that does "foo".green,
without knowing exactly what the actual result will be, but trusting
that it will be green-ified in some manner than makes sense.

Then you have a tty-colors module that will attach the
String.prototype.green getter to return a string with the tty escape
codes (and perhaps strips them off if the output is not a TTY) and
let's say an html-colors module that attaches a String.prototype.green
getter that returns a string with html tags.

A fourth module switches between loading the appropriate coloring
module for the current environment. That is the *only* one that knows
whether it's dealing with HTML or TTY output.

So, you can do "foo".green, and it'll work the same, whether it's a
TTY or a web page, without having decision points all over the place
that decide which one to use.

In a C++ or Java world, you might have something like this:

String greenStr = StringColorizerFactory::New()->green( myString );

and then have StringColorizerFactory return an object that implements
the StringColorizerImpl implementation (either a StringColorizerTTY or
StringColorizerHTML).

Too often, people hear OOP and think Classes. OOP was never about
classes, but rather about encapsulation and message passing, since
that makes it *possible* to have consistent interfaces. With
JavaScript, you can just throw all that garbage away, and deal with
the principles of OOP much more directly. That's why I love it, even
with its warts.

Marak didn't give you the HTML outputting functionality, or the thing
to switch between them. But I'd argue that his (well, cloudhead's)
approach for handling the TTY coloring is actually OOP done right.

--i

Dean Landolt

unread,
Jun 12, 2010, 1:37:07 AM6/12/10
to nod...@googlegroups.com
On Fri, Jun 11, 2010 at 6:28 PM, Marak Squires <marak....@gmail.com> wrote:
I'm glad we have a really easy example of object prototyping in JavaScript that everyone can understand and apply their own knowledge and experience to. Surely this collaborative discussion will yield a fruitful bounty of information in which we can all benefit from.


I can't quite tell if you were just being a bit snarky but oh how prescient you were...

Thanks Isaac.

Debacker

unread,
Jun 13, 2010, 6:13:35 AM6/13/10
to nod...@googlegroups.com
Thanks Marak for this fine explanation, I appreciate.

While I understand polymorphism at the abstract OOP level, and agree with your definition, I was not sure how to do it right in JS.
With your API, I don't really see how I can implement one function to print green text to the TTY, and another to print green text in HTML.

Let's suppose I want a generic function to build a log line using polymorphism:

function info_log_line(text) {
    return "Info: ".green + text;
}

All right, then if I want to implement my function to print to TTY and write to HTML file on the disk (for logging purpose), I guess I need to do something like:

function log(text) {
    html( function() { logFile.write(info_log_line(text); });
    tty( function() { sys.puts(info_log_line(text); });
}

because your "green" property for string depends on the global state of String.prototype AFAIK.
So you would need a way to define the scope of your "customized" String.prototype.
Is this what you had in mind when designing your API?

But if I implement html and tty using defineProperty, on the second call, I get "Cannot redefine property".

I believe I don't really like this is because the meaning of ".green" depends on the global state, or in this case the state of "String.prototype", it does not only depends on the type of the object. Indeed, what if you do the following:

function log(text, cb) {
    var s = 'Info: '.green + text + ' ';
    disk.fooBar(function(result) {
        cb(s + result.green);
    };
}

The problem there is that between the time "log" returns and the callback "cb" is called again by the event loop, another callback may have modified String#green(getter).

The reason why I discuss this in details is because you considered the design of other libraries as "crap". By using such a strong term, I guessed that your design must be rock-solid to justify that. So I was interested in understand your logic.

The following API used in the following example solve theses. Maybe you will consider it "crap", but is it also OO, and using polymorphism:

function log(formatter, text, cb) {
    var s = formatter.green('Info: ') + text + ' ';
    disk.fooBar(function(result) {
        cb(s + formatter.green(result));
    };
}

function log(text) {
    logFile.write(html, info_log_line(text));
    sys.puts(tty, info_log_line(text));
}

Global state should be configured once. Changing it all the time is not a good OO practice (illustrated for the reason above). It is not going to be fine just because you are you are using polymorphism for the global state.

Laurent

Isaac Schlueter

unread,
Jun 13, 2010, 12:41:19 PM6/13/10
to nod...@googlegroups.com
Doing it at the global level does mean that there can be only one
String#green at any given time, it's true.

In other words, whichever thing is deciding which set of colors to
attach to the String prototype must know where *all* the output is
going.

> But if I implement html and tty using defineProperty, on the second call, I
> get "Cannot redefine property".

Unless you add { configurable : true } to the property definition.
But the point is valid, globals suck in a lot of use cases.

I'd argue that if you have a case where all of your output is
definitely going to one place, then modifying the global String
prototype could yield complexity benefits. But if you need to have
both available, then yes, either the colorizing functions need to be
namespaced, or you need to pass around formatter objects, or have a
configuration thing somewhere, like your "html" and "tty" functions
that take a callback. When that callback returns, it can set the
styling mechanism back the way it was, so nesting works fine.

--i

Marak Squires

unread,
Jun 13, 2010, 1:11:31 PM6/13/10
to nod...@googlegroups.com
zzzzzzzzzzzzzzzzzzzz

Ricardo Tomasi

unread,
Jun 13, 2010, 7:45:29 PM6/13/10
to nodejs
As I see it this whole discussion is moot. It's not like anyone would
define styles for HTML in server-side code (is it?). This thing is
just for use in the terminal. If you're worried about clashes because
of the prototype, just put the code in a different object and use it
as a constructor.
> >> On Fri, Jun 11, 2010 at 15:28, Marak Squires <marak.squi...@gmail.com>
> >> wrote:
> >> > I'm glad we have a really easy example of object prototyping in
> >> > JavaScript
> >> > that everyone can understand and apply their own knowledge and
> >> > experience
> >> > to. Surely this collaborative discussion will yield a fruitful bounty of
> >> > information in which we can all benefit from.
>
> >> >>> On Fri, Jun 11, 2010 at 14:07, Debacker <deback...@gmail.com> wrote:
> >> >>> > Okay, I meant good "OO practice", it's not because you are using
> >> >>> > methods,
> >> >>> > properties, and prototypes that you are doing good OO ;-) If I
> >> >>> > wanted
> >> >>> > to
> >> >>> > make a joke, I would say that the API had a bad smell.
>
> >> >>> > 'green text'.tty.green is indeed interesting.
>
> >> >>> > Laurent
>
> >> >>> > On Fri, Jun 11, 2010 at 10:55 PM, Marak Squires
> >> >>> > <marak.squi...@gmail.com>
> >> >>> > wrote:
>
> >> >>> >> :p the internet is serious bidness!
> >> >>> >> your namespacing suggestion isnt that bad. in my general coding
> >> >>> >> practices
> >> >>> >> the only thing i would allow to prototype String is a helper
> >> >>> >> library.
> >> >>> >> i'm
> >> >>> >> almost never going to be prototyping String in my applications
> >> >>> >> code.
> >> >>> >> with that being said, you do have a point. i think the best
> >> >>> >> compromise
> >> >>> >> here would be to introduce a noconflict mode or something along the
> >> >>> >> lines of
> >> >>> >> that? this way a developer could specify an optional namespace like
> >> >>> >> "tty" if
> >> >>> >> they wanted?
> >> >>> >> On Fri, Jun 11, 2010 at 4:51 PM, anders conbere
> >> >>> >> <aconb...@gmail.com>
> >> >>> >> wrote:
>
> >> >>> >>> Even namespacing these methods properly would help
>
> >> >>> >>> "my string".tty.green
>
> >> >>> >>> On Fri, Jun
>
> ...
>
> mais »

Ryan Gahl

unread,
Jun 14, 2010, 10:37:44 AM6/14/10
to nod...@googlegroups.com
On Sun, Jun 13, 2010 at 6:45 PM, Ricardo Tomasi <ricar...@gmail.com> wrote:
As I see it this whole discussion is moot.


All conversations are moot.

:)

Tom Robinson

unread,
Jun 15, 2010, 2:31:00 PM6/15/10
to nod...@googlegroups.com
Just to throw out another way of doing this, term.js lets you annotate strings with null delimited markers:

    stream.write("Hello \0green(world\0). Goodbye \0red(world\0).")

(stream is a special stream wrapper that understands these markers)

Shouldn't be hard to port to Node if anyone is interested. http://github.com/280north/narwhal/blob/master/lib/term.js

Marak Squires

unread,
Jun 15, 2010, 2:33:37 PM6/15/10
to nod...@googlegroups.com
Tom -

I'm sure there are use cases but I really dislike that approach.

--

Dean Landolt

unread,
Jun 15, 2010, 2:36:17 PM6/15/10
to nod...@googlegroups.com
On Tue, Jun 15, 2010 at 2:33 PM, Marak Squires <marak....@gmail.com> wrote:
Tom -

I'm sure there are use cases but I really dislike that approach.


This is where xml really shines!

/me ducks
Reply all
Reply to author
Forward
0 new messages