Development Integration, Custom Web Protocols, and other stuff

Posted on by

*Development Integration*
I’ve been slowly altering my development environments on both my laptop and my main server over the last week so that when I get around to doing the full re-install (which they both need) I can have more of a set game plan on which pieces of software I’ll use, their configurations, etc. mainly because there’s a lot of stray files lingering from apps that I installed and decided they either didn’t fit my style or they just sucked. The point being is that I’ve been using Sublime Text for a long time now and was looking into ways that would integrate it a little more into my flow. On a Mac, you can install a plug in for Sublime (or it might be installed with it by default) where you can open documents directly in Sublime using their custom protocol. Similar to how iTunes will open if you click on a link to an iPhone/iPad app on a webpage.
I did some research to see if it could be done on Windows and let’s just say, my searches didn’t garner promising results. Most of the sites either gave directions of how to activate/use it on a Mac or whatever, with the only reference to Windows is that people claimed it would work or third party apps I have no need for were required. So, I did my usual and got pissed, then decided I would just do it myself, so I’ve managed to get ‘most’ of the same functionality they have on the Mac.

*Custom Web Protocol*
Most people have at least some knowledge of web protocols whether they know it or not. For example, when you type an address into your web browser to visit Google, some users still have a tendency to fully write out http://www.google.com, but even if you don’t, when you click up there, you’ll notice it appended the http:// to it anyway and that’s the part we’re interested in for now. Some other common ones that people have probably heard of would be FTP (ftp://), POP and SMTP for email use, etc.
When I mentioned iTunes above, that’s an example of a custom protocol and is similar to what we’ll be creating for Sublime on Windows (tested on Windows 7 and Windows 8). But some may ask, “What’s the point of all of this?” or “Why would this be useful?” and a great example of this are people that want to implement Custom Error Control into their development so that when something does go wrong, not only do you have some usable information about the problem, but you could just click a link and the source file that contains the error would be opened automatically.


Basic Error in Chrome

Custom Error Control

If you click the second image, you should see near the top middle it says “Open: C:\inetpub\wwwroot\test1\index.php” and that’s the link we’ll be manipulating. Here’s where the platforms are slightly divided, on a Mac, the URI will end up being in the following format: subl://open?url=file://<filename>&line=<number> where ‘<filename>‘ would be the source file with the error and the <number> would take you directly to where the error is located. On the PC side, I haven’t been able to figure out how to utilize the actual line number so I’ve removed it from this, but will make sure to update this post with it if I ever figure it out. Along with the line number, I’ve also removed the starting part of the protocol (open/?url=file://) which leaves you with the following syntax: subl://<filename>. [In both cases, the filename is URLEncoded and has to be decoded for use].

*Now the fun begins*
We have the format of how we’ll set this up, so now we need to create a small Registry file and a single batch file that will handle calling Sublime and passing the required file to it. The actual protocol is subl:// and if you decided to change that, you’ll need to make a few changes to the Registry file (the batch file will stay the same).

Warning:
Modifying the Windows Registry can be hazardous to your computer and cause data corruption, data loss, or just outright kill your system, therefore proceed at your own risk and I will not be held responsible for any damage you may/may not cause. This registry file has been tested and deemed safe on both Windows 7 and Windows 8 but has not been tested on XP or Vista.

Registry File

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\subl]
"URL Protocol"=""
@="URL:SublimeText"

[HKEY_CLASSES_ROOT\subl\DefaultIcon]
@="C:\\Program Files\\Sublime Text 2\\sublime_text.exe"

[HKEY_CLASSES_ROOT\subl\shell]

[HKEY_CLASSES_ROOT\subl\shell\open]

[HKEY_CLASSES_ROOT\subl\shell\open\command]
@="C:\\Windows\\System32\\cmd.exe /K SublimeProtocol.cmd \"%1\""

Notes:

  • If you change the trigger for the protocol (subl) it needs all five references changed.
  • The double \ in the file paths are required.
  • From what I can tell, the icon is not shown anywhere, but still needs to be a valid path.

The command on the last line is going to call a Command/Batch script which we will be doing next, however I wanted to point out, due to security settings on some systems, you may have to make a copy of cmd.exe and call that instead, if that’s the case, just make sure whatever you name the copy is also in your System Path and you change that above as well. The %1 at the end of the command line is what allows us to pass the file through this command, all the \ and ” are just escape characters the Registry needs when writing the “*.reg” file. Copy the above code, and paste it into a new blank document (either in Sublime, or even Notepad) but make sure to save it with the extension “.reg” (for example sublime-protocol.reg) but don’t run it just yet (it wont hurt anything if you do).

Batch File
Taking the name from the registry file, in this case “SublimeProtocol.cmd”, we create a new empty document with that name and copy the below code into it.

@ECHO OFF
TITLE Sublime Protocol Parser
for /F "tokens=1,2,3* delims=/" %%a in ("%~1") do set protocol=%%a&set str=%%b
for /f %%a in ('php -r "echo urldecode('%str%');";') do ( set file=%%a )
START "C:\Program Files\Sublime Text 2\sublime_text.exe" %file%
exit

The protocol sends the entire string (including the protocol itself) to the batch file, so the third line takes that input and strips it down to what we need and the fourth line, with the help of PHP (which I assume you have installed on your development system) takes the URL Encoded Filename and decodes it back into a usable Windows File Path. The entire process would look something like this:
You click a link that looks like this: subl://C%3A%5Cinetpub%5Cwwwroot%5Ctest1%5Cindex.php
The protocol passes that entire string to the batch file, where line three splits it to subl:// and C%3A%5Cinetpub%5Cwwwroot%5Ctest1%5Cindex.php and throws away the first part, now line four takes that and converts it into C:\inetpub\wwwroot\test1\index.php which is now valid to send to Sublime Text (the file replaces %file% dynamically above). Once you have the registry and batch files saved in your Windows Path, double click the registry file in Windows Explorer and it will ask about merging it into the Registry, tell it yes and you should be set.

*Testing*
To test that it works we’ll need to create a simple four line PHP script that creates a subl:// link for us. Open Sublime and create a new file somewhere that is accessible on your server, in my case I’ve been using C:\inetpub\wwwroot\test1\index.php throughout this post. For Microsoft IIS Users, it’d be C:\inetpub\wwwroot\ and for Apache users, the location depends on which package you have installed (Apache, XAMPP, WAMP, etc.) but will normally be inside an htdocs directory.

Sublime Test";
?>

With the above file created, make sure to close the file, than close Sublime. Sadly there’s an issue (at least in Windows 8) where clicking the link will not open the file if Sublime is already running. If I find a fix, I’ll update this post with the information. Open a new tab on your web browser and navigate to where you saved that file (ex. http://localhost/test1/index.php) and you should be presented with a page that looks similar to this:

Clicking that link will spawn a Command Prompt Window with the title “Sublime Protocol Parser” for a brief second, close, and than Sublime should open with the correct file loaded. If it doesn’t, most likely you’re experiencing the security issue I mentioned above. (See the bottom for a more detailed way to correct it.)

*Practical Use*
With my current development environment, I use a modified version of Whoops to handle most of my Error Control and a snippet in Sublime that not only throws the required code into my file as needed, but automatically activates it so I can verify it’s working, at which point I delete a single line than get to coding. The screenshot on the right in the above table gives you a rough idea of how it looks.

Whoops has built-in functionality to allow default code editors and Sublime is already one of them, but if we just set it up to use that, it will give us the links in the wrong format, so this snippet will adjust for that as well. Start by opening Sublime Text and going up to “Tools” => “New Snippet…” and you should be presented with the following code:


  
  
  
  
  

We need to modify the highlighted lines by replacing the code on line 3 with our code and uncommenting lines 6 and 8 to set up the tag trigger and set the scope to PHP:


  
  
  whoops
  
  source.php

Make sure that you leave the <![CDATA[ and ]]> in-tact and you can rename the tab trigger to anything you want, I used ‘whoops’ for the example. Now comes the code to make this snippet worth anything. However, you have to make a small decision (or write two snippets):

  • Are you creating this solely for personal sites or sites that you will run on your system(s) in which you can verify Whoops will be available at all times?
  • Are you creating a site that is meant to be distributed, like an Open Source Web App where you can’t be sure of the environment this will be run on?

If you answered yes to the first question, your snippet can be a lot smaller since you would already know what’s available and what isn’t, however if you answered yes for the second question, you can go about this in two ways:

  • Do the same as you would have answering Yes to question one and remembering to delete or comment out all references before distribution.
  • Write a little extra code so that it only runs on your system and not the end users, leaving it all intact for when you do updates.

The Quickie Version: (From Question 1)

<snippet>
  <content><![CDATA[
  require \$_SERVER['DOCUMENT_ROOT']."/whoops/vendor/autoload.php";
  \$whoops = new Whoops\Run();
  \$errorPg  = new Whoops\Handler\PrettyPageHandler();
  \$errorPg->setEditor(function(\$file) { return "subl://%file"; } );
  \$whoops->pushHandler(\$errorPg);
  \$whoops->pushHandler(\$handler);
  \$whoops->register();

  // Test to verify it works with project, comment out or erase when done
  throw new RuntimeException("Whoops works, you can delete this line now...");

$0
]]></content>
  <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
  <tabTrigger>whoops</tabTrigger>
  <!-- Optional: Set a scope to limit where the snippet will trigger -->
  <scope>source.php</scope>
</snippet>

Extended Version: (From Question 2)

<snippet>
  <content><![CDATA[
  if(\$_SERVER['COMPUTERNAME'] == "YOURSYSTEMNAME") {
    require \$_SERVER['DOCUMENT_ROOT']."/whoops/vendor/autoload.php";
    \$whoops = new Whoops\Run();
    \$errorPg = new Whoops\Handler\PrettyPageHandler();
    \$handler = new Whoops\Handler\JsonResponseHandler();
    \$handler->onlyForAjaxRequests(true);
    \$errorPg->setEditor(function(\$file) { return "subl://%file"; } );
    \$whoops->pushHandler(\$errorPg);
    \$whoops->pushHandler(\$handler);
    \$whoops->register();
  }
  // Test to verify it works with project, comment out or erase when done
  throw new RuntimeException("Whoops works, you can delete this line now...");

$0
]]></content>
  <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
  <tabTrigger>whoops</tabTrigger>
  <!-- Optional: Set a scope to limit where the snippet will trigger -->
  <scope>source.php</scope>
</snippet>

In both cases, you have to verify the ‘require’ path is correct and in the second example change “YOURSYSTEMNAME” to the proper name (you can echo it in the test file if unsure what to use).


*Troubleshooting*
Scenario 1: No Command Prompt flash
If you don’t see the command prompt window pop up for a second than most likely the issue is with the registry not being able to forward the info to the batch file. You can open the registry by running “regedit” from the command prompt or run dialog and drill down in the left menu to HKEY_CLASSES_ROOT\subl\ and you should see two folders inside subl (DefaultIcon and shell) and the file paths from the *.reg file will be converted to single “\”. If this is not the case, you can either edit these directly or delete the ‘subl’ key and edit your *.reg file and re-import it.

Scenario 2: Command Prompt opens but doesn’t work
Open your batch file and add “pause” on line above the first for statement. Close Sublime and try your test again, this time, hopefully you should see the command prompt open with the correct title.
One of two things most likely happened, the title showed which suggests you have a typo somewhere else so double check the code you used (again) in each phase… or the title didn’t match which implies there is probably a security issue similar to the one I experienced on one of my systems.
If this is the case, you’ll have to do a little modification to your *.reg file and a single command from the prompt.
Open a command prompt and type:

cd C:\Windows\System32
copy cmd.exe customCMD.exe

Re-open your *.reg and change the last line to @="C:\\Windows\\System32\\customCMD.exe /K SublimeProtocol.cmd \"%1\"" and re-importing that should resolve the problem.

If you need any more explanation or something still doesn’t work you can feel free to comment below, but please note, comments are moderated and wont automatically appear.

Comments are disabled