// Copyright (c) 2007 Omer Rauchwerger (a.k.a rauchy) (omer@rauchy.net) // All rights reserved. // // This file is part of Regionerate. // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Rauchy.Regionerate.Shared.Components; using Rauchy.Regionerate.Shared.Components.Rendering; namespace Rauchy.Regionerate.ServiceLayer.Components.Tools { /// /// Removes existing regions from the specified code. /// /// The code. /// The same code blocks, without the unwanted regions. /// /// Thrown when code is null. /// /// /// Handles type-level regions only, does not remove method-level or property-level regions. /// public sealed class RegionUnpacker { #region Fields (2)  ///// ///// Removes text from the specified code. ///// ///// The code. ///// The same code blocks, without the unwanted text. ///// ///// Thrown when code is null. ///// ///// ///// Handles type-level text only, does not remove method-level or property-level text. ///// //public string Unpack(string code) //{ // if (code == null) // { // throw new ArgumentNullException("code"); // } // IList lines = TextUtilities.GetLines(code); // StringBuilder filteredCode = new StringBuilder(); // foreach (string line in lines) // { // bool isRegionDeclaration = ShouldRemove(line); // if (!isRegionDeclaration) // { // filteredCode.Append(line); // } // } // return filteredCode.ToString(); //} private readonly Symbol _symbol; private readonly CodeLayout.UnpackOptions _unpackOptions; #endregion Fields  #region Constructors (1)  /// /// Initializes a new instance of the class. /// /// The symbol. /// The unpack options. public RegionUnpacker( Symbol symbol, CodeLayout.UnpackOptions unpackOptions ) { _symbol = symbol; _unpackOptions = unpackOptions; } #endregion Constructors  #region Methods (8)  // Public Methods (1)  /// /// Removes text from the specified code. /// /// The code. /// The same code blocks, without the unwanted text. /// /// Thrown when code is null. /// /// /// Handles type-level text only, does not remove method-level or property-level text. /// public string Unpack( string code ) { if ( code == null ) { throw new ArgumentNullException( "code" ); } IList lines = code.GetLines(); IList unpackedLines = Unpack( lines ); string unpackedCode = JoinLines( unpackedLines ); return unpackedCode; } // Private Methods (7)  private int FindEndRegionPosition( IList lines ) { int currentLineNumber = 0; while ( currentLineNumber < lines.Count ) { string line = lines[ currentLineNumber ].Trim(); if ( line.StartsWith( "#region" ) ) { // Skip to the line after this region ends. List remainingLines = GetLinesStartingFrom( lines, currentLineNumber + 1 ); try { currentLineNumber += FindEndRegionPosition( remainingLines ) + 1; } catch ( ArgumentOutOfRangeException e ) { string message = "Cannot find a matching #endregion declaration for " + line; throw new UnpackingException( message, e ); } } else if ( line.StartsWith( "#endregion" ) ) { return currentLineNumber; } currentLineNumber++; } throw new ArgumentOutOfRangeException( "Cannot locate an #endregion declaration" ); } private static List GetLinesStartingFrom( IList lines, int from ) { List remainingLines = new List(); for ( int i = from; i < lines.Count; i++ ) { remainingLines.Add( lines[ i ] ); } return remainingLines; } private static string JoinLines( IList lines ) { StringBuilder jointLines = new StringBuilder(); foreach ( string line in lines ) { jointLines.Append( line ); } return jointLines.ToString(); } private bool LineMatchesAnyUndesiredPattern( string line ) { if ( _unpackOptions == null ) { return false; } else if ( _unpackOptions.RegionPatterns.Count == 0 ) { return false; } else if ( line.Trim().StartsWith( "#region" ) == false ) { return false; } else { foreach ( string pattern in _unpackOptions.RegionPatterns ) { Regex regex = new Regex( pattern ); bool isMatch = regex.IsMatch( line ); if ( isMatch ) { return true; } } // No pattern matches this line. return false; } } /// /// Determines wether a line, when not placed in a method or property (or such), should be removed. /// /// /// If the line begins a region or ends a region, it should be removed. /// /// The line. private bool ShouldRemove( string line ) { string trimmedLine = line.Trim(); if ( trimmedLine.Length == 0 ) { return false; } bool symbolIsEmbedded = _symbol.IsEmbeddedIn( trimmedLine ); if ( symbolIsEmbedded ) { return true; } else { return false; } } private bool SymbolIsEmbeddedIn( string line ) { if ( _symbol == null ) { return false; } else { return _symbol.IsEmbeddedIn( line ); } } private IList Unpack( IList lines ) { int currentLineNumber = 0; while ( currentLineNumber < lines.Count ) { string line = lines[ currentLineNumber ].Trim(); if ( SymbolIsEmbeddedIn( line ) ) { lines.RemoveAt( currentLineNumber ); } else if ( LineMatchesAnyUndesiredPattern( line ) ) { int regionDeclarationPosition = currentLineNumber; // Find the corresponding #endregion tag and remove both. List remainingLines = GetLinesStartingFrom( lines, currentLineNumber + 1 ); int endRegionDeclarationPosition = 0; try { int endRegionDeclarationPositionInsideRemainingLines = FindEndRegionPosition( remainingLines ); endRegionDeclarationPosition = endRegionDeclarationPositionInsideRemainingLines + currentLineNumber; } catch ( ArgumentOutOfRangeException e ) { string message = "Cannot find a matching #endregion declaration for " + line; throw new UnpackingException( message, e ); } // Remove both #region and #endregion. lines.RemoveAt( regionDeclarationPosition ); lines.RemoveAt( endRegionDeclarationPosition ); } else { currentLineNumber++; } } return lines; } #endregion Methods  #region Nested Classes (1)  public class UnpackingException : Exception { #region Constructors (1)  public UnpackingException( string message, Exception innerException ) : base( message, innerException ) {} #endregion Constructors  } #endregion Nested Classes  } }