feat: Filter ignored files if query begins with !

This commit is contained in:
Clayton Carter 2024-01-07 00:14:44 -04:00
parent 3ed35741b0
commit 980aae5cbb
3 changed files with 157 additions and 8 deletions

View File

@ -12,6 +12,7 @@ When opening a file, you can control the behavior.
* <kbd>shift-enter</kbd> defaults to switching to another pane if the file is already open there
* <kbd>cmd-k</kbd> <kbd>right</kbd> *(macOS)* or <kbd>ctrl-k</kbd> <kbd>right</kbd> *(Linux/Windows)* (or any other directional arrow) will open the highlighted file in a new pane on the side indicated by the arrow
* Adding `:<line number>` to the end of your search will go directly to the line number you specify, or the last line if the number is larger
* Beginning your search with `!` will search for VCS ignored files (only if using ripgrep indexing)
Turning on the "Search All Panes" setting reverses the behavior of <kbd>enter</kbd> and <kbd>shift-enter</kbd> so <kbd>enter</kbd> opens the file in any pane and <kbd>shift-enter</kbd> creates a new tab in the current pane.

View File

@ -12,7 +12,9 @@ const MAX_RESULTS = 10
module.exports = class FuzzyFinderView {
constructor () {
this.previousQueryWasLineJump = false
this.previousQueryOverrodeIgnore = false
this.items = []
this.ignoredItems = []
this.filterFn = this.filterFn.bind(this)
this.selectListView = new SelectListView({
@ -25,6 +27,11 @@ module.exports = class FuzzyFinderView {
if (colon !== -1) {
query = query.slice(0, colon)
}
if (query.indexOf('!') === 0 ) {
query = query.slice(1)
}
// Normalize to backslashes on Windows
if (process.platform === 'win32') {
query = query.replace(/\//g, '\\')
@ -45,7 +52,11 @@ module.exports = class FuzzyFinderView {
this.iconDisposables = null
}
const isLineJump = this.isQueryALineJump()
const overridesIgnore = this.queryOverridesIgnore()
// if last query was not line jump and this one is, clear the list of items
if (isLineJump) {
this.previousQueryWasLineJump = true
const query = this.selectListView.getQuery()
let emptyMessage = null
@ -65,8 +76,24 @@ module.exports = class FuzzyFinderView {
emptyMessage: emptyMessage,
errorMessage: errorMessage
})
} else if (this.previousQueryWasLineJump) {
// if last query did not override ignored paths and this one does,
// set the filter items to the ignored paths
} else if (!this.previousQueryOverrodeIgnore && overridesIgnore) {
this.previousQueryOverrodeIgnore = true
this.selectListView.update({
items: this.ignoredItems,
emptyMessage: this.getEmptyMessage(),
errorMessage: null
})
// if last query was line jump and this one is not,
// OR if last query overrode ignored paths and this one doesn't
// reset the filter items to the regular items
} else if ((this.previousQueryWasLineJump && !isLineJump) ||
(this.previousQueryOverrodeIgnore && !overridesIgnore)) {
this.previousQueryWasLineJump = false
this.previousQueryOverrodeIgnore = false
this.selectListView.update({
items: this.items,
emptyMessage: this.getEmptyMessage(),
@ -124,10 +151,13 @@ module.exports = class FuzzyFinderView {
}
})
if (!this.nativeFuzzy) {
this.nativeFuzzy = atom.ui.fuzzyMatcher.setCandidates(
if (!this.nativeFuzzyTracked) {
this.nativeFuzzyTracked = atom.ui.fuzzyMatcher.setCandidates(
this.items.map(el => el.label)
);
this.nativeFuzzyIgnored = atom.ui.fuzzyMatcher.setCandidates(
this.ignoredItems.map(el => el.label)
)
// We need a separate instance of the fuzzy finder to calculate the
// matched paths only for the returned results. This speeds up considerably
// the filtering of items.
@ -268,6 +298,10 @@ module.exports = class FuzzyFinderView {
)
}
queryOverridesIgnore () {
return this.selectListView.getQuery().indexOf('!') === 0
}
getCaretPosition () {
const query = this.selectListView.getQuery()
const firstColon = query.indexOf(':')
@ -287,12 +321,18 @@ module.exports = class FuzzyFinderView {
return position
}
setItems (items) {
setItems (items, ignoredItems = []) {
this.items = items
this.ignoredItems = ignoredItems
atom.ui.fuzzyMatcher.setCandidates(
this.nativeFuzzy,
this.nativeFuzzyTracked,
this.items.map(item => item.label)
);
atom.ui.fuzzyMatcher.setCandidates(
this.nativeFuzzyIgnored,
this.ignoredItems.map(item => item.label)
);
if (this.isQueryALineJump()) {
this.selectListView.update({
@ -303,7 +343,9 @@ module.exports = class FuzzyFinderView {
})
} else {
this.selectListView.update({
items: this.items,
items: this.queryOverridesIgnore()
? this.ignoredItems
: this.items,
infoMessage: null,
loadingMessage: null,
loadingBadge: null
@ -337,7 +379,15 @@ module.exports = class FuzzyFinderView {
filterFn(items, query) {
if (!query) return items
return this.nativeFuzzy.match(query, {maxResults: MAX_RESULTS, algorithm: 'command-t'})
if (this.queryOverridesIgnore()) {
return this.nativeFuzzyIgnored
.match(query, {maxResults: MAX_RESULTS, algorithm: 'command-t'})
.map(({id}) => this.ignoredItems[id])
}
return this.nativeFuzzyTracked
.match(query, {maxResults: MAX_RESULTS, algorithm: 'command-t'})
.map(({id}) => this.items[id])
}
}

View File

@ -1644,7 +1644,7 @@ describe('FuzzyFinder', () => {
})
if (useRipGrep) {
it('does excludes paths that are git ignored', async () => {
it('excludes paths that are git ignored', async () => {
fs.writeFileSync(path.join(projectPath, 'dir', 'a.txt'), 'something')
await projectView.toggle()
@ -1693,6 +1693,81 @@ describe('FuzzyFinder', () => {
a.textContent.includes('HEAD'))).not.toBeDefined()
})
})
describe('when the query starts with an exclamation point', () => {
beforeEach(() => {
const ignoreFile = path.join(projectPath, '.gitignore')
fs.writeFileSync(ignoreFile, "ignored.txt\nanother.txt")
fs.writeFileSync(
path.join(projectPath, 'ignored.txt'),
'this text is not important'
)
fs.writeFileSync(
path.join(projectPath, 'another.txt'),
'this text is not important'
)
})
it('excludes paths that are tracked when indexIgnoredPaths is true', async () => {
atom.config.set('fuzzy-finder.indexIgnoredPaths', true)
projectView.selectListView.refs.queryEditor.insertText('!')
await projectView.toggle()
await waitForPathsToDisplay(projectView)
expect(
Array.from(projectView.element.querySelectorAll('li'))
.find(a => a.textContent.includes('a.txt'))
).not.toBeDefined()
})
it('includes paths that are git ignored when indexIgnoredPaths is true', async () => {
atom.config.set('fuzzy-finder.indexIgnoredPaths', true)
projectView.selectListView.refs.queryEditor.insertText('!')
await projectView.toggle()
await waitForPathsToDisplay(projectView)
expect(projectView.queryOverridesIgnore()).toBe(true)
expect(
Array.from(projectView.element.querySelectorAll('li'))
.find(a => a.textContent.includes('ignored.txt'))
).toBeDefined()
expect(
Array.from(projectView.element.querySelectorAll('li'))
.find(a => a.textContent.includes('another.txt'))
).toBeDefined()
})
it('matches paths that are git ignored when indexIgnoredPaths is true', async () => {
atom.config.set('fuzzy-finder.indexIgnoredPaths', true)
projectView.selectListView.refs.queryEditor.insertText('!anoth')
await projectView.toggle()
await waitForPathsToDisplay(projectView)
expect(
Array.from(projectView.element.querySelectorAll('li'))
.find(a => a.textContent.includes('ignored.txt'))
).not.toBeDefined()
expect(
Array.from(projectView.element.querySelectorAll('li'))
.find(a => a.textContent.includes('another.txt'))
).toBeDefined()
})
it('excludes paths that are git ignored when indexIgnoredPaths is false', async () => {
atom.config.set('fuzzy-finder.indexIgnoredPaths', false)
projectView.selectListView.refs.queryEditor.insertText('!ig')
await projectView.toggle()
await waitForReCrawlerToFinish(projectView)
expect(projectView.queryOverridesIgnore()).toBe(true)
expect(projectView.element.querySelectorAll('li').length).toBe(0)
})
})
})
describe('when core.excludeVcsIgnoredPaths is set to false', () => {
@ -1715,6 +1790,29 @@ describe('FuzzyFinder', () => {
expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('ignored.txt'))).toBeDefined()
})
})
describe('when the query starts with an exclamation point', () => {
beforeEach(() => {
const ignoreFile = path.join(projectPath, '.gitignore')
fs.writeFileSync(ignoreFile, 'ignored.txt')
const ignoredFile = path.join(projectPath, 'ignored.txt')
fs.writeFileSync(ignoredFile, 'ignored text')
})
it('excludes paths that are git ignored when indexIgnoredPaths is true', async () => {
atom.config.set('fuzzy-finder.indexIgnoredPaths', false)
projectView.selectListView.refs.queryEditor.insertText('!ig')
await projectView.toggle()
await waitForReCrawlerToFinish(projectView)
expect(
Array.from(projectView.element.querySelectorAll('li'))
.find(a => a.textContent.includes('ignored.txt'))
).not.toBeDefined()
})
})
})
})