@@ -12,14 +12,16 @@ public static class IEnumerableExtensions
1212 {
1313 internal const string MacroBeforeMode = "^^" ;
1414 internal const string MacroStartGroup = "{[{" ;
15- internal const string MarcoEndGroup = "}]}" ;
15+ internal const string MacroEndGroup = "}]}" ;
1616
1717 internal const string MacroStartDocumentation = "{**" ;
1818 internal const string MacroEndDocumentation = "**}" ;
1919
2020 private const string MacroStartDelete = "{--{" ;
2121 private const string MacroEndDelete = "}--}" ;
2222
23+ private static string [ ] macros = new string [ ] { MacroBeforeMode , MacroStartGroup , MacroEndGroup , MacroStartDocumentation , MacroEndDocumentation , MacroStartDelete , MacroEndDelete } ;
24+
2325 private const string OpeningBrace = "{" ;
2426 private const string ClosingBrace = "}" ;
2527
@@ -56,98 +58,133 @@ public static IEnumerable<string> Merge(this IEnumerable<string> source, IEnumer
5658 errorLine = string . Empty ;
5759 int lastLineIndex = - 1 ;
5860 var insertionBuffer = new List < string > ( ) ;
61+ var removalBuffer = new List < string > ( ) ;
5962
6063 bool beforeMode = false ;
61- bool isInBlock = false ;
62- bool isInDocumentation = false ;
64+ MergeMode mergeMode = MergeMode . Context ;
6365
6466 var diffTrivia = FindDiffLeadingTrivia ( source , merge ) ;
6567 var result = source . ToList ( ) ;
6668 var currentLineIndex = - 1 ;
6769
6870 foreach ( var mergeLine in merge )
6971 {
70- if ( ! isInBlock && ! isInDocumentation )
72+ // try to find line
73+ if ( mergeMode == MergeMode . Context )
7174 {
7275 currentLineIndex = result . SafeIndexOf ( mergeLine . WithLeadingTrivia ( diffTrivia ) , lastLineIndex ) ;
7376 }
7477
78+ // if line is found, add buffer if any
7579 if ( currentLineIndex > - 1 )
7680 {
7781 var linesAdded = TryAddBufferContent ( insertionBuffer , result , lastLineIndex , currentLineIndex , beforeMode ) ;
82+ var linesRemoved = TryRemoveBufferContent ( removalBuffer , result , lastLineIndex , currentLineIndex ) ;
7883
79- if ( beforeMode )
84+ if ( linesAdded > 0 )
8085 {
81- beforeMode = false ;
86+ lastLineIndex = currentLineIndex + linesAdded ;
8287 }
8388
84- lastLineIndex = currentLineIndex + linesAdded ;
85- insertionBuffer . Clear ( ) ;
86- }
87- else
88- {
89- if ( mergeLine . Contains ( MacroBeforeMode ) )
89+ if ( linesRemoved > 0 )
9090 {
91- beforeMode = true ;
91+ lastLineIndex = currentLineIndex - linesRemoved ;
9292 }
93- else if ( mergeLine . Contains ( MacroStartGroup ) )
94- {
95- isInBlock = true ;
96- }
97- else if ( mergeLine . Contains ( MarcoEndGroup ) )
98- {
99- isInBlock = false ;
100- }
101- else if ( ! isInDocumentation && ( isInBlock || mergeLine == string . Empty ) )
93+
94+ if ( beforeMode )
10295 {
103- insertionBuffer . Add ( mergeLine . WithLeadingTrivia ( diffTrivia ) ) ;
96+ beforeMode = false ;
10497 }
105- else if ( mergeLine . Contains ( MacroStartDocumentation ) )
98+
99+ if ( linesRemoved == 0 && linesAdded == 0 )
106100 {
107- isInDocumentation = true ;
101+ lastLineIndex = currentLineIndex ;
108102 }
109- else if ( mergeLine . Contains ( MacroEndDocumentation ) )
103+
104+ insertionBuffer . Clear ( ) ;
105+ removalBuffer . Clear ( ) ;
106+ }
107+ else
108+ {
109+ // if line is not found check if merge direction, else add to buffer
110+ if ( IsMergeDirection ( mergeLine ) )
110111 {
111- isInDocumentation = false ;
112+ mergeMode = GetMergeMode ( mergeLine , mergeMode ) ;
112113 }
113- else if ( ! isInDocumentation )
114+ else
114115 {
115- errorLine = mergeLine ;
116- return source ;
116+ if ( mergeMode == MergeMode . Insert || mergeMode == MergeMode . InsertBefore || mergeLine == string . Empty )
117+ {
118+ if ( mergeMode == MergeMode . InsertBefore )
119+ {
120+ beforeMode = true ;
121+ }
122+
123+ insertionBuffer . Add ( mergeLine . WithLeadingTrivia ( diffTrivia ) ) ;
124+ }
125+ else if ( mergeMode == MergeMode . Remove )
126+ {
127+ removalBuffer . Add ( mergeLine . WithLeadingTrivia ( diffTrivia ) ) ;
128+ }
129+ else if ( mergeMode == MergeMode . Context )
130+ {
131+ errorLine = mergeLine ;
132+ return source ;
133+ }
117134 }
118135 }
119136 }
120137
121138 TryAddBufferContent ( insertionBuffer , result , lastLineIndex ) ;
139+ TryRemoveBufferContent ( removalBuffer , result , lastLineIndex ) ;
122140
123141 return result ;
124142 }
125143
126- // Removes anything from the target file that should be deleted.
127- public static List < string > HandleRemovals ( this IEnumerable < string > source , IEnumerable < string > merge )
144+ private static bool IsMergeDirection ( string mergeLine )
128145 {
129- var mergeString = string . Join ( Environment . NewLine , merge ) ;
130- var sourceString = string . Join ( Environment . NewLine , source ) ;
131-
132- var startIndex = mergeString . IndexOf ( MacroStartDelete , StringComparison . OrdinalIgnoreCase ) ;
133- var endIndex = mergeString . IndexOf ( MacroEndDelete , StringComparison . OrdinalIgnoreCase ) ;
146+ return macros . Any ( c => mergeLine . Contains ( c ) ) ;
147+ }
134148
135- while ( startIndex > 0 && endIndex > startIndex )
149+ private static MergeMode GetMergeMode ( string mergeLine , MergeMode current )
150+ {
151+ if ( mergeLine . Contains ( MacroBeforeMode ) )
136152 {
137- // VB uses a single character (') to start the comment, C# uses two (//)
138- int commentIndicatorLength = mergeString [ startIndex - 1 ] == '\' ' ? 1 : 2 ;
139-
140- var toRemove = mergeString . Substring (
141- ( startIndex - commentIndicatorLength ) + ( MacroStartDelete . Length + commentIndicatorLength ) ,
142- ( endIndex - commentIndicatorLength ) - ( startIndex - commentIndicatorLength ) - ( MacroStartDelete . Length + commentIndicatorLength ) ) ;
143-
144- sourceString = sourceString . Replace ( toRemove , string . Empty ) ;
145- mergeString = mergeString . Substring ( endIndex + MacroEndDelete . Length ) ;
146- startIndex = mergeString . IndexOf ( MacroStartDelete , StringComparison . InvariantCultureIgnoreCase ) ;
147- endIndex = mergeString . IndexOf ( MacroEndDelete , StringComparison . InvariantCultureIgnoreCase ) ;
153+ return MergeMode . InsertBefore ;
154+ }
155+ else if ( mergeLine . Contains ( MacroStartGroup ) )
156+ {
157+ if ( current == MergeMode . InsertBefore )
158+ {
159+ return MergeMode . InsertBefore ;
160+ }
161+ else
162+ {
163+ return MergeMode . Insert ;
164+ }
165+ }
166+ else if ( mergeLine . Contains ( MacroEndGroup ) )
167+ {
168+ return MergeMode . Context ;
169+ }
170+ else if ( mergeLine . Contains ( MacroStartDocumentation ) )
171+ {
172+ return MergeMode . Documentation ;
173+ }
174+ else if ( mergeLine . Contains ( MacroEndDocumentation ) )
175+ {
176+ return MergeMode . Context ;
177+ }
178+ else if ( mergeLine . Contains ( MacroStartDelete ) )
179+ {
180+ return MergeMode . Remove ;
181+ }
182+ else if ( mergeLine . Contains ( MacroEndDelete ) )
183+ {
184+ return MergeMode . Context ;
148185 }
149186
150- return sourceString . Split ( new [ ] { Environment . NewLine } , StringSplitOptions . None ) . ToList ( ) ;
187+ return current ;
151188 }
152189
153190 // Remove any comments from the merged file that indicate something should be removed.
@@ -198,6 +235,21 @@ private static int TryAddBufferContent(List<string> insertionBuffer, List<string
198235 return 0 ;
199236 }
200237
238+ private static int TryRemoveBufferContent ( List < string > removalBuffer , List < string > result , int lastLineIndex , int currentLineIndex = 0 )
239+ {
240+ if ( removalBuffer . Any ( ) && BlockExists ( removalBuffer , result , lastLineIndex ) && currentLineIndex > - 1 )
241+ {
242+ var index = result . SafeIndexOf ( removalBuffer [ 0 ] , lastLineIndex ) ;
243+ if ( index <= currentLineIndex )
244+ {
245+ result . RemoveRange ( index , removalBuffer . Count ) ;
246+ return removalBuffer . Count ;
247+ }
248+ }
249+
250+ return 0 ;
251+ }
252+
201253 private static void EnsureNoWhiteLinesNextToBraces ( List < string > insertionBuffer , List < string > result , int insertIndex )
202254 {
203255 if ( LastLineIsOpeningBrace ( result , insertIndex ) && insertionBuffer . First ( ) . Trim ( ) == string . Empty )
@@ -242,9 +294,9 @@ private static bool BlockExists(IEnumerable<string> blockBuffer, IEnumerable<str
242294 . All ( b => target . SafeIndexOf ( b , skip ) > - 1 ) ;
243295 }
244296
245- private static int GetInsertLineIndex ( int currentLine , int lastLine , bool isBeforeMode )
297+ private static int GetInsertLineIndex ( int currentLine , int lastLine , bool beforeMode )
246298 {
247- if ( isBeforeMode )
299+ if ( beforeMode )
248300 {
249301 return currentLine ;
250302 }
0 commit comments