Skip to content

Commit fe1a9c6

Browse files
authored
Merge pull request #5912 from retailcoder/next
Introduce ISimpleIndenter
2 parents 0787e31 + f121ba8 commit fe1a9c6

File tree

6 files changed

+261
-242
lines changed

6 files changed

+261
-242
lines changed

Rubberduck.SmartIndenter/AbsoluteCodeLine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Rubberduck.SmartIndenter
99
{
10-
internal class AbsoluteCodeLine
10+
public class AbsoluteCodeLine
1111
{
1212
private const string StupidLineEnding = ": _";
1313
private static readonly Regex LineNumberRegex = new Regex(@"^(?<number>(-?\d+)|(&H[0-9A-F]{1,8}))(?<separator>:)?\s+(?<code>.*)", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);

Rubberduck.SmartIndenter/IIndenter.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
using System.Collections.Generic;
2-
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
1+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
32

43
namespace Rubberduck.SmartIndenter
54
{
6-
public interface IIndenter
5+
6+
public interface IIndenter : ISimpleIndenter
77
{
88
void IndentCurrentProcedure();
99
void IndentCurrentModule();
1010
void IndentCurrentProject();
1111
void Indent(IVBComponent component);
12-
IEnumerable<string> Indent(string code);
13-
IEnumerable<string> Indent(IEnumerable<string> lines);
14-
IEnumerable<string> Indent(IEnumerable<string> codeLines, bool forceTrailingNewLines);
1512
}
1613
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
3+
namespace Rubberduck.SmartIndenter
4+
{
5+
public interface ISimpleIndenter
6+
{
7+
IEnumerable<string> Indent(string code, IIndenterSettings settings = null);
8+
IEnumerable<string> Indent(IEnumerable<string> lines, IIndenterSettings settings = null);
9+
IEnumerable<string> Indent(IEnumerable<string> codeLines, bool forceTrailingNewLines, IIndenterSettings settings = null);
10+
}
11+
}

Rubberduck.SmartIndenter/Indenter.cs

Lines changed: 5 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
42
using Rubberduck.VBEditor;
53
using Rubberduck.VBEditor.SafeComWrappers;
64
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
75

86
namespace Rubberduck.SmartIndenter
97
{
10-
public class Indenter : IIndenter
8+
public sealed class Indenter : SimpleIndenter, IIndenter
119
{
1210
private readonly IVBE _vbe;
1311
private readonly Func<IIndenterSettings> _settings;
@@ -18,6 +16,8 @@ public Indenter(IVBE vbe, Func<IIndenterSettings> settings)
1816
_settings = settings;
1917
}
2018

19+
protected override Func<IIndenterSettings> Settings => _settings;
20+
2121
/// <summary>
2222
/// Indents the procedure selected in the ActiveCodePane. If more than one is selected, the first is indented.
2323
/// </summary>
@@ -152,7 +152,7 @@ public void Indent(IVBComponent component)
152152
}
153153

154154
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());
156156

157157
module.DeleteLines(1, lineCount);
158158
module.InsertLines(1, string.Join("\r\n", indented));
@@ -180,7 +180,7 @@ private void Indent(IVBComponent component, Selection selection, bool procedure
180180
var codeLines = module.GetLines(selection.StartLine, selection.LineCount).Replace("\r", string.Empty)
181181
.Split('\n');
182182

183-
var indented = Indent(codeLines, false, procedure);
183+
var indented = Indent(codeLines, false, procedure, _settings.Invoke());
184184

185185
var start = selection.StartLine;
186186
var lines = selection.LineCount;
@@ -190,234 +190,5 @@ private void Indent(IVBComponent component, Selection selection, bool procedure
190190
module.InsertLines(start, string.Join("\r\n", indented));
191191
}
192192
}
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-
}
422193
}
423194
}

Rubberduck.SmartIndenter/LogicalCodeLine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Rubberduck.SmartIndenter
77
{
8-
internal class LogicalCodeLine
8+
public class LogicalCodeLine
99
{
1010
private readonly List<AbsoluteCodeLine> _lines = new List<AbsoluteCodeLine>();
1111
private AbsoluteCodeLine _rebuilt;

0 commit comments

Comments
 (0)