| using System; |
| using System.IO; |
| using System.Text.RegularExpressions; |
| |
| namespace Lucene.Net.Cli.SourceCode |
| { |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /// <summary> |
| /// A <see cref="TextReader"/> that conditionally includes or excludes lines |
| /// of source code based on commented sections in the original |
| /// source. |
| /// </summary> |
| /// <remarks> |
| /// Idenitifies sections of code based on tokens to transform |
| /// the output code to either contain extra code sections or |
| /// remove unwanted code sections. |
| /// <para/> |
| /// There are 5 different types of tokens considered: |
| /// <list type="table"> |
| /// <item> |
| /// <term>// <comment></term> |
| /// <description> |
| /// Beginning of commented block. This line and all lines |
| /// until the end of a comment block are ignored. |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>// <\comment></term> |
| /// <description> |
| /// End of a commented block. This line is ignored, but any |
| /// lines following will be included. |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>// <include></term> |
| /// <description> |
| /// Beginning of an include block. This line is ignored, but |
| /// all lines following will have the //// comment marker |
| /// removed from the beginning of the line. Effectively, |
| /// it uncomments lines of code that were previously commented |
| /// and ignored by the compiler. All normal C# comments (// and ///) |
| /// are ignored and left in place. |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>// <\\include></term> |
| /// <description> |
| /// End of an include block. This line is ignored and following |
| /// lines will be treated normally again. In other words, the //// |
| /// comment will no longer be removed from following lines. |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>////</term> |
| /// <description> |
| /// A double comment. This comment is removed in include blocks |
| /// to uncomment code that was previously commented and ignored |
| /// by the compiler. This allows adding using directives, alternate |
| /// type names, etc. to be output in the demo even if they don't exist |
| /// in the compiled application. |
| /// </description> |
| /// </item> |
| /// </list> |
| /// </remarks> |
| public class SourceCodeSectionReader : TextReader |
| { |
| public static readonly Regex COMMENT_START = new Regex(@"//\s*?<comment>", RegexOptions.Compiled); |
| public static readonly Regex COMMENT_END = new Regex(@"//\s*?</comment>", RegexOptions.Compiled); |
| public static readonly Regex INCLUDE_START = new Regex(@"//\s*?<include>", RegexOptions.Compiled); |
| public static readonly Regex INCLUDE_END = new Regex(@"//\s*?</include>", RegexOptions.Compiled); |
| public static readonly Regex TO_UNCOMMENT = new Regex(@"////", RegexOptions.Compiled); |
| |
| private bool inComment = false; |
| private bool inInclude = false; |
| |
| private readonly TextReader reader; |
| |
| public SourceCodeSectionReader(TextReader reader) |
| { |
| this.reader = reader ?? throw new ArgumentNullException(nameof(reader)); |
| } |
| |
| public override string ReadLine() |
| { |
| string line; |
| while ((line = reader.ReadLine()) != null) |
| { |
| if (inComment) |
| { |
| if (COMMENT_END.IsMatch(line)) |
| { |
| inComment = false; |
| continue; // Skip this line |
| } |
| } |
| else |
| { |
| if (COMMENT_START.IsMatch(line)) |
| { |
| inComment = true; |
| continue; // Skip this line |
| } |
| else |
| { |
| // If not in a comment, consider source code includes. |
| // In this case, we will remove //// from the beginning of |
| // each line if it exists. |
| if (inInclude) |
| { |
| if (INCLUDE_END.IsMatch(line)) |
| { |
| inInclude = false; |
| continue; // Skip this line |
| } |
| line = TO_UNCOMMENT.Replace(line, string.Empty, 1); |
| } |
| else if (INCLUDE_START.IsMatch(line)) |
| { |
| inInclude = true; |
| continue; // Skip this line |
| } |
| } |
| |
| // All other lines, include the line |
| return line; |
| } |
| } |
| return line; |
| } |
| |
| protected override void Dispose(bool disposing) |
| { |
| if (disposing) |
| { |
| this.reader?.Dispose(); |
| } |
| } |
| } |
| } |