Skip to content

Commit 2779e83

Browse files
authored
Merge pull request #46 from dakotahawkins/feature/sort_remove-duplicates
Add option (on by default) to remove duplicates
2 parents 2e88080 + 2fc8482 commit 2779e83

6 files changed

Lines changed: 111 additions & 18 deletions

File tree

IncludeToolbox.vsix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:96da2600a661f022024c446771873504e6aec1d77a25c0f0268adbe1e7dcb784
3-
size 127921
2+
oid sha256:77be8c5da4736b2179aefe8d63416b22e9669705abb3b737253894c7e5ce1d9d
3+
size 127968

IncludeToolbox/Formatter/IncludeFormatter.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,15 @@ private static bool SortIncludeBatch(FormatterOptionsPage settings, string[] pre
134134
// order when rearranged by regex precedence groups.
135135
var includeLines = includeBatch
136136
.Where(x => x.ContainsActiveInclude)
137-
.OrderBy(x => x.IncludeContent);
137+
.OrderBy(x => x.IncludeContent)
138+
.ToList();
139+
140+
if (settings.RemoveDuplicates)
141+
{
142+
HashSet<string> uniqueIncludes = new HashSet<string>();
143+
includeLines.RemoveAll(x => !x.ShouldBePreserved &&
144+
!uniqueIncludes.Add(x.GetIncludeContentWithDelimiters()));
145+
}
138146

139147
// Group the includes by the index of the precedence regex they match, or
140148
// precedenceRegexes.Length for no match, and sort the groups by index.
@@ -176,7 +184,7 @@ private static bool SortIncludeBatch(FormatterOptionsPage settings, string[] pre
176184

177185
foreach (var sortedLine in sortedIncludes)
178186
{
179-
// Advance until there is a include line to replace. There *must* be one left if sortedIncludes is not empty.
187+
// Advance until there is an include line to replace. There *must* be one left if sortedIncludes is not empty.
180188
while (!originalLineEnumerator.Current.ContainsActiveInclude)
181189
{
182190
outSortedList.Add(originalLineEnumerator.Current);
@@ -198,6 +206,13 @@ private static bool SortIncludeBatch(FormatterOptionsPage settings, string[] pre
198206
outSortedList.Add(sortedLine);
199207
firstLine = false;
200208
}
209+
210+
while (hasElements)
211+
{
212+
if (!originalLineEnumerator.Current.ContainsActiveInclude)
213+
outSortedList.Add(originalLineEnumerator.Current);
214+
hasElements = originalLineEnumerator.MoveNext();
215+
}
201216
}
202217

203218
return true;

IncludeToolbox/Formatter/IncludeLineInfo.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public static List<IncludeLineInfo> ParseIncludes(string text, ParseOptions opti
7878
++openMultiLineComments;
7979
commentedSectionStart = multiLineCommentStart;
8080
}
81-
81+
8282
int multiLineCommentEnd = lineText.IndexOf("*/");
8383
if (multiLineCommentEnd > -1)
8484
{
@@ -109,7 +109,7 @@ public static List<IncludeLineInfo> ParseIncludes(string text, ParseOptions opti
109109
int includeOccurence = lineText.IndexOf("#include");
110110

111111
// Not a valid include.
112-
if (includeOccurence == -1 || // Include not found
112+
if (includeOccurence == -1 || // Include not found
113113
isCommented(includeOccurence) || // Include commented out
114114
openIfdefs > 0) // Inside an #ifdef block
115115
{
@@ -204,11 +204,11 @@ public void SetDelimiterType(DelimiterType newDelimiterType)
204204
}
205205

206206
/// <summary>
207-
/// Wheather the line contains a preprocessor directive.
207+
/// Whether the line contains a preprocessor directive.
208208
/// Does not take into account surrounding block comments.
209209
/// </summary>
210210
public bool ContainsPreProcessorDirective
211-
{
211+
{
212212
get
213213
{
214214
// In theory the '#' of a preprocessor directive MUST come first, but just like MSVC we relax the rules a bit here.
@@ -270,7 +270,7 @@ public string GetIncludeContentWithDelimiters()
270270

271271

272272
/// <summary>
273-
/// Changes in the include content will NOT be reflected immediately in the raw line text.
273+
/// Changes in the include content will NOT be reflected immediately in the raw line text.
274274
/// </summary>
275275
/// <see cref="UpdateRawLineWithIncludeContentChanges"/>
276276
public string IncludeContent

IncludeToolbox/Options/FormatterOptionsPage.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ public enum TypeSorting
100100
[Description("Optionally put either includes with angle brackets <...> or quotes \"...\" first.")]
101101
public TypeSorting SortByType { get; set; } = TypeSorting.QuotedFirst;
102102

103+
[Category("Sorting")]
104+
[DisplayName("Remove duplicates")]
105+
[Description("If true, duplicate includes will be removed.")]
106+
public bool RemoveDuplicates { get; set; } = true;
107+
103108
#endregion
104109

105110
public override void SaveSettingsToStorage()
@@ -121,6 +126,7 @@ public override void SaveSettingsToStorage()
121126
var value = string.Join("\n", PrecedenceRegexes);
122127
settingsStore.SetString(collectionName, nameof(PrecedenceRegexes), value);
123128
settingsStore.SetInt32(collectionName, nameof(SortByType), (int)SortByType);
129+
settingsStore.SetBoolean(collectionName, nameof(RemoveDuplicates), RemoveDuplicates);
124130
}
125131

126132
public override void LoadSettingsFromStorage()
@@ -150,6 +156,8 @@ public override void LoadSettingsFromStorage()
150156
}
151157
if (settingsStore.PropertyExists(collectionName, nameof(SortByType)))
152158
SortByType = (TypeSorting) settingsStore.GetInt32(collectionName, nameof(SortByType));
159+
if (settingsStore.PropertyExists(collectionName, nameof(RemoveDuplicates)))
160+
RemoveDuplicates = settingsStore.GetBoolean(collectionName, nameof(RemoveDuplicates));
153161
}
154162
}
155163
}

IncludeToolbox/Package/source.extension.vsixmanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
33
<Metadata>
4-
<Identity Id="IncludeToolbox.Andreas Reich.075c2e2b-7b71-45ba-b2e6-c1dadc81cfac" Version="2.2.0" Language="en-US" Publisher="Andreas Reich" />
4+
<Identity Id="IncludeToolbox.Andreas Reich.075c2e2b-7b71-45ba-b2e6-c1dadc81cfac" Version="2.2.0.1" Language="en-US" Publisher="Andreas Reich" />
55
<DisplayName>IncludeToolbox</DisplayName>
66
<Description xml:space="preserve">Various tools for managing C/C++ #includes: Formatting, sorting, exploring, pruning.</Description>
77
<License>license.txt</License>

Tests/IncludeFormatingTest.cs

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,29 @@ public class IncludeFormatingTest
1010
private static string sourceCode_NoBlanks =
1111
@"#include ""a.h""
1212
#include <b.hpp>
13+
#include ""a.h""
1314
#include ""filename.h""
15+
#include <b.hpp>
1416
#include <d_firstanyways>
1517
#include <e_secondanyways>
16-
#include <c.hpp>";
18+
#include <e_secondanyways>
19+
#include <c.hpp>
20+
#include <d_firstanyways>";
1721

1822
private static string sourceCode_WithBlanks =
1923
@"#include ""c_third""
2024
2125
#include ""filename.h""
2226
27+
#include ""z_first""
28+
29+
#include <b_second>
2330
#include <b_second>
2431
// A comment
25-
#include ""z_first""";
32+
#include ""z_first""
2633
34+
#include <b_second>
35+
#include ""filename.h""";
2736

2837
[TestMethod]
2938
public void Sorting_BlanksAfterRegexGroup()
@@ -45,8 +54,10 @@ public void Sorting_BlanksAfterRegexGroup()
4554
#include <b_second>
4655
4756
#include ""c_third""
57+
58+
#include ""z_first""
4859
// A comment
49-
#include ""z_first""";
60+
";
5061

5162

5263
var settings = new IncludeToolbox.FormatterOptionsPage();
@@ -85,8 +96,10 @@ public void Sorting_AngleBracketsFirst()
8596
#include ""filename.h""
8697
8798
#include ""c_third""
99+
100+
#include ""z_first""
88101
// A comment
89-
#include ""z_first""";
102+
";
90103

91104

92105
var settings = new IncludeToolbox.FormatterOptionsPage();
@@ -106,15 +119,64 @@ public void Sorting_AngleBracketsFirst()
106119
}
107120

108121
[TestMethod]
109-
public void RemoveEmptyLines()
122+
public void Sorting_DontRemoveDuplicates()
110123
{
124+
// With sort by type.
125+
string expectedFormatedCode_NoBlanks =
126+
@"#include ""filename.h""
127+
128+
#include <d_firstanyways>
129+
#include <d_firstanyways>
130+
#include <e_secondanyways>
131+
#include <e_secondanyways>
132+
133+
#include ""a.h""
134+
#include ""a.h""
135+
#include <b.hpp>
136+
#include <b.hpp>
137+
#include <c.hpp>";
138+
139+
111140
string expectedFormatedCode_WithBlanks =
112141
@"#include ""filename.h""
142+
#include ""filename.h""
143+
144+
#include <b_second>
145+
#include <b_second>
113146
#include <b_second>
114-
#include ""c_third""
115147
// A comment
148+
#include ""c_third""
149+
#include ""z_first""
116150
#include ""z_first""";
117151

152+
153+
var settings = new IncludeToolbox.FormatterOptionsPage();
154+
settings.SortByType = IncludeToolbox.FormatterOptionsPage.TypeSorting.None;
155+
settings.PrecedenceRegexes = new string[]
156+
{
157+
IncludeToolbox.RegexUtils.CurrentFileNameKey,
158+
".+_.+"
159+
};
160+
settings.BlankAfterRegexGroupMatch = true;
161+
settings.RemoveEmptyLines = true;
162+
settings.RemoveDuplicates = false;
163+
164+
string formatedCode = IncludeFormatter.FormatIncludes(sourceCode_NoBlanks, "filename.cpp", new string[] { }, settings);
165+
Assert.AreEqual(expectedFormatedCode_NoBlanks, formatedCode);
166+
formatedCode = IncludeFormatter.FormatIncludes(sourceCode_WithBlanks, "filename.cpp", new string[] { }, settings);
167+
Assert.AreEqual(expectedFormatedCode_WithBlanks, formatedCode);
168+
}
169+
170+
[TestMethod]
171+
public void RemoveEmptyLines()
172+
{
173+
string expectedFormatedCode_WithBlanks =
174+
@"#include ""filename.h""
175+
#include <b_second>
176+
#include ""c_third""
177+
#include ""z_first""
178+
// A comment";
179+
118180
var settings = new IncludeToolbox.FormatterOptionsPage();
119181
settings.SortByType = IncludeToolbox.FormatterOptionsPage.TypeSorting.None;
120182
settings.PrecedenceRegexes = new string[] { IncludeToolbox.RegexUtils.CurrentFileNameKey };
@@ -148,13 +210,16 @@ public void OtherPreprocessorDirectives()
148210
@"#pragma once
149211
// SomeComment
150212
#include ""z""
213+
#include <b>
151214
152215
#include ""filename.h""
153216
154217
#if test
155218
#include <d>
156219
// A comment
157220
#include ""a9""
221+
#include <d>
222+
#include <c>
158223
#else
159224
#include <d>
160225
@@ -163,17 +228,21 @@ public void OtherPreprocessorDirectives()
163228
164229
#include <a2>
165230
#endif
231+
#include <b>
166232
#include <a1>";
167233

168234
string expectedFormatedCode =
169235
@"#pragma once
170236
// SomeComment
237+
#include <b>
171238
#include ""filename.h""
172239
173240
#include ""z""
241+
174242
#if test
175-
#include <d>
243+
#include <c>
176244
// A comment
245+
#include <d>
177246
#include ""a9""
178247
#else
179248
#include <a2>
@@ -183,7 +252,8 @@ public void OtherPreprocessorDirectives()
183252
184253
#include <d>
185254
#endif
186-
#include <a1>";
255+
#include <a1>
256+
#include <b>";
187257

188258
var settings = new IncludeToolbox.FormatterOptionsPage();
189259
settings.SortByType = IncludeToolbox.FormatterOptionsPage.TypeSorting.AngleBracketsFirst;

0 commit comments

Comments
 (0)