Friday, September 5, 2008

Overcoming Displaying Code as HTML

On my previous post, I spent about an hour just getting the formatting to look right. I ended up pasting it into word, and fooling around with the formatting till I got it just right, and saving it, then e-mailing it to myself in Gmail so I could view it directly from there, and it looked sort of ok, except that it had some extra lines in it, so I had to work directly with the HTML to get it to look the way I wanted.

Because computer programmers like myself are lazy, and if we have to do something twice, that's once to much, I wrote a program to do this for me. Right now it consists of Two RichTextBoxes and a WebBrowser thrown onto a windows from. Paste RTF code (like the code from VS) into rtfTextBox, and press the convert button and presto, you're done. The Html is outputed in another RichTextBox, and copied to the Clipboard, while the Webrowser gives you a preview. No CSS are needed.

In the near future I'd love to turn this into a VS add in so I can just select some code, right click, and select Convert.

You'll fine the source code posted below, which was generated using itself of course. :)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace RTF2HTMLConverter {
public partial class Form1 : Form {
const string BackwardsSlash = "&bws;";
const string OpenCurlyBracket = "&ocb;";
const string CloseCurlyBracker = "&ccb;";
const string DoubleQuote = """;
const string GreaterThan = ">";
const string LessThan = "<";
const string Ampersand = "&amp";
bool _inColorSpan;

public Form1() {
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e) {
string[] rtf = rtfTextBox.Rtf.Replace("&", Ampersand).Replace("\\\\", BackwardsSlash).Replace("\\}", CloseCurlyBracker).Replace("\\{", OpenCurlyBracket).Replace("\"", DoubleQuote).Replace(">", GreaterThan).Replace("<", LessThan).Split('\n');
string rtfLine;
_inColorSpan = false;
Dictionary<string, string> colors = new Dictionary<string, string>();
StringBuilder output = new StringBuilder();
output.Append("<pre class=\"code\"><span style=\"font-size:85%;\">");

for (int i = 1; i < rtf.Length; i++) {
rtfLine = rtf[i];
if(i == 1){
GetColors(rtfLine, colors);
}
else
output.Append(GetOutputLine(rtfLine, colors));
}
}
output.Append("</span></pre>\n");
htmlTextBox.Text = output.ToString().Replace(BackwardsSlash, "\\").Replace(CloseCurlyBracker, "}").Replace(OpenCurlyBracket,"{");
webBrowser1.DocumentText = htmlTextBox.Text;
Clipboard.SetText(htmlTextBox.Text);
}

private string GetOutputLine(string rtfLine, Dictionary<string, string> colors) {
string outputLine = string.Empty;
string[] rtfLineSegments = rtfLine.Split('\\');
string firstWord;
string currentColor = string.Empty;
foreach (string segment in rtfLineSegments) {
if(segment == string.Empty){
continue;
}
firstWord = GetFirstWord(segment);

if (firstWord.IndexOf(' ') == 0) {//Trailing Spaces, just add it
outputLine += segment;
}
else if (colors.Keys.Contains(firstWord.Trim())) {//Change the Color
if (segment == firstWord) { // No Other Text, just change the color
currentColor = firstWord;
outputLine += GetColorSpan(colors[segment]);
}
else if(segment.Substring(firstWord.Length).Trim() != string.Empty) { // Change color and Add the rest of the segment if there is something to update
if (currentColor != string.Empty && currentColor == firstWord.Trim()) { // Color hasn't changed, skip adding new color span
outputLine += segment.Substring(firstWord.Length);
}
else {
currentColor = firstWord.Trim();
outputLine += GetColorSpan(colors[currentColor]) + segment.Substring(firstWord.Length);
}
}
else//all Blank Spaces, don't worry about the color
outputLine += segment.Substring(firstWord.Length);
}
}
else if (!segment.Contains(' ') && rtfLineSegments.Length > 2) { // Control word, skip it
continue;
}
else if (!segment.Contains(' ') && rtfLineSegments[0] == segment && rtfLineSegments.Length == 2) {// There is no Color for this segment, so use everything
outputLine += segment;
}
else
//First word is control word, skip it and add the rest
outputLine += segment.Substring(firstWord.Length);
}
}
return outputLine += "\n";
}

private static string GetFirstWord(string segment) {
string firstWord;
if (!segment.Contains(' ')) {
firstWord = segment;
}
else {
firstWord = segment.Substring(0, segment.IndexOf(' ') + 1);
}
return firstWord;
}

private static void GetColors(string rtfLine, Dictionary<string, string> colors) {
string[] colorValues = rtfLine.Substring(1, rtfLine.Length - 2).Split(';');
string rtfColor;
string htmlColor;
for (int k = 1; k < colorValues.Length; k++) {
rtfColor = colorValues[k];
if (rtfColor == "}") {
continue;
}
if (rtfColor.Contains("\\red")) {
string[] hexColors = rtfColor.Split('\\');
htmlColor = "#" + GetHexValue(hexColors[1], "red") + GetHexValue(hexColors[2], "green") + GetHexValue(hexColors[3], "blue");
htmlColor = ConvertColor(htmlColor);

htmlColor = "color: " + htmlColor;
}
else {
throw new Exception("Unrecognized Color " + rtfColor);
}

colors.Add("cf" + k.ToString(), htmlColor);
}
}

private static string ConvertColor(string htmlColor) {// Convert the Colors from a Dark Scheme, to a White Scheme
switch (htmlColor) {
case "#ff8000":
htmlColor = "blue"; // Reserved Words
break;
case "#fefffe":
htmlColor = "#010001"; // Regular Text
break;
case "#808080":
htmlColor = "green"; // Comments
break;
case "#ffffff":
htmlColor = "black"; //;
break;
case "#ffff00":
htmlColor = "#2b91af"; //class Names
break;
case "#2892b0":
htmlColor = "red"; // Integers
break;
case "#00ff00":
htmlColor = "#a31515"; // Strings
break;

}
return htmlColor;
}

private static string GetHexValue(string hexColor, string colorName){
return System.Convert.ToString(int.Parse(hexColor.Substring(colorName.Length, hexColor.Length - colorName.Length)), 16).PadLeft(2, '0');
}

private string GetColorSpan(string color){
if (_inColorSpan) {
return string.Format("</span><span style=\"{0}\">", color);
}
else {
_inColorSpan = true;
return string.Format("<span style=\"{0}\">", color);
}
}
}
}

No comments: