Skip to content

Commit af58317

Browse files
authored
Merge pull request #73 from syncpoint/tags
Tags
2 parents f150448 + 5344116 commit af58317

File tree

4 files changed

+41
-9
lines changed

4 files changed

+41
-9
lines changed

src/renderer/components/sidebar/FilterInput.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,14 @@ export const FilterInput = props => {
4848
}
4949

5050
const handleTagClick = tag => {
51-
const tagFilter = `#${tag}`
52-
const newFilter = search.filter
53-
? `${search.filter} ${tagFilter}`
54-
: tagFilter
51+
const tagFilter = `#${tag.toUpperCase()}`
52+
const tokens = search.filter.split(' ').filter(Boolean)
53+
const tagIndex = tokens.findIndex(t => t.toUpperCase() === tagFilter)
54+
55+
const newFilter = tagIndex >= 0
56+
? tokens.filter((_, i) => i !== tagIndex).join(' ')
57+
: search.filter ? `${search.filter} ${tagFilter}` : tagFilter
58+
5559
setCursor(null)
5660
setSearch({ ...search, filter: newFilter, force: true })
5761
}

src/renderer/store/MiniSearch.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export const parseQuery = (terms, ids = []) => {
4040
// Remove hyphens to match the extractField transformation for scope
4141
const scopeValue = token.substring(1).replace(/-/g, '')
4242
scopeValue.length > 1 && acc.scope.push(scopeValue)
43-
} else if (token.startsWith('-#')) token.length > 3 && acc.excludeTags.push(token.substring(2).toLowerCase())
44-
else if (token.startsWith('#')) token.length > 2 && acc.tags.push(token.substring(1))
43+
} else if (token.startsWith('-#')) token.length > 2 && acc.excludeTags.push(token.substring(2))
44+
else if (token.startsWith('#')) token.length > 1 && acc.tags.push(token.substring(1))
4545
else if (token.startsWith('!')) token.length > 2 && acc.ids.push(token.substring(1))
4646
else if (token.startsWith('&')) { /* ignore */ } else if (token) acc.text.push(token)
4747
return acc
@@ -57,7 +57,7 @@ export const parseQuery = (terms, ids = []) => {
5757

5858
add('scope', 'OR')
5959
add('text', 'AND', true)
60-
add('tags', 'AND', true)
60+
add('tags', 'AND')
6161

6262
const filter = parts.ids.length
6363
? result => parts.ids.some(id => result.id.startsWith(id))

src/renderer/store/SearchIndex.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ SearchIndex.prototype.search = async function (terms, options) {
234234
? matches.filter(match => {
235235
const doc = this.cachedDocuments[match.id]
236236
if (!doc || !doc.tags) return true
237-
const docTags = doc.tags.filter(Boolean).map(t => t.toLowerCase())
238-
return !excludeTags.some(tag => docTags.includes(tag))
237+
const docTags = doc.tags.filter(Boolean).map(t => t.toUpperCase())
238+
return !excludeTags.some(tag => docTags.includes(tag.toUpperCase()))
239239
})
240240
: matches
241241

test/renderer/store/MiniSearch-test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,33 @@ describe('MiniSearch', function () {
5454
const actual = index.search(query)
5555
assert.strictEqual(actual.length, _3OSC.docs.length - 1) // minus one installation
5656
})
57+
58+
it('tag search uses exact matching, not prefix matching', function () {
59+
const index = createIndex()
60+
index.addAll([
61+
{ id: 'feature:1', text: 'First feature', tags: ['A'] },
62+
{ id: 'feature:2', text: 'Second feature', tags: ['AA'] },
63+
{ id: 'feature:3', text: 'Third feature', tags: ['AAA'] }
64+
])
65+
66+
const searchTag = (tag) => {
67+
const [query] = parseQuery(tag)
68+
return index.search(query).map(({ id }) => id).sort()
69+
}
70+
71+
// Each tag search should only return exact matches
72+
assert.deepStrictEqual(searchTag('#A'), ['feature:1'])
73+
assert.deepStrictEqual(searchTag('#AA'), ['feature:2'])
74+
assert.deepStrictEqual(searchTag('#AAA'), ['feature:3'])
75+
})
76+
77+
it('single-letter exclude tags are parsed correctly', function () {
78+
// Verify parseQuery handles single-letter exclude tags
79+
const [, options] = parseQuery('-#A')
80+
assert.deepStrictEqual(options.excludeTags, ['A'])
81+
82+
const [, options2] = parseQuery('-#B -#C')
83+
assert.deepStrictEqual(options2.excludeTags, ['B', 'C'])
84+
})
5785
})
5886
})

0 commit comments

Comments
 (0)