Showing posts with label vim. Show all posts
Showing posts with label vim. Show all posts

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.

2011-03-09

Open online PHP reference from vim

Pressing K when over a keyword in vim usually opens the keyword's manpage. In Python it invokes pydoc instead. I wanted it to open PHP's online documentation when I press it over a function name in PHP. Easy.

I wrote a tiny shell script in my ~/bin directory first, phpman:

#!/bin/sh
sensible-browser http://php.net/"$*"

I then added to my .vimrc the line

autocmd FileType php set keywordprg=phpman

Done. And using sensible-browser has the added bonus that it'll run whatever my preferred graphical browser is when I am in X or a textmode browser when I'm not.

2010-10-10

Merging files with unison and vimdiff -- update

I've just updated my post from February about merging files with unison and vimdiff -- I figured out how to do so without launching a new terminal emulator. The solution uses screen. See the updated post.

2010-06-23

Make a single-line XML stream pretty in vim

Usually I view XML in Firefox as that's the quickest way to get a nice tree I can explore. But when I might want to edit it until today I've been loading it into vim and then if necessary adding newlines manually or using a fairly dumb regex to do it for me. Today I made a slightly more sophisticated one.

:%s/>\s*</>\r</g adds the newlines in decent places and then gg=G indents it all.

2010-02-04

Merging a unison conflict with vim

I use unison to synchronize various files. If I've edited the same file on both ends I can pick a version to keep or, until now, I aborted, manually merged them with vimdiff or some other tool and then started synchronizing again.

But unison is able to call an external tool to merge for you. I figured out how to get it to use vimdiff -- add the option -merge "Name * -> urxvt -e vimdiff CURRENT1 CURRENT2".

I've used urxvt rather than my usual urxvtcd because urxvtcd immediately forks and unison continues as soon as the process it runs exits. So why did I run a terminal emulator at all rather than just running vimdiff in the existing terminal? It won't display. Not sure why -- probably to do with it not realizing it has a virtual terminal to output on or something.

Update on 2010-10-10: I had another shot at figuring it out. I tried using screen -- "Must be connected to a terminal". Then I tried using ssh -t and screen -- same issue (but I think the error was from SSH this time rather than screen). Finally I found an option in screen's manual page which can start a screen session detached but yet not fork. That'll do. So now in default.prf (which my other unison config files include) I have these two lines:

merge = Name * -> screen -DmS unisonmerge vimdiff CURRENT1 CURRENT2
merge = Name .* -> screen -DmS unisonmerge vimdiff CURRENT1 CURRENT2

The second line is there because I found just now that dotfiles weren't included when only the first line was present.

So here's what happens when a merge is now requested. A new screen session is started with the session name "unisonmerge". That's started detached but the process doesn't fork as it usually would and so unison stops, waiting. We get the shell to stop the process and give us a prompt by pressing ^Z, then attach the new screen session with screen -RS unisonmerge. The vimdiff instance is running in that -- we merge the files (modifying only the one we want to keep, which will end up on both machines) and then exit. The screen session ends and we're back to the prompt. Then we bring unison back to the foreground with fg. Unison continues.

So now I can run unison on a headless server over SSH, merging when necessary.

2009-12-16

Vim can read zip files

I accidentally opened a zip file with vim just now. It gives a directory listing just like when opening a directory. Fantastic.

2009-11-25

Ranges in vim

I hadn't used ranges in vim (other than % -- the whole file) until now. Thought it was about time I found out how to use them.

. is the current line, $ is the last line. Numbers mean that line so 1 is the first line in the file. That's the most important stuff -- the full list is at :he range.

They can be followed with + or - which adds or takes one from the line number, or the plus or minus can be followed with a number to add or subtract that many.

Ranges can be just one line or from,to. So the range I need to use right now, current line until the end of the file, is .,$ and so to do my replacement I type :.,$s/"#ffbaba"/errorcolour/g.

2009-09-01

Clipboard from the command line -- xclip versus xsel

Until last week I'd been using xclip to set and retrieve the X selection and X clipboard. But the syntax is a bit nasty -- to output the clipboard it's xclip -selection clipboard -o. (I have since found out, thanks to the comments on this post, that it's not quite so bad, the options can be abbreviated as long as it's non-ambiguous.) I came across xsel and decided to give it a go. They both do roughly the same thing, but which is better?

Put simply, xsel is a little more advanced and has a nicer syntax.

They can both be installed easily in Ubuntu with sudo aptitude install xclip and sudo aptitude install xsel.

First of all, it's important to realize there are three selections X keeps track of: the primary X selection, the secondary X selection (but I've never actually seen this used) and the X clipboard.

The (primary) X selection is what is set when some text is selected and is usually retrieved when the middle mouse button is clicked.

The X clipboard is what most programs set when the copy command is used, and what they retrieve from the owner when the paste command is used.

I used the word "owner" there – in the X environment the program in which text is copied/selected takes "ownership" of the X clipboard or X selection. When another program asks for the contents of the clipboard or selection, X tells it which program is the owner and then the querying program asks the owning program for the contents directly. This means when the owning program exits the contents of the clipboard and selection are lost, unless something else takes over selection ownership. There exist system-tray type programs for this purpose.

Both xsel and xclip use the primary X selection by default. To set it:
some command | xsel
or
some command | xclip

The same so far. To retrieve it:
xsel
or
xclip -o
No output flag is required for xsel since it detects what stdin and stdout are and picks input or output mode automatically. See its manpage.

To set the X clipboard, xsel's command is much shorter:
some command | xsel -b
as compared to xclip's equivalent
some command | xclip -selection clipboard

And to retrieve the X clipboard
xsel -b
versus
xclip -selection clipboard -o

I often want to put the contents of a file into the selection. I do that with xsel <file.

Other features

I've never found any of xclip's other features useful – it can be set to hold the selection until it has been retrieved n times and then delete it, for instance. On the other hand, some of xsel's options look very useful. Some examples: some command | xsel -a appends text to the selection, xsel -d deletes the selection and xsel -k keeps (takes over) the selection so that it won't be lost when the program which set it exits.

Getting at the selection and clipboard from vim

In vim you can read and write to both of these by using the "+ (X clipboard) and "* (X selection) registers. For example, to copy the current line to the X clipboard type "+yy or to paste from the X selection type "*p.