2011-03-25

Open online PHP reference from vim in a new split vim window

Following the last post I went a bit further. I haven't decided which solution out of that and the following I like best yet.

This time I wanted the documentation to open in a new window within vim. That means grabbing the documentation HTML, cutting out what I don't want to see, rendering to plain text and putting the result in a new window.

Since the documentation is given as XHTML, as long as it's valid the safest way to chop out the bits I don't want is by parsing it as XML. So since PHP is my quick hacking language of choice I cooked up the following script and saved it as ~/bin/phpman-text.

#!/usr/bin/env php
<?php

if (!isset($_SERVER["argv"][1])) {
 fwrite(STDERR, "No keyword given\n");
 exit(1);
}

$xmlstring = @file_get_contents("http://php.net/" . urlencode($_SERVER["argv"][1]));
if ($xmlstring === false) {
 fwrite(STDERR, "Failed to fetch doc page\n");
 exit(2);
}

// remove default namespace
$xmlstring = preg_replace('%\bxmlns="[^"]*"%', "", $xmlstring);

$xml = @simplexml_load_string($xmlstring);
if ($xml === false) {
 fwrite(STDERR, "Failed to parse doc page\n");
 exit(3);
}

// get content div
$content = array_pop($xml->xpath("//div[@id='content']"));

if (is_null($content)) {
 fwrite(STDERR, "Couldn't find div with ID 'content'\n");
 exit(4);
}

// remove nav bars
foreach ($content->xpath("./div") as $nav)
 if (in_array("manualnavbar", explode(" ", $nav["class"])))
  simplexml_remove_node($nav);

// get new XML
$newxml = $content->asXML();

// run lynx
$lynx = proc_open("lynx -dump -stdin", array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w")), $pipes);
if (!is_resource($lynx)) {
 fwrite(STDERR, "Couldn't run lynx\n");
 exit(5);
}

// poke new XML to lynx's stdin
fwrite($pipes[0], $newxml);
fclose($pipes[0]);

// get lynx's stdout
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
$erroroutput = stream_get_contents($pipes[2]);
fclose($pipes[2]);

// close lynx
$returnval = proc_close($lynx);

// check return value
if ($returnval != 0) {
 fwrite(STDERR, "lynx exited with code $returnval -- error output follows.\n$erroroutput");
 exit(6);
}

exit(0);

function simplexml_remove_node($node) {
 $domnode = dom_import_simplexml($node);
 $domnode->parentNode->removeChild($domnode);
}

?>

Then, with help from the vim wiki, I came up with this, to be added to my .vimrc:

function! OpenPhpFunction (keyword)
 exe "12new"
 exe "silent read !phpman-text ".substitute(a:keyword, "_", "-", "g")
 exe "set buftype=nofile bufhidden=delete filetype=php readonly"
 exe "1"
endfunction
autocmd FileType php map <buffer> K :call OpenPhpFunction('<C-r><C-w>')<CR>

This mostly works. It loads the PHP documentation into a temporary new buffer and sets the filetype to PHP so that bits of text in <?php ?> tags are highlighted as PHP code. There are a few bad things -- some of the blocks of PHP code in the manual don't have the end tag and so highlighting continues beyond the end of the code, some of the manual pages (probably due to dodgy comments) aren't valid XML and so won't go through the script, and lynx's output isn't completely ideal.

1 comment:

  1. Are you looking to make money from your traffic by using popunder ads?
    In case you are, did you take a look at Clickadu?

    ReplyDelete