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