Skip to content

Commit c88a736

Browse files
committed
自己实现editorconfig通配符算法
1 parent f125403 commit c88a736

File tree

13 files changed

+386
-31
lines changed

13 files changed

+386
-31
lines changed

CodeService/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ target_sources(CodeService
1919
${CodeService_SOURCE_DIR}/src/Config/LuaEditorConfig.cpp
2020
${CodeService_SOURCE_DIR}/src/Config/LuaDiagnosticStyle.cpp
2121
${CodeService_SOURCE_DIR}/src/Config/LanguageTranslator.cpp
22-
${CodeService_SOURCE_DIR}/src/Config/LanguageTranslator.cpp
22+
${CodeService_SOURCE_DIR}/src/Config/EditorconfigPattern.cpp
2323

2424
# format
2525
${CodeService_SOURCE_DIR}/src/Format/FormatBuilder.cpp
@@ -40,10 +40,10 @@ target_sources(CodeService
4040
${CodeService_SOURCE_DIR}/src/TypeFormat/LuaTypeFormatOptions.cpp
4141
# diagnostic
4242
${CodeService_SOURCE_DIR}/src/Diagnostic/DiagnosticBuilder.cpp
43-
# # diagnostic/nameStyle
43+
# diagnostic/nameStyle
4444
${CodeService_SOURCE_DIR}/src/Diagnostic/NameStyle/NameStyleChecker.cpp
4545
${CodeService_SOURCE_DIR}/src/Diagnostic/NameStyle/NameStyleRuleMatcher.cpp
46-
# # diagnostic/spell
46+
# diagnostic/spell
4747
${CodeService_SOURCE_DIR}/src/Diagnostic/Spell/CodeSpellChecker.cpp
4848
${CodeService_SOURCE_DIR}/src/Diagnostic/Spell/IdentifyParser.cpp
4949
${CodeService_SOURCE_DIR}/src/Diagnostic/Spell/TextParser.cpp
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#include "CodeService/Config/EditorconfigPattern.h"
2+
#include <algorithm>
3+
#include "LuaParser/Lexer/LuaDefine.h"
4+
#include "Util/StringUtil.h"
5+
6+
7+
EditorconfigPattern::EditorconfigPattern() {
8+
9+
}
10+
11+
void EditorconfigPattern::Compile(std::string_view pattern) {
12+
_patternSource = pattern;
13+
TextReader reader(_patternSource);
14+
while (true) {
15+
auto type = Lex(reader);
16+
if (type == MatchType::Eof) {
17+
break;
18+
}
19+
20+
auto &matchData = _matches.emplace_back(type);
21+
auto text = reader.GetSaveText();
22+
switch (type) {
23+
case MatchType::Path: {
24+
matchData.String = text;
25+
break;
26+
}
27+
case MatchType::AnyCharOf: {
28+
if (text.size() > 2) {
29+
text = text.substr(1, text.size() - 2);
30+
matchData.CharSet = std::set<char>(text.begin(), text.end());
31+
}
32+
break;
33+
}
34+
case MatchType::NotCharOf: {
35+
if (text.size() > 3) {
36+
text = text.substr(2, text.size() - 3);
37+
matchData.CharSet = std::set<char>(text.begin(), text.end());
38+
}
39+
break;
40+
}
41+
case MatchType::StringOf: {
42+
if (text.size() > 2) {
43+
text = text.substr(1, text.size() - 2);
44+
matchData.Strings = string_util::Split(text, ",");
45+
}
46+
break;
47+
}
48+
}
49+
}
50+
}
51+
52+
EditorconfigPattern::MatchType EditorconfigPattern::Lex(TextReader &reader) {
53+
reader.ResetBuffer();
54+
int ch = reader.GetCurrentChar();
55+
switch (ch) {
56+
case '*': {
57+
reader.SaveAndNext();
58+
if (reader.GetCurrentChar() == '*') {
59+
reader.SaveAndNext();
60+
return MatchType::AnyChars;
61+
}
62+
63+
return MatchType::AnyCharsExceptSep;
64+
}
65+
case '{': {
66+
reader.SaveAndNext();
67+
while (!reader.IsEof()) {
68+
ch = reader.GetCurrentChar();
69+
reader.SaveAndNext();
70+
if (ch == '}') {
71+
break;
72+
}
73+
}
74+
return MatchType::StringOf;
75+
}
76+
case '[': {
77+
reader.SaveAndNext();
78+
MatchType type = MatchType::AnyCharOf;
79+
if (reader.GetCurrentChar() == '!') {
80+
type = MatchType::NotCharOf;
81+
reader.SaveAndNext();
82+
}
83+
while (!reader.IsEof()) {
84+
ch = reader.GetCurrentChar();
85+
reader.SaveAndNext();
86+
if (ch == ']') {
87+
break;
88+
}
89+
}
90+
91+
return type;
92+
}
93+
case '?': {
94+
reader.SaveAndNext();
95+
return MatchType::AnyChar;
96+
}
97+
case EOZ: {
98+
return MatchType::Eof;
99+
}
100+
default: {
101+
reader.SaveAndNext();
102+
while (!reader.IsEof()) {
103+
ch = reader.GetCurrentChar();
104+
if (ch == '[' || ch == '{' || ch == '*') {
105+
break;
106+
}
107+
reader.SaveAndNext();
108+
}
109+
110+
return MatchType::Path;
111+
}
112+
}
113+
}
114+
115+
bool EditorconfigPattern::Match(std::string_view filePath) {
116+
if (filePath.empty()) {
117+
return false;
118+
}
119+
std::string newPath(filePath);
120+
for (auto &c: newPath) {
121+
if (c == '\\') {
122+
c = '/';
123+
}
124+
}
125+
std::string pathView = newPath;
126+
127+
std::size_t matchProcess = _matches.size();
128+
for (; matchProcess > 0; matchProcess--) {
129+
auto &matchData = _matches[matchProcess - 1];
130+
switch (matchData.Type) {
131+
case MatchType::Path: {
132+
if (!string_util::EndWith(pathView, matchData.String)) {
133+
return false;
134+
}
135+
pathView = pathView.substr(0, pathView.size() - matchData.String.size());
136+
break;
137+
}
138+
case MatchType::AnyCharsExceptSep: {
139+
std::size_t matchIndex = pathView.size();
140+
for (; matchIndex > 0; matchIndex--) {
141+
char ch = pathView[matchIndex - 1];
142+
if (ch == '/' || ch == '\\') {
143+
break;
144+
}
145+
}
146+
147+
if (matchProcess > 1) {
148+
auto &nextMatchData = _matches[matchProcess - 2];
149+
if (nextMatchData.Type == MatchType::Path) {
150+
auto pos = pathView.rfind(nextMatchData.String);
151+
if (pos == std::string_view::npos) {
152+
return false;
153+
}
154+
if (pos + nextMatchData.String.size() < matchIndex) {
155+
return false;
156+
}
157+
matchIndex = pos + nextMatchData.String.size();
158+
}
159+
}
160+
161+
pathView = pathView.substr(0, matchIndex);
162+
break;
163+
}
164+
case MatchType::AnyChars: {
165+
std::size_t matchIndex = 0;
166+
if (matchProcess > 1) {
167+
auto &nextMatchData = _matches[matchProcess - 2];
168+
if (nextMatchData.Type == MatchType::Path) {
169+
auto pos = pathView.rfind(nextMatchData.String);
170+
if (pos == std::string_view::npos) {
171+
return false;
172+
}
173+
matchIndex = pos + nextMatchData.String.size();
174+
}
175+
}
176+
177+
pathView = pathView.substr(0, matchIndex);
178+
break;
179+
}
180+
case MatchType::AnyChar: {
181+
if (pathView.empty()) {
182+
return false;
183+
}
184+
pathView = pathView.substr(0, pathView.size() - 1);
185+
break;
186+
}
187+
case MatchType::AnyCharOf: {
188+
if (pathView.empty()) {
189+
return false;
190+
}
191+
192+
if (matchData.CharSet.count(pathView.back()) == 0) {
193+
return false;
194+
}
195+
pathView = pathView.substr(0, pathView.size() - 1);
196+
break;
197+
}
198+
case MatchType::NotCharOf: {
199+
if (pathView.empty()) {
200+
return false;
201+
}
202+
203+
if (matchData.CharSet.count(pathView.back()) > 0) {
204+
return false;
205+
}
206+
pathView = pathView.substr(0, pathView.size() - 1);
207+
break;
208+
}
209+
case MatchType::StringOf: {
210+
bool match = false;
211+
for (auto &s: matchData.Strings) {
212+
if (string_util::EndWith(pathView, s)) {
213+
match = true;
214+
pathView = pathView.substr(0, pathView.size() - s.size());
215+
break;
216+
}
217+
}
218+
219+
if (!match) {
220+
return false;
221+
}
222+
break;
223+
}
224+
default: {
225+
return false;
226+
}
227+
}
228+
}
229+
230+
return matchProcess == 0;
231+
}
232+
233+
std::string_view EditorconfigPattern::GetPattern() {
234+
return _patternSource;
235+
}
236+
237+

CodeService/src/Config/LuaEditorConfig.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ LuaStyle &LuaEditorConfig::Generate(std::string_view filePath) {
6161
auto &pattern = _sections[i].Pattern;
6262

6363
// [*] [*.lua]
64-
if (pattern == "*" || pattern == "*.lua") {
64+
if (pattern.GetPattern() == "*" || pattern.GetPattern() == "*.lua") {
6565
patternSection.push_back(i);
6666
}
6767
// [{test.lua,lib.lua}]
68-
else if (string_util::FileWildcardMatch(filePath, pattern)) {
68+
else if (pattern.Match(filePath)) {
6969
patternSection.push_back(i);
7070
}
7171
}
@@ -89,4 +89,4 @@ LuaStyle &LuaEditorConfig::Generate(std::string_view filePath) {
8989
}
9090

9191
return luaStyle;
92-
}
92+
}

CodeService/src/Format/Analyzer/IndentationAnalyzer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ void IndentationAnalyzer::AnalyzeExprList(FormatState &f, LuaSyntaxNode &exprLis
147147
|| syntaxKind == LuaSyntaxNodeKind::StringLiteralExpression) {
148148
return;
149149
}
150+
// if()
150151
}
151152
Indenter(exprList, t, IndentData(
152153
IndentType::Standard,

LuaParser/src/Lexer/TextReader.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ TextReader::TextReader(std::string_view text)
66
: _text(text),
77
_hasSaveText(false),
88
_buffStart(0), _buffIndex(0),
9-
_hasEoz(false),
9+
_isEof(false),
1010
_currentIndex(0) {
1111
}
1212

@@ -23,7 +23,7 @@ void TextReader::SaveAndNext() {
2323
Save();
2424
int ch = NextChar();
2525
if (ch == EOZ) {
26-
_hasEoz = true;
26+
_isEof = true;
2727
}
2828
}
2929

@@ -36,7 +36,7 @@ void TextReader::Save() {
3636
}
3737

3838
int TextReader::GetCurrentChar() {
39-
if (!_hasEoz && _currentIndex < _text.size()) {
39+
if (!_isEof && _currentIndex < _text.size()) {
4040
unsigned char ch = _text[_currentIndex];
4141
return ch;
4242
}
@@ -83,3 +83,7 @@ std::string_view TextReader::GetSaveText() const {
8383
}
8484
return _text.substr(_buffStart, 0);
8585
}
86+
87+
bool TextReader::IsEof() const {
88+
return _isEof;
89+
}

Test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ target_sources(CodeFormatTest
2121
src/Performance_unitest.cpp
2222
src/RangeFormat_unitest.cpp
2323
src/FormatStyle_unitest.cpp
24+
src/FilePattern_unitest.cpp
2425
)
2526

2627
target_link_libraries(CodeFormatTest CodeService Util gtest)

Test/src/FilePattern_unitest.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <gtest/gtest.h>
2+
#include "TestHelper.h"
3+
4+
TEST(FilePattern, simple) {
5+
EXPECT_TRUE(TestHelper::TestPattern("*", ".lua"));
6+
EXPECT_TRUE(TestHelper::TestPattern("*", ".txt"));
7+
8+
EXPECT_TRUE(TestHelper::TestPattern("*.lua", ".lua"));
9+
EXPECT_TRUE(TestHelper::TestPattern("*.lua", "1.lua"));
10+
EXPECT_TRUE(TestHelper::TestPattern("*.lua", "哈哈.lua"));
11+
EXPECT_TRUE(TestHelper::TestPattern("*.lua", "1/1.lua"));
12+
EXPECT_TRUE(TestHelper::TestPattern("*.lua", "ogjogieoirg.lua"));
13+
EXPECT_TRUE(TestHelper::TestPattern("*.lua", "1\\1.lua"));
14+
15+
EXPECT_TRUE(TestHelper::TestPattern("**.lua", ".lua"));
16+
EXPECT_TRUE(TestHelper::TestPattern("**.lua", "1.lua"));
17+
EXPECT_TRUE(TestHelper::TestPattern("**.lua", "哈哈.lua"));
18+
EXPECT_TRUE(TestHelper::TestPattern("**.lua", "1/1.lua"));
19+
EXPECT_TRUE(TestHelper::TestPattern("**.lua", "ogjogieoirg.lua"));
20+
EXPECT_TRUE(TestHelper::TestPattern("**.lua", "1\\1.lua"));
21+
22+
EXPECT_TRUE(TestHelper::TestPattern("Content/*.lua", "Content/1.lua"));
23+
EXPECT_FALSE(TestHelper::TestPattern("Content/*.lua", "Content2/1.lua"));
24+
EXPECT_FALSE(TestHelper::TestPattern("Content/*.lua", "Content/1/1.lua"));
25+
EXPECT_FALSE(TestHelper::TestPattern("Content/*.lua", "1.lua"));
26+
EXPECT_TRUE(TestHelper::TestPattern("Content/aaa*.lua", "Content/aaa.lua"));
27+
EXPECT_TRUE(TestHelper::TestPattern("Content/aaa*.lua", "Content/aaaAAAAAA.lua"));
28+
EXPECT_FALSE(TestHelper::TestPattern("Content/aaa*.lua", "aaaAAAAAA.lua"));
29+
30+
EXPECT_FALSE(TestHelper::TestPattern("Content/**.lua", "aaaAAAAAA.lua"));
31+
EXPECT_TRUE(TestHelper::TestPattern("Content/**.lua", "Content/1.lua"));
32+
EXPECT_TRUE(TestHelper::TestPattern("Content/**.lua", "Content/1/1.lua"));
33+
EXPECT_FALSE(TestHelper::TestPattern("Content/**.lua", "Content2/1/1.lua"));
34+
35+
EXPECT_FALSE(TestHelper::TestPattern("?abc.lua", "abc.lua"));
36+
EXPECT_TRUE(TestHelper::TestPattern("?abc.lua", "Dabc.lua"));
37+
EXPECT_TRUE(TestHelper::TestPattern("?abc.lua", "/abc.lua"));
38+
39+
EXPECT_TRUE(TestHelper::TestPattern("[abc]bc.lua", "abc.lua"));
40+
EXPECT_FALSE(TestHelper::TestPattern("[!a]bc.lua", "abc.lua"));
41+
}
42+
43+

Test/src/TestHelper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ LuaParser TestHelper::GetParser(std::string input) {
8787
return std::move(p);
8888
}
8989

90+
bool TestHelper::TestPattern(std::string_view pattern, std::string_view path) {
91+
EditorconfigPattern p;
92+
p.Compile(pattern);
93+
94+
return p.Match(path);
95+
}
96+

Test/src/TestHelper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class TestHelper {
2929
static void
3030
CollectLuaFile(std::filesystem::path directoryPath, std::vector<std::string> &paths, std::filesystem::path &root);
3131

32+
static bool TestPattern(std::string_view pattern, std::string_view path);
33+
3234
static std::string ScriptBase;
3335

3436
static LuaStyle DefaultStyle;

0 commit comments

Comments
 (0)