1
1
using System ;
2
- using System . Collections . Generic ;
3
- using System . Linq ;
4
2
using Rubberduck . VBEditor ;
5
3
using Rubberduck . VBEditor . SafeComWrappers ;
6
4
using Rubberduck . VBEditor . SafeComWrappers . Abstract ;
7
5
8
6
namespace Rubberduck . SmartIndenter
9
7
{
10
- public class Indenter : IIndenter
8
+ public sealed class Indenter : SimpleIndenter , IIndenter
11
9
{
12
10
private readonly IVBE _vbe ;
13
11
private readonly Func < IIndenterSettings > _settings ;
@@ -18,6 +16,8 @@ public Indenter(IVBE vbe, Func<IIndenterSettings> settings)
18
16
_settings = settings ;
19
17
}
20
18
19
+ protected override Func < IIndenterSettings > Settings => _settings ;
20
+
21
21
/// <summary>
22
22
/// Indents the procedure selected in the ActiveCodePane. If more than one is selected, the first is indented.
23
23
/// </summary>
@@ -152,7 +152,7 @@ public void Indent(IVBComponent component)
152
152
}
153
153
154
154
var codeLines = module . GetLines ( 1 , lineCount ) . Replace ( "\r " , string . Empty ) . Split ( '\n ' ) ;
155
- var indented = Indent ( codeLines , true ) ;
155
+ var indented = Indent ( codeLines , true , _settings . Invoke ( ) ) ;
156
156
157
157
module . DeleteLines ( 1 , lineCount ) ;
158
158
module . InsertLines ( 1 , string . Join ( "\r \n " , indented ) ) ;
@@ -180,7 +180,7 @@ private void Indent(IVBComponent component, Selection selection, bool procedure
180
180
var codeLines = module . GetLines ( selection . StartLine , selection . LineCount ) . Replace ( "\r " , string . Empty )
181
181
. Split ( '\n ' ) ;
182
182
183
- var indented = Indent ( codeLines , false , procedure ) ;
183
+ var indented = Indent ( codeLines , false , procedure , _settings . Invoke ( ) ) ;
184
184
185
185
var start = selection . StartLine ;
186
186
var lines = selection . LineCount ;
@@ -190,234 +190,5 @@ private void Indent(IVBComponent component, Selection selection, bool procedure
190
190
module . InsertLines ( start , string . Join ( "\r \n " , indented ) ) ;
191
191
}
192
192
}
193
-
194
- private IEnumerable < LogicalCodeLine > BuildLogicalCodeLines ( IEnumerable < string > lines , out IIndenterSettings settings )
195
- {
196
- settings = _settings . Invoke ( ) ;
197
- var logical = new List < LogicalCodeLine > ( ) ;
198
- LogicalCodeLine current = null ;
199
- AbsoluteCodeLine previous = null ;
200
-
201
- foreach ( var line in lines )
202
- {
203
- var absolute = new AbsoluteCodeLine ( line , settings , previous ) ;
204
- if ( current == null )
205
- {
206
- current = new LogicalCodeLine ( absolute , settings ) ;
207
- logical . Add ( current ) ;
208
- }
209
- else
210
- {
211
- current . AddContinuationLine ( absolute ) ;
212
- }
213
-
214
- if ( ! absolute . HasContinuation )
215
- {
216
- current = null ;
217
- }
218
- previous = absolute ;
219
- }
220
- return logical ;
221
- }
222
-
223
- /// <summary>
224
- /// Indents the code contained in the passed string. NOTE: This overload should only be used on procedures or modules.
225
- /// </summary>
226
- /// <param name="code">The code block to indent</param>
227
- /// <returns>Indented code lines</returns>
228
- public IEnumerable < string > Indent ( string code )
229
- {
230
- return Indent ( code . Replace ( "\r " , string . Empty ) . Split ( '\n ' ) , false ) ;
231
- }
232
-
233
- /// <summary>
234
- /// Indents a range of code lines. NOTE: If inserting procedures, use the forceTrailingNewLines overload to preserve vertical spacing in the module.
235
- /// Do not call directly on selections. Use Indent(IVBComponent, Selection) instead.
236
- /// </summary>
237
- /// <param name="codeLines">Code lines to indent</param>
238
- /// <returns>Indented code lines</returns>
239
- public IEnumerable < string > Indent ( IEnumerable < string > codeLines )
240
- {
241
- return Indent ( codeLines , false ) ;
242
- }
243
-
244
- /// <summary>
245
- /// Indents a range of code lines. Do not call directly on selections. Use Indent(IVBComponent, Selection) instead.
246
- /// </summary>
247
- /// <param name="codeLines">Code lines to indent</param>
248
- /// <param name="forceTrailingNewLines">If true adds a number of blank lines after the last procedure based on VerticallySpaceProcedures settings</param>
249
- /// <returns>Indented code lines</returns>
250
- public IEnumerable < string > Indent ( IEnumerable < string > codeLines , bool forceTrailingNewLines )
251
- {
252
- return Indent ( codeLines , forceTrailingNewLines , false ) ;
253
- }
254
-
255
- private IEnumerable < string > Indent ( IEnumerable < string > codeLines , bool forceTrailingNewLines , bool procedure )
256
- {
257
- var logical = BuildLogicalCodeLines ( codeLines , out var settings ) . ToList ( ) ;
258
- var indents = 0 ;
259
- var start = false ;
260
- var enumStart = false ;
261
- var inEnumType = false ;
262
- var inProcedure = false ;
263
-
264
- foreach ( var line in logical )
265
- {
266
- inEnumType &= ! line . IsEnumOrTypeEnd ;
267
- if ( inEnumType )
268
- {
269
- line . AtEnumTypeStart = enumStart ;
270
- enumStart = line . IsCommentBlock ;
271
- line . IsEnumOrTypeMember = true ;
272
- line . InsideProcedureTypeOrEnum = true ;
273
- line . IndentationLevel = line . EnumTypeIndents ;
274
- continue ;
275
- }
276
-
277
- if ( line . IsProcedureStart )
278
- {
279
- inProcedure = true ;
280
- }
281
- line . InsideProcedureTypeOrEnum = inProcedure || enumStart ;
282
- inProcedure = inProcedure && ! line . IsProcedureEnd && ! line . IsEnumOrTypeEnd ;
283
- if ( line . IsProcedureStart || line . IsEnumOrTypeStart )
284
- {
285
- indents = 0 ;
286
- }
287
-
288
- line . AtProcedureStart = start ;
289
- line . IndentationLevel = indents - line . Outdents ;
290
- indents += line . NextLineIndents ;
291
- start = line . IsProcedureStart ||
292
- line . AtProcedureStart && line . IsDeclaration ||
293
- line . AtProcedureStart && line . IsCommentBlock ||
294
- settings . IgnoreEmptyLinesInFirstBlocks && line . AtProcedureStart && line . IsEmpty ;
295
- inEnumType = line . IsEnumOrTypeStart ;
296
- enumStart = inEnumType ;
297
- }
298
-
299
- return GenerateCodeLineStrings ( logical , forceTrailingNewLines , procedure ) ;
300
- }
301
-
302
- private IEnumerable < string > GenerateCodeLineStrings ( IEnumerable < LogicalCodeLine > logical , bool forceTrailingNewLines , bool procedure = false )
303
- {
304
- var output = new List < string > ( ) ;
305
- var settings = _settings . Invoke ( ) ;
306
-
307
- List < LogicalCodeLine > indent ;
308
- if ( ! procedure && settings . VerticallySpaceProcedures )
309
- {
310
- indent = new List < LogicalCodeLine > ( ) ;
311
- var lines = logical . ToArray ( ) ;
312
- var header = true ;
313
- var inEnumType = false ;
314
- var propertyGroupIdentifier = string . Empty ;
315
-
316
- for ( var i = 0 ; i < lines . Length ; i ++ )
317
- {
318
- indent . Add ( lines [ i ] ) ;
319
-
320
- if ( header && lines [ i ] . IsEnumOrTypeStart )
321
- {
322
- inEnumType = true ;
323
- }
324
- if ( header && lines [ i ] . IsEnumOrTypeEnd )
325
- {
326
- inEnumType = false ;
327
- }
328
-
329
- if ( header && ! inEnumType && lines [ i ] . IsProcedureStart )
330
- {
331
- header = false ;
332
- SpaceHeader ( indent , settings ) ;
333
-
334
- propertyGroupIdentifier = lines [ i ] . IsPropertyStart
335
- ? ExtractPropertyIdentifier ( lines [ i ] . ToString ( ) )
336
- : string . Empty ;
337
-
338
- continue ;
339
- }
340
- if ( ! lines [ i ] . IsEnumOrTypeEnd && ! lines [ i ] . IsProcedureEnd )
341
- {
342
- continue ;
343
- }
344
-
345
- while ( ++ i < lines . Length && lines [ i ] . IsEmpty ) { }
346
- if ( i != lines . Length )
347
- {
348
- var linesBetweenProcedures = settings . LinesBetweenProcedures ;
349
-
350
- if ( lines [ i ] . IsPropertyStart )
351
- {
352
- var propertyIdentifier = ExtractPropertyIdentifier ( lines [ i ] . ToString ( ) ) ;
353
- if ( propertyIdentifier . Equals ( propertyGroupIdentifier , StringComparison . InvariantCultureIgnoreCase )
354
- && settings . GroupRelatedProperties )
355
- {
356
- linesBetweenProcedures = 0 ;
357
- }
358
- else
359
- {
360
- propertyGroupIdentifier = propertyIdentifier ;
361
- }
362
- }
363
-
364
- if ( linesBetweenProcedures > 0 )
365
- {
366
- indent . Add ( new LogicalCodeLine ( Enumerable . Repeat ( new AbsoluteCodeLine ( string . Empty , settings ) , linesBetweenProcedures ) , settings ) ) ;
367
- }
368
-
369
- indent . Add ( lines [ i ] ) ;
370
- }
371
- else if ( forceTrailingNewLines && i == lines . Length )
372
- {
373
- indent . Add ( new LogicalCodeLine ( Enumerable . Repeat ( new AbsoluteCodeLine ( string . Empty , settings ) , Math . Max ( settings . LinesBetweenProcedures , 1 ) ) , settings ) ) ;
374
- }
375
- }
376
- }
377
- else
378
- {
379
- indent = logical . ToList ( ) ;
380
- }
381
-
382
- foreach ( var line in indent )
383
- {
384
- output . AddRange ( line . Indented ( ) . Split ( new [ ] { Environment . NewLine } , StringSplitOptions . None ) ) ;
385
- }
386
- return output ;
387
- }
388
-
389
- private static string ExtractPropertyIdentifier ( string line )
390
- {
391
- var declarationElementsStartingAtGetLetOrSet = line . ToString ( ) . Split ( ' ' ) . SkipWhile ( c => ! c . EndsWith ( "et" ) ) . ToArray ( ) ;
392
- return declarationElementsStartingAtGetLetOrSet [ 1 ] . Split ( new string [ ] { "(" } , StringSplitOptions . None ) . FirstOrDefault ( ) ;
393
- }
394
-
395
- private static void SpaceHeader ( IList < LogicalCodeLine > header , IIndenterSettings settings )
396
- {
397
- var commentSkipped = false ;
398
- var commentLines = 0 ;
399
- for ( var i = header . Count - 2 ; i >= 0 ; i -- )
400
- {
401
- if ( ! commentSkipped && header [ i ] . IsCommentBlock )
402
- {
403
- commentLines ++ ;
404
- continue ;
405
- }
406
-
407
- commentSkipped = true ;
408
- if ( header [ i ] . IsEmpty )
409
- {
410
- header . RemoveAt ( i ) ;
411
- }
412
- else
413
- {
414
- header . Insert ( header . Count - 1 - commentLines ,
415
- new LogicalCodeLine (
416
- Enumerable . Repeat ( new AbsoluteCodeLine ( string . Empty , settings ) ,
417
- settings . LinesBetweenProcedures ) , settings ) ) ;
418
- return ;
419
- }
420
- }
421
- }
422
193
}
423
194
}
0 commit comments