...Well, until my previous post, anyway.
A then-coworker told me a while back about vim's :TOhtml feature, but it wasn't until last night that I actually checked it out. As it turns out, it was just what I was looking for. Out of the box, it's a little cumbersome for my purposes, but a little vim scripting helped a lot.
Default Behavior
To start, I set a few options in my .vimrc:
let html_use_css = 1 " Use stylesheet instead of inline style
let html_number_lines = 0 " don't show line numbers
let html_no_pre = 1 " don't wrap lines in <pre>
let html_number_lines = 0 " don't show line numbers
let html_no_pre = 1 " don't wrap lines in <pre>
I also choose a vim color scheme I like (wombat). You can look through examples of tons of schemes here. (I spent a while trying to figure out why I couldn't set the color scheme (after I downloaded it to .vim/colors/), and the answer I found was that color schemes only work in gVim.)
So, having set some options in my .vimrc, and chosen a colorscheme in gVim, calling :TOhtml on
class Person
attr_accessor :age
def speak
"Hi!"
end
def say_age
"I am this many: #{'|' * @age}"
end
end
attr_accessor :age
def speak
"Hi!"
end
def say_age
"I am this many: #{'|' * @age}"
end
end
gives:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>~/demo.rb.html</title>
<meta name="Generator" content="Vim/7.2">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
<!--
.Identifier { color: #cae682; }
.Type { color: #cae682; }
.Statement { color: #8ac6f2; }
.Constant { color: #e5786d; }
.Function { color: #cae682; }
.Special { color: #e7f6da; }
.String { color: #95e454; font-style: italic; }
body { color: #f6f3e8; background-color: #242424; font-family: monospace; }
.PreProc { color: #e5786d; }
-->
</style>
</head>
<body>
<span class="PreProc">class</span> <span class="Type">Person</span><br>
<span class="Statement">attr_accessor</span> <span class="Constant">:age</span><br>
<br>
<span class="PreProc">def</span> <span class="Function">speak</span><br>
<span class="Special">"</span><span class="String">Hi!</span><span class="Special">"</span><br>
<span class="PreProc">end</span><br>
<br>
<span class="PreProc">def</span> <span class="Function">say_age</span><br>
<span class="Special">"</span><span class="String">I am this many: </span><span class="Special">#{</span><span class="Special">'</span><span class="String">|</span><span class="Special">'</span> * <span class="Identifier">@age</span><span class="Special">}</span><span class="Special">"</span><br>
<span class="PreProc">end</span><br>
<span class="PreProc">end</span><br>
</body>
</html>
<html>
<head>
<title>~/demo.rb.html</title>
<meta name="Generator" content="Vim/7.2">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
<!--
.Identifier { color: #cae682; }
.Type { color: #cae682; }
.Statement { color: #8ac6f2; }
.Constant { color: #e5786d; }
.Function { color: #cae682; }
.Special { color: #e7f6da; }
.String { color: #95e454; font-style: italic; }
body { color: #f6f3e8; background-color: #242424; font-family: monospace; }
.PreProc { color: #e5786d; }
-->
</style>
</head>
<body>
<span class="PreProc">class</span> <span class="Type">Person</span><br>
<span class="Statement">attr_accessor</span> <span class="Constant">:age</span><br>
<br>
<span class="PreProc">def</span> <span class="Function">speak</span><br>
<span class="Special">"</span><span class="String">Hi!</span><span class="Special">"</span><br>
<span class="PreProc">end</span><br>
<br>
<span class="PreProc">def</span> <span class="Function">say_age</span><br>
<span class="Special">"</span><span class="String">I am this many: </span><span class="Special">#{</span><span class="Special">'</span><span class="String">|</span><span class="Special">'</span> * <span class="Identifier">@age</span><span class="Special">}</span><span class="Special">"</span><br>
<span class="PreProc">end</span><br>
<span class="PreProc">end</span><br>
</body>
</html>
That's pretty good. If your goal was a stand-alone HTML file you'd be done, but for paste-ready output we need a little vim scripting help.
Altered Behavior
Instead of wrapping the output in a full html page, I really just want it wrapped in a div. I also want to strip out some "extra" (according to Blogger's HTML interpreter) line breaks, and pull out the CSS definitions (for later). To accomplish this, I've put together a simple vim script, which defines a new method :DivHtml
function! DivHtml(line1, line2)
exec a:line1.','.a:line2.'TOhtml'
%g/<style/normal $dgg
%s/<\/style>\n<\/head>\n//
%s/.vim_block {/.vim_block {/
%s/<body\(.*\)>\n/<div class="vim_block"\1>/
%s/<\/body>\n<\/html>/<\/div>
%s/<br>//g
set nonu
endfunction
command -range=% DivHtml :call DivHtml(<line1>,<line2>)
exec a:line1.','.a:line2.'TOhtml'
%g/<style/normal $dgg
%s/<\/style>\n<\/head>\n//
%s/.vim_block {/.vim_block {/
%s/<body\(.*\)>\n/<div class="vim_block"\1>/
%s/<\/body>\n<\/html>/<\/div>
%s/<br>//g
set nonu
endfunction
command -range=% DivHtml :call DivHtml(<line1>,<line2>)
Now, calling :DivHtml on the ruby code above gives code I can just cut & paste into the 'Edit Html' Blogger window:
<!--
.Identifier { color: #cae682; }
.Type { color: #cae682; }
.Statement { color: #8ac6f2; }
.Constant { color: #e5786d; }
.Function { color: #cae682; }
.Special { color: #e7f6da; }
.String { color: #95e454; font-style: italic; }
.vim_block { color: #f6f3e8; background-color: #242424; font-family: monospace; }
.PreProc { color: #e5786d; }
-->
<div class="vim_block"><span class="PreProc">class</span> <span class="Type">Person</span>
<span class="Statement">attr_accessor</span> <span class="Constant">:age</span>
<span class="PreProc">def</span> <span class="Function">speak</span>
<span class="Special">"</span><span class="String">Hi!</span><span class="Special">"</span>
<span class="PreProc">end</span>
<span class="PreProc">def</span> <span class="Function">say_age</span>
<span class="Special">"</span><span class="String">I am this many: </span><span class="Special">#{</span><span class="Special">'</span><span class="String">|</span><span class="Special">'</span> * <span class="Identifier">@age</span><span class="Special">}</span><span class="Special">"</span>
<span class="PreProc">end</span>
<span class="PreProc">end</span>
</div>
.Identifier { color: #cae682; }
.Type { color: #cae682; }
.Statement { color: #8ac6f2; }
.Constant { color: #e5786d; }
.Function { color: #cae682; }
.Special { color: #e7f6da; }
.String { color: #95e454; font-style: italic; }
.vim_block { color: #f6f3e8; background-color: #242424; font-family: monospace; }
.PreProc { color: #e5786d; }
-->
<div class="vim_block"><span class="PreProc">class</span> <span class="Type">Person</span>
<span class="Statement">attr_accessor</span> <span class="Constant">:age</span>
<span class="PreProc">def</span> <span class="Function">speak</span>
<span class="Special">"</span><span class="String">Hi!</span><span class="Special">"</span>
<span class="PreProc">end</span>
<span class="PreProc">def</span> <span class="Function">say_age</span>
<span class="Special">"</span><span class="String">I am this many: </span><span class="Special">#{</span><span class="Special">'</span><span class="String">|</span><span class="Special">'</span> * <span class="Identifier">@age</span><span class="Special">}</span><span class="Special">"</span>
<span class="PreProc">end</span>
<span class="PreProc">end</span>
</div>
(which renders as the ruby snippet I pasted above)
The only part of the process that is still kinda annoying is that you have to copy/paste the CSS into your header or external CSS file. Both :TOhtml and :DivHtml only output the CSS definitions for styles actually used in a snippet, so it's up to the user to check if all the definitions in a new snippet are already in your layout, or if you need to add them. The alternative would be to use inline CSS (:help :TOhtml), but that's ugly.
To finish things off, I gave the wrapping div the vim_block class, and gave that a background-color and border in my header, to make it look a little nicer. I also got rid of the "font-family: monospace" bit, because I thought it made the code hard to read.
Other than manually checking the CSS, it's a very painless process to put code snippets on the blog, and I'm happy with the look and feel of them.

4 comments:
Very nice. One (minor) downside of using CSS vs. inline styles is that the coloration doesn't make it through to feed readers. But I'm used to viewing the original when code is present, so that isn't such a big deal.
Also, you seem to have lost the indentation (non-breaking spaces) in your ruby example. perhaps retaining the pre would solve that?
nevans -- Thanks for the heads up about the indentation. I had written this post as I developed my vimrc, and the snippet in question actually had been generated with html_no_pre unset. For some reason, not setting that option means you won't get nbsp's for spaces (and the css doesn't manage indentation, either). I regenerated that snippet with the version of my vimrc represented in the post, and now it looks better :)
As for the the lack of CSS in readers, I hear ya. I'm ok with it, though. I'm like you -- if a post in Google Reader looks funky, I just click on the link.
nevans -- Oh, after regenerating the snippets, RSS readers now correctly show the indentation (because I'm now using nbsp's). It doesn't have colors, but I think it's much more readable now (with indentation) that it was before.
Post a Comment