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