Skip to content

Commit

Permalink
feat: Filter ignored files if query begins with !
Browse files Browse the repository at this point in the history
  • Loading branch information
claytonrcarter committed Jan 14, 2024
1 parent 71c8285 commit 8554ff6
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 8 deletions.
1 change: 1 addition & 0 deletions packages/fuzzy-finder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
64 changes: 57 additions & 7 deletions packages/fuzzy-finder/lib/fuzzy-finder-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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, '\\')
Expand All @@ -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
Expand All @@ -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(),
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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(':')
Expand All @@ -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({
Expand All @@ -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
Expand Down Expand Up @@ -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])
}
}
Expand Down
100 changes: 99 additions & 1 deletion packages/fuzzy-finder/spec/fuzzy-finder-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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', () => {
Expand All @@ -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()
})
})
})
})

Expand Down

0 comments on commit 8554ff6

Please sign in to comment.