How to keep the original coloring of your code from Visual Studio in a publication on Habrahabr. Compare colors. Poll

    Hi, Habrauser! In this post I will tell you how you can make your Habré code more “alive” thanks to a simple way to save its original color scheme. And also I propose to compare different options for coloring the code.

    Foreword


    Now I am in the process of writing my first article for Habr about web services. And from the very beginning I decided that I would highlight the source codes with a third-party habr-highlighter, since the standard tagin my opinion does not give a qualitative syntax highlighting effect. However, I found only one alternative highlighter - http://highlight.hohli.com . The result of its coloring, unfortunately, did not inspire me. At the end of the post, I show it among 6 color options for direct comparison. Once before there was another highlighter - Source Code Highlighter , described on Habré here and here , but it has not been working for a long time . Then I remembered that the code from Visual Studio completely retains its appearance when copying to Word, this simple technique became the basis of my method.

    Method


    The idea is simple: the code is copied to Word, the document is saved as an html web page and the function converts the html code to a Habra-compatible one. Let's look at an example. This simple code when saved gives the following contentswhere in blue I marked all the tags , pink is the color of the style, and brown is the displayed text itself.
    private void Hello () {
        MessageBox.Show ("Hello Habrahabr!");
    }
    Hello.htm


     

    normal; mso-layout-grid-align: none; text-autospace: none '> style =' font-size: 9.5pt; font-family: Consolas; color: black; background: white;
    mso-highlight: white; mso-ansi-language: EN-US '> style = 'mso-spacerun: yes'>       
    lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: blue; background:
    white; mso-highlight: white; mso-ansi-language: EN-US'> private
    lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: black; background:
    white; mso-highlight: white; mso-ansi-language: EN-US'>  style = 'font -size: 9.5pt; font-family: Consolas; color: blue; background: white;
    mso-highlight: white; mso-ansi-language: EN-US '> void
    style =' font-size: 9.5pt; font-family: Consolas; color: black; background: white;
    mso-highlight: white; mso-ansi-language: EN-US '>  Hello () {


     

    normal; mso-layout-grid-align: none; text-autospace: none '> style =' font-size: 9.5pt; font-family: Consolas; color: black; background: white;
    mso-highlight: white; mso-ansi-language: EN-US '> style = 'mso-spacerun: yes'>           
    lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: # 2B91AF;
    background: white; mso-highlight: white; mso-ansi-language: EN-US '> MessageBox
    lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: black; background:
    white; mso-highlight: white; mso-ansi-language: EN-US'> .Show ( lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: # A31515;
    background: white; mso-highlight: white; mso-ansi-language: EN-US '> "Hello
    Habrahabr ! & quot ; );


     

            style = 'font-size: 9.5pt; line-height: 115%; font-family: Consolas; color: black;
    background: white; mso-highlight: white '> }


     


    As you can see, each line of source code is converted to a tag

    , inside of which text is formatted using nested tags , and its color is stored in the style attribute . The conversion algorithm becomes clear: for each tag

    from "/ html / body / div / p" recursively translate its contents into a new html document, along with the tagsetting the color of the text. Under the spoiler is the full source code of the resulting method, which looks in accordance with my original color scheme. To work with html, the Html Agility Pack library was used .

    HabraCodeFormatter.cs
    1. using System;
    2. using System.IO;
    3. using HtmlAgilityPack;
    4.  
    5. namespace HabraCode {
    6.     public static class HabraCodeFormatter {
    7.         const char  spaceClassic  = (char) 32 ;
    8.         const char  spaceNbsp  = (char) 160 ;
    9.  
    10.         public static void Format (string fileHtm, bool withLineNumbers = false) {
    11.             var info = new FileInfo (fileHtm);
    12.             string destFile = info.DirectoryName + "\\" + info.Name.Replace (info.Extension, null) + "_result.txt";
    13.             Format (fileHtm, destFile, withLineNumbers);
    14.         }
    15.  
    16.  
    17.         public static void Format (string fileHtm, string fileDest, bool withLineNumbers = false) {
    18.             var doc = new HtmlDocument ();
    19.             doc.Load (fileHtm);
    20.             var nodes = doc.DocumentNode.SelectNodes ("/ html / body / div / p");
    21.             int spacesToDelete = getSpacesToDelete (nodes [ 0 ]);
    22.  
    23.             var result = new HtmlDocument ();
    24.             var rootNode = result.CreateElement ("blockquote");
    25.             result.DocumentNode.AppendChild (rootNode);
    26.  
    27.             if (withLineNumbers) {
    28.                 var nodeOl = result.CreateElement ("ol");
    29.                 rootNode.AppendChild (nodeOl);
    30.                 rootNode = nodeOl;
    31.             }
    32.  
    33.             foreach (var node in nodes) {
    34.                 if (withLineNumbers) {
    35.                     var nodeLi = doc.CreateElement ("li");
    36.                     nodeLi.AppendChildren (node.ChildNodes);
    37.                     node.RemoveAllChildren ();
    38.                     node.AppendChild (nodeLi);
    39.                 }
    40.  
    41.                 int refSpaces = spacesToDelete;
    42.                 translateNode (node, rootNode, ref refSpaces);
    43.                 rootNode.AppendChild (result.CreateTextNode (Environment.NewLine));
    44.             }
    45.  
    46.             result.Save (fileDest);
    47.         }
    48.  
    49.  
    50.         private static int getSpacesToDelete (HtmlNode node) {
    51.             for (int index =  0 ; index <node.InnerText.Length; index ++) {
    52.                 if (! isSpace (node.InnerText [index])) {
    53.                     return index;
    54.                 }
    55.             }
    56.  
    57.             return  0 ;
    58.         }
    59.  
    60.  
    61.         private static void translateNode (HtmlNode node, HtmlNode destParent, ref int spacesToDelete) {
    62.             HtmlNode destNode = destParent;
    63.  
    64.             switch (node.Name) {
    65.                 case "o: p":
    66.                 case "p":
    67.                     break;
    68.  
    69.                 case "span":
    70.                     string color = getColor (node);
    71.  
    72.                     if (color! = null) {
    73.                         destNode = destParent.OwnerDocument.CreateElement ("font");
    74.                         destNode.SetAttributeValue ("color", color);
    75.                     }
    76.                     break;
    77.  
    78.                 case "#text":
    79.                     string text = translateText (node.InnerText, ref spacesToDelete);
    80.                     destNode = destParent.OwnerDocument.CreateTextNode (text);
    81.                     break;
    82.  
    83.                 case "b":
    84.                 case "li":
    85.                     destNode = destParent.OwnerDocument.CreateElement (node.Name);
    86.                     break;
    87.  
    88.                 default:
    89.                     throw new InvalidOperationException ("Unexpected node.Name" + node.Name);
    90.             }
    91.  
    92.             if (! ReferenceEquals (destNode, destParent)) {
    93.                 destParent.ChildNodes.Add (destNode);
    94.             }
    95.  
    96.             if (node.HasChildNodes) {
    97.                 foreach (HtmlNode child in node.ChildNodes) {
    98.                     translateNode (child, destNode, ref spacesToDelete);
    99.                 }
    100.             }
    101.         }
    102.  
    103.  
    104.         private static string translateText (string text, ref int spaces) {
    105.             if (string.IsNullOrEmpty (text)) {
    106.                 return text;
    107.             }
    108.  
    109.             text = text.Replace ("http: //", "http: //");
    110.             text = text.Replace ("\ r \ n", "");
    111.  
    112.             if (spaces>  0  && text.Length> = spaces && isSpace (text.Substring ( 0 , spaces))) {
    113.                 text = text.Remove ( 0 , spaces);
    114.                 spaces =  0 ;
    115.             }
    116.  
    117.             text = text.Replace ( spaceClassic .ToString (), "");
    118.             text = text.Replace ( spaceNbsp .ToString (), "");
    119.             return text;
    120.         }
    121.  
    122.  
    123.         private static bool isSpace (char ch) {
    124.             return (ch ==  spaceClassic  || ch ==  spaceNbsp );
    125.         }
    126.  
    127.  
    128.         private static bool isSpace (string text) {
    129.             foreach (char ch in text) {
    130.                 if (! isSpace (ch)) {
    131.                     return false;
    132.                 }
    133.             }
    134.  
    135.             return true;
    136.         }
    137.  
    138.  
    139.         private static string getColor (HtmlNode node) {
    140.             var attr = node.Attributes ["style"];
    141.  
    142.             if (attr == null || attr.Value == null) {
    143.                 return null;
    144.             }
    145.  
    146.             string [] values ​​= attr.Value.Split (new [] {';'});
    147.  
    148.             foreach (string value in values) {
    149.                 const string  prefixColor  = "color:";
    150.                 string trimmed = value.Trim ();
    151.  
    152.                 if (trimmed.StartsWith ( prefixColor )) {
    153.                     return trimmed.Remove ( 0prefixColor .Length);
    154.                 }
    155.             }
    156.  
    157.             return null;
    158.         }
    159.     }
    160. }

    Most likely, many will call my color code too colorful, and therefore uncomfortable, but it significantly improves my process of working with source code. This is a very simple way to improve your performance a bit. A little comment on the code. The class contains two overloads of the Format method, where the required parameter is the path to the source html file, and the optional flag for adding line numbers. The second overload allows you to explicitly specify the final file, otherwise the result will be saved as [source_name] _result.txt. The getSpacesToDelete method allows you to find the number of leading spaces in the first line to remove them in all subsequent lines.

    The font and coloring of the source code in Visual Studio is configured in the menu Tools> Options> Environment> Fonts and Colors. However, initially it does not have the ability to set its color for a method or property. But if you use ReSharper, such an opportunity appears. To do this, in the menu ReSharper> Options> Code Inspection> Settings , enable the item Color identifires . And here you can experience a slight cognitive dissonance, because the methods will become turquoise - the classes have this color in the traditional scheme, and the classes will become dark blue - all this can be seen below, where I compare the colors.

    In my scheme, classes, keywords, and other elements have a classic color, but they add their own colors for methods and properties. For those who want to try it, I bring the setting. Save the xml under the spoiler as a file with the .vssettings extension in UTF-8 encoding without a BOM, for example, HabraCode.vssettings, and import the settings through the menu Tools> Import and Export Settings> Import ... The encoding can be set, for example, using Notepad ++ . By default, the wizard also saves all your current settings along the way - so that changes can be rolled back. After import, the font will be reset to default, and if you had a custom one, you will need to specify it again. Also, in the “Plain Text” setting, I slightly reduced the whiteness of the background, reducing it from absolute to #FAFAFA.

    HabraCode.vssettings
    2

    Comparison


    Now I propose to compare 6 options for coloring the code on the example of one of the methods. It cannot be argued that some kind of color is, in principle, the best, because, as you know, there are no comrades for the taste and color. But I am interested in the collective opinion of the habr community.

    1.
    private static string getColor(HtmlNode node){
        var attr = node.Attributes["style"];
        if (attr == null || attr.Value == null){
            return null;
        }
        string[] values = attr.Value.Split(new [] {';'});
        foreach (string value in values){
            const string prefixColor = "color:";
            string trimmed = value.Trim();
            if (trimmed.StartsWith(prefixColor)){
                return trimmed.Remove(0, prefixColor.Length);
            }
        }
        return null;
    }
    

    2. Black-and-white code (obtained through HabraCodeFormatter with rejection of color and bold)
    private static string getColor (HtmlNode node) {
        var attr = node.Attributes ["style"];
     
        if (attr == null || attr.Value == null) {
            return null;
        }
     
        string [] values ​​= attr.Value.Split (new [] {';'});
     
        foreach (string value in values) {
            const string prefixColor = "color:";
            string trimmed = value.Trim ();
     
            if (trimmed.StartsWith (prefixColor)) {
                return trimmed.Remove (0, prefixColor.Length);
            }
        }
     
        return null;
    }
     

    3.http: //highlight.hohli.com
    private static string getColor (HtmlNode node) {
        var attr = node.Attributes ["style"];
     
        if (attr == null || attr.Value == null) {
            return null;
        }
     
        string [] values ​​= attr.Value.Split (new [] {';'});
     
        foreach (string value in values) {
            const string prefixColor = "color:";
            string trimmed = value.Trim ();
     
            if (trimmed.StartsWith (prefixColor)) {
                return trimmed.Remove (0, prefixColor.Length);
            }
        }
     
        return null;
    }

    4. Standard coloring of Visual Studio
    private static string getColor (HtmlNode node) {
        var attr = node.Attributes ["style"];
     
        if (attr == null || attr.Value == null) {
            return null;
        }
     
        string [] values ​​= attr.Value.Split (new [] {';'});
     
        foreach (string value in values) {
            const string prefixColor = "color:";
            string trimmed = value.Trim ();
     
            if (trimmed.StartsWith (prefixColor)) {
                return trimmed.Remove (0, prefixColor.Length);
            }
        }
     
        return null;
    }

    5. Standard color reshaper
    private static string getColor (HtmlNode node) {
        var attr = node.Attributes ["style"];
     
        if (attr == null || attr.Value == null) {
            return null;
        }
     
        string [] values ​​= attr.Value.Split (new [] {';'});
     
        foreach (string  value  in values) {
            const string  prefixColor  = "color:";
            string trimmed =  value .Trim ();
     
            if (trimmed.StartsWith ( prefixColor )) {
                return trimmed.Remove (0,  prefixColor .Length);
            }
        }
     
        return null;
    }
     

    6. Author's coloring
    private static string getColor (HtmlNode node) {
        var attr = node.Attributes ["style"];
     
        if (attr == null || attr.Value == null) {
            return null;
        }
     
        string [] values ​​= attr.Value.Split (new [] {';'});
     
        foreach (string value in values) {
            const string  prefixColor  = "color:";
            string trimmed = value.Trim ();
     
            if (trimmed.StartsWith ( prefixColor )) {
                return trimmed.Remove ( 0prefixColor .Length);
            }
        }
     
        return null;
    }
     

    Only registered users can participate in the survey. Please come in.

    And now the survey. Which of these color code options will suit you in publications on Habrahabr?

    • 37.6% source lang = "cs" 94
    • 6.4% Black and White Code 16
    • 6% http://highlight.hohli.com 15
    • 40.4% Standard Color Visual Studio 101
    • 30.8% Standard color Reshaper 77
    • 24.4% Color 61

    Also popular now: