Monday, August 31, 2015

A Side, Side Project


While writing a post on a side-project I noticed that my code snippets were not always well presented. The challenge is to keep the code clear and easy for the interested reader to copy. A glance back over some posts shows a couple of approaches. Sometimes the code is just copied and pasted from my IDE and therefore looks nicely formatted with colour coding and sometimes I have gone the way of wrapping the code as HTML inside <pre> tags – which works best when the code lines (or indentation) would otherwise result in line wraps that obscure the meaning.

I did come across a useful tool here http://codeformatter.blogspot.co.uk/ which is great but the colour coding is lost and I thought about a Sunday afternoon mini-project (sad, but the Rugby World Cup has not started yet and it is raining) to take code directly from Visual studio or Android Studio or what have you and present it within <pre> tags with colours intact. I expect there are loads of tools out there that do this but…

First thing I did was look at some long ago VB.NET code I wrote to create a sub-classed RichTextBox control that could output HTML. This could certainly do the business but it did it laboriously and I did not fancy the long task of converting that code to C#.

A search led me here https://code.msdn.microsoft.com/windowsdesktop/Converting-between-RTF-and-aaa02a6e#content to a WPF project written by Matthew Manela that does the trick with some succinct code – relying somewhat on the capabilities of the WPF version of the RichTextBox. So I added references for PresentationCore and PresentationFramework to my Windows Forms project and snaffled two of the classes – namely HtmlFromXamlConverter and RtfToHtmlConverter which did the job.

The project is a simple form with a RichTextBox to copy the code into, a button to trigger the translation and a regular multi-line TextBox to receive the output. I added some pre-processing code to remove any indentation common to all of the lines in a code snippet and just wrapped the HTML output in <pre> and <code> tags with a bit of styling boldly stolen and then modified from the code formatter at blogspot.

Which got the code I had to write down to:
private const string preTag = "<pre style=\"border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif);padding:0px;margin:0px;text-align:left;font-size:110%;line-height:1;color:#000000;\"><code style = \"word-wrap:normal;\" >";
private const string preTail = "</code></pre>";
........ and then .......


private void preProcessRtf() {     if(rtbInput.Lines.Count() > 0)     {         int blCount = 0;         rtbInput.Rtf = rtbInput.Rtf.Replace(new string('\t', 1), "    "); // first convert any tabs to spaces         string firstLine = rtbInput.Lines[0];         // count the number of spaces at the start of the first line         while (firstLine.Substring(blCount, 1) == " ")         {             blCount++;         }         if(blCount > 0)         {             string tstString = "\n" + new string(' ', blCount);             rtbInput.Rtf = rtbInput.Rtf.Replace(tstString, "\n");             rtbInput.SelectionStart = 0;             rtbInput.SelectionLength = blCount;             rtbInput.Cut(); // to remove the first line leading spaces         }         tbOutput.Text = preTag + tidyHtml(RtfToHtmlConverter.ConvertRtfToHtml(rtbInput.Rtf)) + preTail;     } }

And that would have been that except for the fact that the Google Blogger web site changes your HTML during the publish process – and of course adds some styles.

So it made sense to post-process the result to tidy up the HTML.
private string tidyHtml(string rawHtml) {     StringBuilder sb = new StringBuilder(rawHtml);     int sPos = sb.IndexOf("<p");     int ePos;     while (sPos > -1)     {         ePos = sb.IndexOf(">", sPos);         if(ePos > sPos)         {             sb.Remove(sPos, ++ePos - sPos);         }         sPos = sb.IndexOf("<p", sPos);     }     sb.Replace("</p>", "\r");     sb.Replace("background-color:#ffffff", "");     sPos = sb.IndexOf("<span style=\"\">");     while (sPos > -1)     {         sb.Remove(sPos, 15);         sPos = sb.IndexOf("</span>", sPos);         if (sPos > -1)         {             sb.Remove(sPos, 7);             sPos = sb.IndexOf("<span style=\"\">", sPos);         }     }     sb.Replace("    ", "&nbsp;&nbsp;&nbsp;&nbsp;");     return sb.ToString(); }

Afterwards I added some event one liners to make copying and pasting a tad more intuitive. Yes, there are probably a dozen edge cases where this will product imperfect results but this is not code to run a business on – just a utility written in thirty odd lines of C#. In any case, it is time for a pre-dinner G&T.

Let us hope it improves my presentation in future.

If anyone wants a copy (executable or source as VS2015 project) to play with – just let me know.

Addendum:

Clearly the HTML tidy up routine could wreck some actual HTML embedded in the code so I added a simplified routine just to handle that.

private void processHTML() {     if (rtbInput.Lines.Count() > 0)     {         int blCount = 0;         rtbInput.Rtf = rtbInput.Rtf.Replace(new string('\t', 1), "    ");         rtbInput.Rtf = rtbInput.Rtf.Replace("&", "&amp;");         rtbInput.Rtf = rtbInput.Rtf.Replace("\"", "&quot;");         rtbInput.Rtf = rtbInput.Rtf.Replace("'", "&apos;");         rtbInput.Rtf = rtbInput.Rtf.Replace("<", "&lt;");         rtbInput.Rtf = rtbInput.Rtf.Replace(">", "&gt;");         string firstLine = rtbInput.Lines[0];         while (firstLine.Substring(blCount, 1) == " ")         {             blCount++;         }         if (blCount > 0)         {             string tstString = new string(' ', blCount);             List<string> sl = new List<string>();             for (int tl=0; tl < rtbInput.Lines.Count(); tl++)             {                 sl.Add(rtbInput.Lines[tl]);                 if (rtbInput.Lines[tl].Length >= blCount)                 {                     if(rtbInput.Lines[tl].Substring(0, blCount) == tstString)                     {                         sl[tl] = rtbInput.Lines[tl].Substring(blCount);                     }                 }             }             rtbInput.Lines = sl.ToArray();         }         rtbInput.Refresh();         tbOutput.Text = preTag + rtbInput.Text + preTail;              } }

Which would produce HTML results like:
<table style="width: 100%; border: solid 1px #ccc;">
    <thead><tr><th colspan="3" style="text-align: center;">High Water</th></tr><tr><th colspan="3" style="text-align: center;">POR 
        <asp:TextBox ID="tbPOR" runat="server" Width="90px" Text="Dover" ReadOnly="True"></asp:TextBox>
    </th></tr></thead>
    <tbody>
    <tr><td valign="middle">Springs</td><td>
        <asp:RadioButton ID="rbSPlus" runat="server" 
            ToolTip="Adjust HW Springs time" Text="+" Checked="True" GroupName="rbSpring" CssClass="rbBut" />
        <asp:RadioButton ID="rbSMinus" runat="server" 
            ToolTip="Adjust HW Springs time" Text="-" GroupName="rbSpring" CssClass="rbBut" />
    </td><td valign="middle">
        <asp:TextBox ID="tbHWs" runat="server" CssClass="smlTb timepicker">00:00</asp:TextBox>
    </td></tr>
    <tr><td valign="middle">Neaps</td><td>
        <asp:RadioButton ID="rbNPlus" runat="server" 
            ToolTip="Adjust HW Neaps time" Text="+" Checked="True" GroupName="rbNeap" CssClass="rbBut" />
        <asp:RadioButton ID="rbNMinus" runat="server" 
            ToolTip="Adjust HW Neaps time" Text="-" GroupName="rbNeap" CssClass="rbBut" />
    </td><td valign="middle">
        <asp:TextBox ID="tbHWn" runat="server" CssClass="smlTb timepicker">00:00</asp:TextBox>
    </td></tr>
    </tbody>
</table>

And would would process itself as:
private void processHTML()
{
    if (rtbInput.Lines.Count() > 0)
    {
        int blCount = 0;
        rtbInput.Rtf = rtbInput.Rtf.Replace(new string('\t', 1), "    ");
        rtbInput.Rtf = rtbInput.Rtf.Replace("&", "&amp;");
        rtbInput.Rtf = rtbInput.Rtf.Replace("\"", "&quot;");
        rtbInput.Rtf = rtbInput.Rtf.Replace("'", "&apos;");
        rtbInput.Rtf = rtbInput.Rtf.Replace("<", "&lt;");
        rtbInput.Rtf = rtbInput.Rtf.Replace(">", "&gt;");
        string firstLine = rtbInput.Lines[0];
        while (firstLine.Substring(blCount, 1) == " ")
        {
            blCount++;
        }
        if (blCount > 0)
        {
            string tstString = new string(' ', blCount);
            List<string> sl = new List<string>();
            for (int tl=0; tl < rtbInput.Lines.Count(); tl++)
            {
                sl.Add(rtbInput.Lines[tl]);
                if (rtbInput.Lines[tl].Length >= blCount)
                {
                    if(rtbInput.Lines[tl].Substring(0, blCount) == tstString)
                    {
                        sl[tl] = rtbInput.Lines[tl].Substring(blCount);
                    }
                }
            }
            rtbInput.Lines = sl.ToArray();
        }
        rtbInput.Refresh();
        tbOutput.Text = preTag + rtbInput.Text + preTail;
        
    }

}

Friday, August 28, 2015

Nice C# Code Abstractions

A little side C# project had me needing to read an XML file coming from an external source. It has been a while since I did battle with XML as my personal preference is for JSON wherever possible as I feel the latter is more about the data and less about the structure.

Anyway, this was an opportunity to try a Linq query against an XML file.

var xdoc = XDocument.Load(“path to XML file”);
List < Feed > newFeeds = (from lvl in xdoc.Descendants("outline")
                          select new Feed
                          {
                               FeedTitle = lvl.Attribute("title").Value,
                               RSSUrl = lvl.Attribute("xmlUrl").Value,
                               MainUrl = lvl.Attribute("htmlUrl").Value
                          }).ToList();

This statement reads an XML file and creates a list of classes (Feed) based upon the file content.

An elegant and clear method that shifts the processing from being about the file structure to concentrating on the data. OK – this is an abstraction – so things might well go wrong.

So course you can’t actually implement the code above no matter how elegant – you have to let the real world of dirty and incomplete files in. Something like:

var xdoc = XDocument.Load(“Path to XML file”);
List < Feed > newFeeds = (from lvl in xdoc.Descendants("outline")
                          where (string)lvl.Attribute("type") != null
                          select new Feed
     {
     FeedTitle = (string)lvl.Attribute("title") != null ? lvl.Attribute("title").Value : "",
     RSSUrl = (string)lvl.Attribute("xmlUrl") != null ? lvl.Attribute("xmlUrl").Value : "",
     MainUrl = (string)lvl.Attribute("htmlUrl") != null ? lvl.Attribute("htmlUrl").Value : ""
     }).ToList();

Where the objects (say lvl.Attribute("type")) is cast to a string and then that string is tested for null.

The same project had me playing around with some large strings where the .NET StringBuilder class is usually your friend. I needed to locate one or more occurrence of a given string and insert some additional characters near that location. The StringBuilder class has an Insert() method that can inject all sorts of types into a specified location BUT no inbuilt way to find that location.

Time for one of those new-fangled Extension methods which are very straightforward to implement.
I started with this:
 internal static class Extensions  
 {  
     public static int IndexOf(this StringBuilder sb, string value, int startIndex, bool ignoreCase)  
     {  
       int index;  
       int length = value.Length;  
       int maxSearchLength = (sb.Length - length) + 1;  
         for (int i = startIndex; i < maxSearchLength; ++i)  
         {  
           if (sb[i] == value[0] || (Char.ToLower(sb[i]) == Char.ToLower(value[0]) && ignoreCase))  
           {  
             index = 1;  
             while ((index < length) && (sb[i + index] == value[index] || (Char.ToLower(sb[i + index]) == Char.ToLower(value[index]) && ignoreCase)))  
               ++index;  
             if (index == length)  
               return i;  
           }  
         }  
         return -1;  
     }  
 }  

But I am lazy so then added the obvious alternate method signatures to the class:
 public static int IndexOf(this StringBuilder sb, string value, int startIndex)  
     {  
       return IndexOf(sb, value, startIndex, false);  
     }  
     public static int IndexOf(this StringBuilder sb, string value)  
     {  
       return IndexOf(sb, value, 0, false);  
     }  
     public static int IndexOf(this StringBuilder sb, string value, bool ignoreCase)  
     {  
       return IndexOf(sb, value, 0, ignoreCase);  
     }  

And it just worked:

sPos = myStringBuilder.IndexOf("<iframe", true);

This project also allowed me to try out an asynchronous method without the hassle of messing with Threads even wrapped as a BackgroundWorker.

await Task.Run(() => doFeedCheck()); // run doFeedCheck() on another thread

is clear, easy to understand and abstracts away a whole raft of code.