PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/BlogEngine/BlogEngine.NET/App_Code/Extensions/CodeFormatter/HtmlFormat.cs

#
C# | 209 lines | 103 code | 29 blank | 77 comment | 13 complexity | e6956dc99e76e613b8dbba21c634c186 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause
  1. #region Copyright © 2001-2003 Jean-Claude Manoli [jc@manoli.net]
  2. /*
  3. * This software is provided 'as-is', without any express or implied warranty.
  4. * In no event will the author(s) be held liable for any damages arising from
  5. * the use of this software.
  6. *
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. *
  11. * 1. The origin of this software must not be misrepresented; you must not
  12. * claim that you wrote the original software. If you use this software
  13. * in a product, an acknowledgment in the product documentation would be
  14. * appreciated but is not required.
  15. *
  16. * 2. Altered source versions must be plainly marked as such, and must not
  17. * be misrepresented as being the original software.
  18. *
  19. * 3. This notice may not be removed or altered from any source distribution.
  20. */
  21. #endregion
  22. namespace CodeFormatter
  23. {
  24. using System.IO;
  25. using System.Text;
  26. using System.Text.RegularExpressions;
  27. /// <summary>
  28. /// Generates color-coded HTML 4.01 from HTML/XML/ASPX source code.
  29. /// </summary>
  30. /// <remarks>
  31. /// <para>
  32. /// This implementation assumes that code inside &lt;script&gt; blocks
  33. /// is JavaScript, and code inside &lt;% %&gt; blocks is C#.
  34. /// </para>
  35. /// <para>
  36. /// The default tab width is set to 2 characters in this class.
  37. /// </para>
  38. /// </remarks>
  39. public class HtmlFormat : SourceFormat
  40. {
  41. #region Constants and Fields
  42. /// <summary>
  43. /// The attrib regex.
  44. /// </summary>
  45. private readonly Regex attribRegex;
  46. /// <summary>
  47. /// To format embedded C# code.
  48. /// </summary>
  49. private readonly CSharpFormat csf;
  50. /// <summary>
  51. /// To format client-side JavaScript code.
  52. /// </summary>
  53. private readonly JavaScriptFormat jsf;
  54. #endregion
  55. #region Constructors and Destructors
  56. /// <summary>
  57. /// Initializes a new instance of the <see cref="HtmlFormat"/> class.
  58. /// The html format.
  59. /// </summary>
  60. public HtmlFormat()
  61. {
  62. const string RegJavaScript = @"(?<=&lt;script(?:\s.*?)?&gt;).+?(?=&lt;/script&gt;)";
  63. const string RegComment = @"&lt;!--.*?--&gt;";
  64. const string RegAspTag = @"&lt;%@.*?%&gt;|&lt;%|%&gt;";
  65. const string RegAspCode = @"(?<=&lt;%).*?(?=%&gt;)";
  66. const string RegTagDelimiter = @"(?:&lt;/?!?\??(?!%)|(?<!%)/?&gt;)+";
  67. const string RegTagName = @"(?<=&lt;/?!?\??(?!%))[\w\.:-]+(?=.*&gt;)";
  68. const string RegAttributes = @"(?<=&lt;(?!%)/?!?\??[\w:-]+).*?(?=(?<!%)/?&gt;)";
  69. const string RegEntity = @"&amp;\w+;";
  70. const string RegAttributeMatch = @"(=?"".*?""|=?'.*?')|([\w:-]+)";
  71. // the regex object will handle all the replacements in one pass
  72. const string RegAll = "(" + RegJavaScript + ")|(" + RegComment + ")|(" + RegAspTag + ")|(" + RegAspCode + ")|(" +
  73. RegTagDelimiter + ")|(" + RegTagName + ")|(" + RegAttributes + ")|(" + RegEntity + ")";
  74. this.CodeRegex = new Regex(RegAll, RegexOptions.IgnoreCase | RegexOptions.Singleline);
  75. this.attribRegex = new Regex(RegAttributeMatch, RegexOptions.Singleline);
  76. this.csf = new CSharpFormat();
  77. this.jsf = new JavaScriptFormat();
  78. }
  79. #endregion
  80. #region Methods
  81. /// <summary>
  82. /// Called to evaluate the HTML fragment corresponding to each
  83. /// matching token in the code.
  84. /// </summary>
  85. /// <param name="match">
  86. /// The <see cref="Match"/> resulting from a
  87. /// single regular expression match.
  88. /// </param>
  89. /// <returns>
  90. /// A string containing the HTML code fragment.
  91. /// </returns>
  92. protected override string MatchEval(Match match)
  93. {
  94. if (match.Groups[1].Success)
  95. {
  96. // JavaScript code
  97. var s = match.ToString();
  98. return this.jsf.FormatSubCode(match.ToString());
  99. }
  100. if (match.Groups[2].Success)
  101. {
  102. // comment
  103. StringBuilder sb;
  104. using (var reader = new StringReader(match.ToString()))
  105. {
  106. string line;
  107. sb = new StringBuilder();
  108. while ((line = reader.ReadLine()) != null)
  109. {
  110. if (sb.Length > 0)
  111. {
  112. sb.Append("\n");
  113. }
  114. sb.Append("<span class=\"rem\">");
  115. sb.Append(line);
  116. sb.Append("</span>");
  117. }
  118. }
  119. return sb.ToString();
  120. }
  121. if (match.Groups[3].Success)
  122. {
  123. // asp tag
  124. return string.Format("<span class=\"asp\">{0}</span>", match);
  125. }
  126. if (match.Groups[4].Success)
  127. {
  128. // asp C# code
  129. return this.csf.FormatSubCode(match.ToString());
  130. }
  131. if (match.Groups[5].Success)
  132. {
  133. // tag delimiter
  134. return string.Format("<span class=\"kwrd\">{0}</span>", match);
  135. }
  136. if (match.Groups[6].Success)
  137. {
  138. // html tagname
  139. return string.Format("<span class=\"html\">{0}</span>", match);
  140. }
  141. if (match.Groups[7].Success)
  142. {
  143. // attributes
  144. return this.attribRegex.Replace(match.ToString(), new MatchEvaluator(AttributeMatchEval));
  145. }
  146. if (match.Groups[8].Success)
  147. {
  148. // entity
  149. return string.Format("<span class=\"attr\">{0}</span>", match);
  150. }
  151. return match.ToString();
  152. }
  153. /// <summary>
  154. /// Called to evaluate the HTML fragment corresponding to each
  155. /// attribute's name/value in the code.
  156. /// </summary>
  157. /// <param name="match">
  158. /// The <see cref="Match"/> resulting from a
  159. /// single regular expression match.
  160. /// </param>
  161. /// <returns>
  162. /// A string containing the HTML code fragment.
  163. /// </returns>
  164. private static string AttributeMatchEval(Match match)
  165. {
  166. if (match.Groups[1].Success)
  167. {
  168. // attribute value
  169. return string.Format("<span class=\"kwrd\">{0}</span>", match);
  170. }
  171. if (match.Groups[2].Success)
  172. {
  173. // attribute name
  174. return string.Format("<span class=\"attr\">{0}</span>", match);
  175. }
  176. return match.ToString();
  177. }
  178. #endregion
  179. }
  180. }