Textmate and Perlbrew

In: Articles

14 Oct 2012

Textmate is a marvelous text editor for programming and other text based tasks on OSX. It even has a great extension for assisting when programming Perl. One of the really helpful features is a syntax validation happening when a file is saved.

Take for example this incomplete Perl source file below

wpid-hell-2012-10-14-20-291.png

If you specify the contents as perl (see the bottom of the window) or let Textmate resolve this Textmate will evaluate the contents when I save and get an error due to the very obvious syntax error in line 3.

wpid-warning-2012-10-14-20-291.png

Correcting the contents of the file, will give me status indicating an evaluation success.

wpid-no-errors-2012-10-14-20-291.png

This is really nifty most of the time, but I ran into a problem.

I am using App::perlbrew (perlbrew) to handle my local Perl installations. Perlbrew is a magnificent tool and it lets me install several different Perl interpreters in parallel. So I can evaluate my code using different versions of Perl.

The check executed by Textmate is handled by a script named: perlcheckmate.pl (available on Github) and it relies solely on the system perl installed in /usr/bin.

So when I work on a project requiring a newer (or older) version and I then use Perlbrew to satisfy this, I have to install external dependencies with two Perls – not exactly optimal also because I am not interested in maintaining and feeding all sort of crazy modules to my system Perl, just because I am working on some project.

Luckily adjusting perlcheckmate.pl to recognize and use perlbrew is quite easy.

perlbrew sets some environment variables when active:

  • PERLBREW_PERL
  • PERLBREW_ROOT

When perlbrew is active these variables will have content, if not or not installed, existing behavior should be preserved – and not everyone uses perlbrew.

So if PERLBREW_PERL is defined we have a Perl interpreter controlled by perlbrew and we can adjust accordingly. See lines 34 to 42. So We define our Perl interpreter to point to this instead of the Perl interpreter located in /usr/bin.

  1. #!/usr/bin/perl
  2. use strict;
  3. use Env qw($PERLBREW_PERL $PERLBREW_ROOT);
  4. # cwd should be $™_DIRECTORY
  5. # filename to check is $ARGV[0]
  6. my $file = $ARGV[0];
  7. my %file_source;
  8. sub read_source {
  9. require File::Spec;
  10. require File::Basename;
  11. my $file = shift;
  12. my $file_source;
  13. { local $/ = undef; open F,<$ENV{™_FILEPATH}; $file_source = <F>; close F }
  14. my @file_source = split /\r?\n/, $file_source;
  15. my $path = $file;
  16. if (!-f $path || !File::Spec->file_name_is_absolute($path)) {
  17. $path = File::Spec->rel2abs($path, $ENV{™_DIRECTORY});
  18. if (!-e $path) {
  19. $path = undef;
  20. my $base = File::Basename::basename($path);
  21. foreach (@INC) {
  22. my $file = File::Spec->catfile($_, $base);
  23. $path = $file, last if -e $file;
  24. }
  25. }
  26. }
  27. $file_source{$file} = { source => \@file_source, path => $path };
  28. }
  29. my $perl;
  30. if ($PERLBREW_PERL) {
  31. $perl =$PERLBREW_ROOT/perls/$PERLBREW_PERL/bin/perl”;
  32. } else {
  33. $perl = ‘perl’;
  34. }
  35. my @lines = `”$perl” -Tcw “$file” 2>&1`;
  36. my $lines = join ‘’, @lines;
  37. if ((scalar(@lines) == 1) && ($lines =~ m/ syntax OK$/s)) {
  38. exit 0;
  39. }
  40. $lines =~ s/&/&/g;
  41. $lines =~ s/</</g;
  42. $lines =~ s/>/>/g;
  43. # link line numbers to source
  44. $lines =~ s%^((?:.+)[ ]+at[ ]+(.+)[ ]+line[ ]+)(\d+)[.,]%
  45. my $pre = $1;
  46. my $file = $2;
  47. my $lnum = $3;
  48. my $col;
  49. if ($pre =~ m/“([^”]+)”/) {
  50. read_source($file)
  51. unless exists $file_source{$file};
  52. my $source_line = $file_source{$file}{source}[$lnum-1];
  53. $file = $file_source{$file}{path};
  54. $col = index($source_line, $1);
  55. $col = $col != -1 ? $col + 1 : 0;
  56. } else {
  57. if ($file !~ m!^/!) {
  58. read_source($file)
  59. unless exists $file_source{$file};
  60. $file = $file_source{$file}{path};
  61. }
  62. }
  63. my $url = qq{txmt://open?url=file://$file&line=$lnum};
  64. $url .=&column=$colif $col;
  65. qq{$pre<a href=$url>$lnum</a>.};
  66. %gmex;
  67. my $output =<pre style=“word-wrap: break-word;>;
  68. $output .= $lines;
  69. $output .=</pre>;
  70. print $output;

To make a point on my opinion on the use of system perl. You can have a look at the perlcheckmate.pl script above. This script is an external application, bundled with Textmate and therefor it relies on the presence of perl in /usr/bin in order to work, so this line is perfectly okay and it should work even though the operating system is updated.

If you read the script carefully you can see that the script uses two external components:

  • File::Spec
  • File::Basename::basename

These are Perl core modules and they should not give any problems. But if you by some weird coincidence and accidentally change or break these as part of development, you are breaking your toolchain at the same time. Your system perl should be considered a key component in your operating system on most modern operating systems.

3 Responses to Textmate and Perlbrew

Avatar

Joel Berger

October 14th, 2012 at 15:47

I know on Linux, its easier to just invoke a script using ‘#!/usr/bin/env perl’. A quick google search shows that env exists on mac too. Might you just want to change the #! line to this in perlcheckmate.pl?

Avatar

Alex

October 17th, 2012 at 01:23

If you use…

#!/usr/bin/env perl

As your shebang line it should pick up whatever perl you currently have set as your currently active perlbrew perl, or the system wide perl if perlbrew is in “off” mode.

Then in your code if you really need access to your perl binary’s path you can use $^X.

alex@karin:~$ perlbrew list
* perl-5.16.1

alex@karin:~$ /usr/bin/env perl -E ‘say $^V; say $^X;’
v5.16.1
/home/alex/perl5/perlbrew/perls/perl-5.16.1/bin/perl

alex@karin:~$ /usr/bin/perl -E ‘say $^V; say $^X;’
v5.14.2
/usr/bin/perl

Avatar

jonasbn

January 12th, 2013 at 13:49

Thanks for the feedback. I am very happy to see the use of env working on OSX. It works like a charm…

Comment Form

About this blog

This blog acts as a channel for communicating logicLAB’s open source activities. Announcements on open source initiatives, involvements and releases of open source distributions of software products, projects and applications.

Photostream

Calendar

October 2012
M T W T F S S
« Apr   Nov »
1234567
891011121314
15161718192021
22232425262728
293031