Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Merge pull request #6 from atom/normalize-path-separators
Browse files Browse the repository at this point in the history
Allow _ and \ to match path separators
  • Loading branch information
rafeca authored Jul 2, 2019
2 parents c089336 + 2470b25 commit cff4808
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 8 deletions.
76 changes: 75 additions & 1 deletion spec/fuzzy-native-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,79 @@ describe('fuzzy-native', function() {
expect(matcher.match('ac').length).toBe(2);
matcher.setCandidates([0, 0], ['abc', 'abc']);
expect(matcher.match('ac').length).toBe(1);
})
});

it('returns matches when using different path separators', () => {
expect(
values(matcher.match('path1_path2_path3_zzz', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz',
]);
expect(
values(matcher.match('path1_path2_path3_zzz', {caseSensitive: false}))
).toEqual([
'/path1/path2/path3/zzz',
]);

expect(
values(matcher.match('\\path1\\path2\\path3\\zzz', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz',
]);
expect(
values(matcher.match('\\path1\\path2\\path3\\zzz', {caseSensitive: false}))
).toEqual([
'/path1/path2/path3/zzz',
]);
});

it('returns exact matches than normalized path separator matches', () => {
matcher.setCandidates(
[0, 1, 2],
['/path1/path2/path3/zzz', '/path1/path2/path3/zzz_ooo', '/path1/path2/path3/zzz/ooo']
);

expect(
values(matcher.match('path1/path2/path3/zzz', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz',
'/path1/path2/path3/zzz/ooo',
'/path1/path2/path3/zzz_ooo'
]);
expect(
values(matcher.match('zzz_ooo', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz_ooo',
'/path1/path2/path3/zzz/ooo'
]);
expect(
values(matcher.match('path1/path2/path3/zzz_ooo', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz_ooo',
'/path1/path2/path3/zzz/ooo'
]);
expect(
values(matcher.match('path1/path2/path3/zzz_ooo', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz_ooo',
'/path1/path2/path3/zzz/ooo'
]);
expect(
values(matcher.match('path1_path2_path3_zzz_ooo', {caseSensitive: true}))
).toEqual([
'/path1/path2/path3/zzz_ooo',
'/path1/path2/path3/zzz/ooo'
]);
expect(
values(matcher.match('path1/path2_path3/zzz_ooo', {caseSensitive: false}))
).toEqual([
'/path1/path2/path3/zzz_ooo',
'/path1/path2/path3/zzz/ooo'
]);
expect(
values(matcher.match('zzz/ooo', {caseSensitive: false}))
).toEqual([
'/path1/path2/path3/zzz/ooo'
]);
});
});
2 changes: 0 additions & 2 deletions src/MatcherBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ inline uint64_t letter_bitmask(const std::string &str) {
result |= count_bit << (index * 2);
} else if (c == '-') {
result |= (1UL << 52);
} else if (c == '_') {
result |= (1UL << 53);
} else if (c >= '0' && c <= '9') {
result |= (1UL << (c - '0' + 54));
}
Expand Down
24 changes: 19 additions & 5 deletions src/score_match.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ float recursive_match(const MatchInfo &m,
size_t last_slash = 0;
for (size_t j = haystack_idx; j <= lim; j++) {
char d = m.haystack_case[j];
if (needle_idx == 0 && (d == '/' || d == '\\')) {
bool is_path_sep = d == '/' || d == '\\';

if (needle_idx == 0 && is_path_sep) {
last_slash = j;
}
if (c == d) {
if (c == d || (is_path_sep && (c == '_' || c == '\\'))) {
// calculate score
float char_score = 1.0;
if (j > haystack_idx) {
Expand All @@ -123,8 +125,12 @@ float recursive_match(const MatchInfo &m,
}

// Apply a severe penalty if the case doesn't match.
// This should always hoist the exact case matches above all others.
if (m.smart_case && m.needle[needle_idx] != m.haystack[j]) {
// This will make the exact matches have higher score than the case
// insensitive and the path insensitive matches.
if (
(m.smart_case || m.haystack[j] == '/') &&
m.needle[needle_idx] != m.haystack[j]
) {
char_score *= 0.001;
}

Expand Down Expand Up @@ -200,7 +206,15 @@ float score_match(const char *haystack,
for (int i = m.needle_len - 1; i >= 0; i--) {
char* ptr = (char*)memrchr(m.haystack_case, m.needle_case[i], hindex);
if (ptr == nullptr) {
return 0;
// Since we treat _ and \\ as path separators, we need to re-check if path
// separator exists on the string in case they exact chars are not found.
if (m.needle_case[i] == '_' || m.needle_case[i] == '\\') {
ptr = (char*)memrchr(m.haystack_case, '/', hindex);
}

if (ptr == nullptr) {
return 0;
}
}
hindex = ptr - m.haystack_case;
last_match[i] = hindex;
Expand Down

0 comments on commit cff4808

Please sign in to comment.