What with one thing or another, I spend some appreciable amount of my time in Visual Studio. So, like you, I've customized the font and color scheme so that it looks good to me and I can quickly grok code within it. Not as drastically as some, I must say — and given my predilection for grays and muted colors, I'm surprised I haven't gone for this one.
But it's been a bugbear ever since I started this blog on Graffiti CMS using Windows Live Writer as the writing and posting engine, that I haven't like the way the code looks inside the individual posts. I've played around with a couple of plugins, finally ending up with Luis Vildosola's Code Snippet plugin, but I still felt there was something missing.
Finally I resurrected some code I'd written nearly a year ago for my old website to display syntax highlighted code just as it looks in Visual Studio. Visual Studio copies both RTF and normal text to the clipboard with Ctrl+C and the RTF it generated contains color information, for both the font and the background. All you have to do — all! — is write a parser (the RTF generated by Visual Studio is very simple) that converts the text on the clipboard from RTF to HTML. Which is what I did back in March last year.
Now, of course, I'm using Windows Live Writer, so I spent a quick quarter of an hour writing a plugin that called that parser code from within a CreateContent
method. Here's the plugin code:
using System; using System.Windows.Forms; using WindowsLive.Writer.Api; using RtfToHtml; namespace WLWInsertCode { [WriterPlugin("F85C3533-BC93-49e8-8273-4FA33D21EDCC", "PasteCodeFromVS")] [InsertableContentSource("Paste Code From VS")] public class VSCodePaster : ContentSource { public VSCodePaster() : base() { } public override DialogResult CreateContent(IWin32Window dialogOwner, ref string content) { DialogResult result = DialogResult.OK; if (Clipboard.ContainsText(TextDataFormat.Rtf)) { string s = Clipboard.GetText(TextDataFormat.Rtf); string html = RtfParser.ParseRtf(s); content = "<div class=\"jmbcodeblock\"><pre>" + Environment.NewLine + html + "</pre></div>" + Environment.NewLine; } else { content = "Clipboard is empty of RTF text"; } return result; } } }
Simple enough, but of course the real work is done in the RtfParser
class.
Notice that, first of all, any text selected when the method is called is ignored. Also the method always returns with DialogResuilt.OK
, meaning that whatever string is returned from the call will be pasted in the current document. For example, in this method, should I have forgotten to copy some code from Visual Studio, an error message will be inserted in the document. The parser also return its errors in the same manner (the parser doesn't throw exceptions). That's good enough for me: usually it'll be a slap-on-the-forehead moment anyway as I realize that I haven't copied the code to the clipboard.
The parser is a simple enough recursive descent parser, with a lot of assumptions about the RTF it'll parse. It won't work on RTF created by Microsoft Word for example, although it should degrade fairly gracefully (it ignores blocks it doesn't understand). On day I'll write up a series of posts about how it works.
Now playing:
Sting - Moon over Bourbon Street
(from The Dream of the Blue Turtles)
2 Responses
#1 Pasting code from Visual Studio into Windows Live Writer said...
27-Nov-09 7:53 PMWay back in January this year, I briefly explained how I was pasting code into my blog posts so that they were displayed fully syntax-highlighted. At the time I said I'd explain how the underlying parser works, but never got round to it. Well, it's the
#2 Pasting code from VS into WLW, part 2 said...
28-Nov-09 3:07 PMLast time in this two-parter, I laid down the basics of the RTF I followed in pasting code from VS to WLW, and some of the helper classes I started off with. This time, we'll look at the parser and the various tricks I used to make sure that the translated
Leave a response
Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.
_emphasis_
**strong**
[text](url)
`IEnumerable`
* an item
1. an item
> Now is the time...
Preview of response