📜 ⬆️ ⬇️

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

Hi, Habrayuzer! In this post, I will tell you how you can make your code on Habré more "alive" thanks to a simple way to preserve its original color scheme. And also I propose to compare various color code options.

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 the source codes will be highlighted with a third-party habr-highlighter, since the standard <source> tag in my opinion does not give a qualitative effect of syntax highlighting. However, I found only one alternative highlighter - http://highlight.hohli.com . The result of his coloring, unfortunately, did not inspire me. At the end of the post I show it in the number of 6 color options for direct comparison. Once there used to be another HighLater - 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 fully 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 habra-compatible. Consider an example. This simple code, when saved, gives the following <body> content, where I marked all the <span> tags in blue, pink - the color of the style, and brown - the displayed text itself.
private   void Hello () {
     MessageBox .Show ( "Hello Habrahabr!" );
}
Hello.htm
<body lang = RU style = 'tab-interval: 35.4pt'>
<div class = WordSection1>
')
<p class = MsoNormal style = 'margin-bottom: 0cm; margin-bottom: .0001pt; line-height:
normal; mso-layout-grid-align: none; text-autospace: none '> <span lang = EN-US
style = 'font-size: 9.5pt; font-family: Consolas; color: black ; background: white;
mso-highlight: white; mso-ansi-language: EN-US ' > <span
style = 'mso-spacerun: yes' > </ span> </ span> <span class = GramE > <span
lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: blue ; background:
white; mso-highlight: white; mso-ansi-language: EN-US ' > private </ span> </ span> <span
lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: black ; background:
white; mso-highlight: white; mso-ansi-language: EN-US ' > </ span> <span lang = EN-US
style = 'font-size: 9.5pt; font-family: Consolas; color: blue ; background: white;
mso-highlight: white; mso-ansi-language: EN-US ' > void </ span> <span lang = EN-US
style = 'font-size: 9.5pt; font-family: Consolas; color: black ; background: white;
mso-highlight: white; mso-ansi-language: EN-US ' > Hello () { <o: p> </ o: p> </ span> </ p>

<p class = MsoNormal style = 'margin-bottom: 0cm; margin-bottom: .0001pt; line-height:
normal; mso-layout-grid-align: none; text-autospace: none '> < span lang = EN-US
style = 'font-size: 9.5pt; font-family: Consolas; color: black ; background: white;
mso-highlight: white; mso-ansi-language: EN-US '> <span
style = 'mso-spacerun: yes'> </ span> </ span> <span class = GramE> < span
lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: # 2B91AF ;
background: white; mso-highlight: white; mso-ansi-language: EN-US '> MessageBox </ span > < span
lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: black ; background:
white; mso-highlight: white; mso-ansi-language: EN-US '> .Show ( </ span> </ span> <span
lang = EN-US style = 'font-size: 9.5pt; font-family: Consolas; color: # A31515 ;
background: white; mso-highlight: white; mso-ansi-language: EN-US ' > & quot; Hello
Habrahabr ! & Quot ; </ span> <span lang = EN-US style = 'font-size: 9.5pt; font-family:
Consolas; color: black ; background: white; mso-highlight: white; mso-ansi-language:
EN-US '> ); <o: p> </ o: p> </ span> </ p>

<p class = MsoNormal> <span lang = EN-US style = 'font-size: 9.5pt; line-height: 115%;
font-family: Consolas; color: black ; background: white; mso-highlight: white;
mso-ansi-language: EN-US '> <span style =' mso-spacerun: yes' > </ span> </ span> <span
style = 'font-size: 9.5pt; line-height: 115%; font-family: Consolas; color: black ;
background: white; mso-highlight: white ' > } </ span> </ p>

</ div>
</ body>

As you can see, each line of the source code is converted into a <p> tag , inside which the text is formatted using nested <span> tags, and its color is stored in the style attribute. The transformation algorithm becomes clear: for each <p> tag from "/ html / body / div / p" to produce a recursive translation of its contents into a new html document, setting the text color using the <font> tag. 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 used library Html Agility Pack .

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

Probably, many will call my code coloring too motley, and therefore inconvenient, but it significantly improves my process of working with the source code. This is a very simple way to increase your efficiency 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 flag of adding line numbers is optional. The second overload allows you to explicitly specify the target file, otherwise the result will be saved as [original_name] _result.txt. The getSpacesToDelete method allows you to find the number of leading spaces in the first line in order to remove them in all subsequent lines.

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

In my diagram, 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, quote setting. Save the xml as a spoiler as a file with the .vssettings extension in UTF-8 encoding without a BOM, for example, HabraCode.vssettings, and import the settings using the Tools> Import and Export Settings> Import ... menu . You can set the encoding, for example, using Notepad ++ . By default, the wizard also saves all your current settings along the way - to be able to roll back changes. After importing, the font will be reset to default, and if you had a custom one, you will have to specify it again. Also in the “Plain Text” setting, I slightly reduced the whiteness of the background, reducing from absolute to #FAFAFA.

HabraCode.vssettings
<UserSettings> <ApplicationIdentity version="10.0"/> <ToolsOptions> <ToolsOptionsCategory name="Environment" RegisteredName="Environment"/> </ToolsOptions> <Category name="Environment_Group" RegisteredName="Environment_Group"> <Category name="Environment_FontsAndColors" Category="{1EDA5DD4-927A-43a7-810E-7FD247D0DA1D}" Package="{DA9FB551-C724-11d0-AE1F-00A0C90FFFC3}" RegisteredName="Environment_FontsAndColors" PackageName="Visual Studio Environment Package"> <PropertyValue name="Version">2</PropertyValue> <FontsAndColors Version="2.0"> <Categories> <Category GUID="{A27B4E24-A735-4D1D-B8E7-9716E1E3D8E0}"> <Items> <!-- --> <Item Name="Plain Text" Foreground="0x02000000" Background="0x00FAFAFA" BoldFont="No"/> <Item Name="Literal" Foreground="0x02000000" Background="0x02000000" BoldFont="Yes"/> <Item Name="Number" Foreground="0x02000000" Background="0x02000000" BoldFont="Yes"/> <Item Name="ReSharper Namespace Identifier" Foreground="0x02000000" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Mutable Local Variable Identifier" Foreground="0x02000000" Background="0x02000000" BoldFont="No"/> <!--:  --> <Item Name="String" Foreground="0x001515A3" Background="0x02000000" BoldFont="No"/> <Item Name="String(C# @ Verbatim)" Foreground="0x001515A3" Background="0x02000000" BoldFont="No"/> <!--: - --> <Item Name="ReSharper Extension Method Identifier" Foreground="0x008812C7" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Method Identifier" Foreground="0x008812C7" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Operator Identifier" Foreground="0x008812C7" Background="0x02000000" BoldFont="No"/> <!--, , : - --> <Item Name="ReSharper Event Identifier" Foreground="0x001256C7" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Field Identifier" Foreground="0x001256C7" Background="0x02000000" BoldFont="No"/> <!--:  --> <Item Name="ReSharper Class Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Delegate Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Enum Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Static Class Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Interface Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Struct Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <Item Name="ReSharper Type Parameter Identifier" Foreground="0x00AC8500" Background="0x02000000" BoldFont="No"/> <!-- todo  bug. NotImplementedException: --> <Item Name="ReSharper Todo Item" Foreground="0x000000F5" Background="0x02000000" BoldFont="Yes"/> <Item Name="ReSharper Todo Item Marker on Error Stripe" Foreground="0x000000F5" Background="0x02000000" BoldFont="No"/> <!-- string.Format:  + bold--> <Item Name="ReSharper Format String Item" Foreground="0x00AC8500" Background="0x02000000" BoldFont="Yes"/> <!--:  + bold --> <Item Name="ReSharper Constant Identifier" Foreground="0x00004080" Background="0x02000000" BoldFont="Yes"/> </Items> </Category> </Categories> </FontsAndColors> </Category> </Category> </UserSettings> 

Comparison


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

1. <source lang = "cs">
 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 discarded 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 Visual Studio Color
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 Reshaper Color
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 colors
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 ;
}

Source: https://habr.com/ru/post/242341/


All Articles