Wednesday, November 12, 2014

Pigshell is an omnivore

If you have a shell for the web, wouldn't it be cool if your path were a list of domains?  If you found a cool script on github, shouldn't you be able to load it and use it with ease?  Well, that's what I've wanted when making builin commands for pigshell so that's what I made.



The build is on http://bitdivine.com so you can make builtins too and test them right there, without having to build and host a copy yourself.

Whilst on the note of the effort of maintaining your own build, until I have plugged my credentials into the facebook drive you won't be able to use that bit.  w00t, the best bit is missing?  It's getting there.  In the meantime get coding.  Time for some new data sources, folks!

Sunday, November 9, 2014

Pigshell Pretty

In my last post I wanted to show how to write images to stdout from a builtin in pigshell. THINGS are sent down the pigshell pipeline and when they get to the end they magically appear as images, videos and other things with most un-terminal window like behaviour. That is, unless I use an 0.001 point font and the rendering code is an ascii artist's wet dream.

But there ain't so such thing as magic. THINGS must surely have .toHTML() functions or face being rendered as text. Or mime types. Or something like that. I had a nosey through the code and it turns out that the terminal checks whether THING is one of a number of types of objects it knows how to render. So in particular if I have an instanceof HTMLDivElement or HTMLIFrameElement it should render beautifully. Let's check in the shell.

First I will need a way of putting HTML inside divs:

pig$ echo '<span style="background-color:red;">pop</span>' | jf '(function(x){ans = document.createElement("div");ans.innerHTML=x;return ans;})(x)'



Now let's make a "subshell":


On that basis making a builtin that spits out HTML should be pretty easy.

Thursday, November 6, 2014

Pigshell pipe - speak no evil!

In my last post I showed how to write a hello world program that displays an image in pigshell. However one of the most powerful things in shell scripting is the pipe and if you tried piping with the last program you will have seen:



For better or worse, only the last program in the pipeline has access to the screen. At least, in that way. So my next step is to make a program that talks pipe. Here goes:

In pigshell/src/cmd/jline.sh I put:

function Jline(opts) {
    var self = this;
    self.countdown = 10;
    Jline.base.call(self, opts);
}
inherit(Jline, Command);

Jline.prototype.usage =
    [ 'jline'
    , 'Usage:'
    , '  jline'
    ].join("\n");

Jline.prototype.next = check_next(do_docopt(function(opts, cb) {
    if (this.countdown--) this.output(this.countdown + " green bottles\n");
    else this.exit(0);
}));

Command.register("jline", Jline);


Run make and hey presto:




















No squealing!  Great, but a bit black and white.  Let's see whether we can add colour back in - after dinner!


Saturday, November 1, 2014

Pigshell - A peek at the inside

A shell for the web

Terminal windows are a developer's best friend. But sometimes having to render everything in a grid of 40x60 characters feels just a little bit lacking in expressive power in a world of retina screens. Sure, like most number crunchers I have a set of small scripts that take data from a terminal window and display them in a browser, adhering to that age old adage "Look at your data or get junk out of your analysis." but I recently bumped into a shell that lives right in a web browser. It takes cat img.jpg to a whole new level! It's immature, it's new, it clearly needs some serious thought about the fundamentals, but I do believe that this is the future.
You can start playing with the shell right now at http://pigshell.com. But the developer in you will want to understand how it works and build more tools. There aren't really any guides out there right now on how to hack pigshell so here are my notes. Just to be clear, there are plenty of documents on how to use ps and write shell scripts for it, but not for how to dip under the covers. Today I made the simplest builtin command you could possibly imagine and added it to my local build of pigshell:

Initial installation:

The developer's notes for this are pretty accurate. I recorded the installation commands that I ran for Debian here. The only thing to note is that at the moment the domain name is hardwired in some places in the code and so the easiest way of setting up your own build is to point pigshell.com at your own server in your /etc/hosts file. Hopefully that will change soon!

Making a builtin

Builtin commands are those such as cd and ls that come with pigshell itself. Their code is in src/cmd/

Destructive testing:

Go on, break the code! In src/cmd/ls.js add a call to the non-existent but highly effective function called boom:
function Ls(opts) {
    var self = this;
    boom;
    ...
Build by running make and then, in pigshell, try the newly knobbled ls:
pig:/$ ls facebook
Exception: Uncaught ReferenceError: boom is not defined
OK, now you know your code is being used! Now fix it! Bad boy.
git checkout src/cmd/ls.js

Registering a command

Here is a minimal command that does nothing:

function Jline(opts) {
    // your code will go here
}
Command.register("jline", Jline);

If you put that in src/cmd/jline.js and build you should be able to run jline on the command line:

pig:/$ jline
pig:/$

If you don't:
  • Did you run make?
  • Look for your function in the newly compiled file pigshell.js.
  • Refresh the browser. I haven't needed to but it might help!

Hello Web

To print you need to access the API. And no, console.log won't do that for you! There is an HTML div that you can populate with, say, an image of a cute little piglet:

function Jline(opts) {
    var self = this;
    Jline.base.call(self, opts);
}
inherit(Jline, Command);

Jline.prototype.next = check_next(function(opts, cb) {
    var self = this
      , term = opts.term
      , tdiv = term.div;
    $('<img src="images/pigshell-logo-320x240.png" width="100px" />').appendTo(tdiv);
    $('<span>Doodlebug</span>').appendTo(tdiv);
    self.exit(0);
});

Command.register("jline", Jline);


And bingo:


Much as I love ASCII art that's some cool pig.