From 149889abfc4379877ef7e825d8e31db003323fd3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 3 Oct 2012 15:21:07 -1000 Subject: [PATCH] Start converting fuzzy finder to a subclass of SelectList --- spec/extensions/fuzzy-finder-spec.coffee | 120 ++++++------------ spec/extensions/select-list-spec.coffee | 22 +++- src/app/select-list.coffee | 20 +-- .../fuzzy-finder/fuzzy-finder.coffee | 27 ++-- 4 files changed, 77 insertions(+), 112 deletions(-) diff --git a/spec/extensions/fuzzy-finder-spec.coffee b/spec/extensions/fuzzy-finder-spec.coffee index fd1b3e774..fda47abdd 100644 --- a/spec/extensions/fuzzy-finder-spec.coffee +++ b/spec/extensions/fuzzy-finder-spec.coffee @@ -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' diff --git a/spec/extensions/select-list-spec.coffee b/spec/extensions/select-list-spec.coffee index 053cad469..e5083f142 100644 --- a/spec/extensions/select-list-spec.coffee +++ b/spec/extensions/select-list-spec.coffee @@ -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", -> diff --git a/src/app/select-list.coffee b/src/app/select-list.coffee index 51ae45910..b2d0269d7 100644 --- a/src/app/select-list.coffee +++ b/src/app/select-list.coffee @@ -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? + diff --git a/src/extensions/fuzzy-finder/fuzzy-finder.coffee b/src/extensions/fuzzy-finder/fuzzy-finder.coffee index 70206338b..02f071321 100644 --- a/src/extensions/fuzzy-finder/fuzzy-finder.coffee +++ b/src/extensions/fuzzy-finder/fuzzy-finder.coffee @@ -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