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

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

#
C# | 244 lines | 136 code | 35 blank | 73 comment | 5 complexity | 7f5a058c25ccdceea15d59a59a0f9878 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause
  1. #region using
  2. using System.Text.RegularExpressions;
  3. using System.Web;
  4. using BlogEngine.Core;
  5. using BlogEngine.Core.Web.Controls;
  6. using CodeFormatter;
  7. #endregion
  8. /// <summary>
  9. /// Converts text to formatted syntax highlighted code.
  10. /// </summary>
  11. /// <remarks>
  12. /// It is a work in progress.....
  13. /// </remarks>
  14. [Extension("Converts text to formatted syntax highlighted code (beta).", "0.1", "www.manoli.net")]
  15. public class CodeFormatterExtension
  16. {
  17. #region Constants and Fields
  18. /// <summary>
  19. /// The code regex.
  20. /// </summary>
  21. private static readonly Regex CodeRegex =
  22. new Regex(
  23. @"(?<begin>\[code:(?<lang>.*?)(?:;ln=(?<linenumbers>(?:on|off)))?(?:;alt=(?<altlinenumbers>(?:on|off)))?(?:;(?<title>.*?))?\])(?<code>.*?)(?<end>\[/code\])",
  24. RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Singleline);
  25. #endregion
  26. #region Constructors and Destructors
  27. /// <summary>
  28. /// Initializes static members of the <see cref="CodeFormatterExtension"/> class.
  29. /// </summary>
  30. static CodeFormatterExtension()
  31. {
  32. Page.Serving += ServingContent;
  33. Post.Serving += ServingContent;
  34. }
  35. #endregion
  36. #region Methods
  37. /// <summary>
  38. /// Codes the evaluator.
  39. /// </summary>
  40. /// <param name="match">The match.</param>
  41. /// <returns>The code string.</returns>
  42. private static string CodeEvaluator(Match match)
  43. {
  44. if (!match.Success)
  45. {
  46. return match.Value;
  47. }
  48. var options = new HighlightOptions
  49. {
  50. Language = match.Groups["lang"].Value,
  51. Code = match.Groups["code"].Value,
  52. DisplayLineNumbers = match.Groups["linenumbers"].Value == "on" ? true : false,
  53. Title = match.Groups["title"].Value,
  54. AlternateLineNumbers = match.Groups["altlinenumbers"].Value == "on" ? true : false
  55. };
  56. var result = match.Value.Replace(match.Groups["begin"].Value, string.Empty);
  57. result = result.Replace(match.Groups["end"].Value, string.Empty);
  58. result = Highlight(options, result);
  59. return result;
  60. }
  61. /// <summary>
  62. /// Returns the formatted text.
  63. /// </summary>
  64. /// <param name="options">
  65. /// Whatever options were set in the regex groups.
  66. /// </param>
  67. /// <param name="text">
  68. /// Send the e.body so it can get formatted.
  69. /// </param>
  70. /// <returns>
  71. /// The formatted string of the match.
  72. /// </returns>
  73. private static string Highlight(HighlightOptions options, string text)
  74. {
  75. switch (options.Language)
  76. {
  77. case "c#":
  78. var csf = new CSharpFormat
  79. {
  80. LineNumbers = options.DisplayLineNumbers,
  81. Alternate = options.AlternateLineNumbers
  82. };
  83. return HttpContext.Current.Server.HtmlDecode(csf.FormatCode(text));
  84. case "vb":
  85. var vbf = new VisualBasicFormat
  86. {
  87. LineNumbers = options.DisplayLineNumbers,
  88. Alternate = options.AlternateLineNumbers
  89. };
  90. return HttpContext.Current.Server.HtmlDecode(vbf.FormatCode(text));
  91. case "js":
  92. var jsf = new JavaScriptFormat
  93. {
  94. LineNumbers = options.DisplayLineNumbers,
  95. Alternate = options.AlternateLineNumbers
  96. };
  97. return HttpContext.Current.Server.HtmlDecode(jsf.FormatCode(text));
  98. case "html":
  99. var htmlf = new HtmlFormat
  100. {
  101. LineNumbers = options.DisplayLineNumbers,
  102. Alternate = options.AlternateLineNumbers
  103. };
  104. text = Utils.StripHtml(text);
  105. var code = htmlf.FormatCode(HttpContext.Current.Server.HtmlDecode(text)).Trim();
  106. return code.Replace("\r\n", "<br />").Replace("\n", "<br />");
  107. case "xml":
  108. var xmlf = new HtmlFormat
  109. {
  110. LineNumbers = options.DisplayLineNumbers,
  111. Alternate = options.AlternateLineNumbers
  112. };
  113. text = text.Replace("<br />", "\r\n");
  114. text = Utils.StripHtml(text);
  115. var xml = xmlf.FormatCode(HttpContext.Current.Server.HtmlDecode(text)).Trim();
  116. return xml.Replace("\r\n", "<br />").Replace("\n", "<br />");
  117. case "tsql":
  118. var tsqlf = new TsqlFormat
  119. {
  120. LineNumbers = options.DisplayLineNumbers,
  121. Alternate = options.AlternateLineNumbers
  122. };
  123. return HttpContext.Current.Server.HtmlDecode(tsqlf.FormatCode(text));
  124. case "msh":
  125. var mshf = new MshFormat
  126. {
  127. LineNumbers = options.DisplayLineNumbers,
  128. Alternate = options.AlternateLineNumbers
  129. };
  130. return HttpContext.Current.Server.HtmlDecode(mshf.FormatCode(text));
  131. }
  132. return string.Empty;
  133. }
  134. /// <summary>
  135. /// Handles the Serving event of the control.
  136. /// </summary>
  137. /// <param name="sender">The source of the event.</param>
  138. /// <param name="e">The <see cref="BlogEngine.Core.ServingEventArgs"/> instance containing the event data.</param>
  139. private static void ServingContent(object sender, ServingEventArgs e)
  140. {
  141. if (e.Body.Contains("[/code]"))
  142. {
  143. e.Body = CodeRegex.Replace(e.Body, new MatchEvaluator(CodeEvaluator));
  144. }
  145. }
  146. #endregion
  147. /// <summary>
  148. /// Handles all of the options for changing the rendered code.
  149. /// </summary>
  150. private class HighlightOptions
  151. {
  152. #region Constructors and Destructors
  153. /// <summary>
  154. /// Initializes a new instance of the <see cref="HighlightOptions"/> class.
  155. /// </summary>
  156. public HighlightOptions()
  157. {
  158. }
  159. /// <summary>
  160. /// Initializes a new instance of the <see cref="HighlightOptions"/> class.
  161. /// </summary>
  162. /// <param name="language">
  163. /// The language.
  164. /// </param>
  165. /// <param name="title">
  166. /// The title.
  167. /// </param>
  168. /// <param name="linenumbers">
  169. /// The linenumbers.
  170. /// </param>
  171. /// <param name="code">
  172. /// The code string.
  173. /// </param>
  174. /// <param name="alternateLineNumbers">
  175. /// The alternate line numbers.
  176. /// </param>
  177. public HighlightOptions(string language, string title, bool linenumbers, string code, bool alternateLineNumbers)
  178. {
  179. this.Language = language;
  180. this.Title = title;
  181. this.AlternateLineNumbers = alternateLineNumbers;
  182. this.Code = code;
  183. this.DisplayLineNumbers = linenumbers;
  184. }
  185. #endregion
  186. #region Properties
  187. /// <summary>
  188. /// Gets or sets a value indicating whether AlternateLineNumbers.
  189. /// </summary>
  190. public bool AlternateLineNumbers { get; set; }
  191. /// <summary>
  192. /// Gets or sets Code.
  193. /// </summary>
  194. public string Code { get; set; }
  195. /// <summary>
  196. /// Gets or sets a value indicating whether DisplayLineNumbers.
  197. /// </summary>
  198. public bool DisplayLineNumbers { get; set; }
  199. /// <summary>
  200. /// Gets or sets Language.
  201. /// </summary>
  202. public string Language { get; set; }
  203. /// <summary>
  204. /// Gets or sets Title.
  205. /// </summary>
  206. public string Title { get; set; }
  207. #endregion
  208. }
  209. }