Start converting fuzzy finder to a subclass of SelectList

This commit is contained in:
Nathan Sobo
2012-10-03 15:21:07 -10:00
parent 9e6fc44d39
commit 149889abfc
4 changed files with 77 additions and 112 deletions

View File

@@ -15,7 +15,7 @@ describe 'FuzzyFinder', ->
afterEach ->
rootView.remove()
describe "file-finder behavior", ->
fdescribe "file-finder behavior", ->
describe "toggling", ->
describe "when the root view's project has a path", ->
it "shows the FuzzyFinder or hides it and returns focus to the active editor if it already showing", ->
@@ -41,10 +41,10 @@ describe 'FuzzyFinder', ->
finder.maxResults = 1000
rootView.trigger 'fuzzy-finder:toggle-file-finder'
rootView.project.getFilePaths().done (paths) ->
expect(finder.pathList.children('li').length).toBe paths.length, finder.maxResults
expect(finder.list.children('li').length).toBe paths.length, finder.maxResults
for path in paths
expect(finder.pathList.find("li:contains(#{path})")).toExist()
expect(finder.pathList.children().first()).toHaveClass 'selected'
expect(finder.list.find("li:contains(#{path})")).toExist()
expect(finder.list.children().first()).toHaveClass 'selected'
describe "when root view's project has no path", ->
beforeEach ->
@@ -55,39 +55,23 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-file-finder'
expect(rootView.find('.fuzzy-finder')).not.toExist()
describe "selecting a path", ->
[editor1, editor2] = []
beforeEach ->
describe "when a path selection is confirmed", ->
it "opens the file associated with that path in the editor", ->
rootView.attachToDom()
editor1 = rootView.getActiveEditor()
editor2 = editor1.splitRight()
expect(rootView.getActiveEditor()).toBe editor2
rootView.trigger 'fuzzy-finder:toggle-file-finder'
describe "when a path is highlighted", ->
it "opens the file associated with that path in the editor", ->
finder.trigger 'move-down'
selectedLi = finder.find('li:eq(1)')
finder.confirmed('dir/a')
expectedPath = fixturesProject.resolve('dir/a')
expectedPath = rootView.project.resolve(selectedLi.text())
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).not.toBe expectedPath
expect(finder.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
finder.trigger 'fuzzy-finder:select-path'
expect(finder.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
describe "when no paths are highlighted", ->
it "does nothing", ->
finder.miniEditor.insertText('this should match nothing, because no one wants to drink battery acid')
finder.trigger 'fuzzy-finder:select-path'
expect(finder.hasParent()).toBeTruthy()
describe "buffer-finder behavior", ->
fdescribe "buffer-finder behavior", ->
describe "toggling", ->
describe "when the active editor contains edit sessions for buffers with paths", ->
beforeEach ->
@@ -114,10 +98,10 @@ describe 'FuzzyFinder', ->
it "lists the paths of the current editor's open buffers", ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(finder.pathList.children('li').length).toBe 2
expect(finder.pathList.find("li:contains(sample.js)")).toExist()
expect(finder.pathList.find("li:contains(sample.txt)")).toExist()
expect(finder.pathList.children().first()).toHaveClass 'selected'
expect(finder.list.children('li').length).toBe 2
expect(finder.list.find("li:contains(sample.js)")).toExist()
expect(finder.list.find("li:contains(sample.txt)")).toExist()
expect(finder.list.children().first()).toHaveClass 'selected'
describe "when the active editor only contains edit sessions for anonymous buffers", ->
it "does not open", ->
@@ -136,7 +120,7 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.find('.fuzzy-finder')).not.toExist()
describe "selecting a path", ->
describe "when a path selection is confirmed", ->
[editor1, editor2] = []
beforeEach ->
@@ -148,61 +132,33 @@ describe 'FuzzyFinder', ->
editor2.loadPreviousEditSession()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
describe "when a path is highlighted", ->
describe "when the highlighted path is open in the active editor", ->
it "switches the active editor to the edit session for the selected path", ->
finder.moveDown()
selectedLi = finder.findSelectedLi()
expect(selectedLi.text()).toBe 'sample.txt'
expectedPath = rootView.project.resolve('sample.txt')
describe "when there is an edit session for the confirmed path in the active editor", ->
it "switches the active editor to the edit session for the selected path", ->
expectedPath = fixturesProject.resolve('sample.txt')
finder.confirmed('sample.txt')
finder.trigger 'fuzzy-finder:select-path'
expect(finder.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
expect(finder.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
describe "when there is NO edit session for the confirmed path on the active editor, but there is one on another editor", ->
it "focuses the editor that contains an edit session for the selected path", ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
editor1.focus()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
describe "when the highlighted path is not open in the active editor, but instead is open on another editor", ->
it "focuses the editor that contains an edit session for the selected path", ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
editor1.focus()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.getActiveEditor()).toBe editor1
expect(rootView.getActiveEditor()).toBe editor1
expectedPath = fixturesProject.resolve('sample.txt')
finder.confirmed('sample.txt')
finder.moveDown()
selectedLi = finder.findSelectedLi()
expect(selectedLi.text()).toBe 'sample.txt'
expectedPath = rootView.project.resolve('sample.txt')
finder.trigger 'fuzzy-finder:select-path'
expect(finder.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
expect(finder.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
describe "common behavior between file and buffer finder", ->
describe "when characters are typed into the input element", ->
it "displays matching paths in the ol element and selects the first", ->
rootView.trigger 'fuzzy-finder:toggle-file-finder'
listLengthBefore = finder.pathList.children().length
finder.miniEditor.insertText('samp')
expect(finder.pathList.children().length).toBeLessThan(listLengthBefore)
expect(finder.pathList.find('li:first')).toHaveClass 'selected'
expect(finder.pathList.find('li.selected').length).toBe 1
# we should clear the list before re-populating it
finder.miniEditor.insertText('txt')
expect(finder.pathList.children().length).toBe 1
expect(finder.pathList.find('li:first')).toHaveClass 'selected'
expect(finder.pathList.find('li:first')).toHaveText 'sample.txt'
describe "move-down / move-up events", ->
beforeEach ->
rootView.trigger 'fuzzy-finder:toggle-file-finder'

View File

@@ -2,7 +2,7 @@ SelectList = require 'select-list'
{$$} = require 'space-pen'
$ = require 'jquery'
fdescribe "SelectList", ->
describe "SelectList", ->
[selectList, array, list, miniEditor] = []
beforeEach ->
@@ -17,7 +17,7 @@ fdescribe "SelectList", ->
selectList.itemForElement = (element) ->
$$ -> @li element[1], class: element[0]
selectList.selected = jasmine.createSpy('selected hook')
selectList.confirmed = jasmine.createSpy('confirmed hook')
selectList.cancelled = jasmine.createSpy('cancelled hook')
selectList.setArray(array)
@@ -76,11 +76,19 @@ fdescribe "SelectList", ->
expect(list.scrollBottom()).toBe itemHeight * 3
describe "the core:confirm event", ->
it "triggers the selected hook with the selected array element", ->
miniEditor.trigger 'move-down'
miniEditor.trigger 'move-down'
miniEditor.trigger 'core:confirm'
expect(selectList.selected).toHaveBeenCalledWith(array[2])
describe "when there is an item selected (because the list in not empty)", ->
it "triggers the selected hook with the selected array element", ->
miniEditor.trigger 'move-down'
miniEditor.trigger 'move-down'
miniEditor.trigger 'core:confirm'
expect(selectList.confirmed).toHaveBeenCalledWith(array[2])
describe "when there is no item selected (because the list is empty)", ->
it "does not trigger the confirmed hook", ->
miniEditor.insertText("i will never match anything")
expect(list.find('li')).not.toExist()
miniEditor.trigger 'core:confirm'
expect(selectList.confirmed).not.toHaveBeenCalled()
describe "the core:cancel event", ->
it "triggers the cancelled hook", ->

View File

@@ -6,10 +6,12 @@ fuzzyFilter = require 'fuzzy-filter'
module.exports =
class SelectList extends View
@content: ->
@div class: 'select-list', =>
@div class: @viewClass(), =>
@subview 'miniEditor', new Editor(mini: true)
@ol outlet: 'list'
@viewClass: -> 'select-list'
maxItems: Infinity
filteredArray: null
@@ -28,14 +30,15 @@ class SelectList extends View
populateList: ->
filterQuery = @miniEditor.getText()
if filterQuery.length
@filteredArray = fuzzyFilter(@array, filterQuery, key: @filterKey)
filteredArray = fuzzyFilter(@array, filterQuery, key: @filterKey)
else
@filteredArray = @array
filteredArray = @array
@list.empty()
for i in [0...Math.min(@filteredArray.length, @maxItems)]
item = @itemForElement(@filteredArray[i])
item.data('select-list-index', i)
for i in [0...Math.min(filteredArray.length, @maxItems)]
element = filteredArray[i]
item = @itemForElement(element)
item.data('select-list-element', element)
@list.append(item)
selectPreviousItem: ->
@@ -64,5 +67,6 @@ class SelectList extends View
@list.find('li.selected')
confirmSelection: ->
index = @getSelectedItem().data('select-list-index')
@selected(@filteredArray[index])
element = @getSelectedItem().data('select-list-element')
@confirmed(element) if element?

View File

@@ -1,18 +1,18 @@
{View, $$} = require 'space-pen'
SelectList = require 'select-list'
stringScore = require 'stringscore'
fuzzyFilter = require 'fuzzy-filter'
$ = require 'jquery'
_ = require 'underscore'
Editor = require 'editor'
module.exports =
class FuzzyFinder extends View
class FuzzyFinder extends SelectList
@activate: (rootView) ->
@instance = new FuzzyFinder(rootView)
@content: ->
@div class: 'fuzzy-finder', =>
@ol outlet: 'pathList'
@subview 'miniEditor', new Editor(mini: true)
@viewClass: ->
_.compact([super, 'fuzzy-finder']).join(' ')
paths: null
allowActiveEditorChange: null
@@ -26,13 +26,13 @@ class FuzzyFinder extends View
@rootView.on 'fuzzy-finder:toggle-buffer-finder', => @toggleBufferFinder()
@on 'fuzzy-finder:cancel', => @detach()
@on 'move-up', => @moveUp()
@on 'move-down', => @moveDown()
@on 'fuzzy-finder:select-path', => @select()
@on 'mousedown', 'li', (e) => @entryClicked(e)
@miniEditor.getBuffer().on 'change', => @populatePathList() if @hasParent()
@miniEditor.off 'move-up move-down'
itemForElement: (path) ->
$$ -> @li path
confirmed: (path) ->
toggleFileFinder: ->
if @hasParent()
@@ -52,12 +52,12 @@ class FuzzyFinder extends View
@attach() if @paths?.length
populateProjectPaths: ->
@rootView.project.getFilePaths().done (@paths) => @populatePathList()
@rootView.project.getFilePaths().done (@paths) => @setArray(@paths)
populateOpenBufferPaths: ->
@paths = @rootView.getOpenBufferPaths().map (path) =>
@rootView.project.relativize(path)
@populatePathList() if @paths?.length
@setArray(@paths)
attach: ->
@rootView.append(this)
@@ -80,14 +80,11 @@ class FuzzyFinder extends View
findSelectedLi: ->
@pathList.children('li.selected')
open : (path) ->
confirmed : (path) ->
return unless path.length
@rootView.open(path, {@allowActiveEditorChange})
@detach()
select: ->
@open(@findSelectedLi().text())
entryClicked: (e) ->
@open($(e.currentTarget).text())
false