mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
Convert FileFinder to a proper extension and remove references from RootView code
This commit is contained in:
@@ -39,14 +39,6 @@ describe "Project", ->
|
||||
expect(buffer.path).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(buffer)
|
||||
|
||||
describe ".getFilePaths()", ->
|
||||
it "returns a promise which resolves to a list of all file paths in the project, recursively", ->
|
||||
expectedPaths = (path.replace(project.path, '') for path in fs.listTree(project.path) when fs.isFile path)
|
||||
|
||||
waitsForPromise ->
|
||||
project.getFilePaths().done (result) ->
|
||||
expect(result).toEqual(expectedPaths)
|
||||
|
||||
describe ".resolve(path)", ->
|
||||
it "returns an absolute path based on the project's root", ->
|
||||
absolutePath = require.resolve('fixtures/dir/a')
|
||||
|
||||
@@ -341,67 +341,6 @@ describe "RootView", ->
|
||||
rootView.deactivate()
|
||||
expect(extension.deactivate).toHaveBeenCalled()
|
||||
|
||||
describe "the file finder", ->
|
||||
describe "when the toggle-file-finder event is triggered", ->
|
||||
describe "when there is a project", ->
|
||||
it "shows the FileFinder when it is not on screen and hides it when it is", ->
|
||||
rootView.attachToDom()
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
|
||||
rootView.find('.editor').trigger 'split-right'
|
||||
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
|
||||
|
||||
rootView.trigger 'toggle-file-finder'
|
||||
|
||||
expect(rootView.find('.file-finder')).toExist()
|
||||
expect(rootView.find('.file-finder input:focus')).toExist()
|
||||
rootView.trigger 'toggle-file-finder'
|
||||
|
||||
expect(editor1.isFocused).toBeFalsy()
|
||||
expect(editor2.isFocused).toBeTruthy()
|
||||
expect(rootView.find('.editor:has(:focus)')).toExist()
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
|
||||
it "shows all relative file paths for the current project", ->
|
||||
rootView.trigger 'toggle-file-finder'
|
||||
|
||||
project.getFilePaths().done (paths) ->
|
||||
expect(rootView.fileFinder.pathList.children('li').length).toBe paths.length
|
||||
|
||||
for path in paths
|
||||
relativePath = project.relativize(path)
|
||||
expect(rootView.fileFinder.pathList.find("li:contains(#{relativePath}):not(:contains(#{project.path}))")).toExist()
|
||||
|
||||
describe "when there is no project", ->
|
||||
beforeEach ->
|
||||
rootView = new RootView
|
||||
|
||||
it "does not open the FileFinder", ->
|
||||
expect(rootView.activeEditor().buffer.path).toBeUndefined()
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
rootView.trigger 'toggle-file-finder'
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
|
||||
describe "when a path is selected in the file finder", ->
|
||||
it "opens the file associated with that path in the editor", ->
|
||||
rootView.attachToDom()
|
||||
rootView.find('.editor').trigger 'split-right'
|
||||
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
|
||||
|
||||
rootView.trigger 'toggle-file-finder'
|
||||
rootView.fileFinder.trigger 'move-down'
|
||||
selectedLi = rootView.fileFinder.find('li:eq(1)')
|
||||
|
||||
expectedPath = fs.join(project.path, selectedLi.text())
|
||||
expect(editor1.buffer.path).not.toBe expectedPath
|
||||
expect(editor2.buffer.path).not.toBe expectedPath
|
||||
|
||||
rootView.fileFinder.trigger 'file-finder:select-file'
|
||||
|
||||
expect(editor1.buffer.path).not.toBe expectedPath
|
||||
expect(editor2.buffer.path).toBe expectedPath
|
||||
expect(editor2.isFocused).toBeTruthy()
|
||||
|
||||
describe "keymap wiring", ->
|
||||
commandHandler = null
|
||||
beforeEach ->
|
||||
|
||||
@@ -1,40 +1,82 @@
|
||||
RootView = require 'root-view'
|
||||
FileFinder = require 'file-finder'
|
||||
|
||||
$ = require 'jquery'
|
||||
{$$} = require 'space-pen'
|
||||
|
||||
describe 'FileFinder', ->
|
||||
finder = null
|
||||
paths = null
|
||||
[rootView, finder] = []
|
||||
|
||||
beforeEach ->
|
||||
paths = ['app.coffee', 'buffer.coffee', 'atom/app.coffee', 'atom/buffer.coffee']
|
||||
finder = new FileFinder({paths})
|
||||
finder.enableKeymap()
|
||||
rootView = new RootView(pathToOpen: require.resolve('fixtures/sample.js'))
|
||||
rootView.enableKeymap()
|
||||
rootView.activateExtension(FileFinder)
|
||||
finder = FileFinder.instance
|
||||
|
||||
describe "initialize", ->
|
||||
it "populates the ol with all paths and selects the first element", ->
|
||||
expect(finder.pathList.find('li').length).toBe paths.length
|
||||
expect(finder.pathList.find('li:first')).toHaveClass('selected')
|
||||
expect(finder.pathList.find('li.selected').length).toBe 1
|
||||
describe "when the file-finder:toggle event is triggered on the root view", ->
|
||||
describe "when there is a project", ->
|
||||
it "shows or hides the FileFinder, returning focus to the active editor when hiding it", ->
|
||||
rootView.attachToDom()
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
rootView.find('.editor').trigger 'split-right'
|
||||
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
|
||||
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
expect(rootView.find('.file-finder')).toExist()
|
||||
expect(rootView.find('.file-finder input:focus')).toExist()
|
||||
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
expect(editor1.isFocused).toBeFalsy()
|
||||
expect(editor2.isFocused).toBeTruthy()
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
|
||||
it "shows all relative file paths for the current project and selects the first", ->
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
rootView.project.getFilePaths().done (paths) ->
|
||||
expect(finder.pathList.children('li').length).toBe paths.length
|
||||
for path in paths
|
||||
expect(finder.pathList.find("li:contains(#{path})")).toExist()
|
||||
expect(finder.pathList.children().first()).toHaveClass 'selected'
|
||||
|
||||
describe "when root view's project has no path", ->
|
||||
beforeEach ->
|
||||
rootView.project.path = undefined
|
||||
|
||||
it "does not open the FileFinder", ->
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
expect(rootView.find('.file-finder')).not.toExist()
|
||||
|
||||
describe "file-finder:cancel event", ->
|
||||
it "hides the finder", ->
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
expect(finder.hasParent()).toBeTruthy()
|
||||
|
||||
finder.trigger 'file-finder:cancel'
|
||||
expect(finder.hasParent()).toBeFalsy()
|
||||
|
||||
describe "when characters are typed into the input element", ->
|
||||
it "displays matching paths in the ol element and selects the first", ->
|
||||
finder.editor.insertText('ap')
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
|
||||
expect(finder.pathList.children().length).toBe 2
|
||||
expect(finder.pathList.find('li:contains(app.coffee)').length).toBe 2
|
||||
expect(finder.pathList.find('li:contains(atom/app.coffee)').length).toBe 1
|
||||
listLengthBefore = finder.pathList.children().length
|
||||
|
||||
finder.editor.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.editor.setCursorScreenPosition([0, 0])
|
||||
finder.editor.insertText('a/')
|
||||
finder.editor.insertText('txt')
|
||||
|
||||
expect(finder.pathList.children().length).toBe 1
|
||||
expect(finder.pathList.find('li:contains(atom/app.coffee)').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 'file-finder:toggle'
|
||||
|
||||
it "selects the next / previous path in the list", ->
|
||||
expect(finder.find('li:eq(0)')).toHaveClass "selected"
|
||||
expect(finder.find('li:eq(2)')).not.toHaveClass "selected"
|
||||
@@ -56,41 +98,55 @@ describe 'FileFinder', ->
|
||||
finder.editor.trigger keydownEvent('up')
|
||||
expect(finder.find('li:first')).toHaveClass "selected"
|
||||
|
||||
for i in [1..paths.length+10]
|
||||
for i in [1..finder.pathList.children().length+2]
|
||||
finder.editor.trigger keydownEvent('down')
|
||||
|
||||
expect(finder.find('li:last')).toHaveClass "selected"
|
||||
|
||||
describe "select", ->
|
||||
selectedCallback = jasmine.createSpy 'selected'
|
||||
describe "select-file events", ->
|
||||
[editor1, editor2] = []
|
||||
|
||||
beforeEach ->
|
||||
finder = new FileFinder({paths, selected: selectedCallback})
|
||||
finder.enableKeymap()
|
||||
rootView.find('.editor').trigger 'split-right'
|
||||
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
|
||||
|
||||
it "when a file is selected Editor.open is called", ->
|
||||
spyOn(finder, 'remove')
|
||||
finder.moveDown()
|
||||
finder.editor.trigger keydownEvent('enter')
|
||||
expect(selectedCallback).toHaveBeenCalledWith(paths[1])
|
||||
expect(finder.remove).toHaveBeenCalled()
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
|
||||
it "when no file is selected, does nothing", ->
|
||||
spyOn(atom, 'open')
|
||||
finder.editor.insertText('this-will-match-nothing-hopefully')
|
||||
finder.populatePathList()
|
||||
finder.editor.trigger keydownEvent('enter')
|
||||
expect(atom.open).not.toHaveBeenCalled()
|
||||
describe "when there is a path selected", ->
|
||||
it "opens the file associated with that path in the editor", ->
|
||||
finder.trigger 'move-down'
|
||||
selectedLi = finder.find('li:eq(1)')
|
||||
|
||||
expectedPath = rootView.project.resolve(selectedLi.text())
|
||||
expect(editor1.buffer.path).not.toBe expectedPath
|
||||
expect(editor2.buffer.path).not.toBe expectedPath
|
||||
|
||||
finder.trigger 'file-finder:select-file'
|
||||
|
||||
expect(finder.hasParent()).toBeFalsy()
|
||||
expect(editor1.buffer.path).not.toBe expectedPath
|
||||
expect(editor2.buffer.path).toBe expectedPath
|
||||
expect(editor2.isFocused).toBeTruthy()
|
||||
|
||||
describe "when there is no path selected", ->
|
||||
it "does nothing", ->
|
||||
finder.editor.insertText('this should match nothing, because no one wants to drink battery acid')
|
||||
finder.trigger 'file-finder:select-file'
|
||||
expect(finder.hasParent()).toBeTruthy()
|
||||
|
||||
describe "findMatches(queryString)", ->
|
||||
it "returns up to finder.maxResults paths if queryString is empty", ->
|
||||
expect(paths.length).toBeLessThan finder.maxResults
|
||||
expect(finder.findMatches('').length).toBe paths.length
|
||||
beforeEach ->
|
||||
rootView.trigger 'file-finder:toggle'
|
||||
|
||||
finder.maxResults = paths.length - 1
|
||||
it "returns up to finder.maxResults paths if queryString is empty", ->
|
||||
expect(finder.paths.length).toBeLessThan finder.maxResults
|
||||
expect(finder.findMatches('').length).toBe finder.paths.length
|
||||
|
||||
finder.maxResults = finder.paths.length - 1
|
||||
|
||||
expect(finder.findMatches('').length).toBe finder.maxResults
|
||||
|
||||
it "returns paths sorted by score of match against the given query", ->
|
||||
expect(finder.findMatches('ap')).toEqual ["app.coffee", "atom/app.coffee"]
|
||||
expect(finder.findMatches('a/ap')).toEqual ["atom/app.coffee"]
|
||||
finder.paths = ["app.coffee", "atom/app.coffee"]
|
||||
expect(finder.findMatches('app.co')).toEqual ["app.coffee", "atom/app.coffee"]
|
||||
expect(finder.findMatches('atom/app.co')).toEqual ["atom/app.coffee"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
window.keymap.bindKeys '*'
|
||||
'meta-t': 'toggle-file-finder'
|
||||
'meta-t': 'file-finder:toggle'
|
||||
|
||||
window.keymap.bindKeys ".file-finder .editor",
|
||||
'enter': 'file-finder:select-file',
|
||||
'escape': 'file-finder:close'
|
||||
'escape': 'file-finder:cancel'
|
||||
|
||||
@@ -32,8 +32,8 @@ class Project
|
||||
|
||||
getFilePaths: ->
|
||||
projectPath = @path
|
||||
fs.async.listTree(@path).pipe (paths) ->
|
||||
path.replace(projectPath, "") for path in paths when fs.isFile(path)
|
||||
fs.async.listTree(@path).pipe (paths) =>
|
||||
@relativize(path) for path in paths when fs.isFile(path)
|
||||
|
||||
open: (filePath) ->
|
||||
if filePath?
|
||||
|
||||
@@ -6,7 +6,6 @@ _ = require 'underscore'
|
||||
{View} = require 'space-pen'
|
||||
Buffer = require 'buffer'
|
||||
Editor = require 'editor'
|
||||
FileFinder = require 'file-finder'
|
||||
Project = require 'project'
|
||||
VimMode = require 'vim-mode'
|
||||
CommandPanel = require 'command-panel'
|
||||
@@ -29,7 +28,6 @@ class RootView extends View
|
||||
extensionStates: null
|
||||
|
||||
initialize: ({ pathToOpen, projectPath, panesViewState, @extensionStates }) ->
|
||||
@on 'toggle-file-finder', => @toggleFileFinder()
|
||||
@on 'show-console', => window.showConsole()
|
||||
@on 'focus', (e) =>
|
||||
if @activeEditor()
|
||||
@@ -74,7 +72,7 @@ class RootView extends View
|
||||
serializeExtensions: ->
|
||||
extensionStates = {}
|
||||
for name, extension of @extensions
|
||||
extensionStates[name] = extension.serialize()
|
||||
extensionStates[name] = extension.serialize?()
|
||||
|
||||
extensionStates
|
||||
|
||||
@@ -91,7 +89,7 @@ class RootView extends View
|
||||
|
||||
deactivate: ->
|
||||
atom.rootViewStates[$windowNumber] = @serialize()
|
||||
extension.deactivate() for name, extension of @extensions
|
||||
extension.deactivate?() for name, extension of @extensions
|
||||
@remove()
|
||||
|
||||
open: (path, changeFocus=true) ->
|
||||
@@ -139,21 +137,6 @@ class RootView extends View
|
||||
rootPane?.css(width: '100%', height: '100%', top: 0, left: 0)
|
||||
rootPane?.adjustDimensions()
|
||||
|
||||
toggleFileFinder: ->
|
||||
return unless @project.getPath()?
|
||||
|
||||
if @fileFinder and @fileFinder.parent()[0]
|
||||
@fileFinder.remove()
|
||||
@fileFinder = null
|
||||
else
|
||||
@project.getFilePaths().done (paths) =>
|
||||
relativePaths = (@project.relativize(path) for path in paths)
|
||||
@fileFinder = new FileFinder
|
||||
paths: relativePaths
|
||||
selected: (relativePath) => @open(relativePath)
|
||||
@append @fileFinder
|
||||
@fileFinder.editor.focus()
|
||||
|
||||
remove: ->
|
||||
editor.remove() for editor in @editors()
|
||||
super
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
$ = require 'jquery'
|
||||
{View} = require 'space-pen'
|
||||
{View, $$} = require 'space-pen'
|
||||
stringScore = require 'stringscore'
|
||||
fuzzyFilter = require 'fuzzy-filter'
|
||||
Editor = require 'editor'
|
||||
|
||||
module.exports =
|
||||
class FileFinder extends View
|
||||
@activate: (rootView) ->
|
||||
@instance = new FileFinder(rootView)
|
||||
rootView.on 'file-finder:toggle', => @instance.toggle()
|
||||
|
||||
@content: ->
|
||||
@div class: 'file-finder', =>
|
||||
@ol outlet: 'pathList'
|
||||
@@ -14,13 +17,11 @@ class FileFinder extends View
|
||||
paths: null
|
||||
maxResults: null
|
||||
|
||||
initialize: ({@paths, @selected}) ->
|
||||
initialize: (@rootView) ->
|
||||
requireStylesheet 'file-finder.css'
|
||||
@maxResults = 10
|
||||
|
||||
@populatePathList()
|
||||
|
||||
@on 'file-finder:close', => @remove()
|
||||
@on 'file-finder:cancel', => @detach()
|
||||
@on 'move-up', => @moveUp()
|
||||
@on 'move-down', => @moveDown()
|
||||
@on 'file-finder:select-file', => @select()
|
||||
@@ -29,10 +30,25 @@ class FileFinder extends View
|
||||
@editor.buffer.on 'change', => @populatePathList()
|
||||
@editor.off 'move-up move-down'
|
||||
|
||||
toggle: ->
|
||||
if @hasParent()
|
||||
@detach()
|
||||
else
|
||||
@attach() if @rootView.project.path?
|
||||
|
||||
attach: ->
|
||||
@rootView.project.getFilePaths().done (@paths) => @populatePathList()
|
||||
@rootView.append(this)
|
||||
@editor.focus()
|
||||
|
||||
detach: ->
|
||||
@rootView.focus()
|
||||
super
|
||||
|
||||
populatePathList: ->
|
||||
@pathList.empty()
|
||||
for path in @findMatches(@editor.buffer.getText())
|
||||
@pathList.append $("<li>#{path}</li>")
|
||||
@pathList.append $$ -> @li path
|
||||
|
||||
@pathList.children('li:first').addClass 'selected'
|
||||
|
||||
@@ -40,8 +56,9 @@ class FileFinder extends View
|
||||
@pathList.children('li.selected')
|
||||
|
||||
select: ->
|
||||
filePath = @findSelectedLi().text()
|
||||
@selected(filePath) if filePath and @selected
|
||||
selectedLi = @findSelectedLi()
|
||||
return unless selectedLi.length
|
||||
@rootView.open(selectedLi.text())
|
||||
@remove()
|
||||
|
||||
moveUp: ->
|
||||
@@ -60,7 +77,3 @@ class FileFinder extends View
|
||||
|
||||
findMatches: (query) ->
|
||||
fuzzyFilter(@paths, query, maxResults: @maxResults)
|
||||
|
||||
remove: ->
|
||||
$('#root-view').focus()
|
||||
super
|
||||
|
||||
@@ -22,3 +22,6 @@ $.fn.preempt = (eventName, handler) ->
|
||||
eventNameWithoutNamespace = eventName.split('.')[0]
|
||||
handlers = @data('events')[eventNameWithoutNamespace]
|
||||
handlers.unshift(handlers.pop())
|
||||
|
||||
$.fn.hasParent = ->
|
||||
@parent()[0]?
|
||||
|
||||
Reference in New Issue
Block a user