Muffinresearch Labs by Stuart Colville

Using PHP CLI for TextMate commands | Comments (3)

Posted in Code on 19th March 2007, 11:51 pm by Stuart

TextMate comands are very flexible ways to harness the power of the commandline. In previous commands that I have written I have tended to use BASH directly but one of the clever things about TextMate is that it allows you to use pretty much any language that exists on your mac.

As an example PHP on CLI is not that likely to be your first choice when you think about working on the command line. In fact the majority of bundles make use of Ruby as this is a very sleek programming language and has some nice touches to facilitate it’s use on the command line. However for this article I am going to simply outline how to make use of PHP from within textmate and look at a very basic but potentially very useful (to JS programmers) example.

First of all to start a php command we have two options:

  1. To use php with the -r switch so that we can write simple code without the need for php code blocks
  2. To use php as a shell script with a shebang and the opening and closing code blocks.

Personally unless you are doing a very simple one-liner you are probably best to stick to the latter which is ideal for creating shells scripts in PHP.

To start, first you need to open the bundle editor, create a new command and start with the PHP bang. This is a way of indicating that we want the following script to be read by PHP. This looks like this:

#!/usr/bin/php

Where /usr/bin/php is the path to your php binary

Environment Variables

All of the special environment variables are available to TextMate via the $_ENV array. This makes accessing them a breeze.

So as a starting point let’s print out the $_ENV array in textmate so we can see what’s available. Set-up the command window as follows:

Save:
Nothing
Command(s)
#!/usr/bin/php
<?php
print_r($_ENV);
?>
Input
None
Output
Create New Document

You should see output similar to the following (some entries removed to save space):

[PATH] => /usr/bin:/bin:/usr/sbin:/sbin
  [DIALOG] => /Applications/TextMate.app/Contents/PlugIns/Dialog.tmplugin/Contents/Resources/tm_dialog
  [TM_LINE_NUMBER] => 1
  [TM_CURRENT_LINE] =>
  [TM_SOFT_TABS] => YES
  [TM_TAB_SIZE] => 2
  [BASH_ENV] => /Users/scol/Library/Application Support/TextMate/Support/lib/bash_init.sh
  [TM_SUPPORT_PATH] => /Users/scol/Library/Application Support/TextMate/Support
  [TM_SCOPE] => text.plain
  [TM_ORGANIZATION_NAME] => __MyCompanyName__
  [TM_BUNDLE_PATH] => /Users/scol/Library/Application Support/TextMate/Bundles/JSMin.tmbundle
  [TM_MODE] => Plain Text
  [TM_COLUMN_NUMBER] => 1
  [TM_LINE_INDEX] => 0
  [TM_COLUMNS] => 190
  [TM_BUNDLE_SUPPORT] => /Users/scol/Library/Application Support/TextMate/Bundles/JSMin.tmbundle/Support
  [SHLVL] => 1

Now we can simply access these vars with getenv e.g. getenv('TM_TAB_SIZE'); or by directly looking at the $_ENV array $ENV['TM_TAB_SIZE'];

Reading Standard Input

Now another thing that’s needed to be able to do anything in a textmate command is accessing STDIN. STDIN is the standard input (who’d have thunk it?!) to the command and it’s that which is set-up through the command window. The current main options are:

  1. None
  2. Selected Text
  3. Entire Document

Note: If you select “Selected Text” fallbacks to word, line, scope, document, character or nothing are also available.

So if we have “Selected Text” as out input this will be fed through to our command as the Standard input. In addition we also can make use of the $_ENV variable TM_SELECTED_TEXT too but for this example I’ll stick to demonstrating STDIN.

Within PHP CLI STDIN is a constant that points to an already open stream resource. This allows you to read in the stdin line by line or as you see fit. To get the entire STDIN instead one needs to use fread and supply the number of bytes to be read. To do this precisely you can use fstat to work out the size of the resource and therefore set a variable equal to the contents of STDIN in it’s entirety as follows:

$fstat = fstat(STDIN);
$stdin = fread(STDIN,$fstat['size']);

Now that we have STDIN we can now do something with it. This example is a follow on from the small bundle I had created to carry out JavaScript Minification with JSMin. This script takes a selected set of external (but local) JavaScript file references from an HTML file and runs those files through JSMin which is contained within the Bundle support files. This code would also be easy to simply modify to use a local copy of JSmin if this is more convenient.

So in your HTML file you would select your script elements that look something like this (Note: this will only work with locally referenced files for obvious reasons):

<script src="../yui/calendar.js" type="text/javascript"></script>
<script src="../yui/connection.js" type="text/javascript"></script>
<script src="../yui/container.js" type="text/javascript"></script>

When we call our command the selection is piped into the front of the command as the standard input.

Here’s the code that deals with the input:

#!/usr/bin/php
<?php
$fstat = fstat(STDIN);
$stdin = fread(STDIN,$fstat['size']);
preg_match_all(’/src=["\'](.*?)[\'"]/’, $stdin, $m, PREG_SET_ORDER);
if (is_array($m)){
	$j = count($m);
	$files = ”;
	for ($i=0; $i < $j; $i++){
		$files .= $m[$i][1].’ ‘;
	}
}
echo shell_exec(’cat ‘. $files . ‘|’.str_replace(’ ‘, ‘\\ ‘, $_ENV['TM_BUNDLE_SUPPORT']).’/bin/jsmin’);
?>

What this simply does is to create an array of all matches to the src attribute where the backreference matches the contents of the src attribute. Once we have that, it’s possible to build up a string of all of the path names, cat (concatenate) the files together and run the result through JSMin. By setting the command to create a new file you can simply save the file from TextMate and give it the name of your choice.

Have at it and let me know if you spot any ways to improve the examples or have created some cracking commands using PHP in TextMate.

To try this example download the JSMin Bundle which contains the example above along with some other ways to use JSMin. This bundle contains a pre-compiled universal binary of JSMin already. Once you have unpacked the zip simply double click it to install it into TextMate.

Post Tools

Comments: Add yours

1. On March 25th, 2007 at 11:56 am Soryu said:

Very nice. Though I think someone ate at least one backslash in your code snippet. (The str_replace part at the end?)

I also like TextMate for learning Ruby in such situations and try not to resort to using PHP as a language for commands :).

2. On March 25th, 2007 at 11:26 pm Stuart Colville said:

@Soryu: Well spotted on the code example. That’s been fixed now.

I know what you mean about not resorting to using PHP within textmate it feels strange in some respects. However the point of this article was to show that if you like PHP then it’s possible to use PHP for commands and that the ENV vars are still available.

From my own point of view I’m starting to use Ruby and Python for Textmate commands and particularly Python for a few other things. Hopefully from now on that will mean I’m down with the cool kids :-)

3. On January 17th, 2008 at 9:19 am Beautify JavaScript from TextMate or CLI | Muffin Research Labs by Stuart Colville said:

[...] As Einars has pointed out this functionality is part of the built-in JavaScript Bundle under “Reformat Document”. I’ll leave the rest of this post here as it does provide an example of how to set-up a command with an existing PHP script and if you’re not a TextMate user then this will work as a CLI script too and you can find more info on using PHP for CLI in TextMate here [...]







XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Standalone mac battery charger|(0)

Got a spare mac battery? I’ve often wondered why up until now no-one’s produced a standalone charger so that you can charge batteries without having to plug them into the mac. Fortunately Fastmac.com have produced a standalone charger that allows you to do just that. and it’s compatible with iBooks, Powerbooks, macbooks and Macbook Pros. It’s also 110/200v. Exactly what I was looking for!

Django Admin Ominigraffle Stencil|(0)

Colleague Alex Lee has created a nice stencil for omingraffle with the Django Admin UI components, perfect for wireframing customised admin screens. For more details and to download the stencil see Alex’s Blog csensedesign.co.uk

Photos on Flickr

© Copyright 2004-08 Stuart Colville, all rights reserved. May contain traces of Muffin. Powered by WordPress. Hosting by 1&1 This page was baked in 0.739s.