mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Merge branch 'master' into config
Conflicts: spec/app/project-spec.coffee src/extensions/wrap-guide/src/wrap-guide.coffee
This commit is contained in:
@@ -2,4 +2,3 @@ window.keymap.bindKeys ".select-list .mini.editor input",
|
||||
'enter': 'core:confirm',
|
||||
'escape': 'core:cancel'
|
||||
'meta-w': 'core:cancel'
|
||||
|
||||
|
||||
@@ -52,20 +52,14 @@ class Project
|
||||
|
||||
getFilePaths: ->
|
||||
deferred = $.Deferred()
|
||||
fs.getAllPathsAsync @getPath(), (paths) =>
|
||||
fs.getAllFilePathsAsync @getPath(), (paths) =>
|
||||
paths = paths.filter (path) => not @isPathIgnored(path)
|
||||
deferred.resolve(paths)
|
||||
deferred.promise()
|
||||
|
||||
isPathIgnored: (path) ->
|
||||
lastSlash = path.lastIndexOf('/')
|
||||
if lastSlash isnt -1
|
||||
name = path.substring(lastSlash + 1)
|
||||
else
|
||||
name = path
|
||||
|
||||
for ignored in @ignoredNames
|
||||
return true if name is ignored
|
||||
for segment in path.split("/")
|
||||
return true if _.contains(@ignoredNames, segment)
|
||||
|
||||
@ignoreRepositoryPath(path)
|
||||
|
||||
|
||||
@@ -15,13 +15,15 @@ class SelectList extends View
|
||||
@viewClass: -> 'select-list'
|
||||
|
||||
maxItems: Infinity
|
||||
scheduleTimeout: null
|
||||
inputThrottle: 200
|
||||
filteredArray: null
|
||||
cancelling: false
|
||||
|
||||
initialize: ->
|
||||
requireStylesheet 'select-list.css'
|
||||
|
||||
@miniEditor.getBuffer().on 'change', => @populateList()
|
||||
@miniEditor.getBuffer().on 'change', => @schedulePopulateList()
|
||||
@miniEditor.on 'focusout', => @cancel() unless @cancelling
|
||||
@on 'core:move-up', => @selectPreviousItem()
|
||||
@on 'core:move-down', => @selectNextItem()
|
||||
@@ -36,6 +38,10 @@ class SelectList extends View
|
||||
@confirmSelection() if $(e.target).closest('li').hasClass('selected')
|
||||
e.preventDefault()
|
||||
|
||||
schedulePopulateList: ->
|
||||
clearTimeout(@scheduleTimeout)
|
||||
@scheduleTimeout = setTimeout((=> @populateList()), @inputThrottle)
|
||||
|
||||
setArray: (@array) ->
|
||||
@populateList()
|
||||
@selectItem(@list.find('li:first'))
|
||||
@@ -43,12 +49,11 @@ class SelectList extends View
|
||||
|
||||
setError: (message) ->
|
||||
if not message or message.length == ""
|
||||
@error.text("")
|
||||
@error.hide()
|
||||
@error.text("").hide()
|
||||
@removeClass("error")
|
||||
else
|
||||
@error.text(message)
|
||||
@error.show()
|
||||
@setLoading()
|
||||
@error.text(message).show()
|
||||
@addClass("error")
|
||||
|
||||
setLoading: (message) ->
|
||||
@@ -113,8 +118,9 @@ class SelectList extends View
|
||||
@confirmed(element) if element?
|
||||
|
||||
cancel: ->
|
||||
@list.empty()
|
||||
@cancelling = true
|
||||
@cancelled()
|
||||
@detach()
|
||||
@cancelling = false
|
||||
|
||||
clearTimeout(@scheduleTimeout)
|
||||
|
||||
@@ -20,7 +20,9 @@ class EventPalette extends SelectList
|
||||
keyBindings: null
|
||||
|
||||
initialize: (@rootView) ->
|
||||
@command 'event-palette:toggle', => @cancel()
|
||||
@command 'event-palette:toggle', =>
|
||||
@cancel()
|
||||
false
|
||||
super
|
||||
|
||||
attach: ->
|
||||
|
||||
@@ -189,3 +189,23 @@ describe 'FuzzyFinder', ->
|
||||
expect(finder.hasParent()).toBeFalsy()
|
||||
expect(activeEditor.isFocused).toBeTruthy()
|
||||
expect(finder.miniEditor.isFocused).toBeFalsy()
|
||||
|
||||
describe "cached file paths", ->
|
||||
it "caches file paths after first time", ->
|
||||
spyOn(rootView.project, "getFilePaths").andCallThrough()
|
||||
rootView.trigger 'fuzzy-finder:toggle-file-finder'
|
||||
|
||||
waitsFor ->
|
||||
finder.list.children('li').length > 0
|
||||
|
||||
runs ->
|
||||
expect(rootView.project.getFilePaths).toHaveBeenCalled()
|
||||
rootView.project.getFilePaths.reset()
|
||||
rootView.trigger 'fuzzy-finder:toggle-file-finder'
|
||||
rootView.trigger 'fuzzy-finder:toggle-file-finder'
|
||||
|
||||
waitsFor ->
|
||||
finder.list.children('li').length > 0
|
||||
|
||||
runs ->
|
||||
expect(rootView.project.getFilePaths).not.toHaveBeenCalled()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{View, $$} = require 'space-pen'
|
||||
SelectList = require 'select-list'
|
||||
_ = require 'underscore'
|
||||
$ = require 'jquery'
|
||||
Editor = require 'editor'
|
||||
|
||||
module.exports =
|
||||
@@ -20,6 +21,7 @@ class FuzzyFinder extends SelectList
|
||||
|
||||
initialize: (@rootView) ->
|
||||
super
|
||||
$(window).on 'focus', => @array = null
|
||||
|
||||
itemForElement: (path) ->
|
||||
$$ -> @li path
|
||||
@@ -51,9 +53,12 @@ class FuzzyFinder extends SelectList
|
||||
@attach() if @paths?.length
|
||||
|
||||
populateProjectPaths: ->
|
||||
@setLoading("Indexing...")
|
||||
@rootView.project.getFilePaths().done (paths) =>
|
||||
@setArray(paths)
|
||||
if @array?.length > 0
|
||||
@setArray(@array)
|
||||
else
|
||||
@setLoading("Indexing...")
|
||||
@rootView.project.getFilePaths().done (paths) =>
|
||||
@setArray(paths)
|
||||
|
||||
populateOpenBufferPaths: ->
|
||||
@paths = @rootView.getOpenBufferPaths().map (path) =>
|
||||
|
||||
@@ -3,28 +3,31 @@ OutlineView = require 'outline-view'
|
||||
TagGenerator = require 'outline-view/src/tag-generator'
|
||||
|
||||
describe "OutlineView", ->
|
||||
[rootView, outlineView] = []
|
||||
[rootView, outlineView, setArraySpy] = []
|
||||
|
||||
beforeEach ->
|
||||
rootView = new RootView(require.resolve('fixtures'))
|
||||
rootView.activateExtension(OutlineView)
|
||||
outlineView = OutlineView.instance
|
||||
rootView.attachToDom()
|
||||
setArraySpy = spyOn(outlineView, 'setArray').andCallThrough()
|
||||
|
||||
afterEach ->
|
||||
rootView.deactivate()
|
||||
setArraySpy.reset()
|
||||
|
||||
describe "when tags can be generated for a file", ->
|
||||
it "initially displays all JavaScript functions with line numbers", ->
|
||||
rootView.open('sample.js')
|
||||
expect(rootView.find('.outline-view')).not.toExist()
|
||||
attachSpy = spyOn(outlineView, 'attach').andCallThrough()
|
||||
rootView.getActiveEditor().trigger "outline-view:toggle"
|
||||
expect(outlineView.find('.loading')).toHaveText 'Generating symbols...'
|
||||
|
||||
waitsFor ->
|
||||
attachSpy.callCount > 0
|
||||
setArraySpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(outlineView.find('.loading')).toBeEmpty()
|
||||
expect(rootView.find('.outline-view')).toExist()
|
||||
expect(outlineView.list.children('li').length).toBe 2
|
||||
expect(outlineView.list.children('li:first').find('.function-name')).toHaveText 'quicksort'
|
||||
@@ -37,14 +40,15 @@ describe "OutlineView", ->
|
||||
it "displays error when no tags match text in mini-editor", ->
|
||||
rootView.open('sample.js')
|
||||
expect(rootView.find('.outline-view')).not.toExist()
|
||||
attachSpy = spyOn(outlineView, 'attach').andCallThrough()
|
||||
rootView.getActiveEditor().trigger "outline-view:toggle"
|
||||
|
||||
waitsFor ->
|
||||
attachSpy.callCount > 0
|
||||
setArraySpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
outlineView.miniEditor.setText("nothing will match this")
|
||||
window.advanceClock(outlineView.inputThrottle)
|
||||
|
||||
expect(rootView.find('.outline-view')).toExist()
|
||||
expect(outlineView.list.children('li').length).toBe 0
|
||||
expect(outlineView.error).toBeVisible()
|
||||
@@ -53,6 +57,8 @@ describe "OutlineView", ->
|
||||
|
||||
# Should remove error
|
||||
outlineView.miniEditor.setText("")
|
||||
window.advanceClock(outlineView.inputThrottle)
|
||||
|
||||
expect(outlineView.list.children('li').length).toBe 2
|
||||
expect(outlineView).not.toHaveClass "error"
|
||||
expect(outlineView.error).not.toBeVisible()
|
||||
@@ -61,11 +67,11 @@ describe "OutlineView", ->
|
||||
it "shows an error message when no matching tags are found", ->
|
||||
rootView.open('sample.txt')
|
||||
expect(rootView.find('.outline-view')).not.toExist()
|
||||
attachSpy = spyOn(outlineView, 'attach').andCallThrough()
|
||||
rootView.getActiveEditor().trigger "outline-view:toggle"
|
||||
setErrorSpy = spyOn(outlineView, "setError").andCallThrough()
|
||||
|
||||
waitsFor ->
|
||||
attachSpy.callCount > 0
|
||||
setErrorSpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(rootView.find('.outline-view')).toExist()
|
||||
@@ -73,6 +79,7 @@ describe "OutlineView", ->
|
||||
expect(outlineView.error).toBeVisible()
|
||||
expect(outlineView.error.text().length).toBeGreaterThan 0
|
||||
expect(outlineView).toHaveClass "error"
|
||||
expect(outlineView.find('.loading')).not.toBeVisible()
|
||||
|
||||
it "moves the cursor to the selected function", ->
|
||||
tags = []
|
||||
@@ -92,7 +99,7 @@ describe "OutlineView", ->
|
||||
outlineView.attach()
|
||||
expect(rootView.find('.outline-view')).toExist()
|
||||
outlineView.confirmed(tags[1])
|
||||
expect(rootView.getActiveEditor().getCursorBufferPosition()).toEqual [1,0]
|
||||
expect(rootView.getActiveEditor().getCursorBufferPosition()).toEqual [1,2]
|
||||
|
||||
describe "TagGenerator", ->
|
||||
it "generates tags for all JavaScript functions", ->
|
||||
@@ -118,3 +125,29 @@ describe "OutlineView", ->
|
||||
generator = new TagGenerator(path, callback)
|
||||
generator.generate().done ->
|
||||
expect(tags.length).toBe 0
|
||||
|
||||
describe "jump to declaration", ->
|
||||
it "doesn't move the cursor when no declaration is found", ->
|
||||
rootView.open("tagged.js")
|
||||
editor = rootView.getActiveEditor()
|
||||
editor.setCursorBufferPosition([0,2])
|
||||
editor.trigger 'outline-view:jump-to-declaration'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0,2]
|
||||
|
||||
it "moves the cursor to the declaration", ->
|
||||
rootView.open("tagged.js")
|
||||
editor = rootView.getActiveEditor()
|
||||
editor.setCursorBufferPosition([6,24])
|
||||
editor.trigger 'outline-view:jump-to-declaration'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [2,0]
|
||||
|
||||
it "displays matches when more than one exists and opens the selected match", ->
|
||||
rootView.open("tagged.js")
|
||||
editor = rootView.getActiveEditor()
|
||||
editor.setCursorBufferPosition([8,14])
|
||||
editor.trigger 'outline-view:jump-to-declaration'
|
||||
expect(outlineView.list.children('li').length).toBe 2
|
||||
expect(outlineView).toBeVisible()
|
||||
outlineView.confirmed(outlineView.array[0])
|
||||
expect(rootView.getActiveEditor().getPath()).toBe rootView.project.resolve("tagged-duplicate.js")
|
||||
expect(rootView.getActiveEditor().getCursorBufferPosition()).toEqual [0,4]
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
window.keymap.bindKeys '.editor'
|
||||
'meta-j': 'outline-view:toggle'
|
||||
'meta-.': 'outline-view:jump-to-declaration'
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
SelectList = require 'select-list'
|
||||
Editor = require 'editor'
|
||||
TagGenerator = require 'outline-view/src/tag-generator'
|
||||
TagReader = require 'outline-view/src/tag-reader'
|
||||
Point = require 'point'
|
||||
fs = require 'fs'
|
||||
$ = require 'jquery'
|
||||
|
||||
module.exports =
|
||||
class OutlineView extends SelectList
|
||||
@@ -11,6 +15,7 @@ class OutlineView extends SelectList
|
||||
requireStylesheet 'outline-view/src/outline-view.css'
|
||||
@instance = new OutlineView(rootView)
|
||||
rootView.command 'outline-view:toggle', => @instance.toggle()
|
||||
rootView.command 'outline-view:jump-to-declaration', => @instance.jumpToDeclaration()
|
||||
|
||||
@viewClass: -> "#{super} outline-view"
|
||||
|
||||
@@ -32,11 +37,13 @@ class OutlineView extends SelectList
|
||||
@cancel()
|
||||
else
|
||||
@populate()
|
||||
@attach()
|
||||
|
||||
populate: ->
|
||||
tags = []
|
||||
callback = (tag) -> tags.push tag
|
||||
path = @rootView.getActiveEditor().getPath()
|
||||
@setLoading("Generating symbols...")
|
||||
new TagGenerator(path, callback).generate().done =>
|
||||
if tags.length > 0
|
||||
@miniEditor.show()
|
||||
@@ -46,13 +53,19 @@ class OutlineView extends SelectList
|
||||
@setError("No symbols found")
|
||||
setTimeout (=> @detach()), 2000
|
||||
|
||||
@attach()
|
||||
|
||||
confirmed : ({position, name}) ->
|
||||
confirmed : (tag) ->
|
||||
@cancel()
|
||||
@openTag(tag)
|
||||
|
||||
openTag: ({position, file}) ->
|
||||
@rootView.openInExistingEditor(file, true, true) if file
|
||||
@moveToPosition(position)
|
||||
|
||||
moveToPosition: (position) ->
|
||||
editor = @rootView.getActiveEditor()
|
||||
editor.scrollToBufferPosition(position, center: true)
|
||||
editor.setCursorBufferPosition(position)
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
|
||||
cancelled: ->
|
||||
@miniEditor.setText('')
|
||||
@@ -61,3 +74,30 @@ class OutlineView extends SelectList
|
||||
attach: ->
|
||||
@rootView.append(this)
|
||||
@miniEditor.focus()
|
||||
|
||||
getTagLine: (tag) ->
|
||||
pattern = $.trim(tag.pattern?.replace(/(^^\/\^)|(\$\/$)/g, '')) # Remove leading /^ and trailing $/
|
||||
return unless pattern
|
||||
for line, index in fs.read(@rootView.project.resolve(tag.file)).split('\n')
|
||||
return new Point(index, 0) if pattern is $.trim(line)
|
||||
|
||||
jumpToDeclaration: ->
|
||||
editor = @rootView.getActiveEditor()
|
||||
matches = TagReader.find(editor)
|
||||
return unless matches.length
|
||||
|
||||
if matches.length is 1
|
||||
position = @getTagLine(matches[0])
|
||||
@openTag(file: matches[0].file, position: position) if position
|
||||
else
|
||||
tags = []
|
||||
for match in matches
|
||||
position = @getTagLine(match)
|
||||
continue unless position
|
||||
tags.push
|
||||
file: match.file
|
||||
name: fs.base(match.file)
|
||||
position: position
|
||||
@miniEditor.show()
|
||||
@setArray(tags)
|
||||
@attach()
|
||||
|
||||
@@ -31,8 +31,5 @@
|
||||
color: #ddd;
|
||||
-webkit-border-radius: 3px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.outline-view ol .function-line {
|
||||
background: rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
13
src/extensions/outline-view/src/tag-reader.coffee
Normal file
13
src/extensions/outline-view/src/tag-reader.coffee
Normal file
@@ -0,0 +1,13 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports =
|
||||
|
||||
find: (editor) ->
|
||||
word = editor.getTextInRange(editor.getCursor().getCurrentWordBufferRange())
|
||||
return [] unless word.length > 0
|
||||
|
||||
project = editor.rootView().project
|
||||
tagsFile = project.resolve("tags") or project.resolve("TAGS")
|
||||
return [] unless fs.isFile(tagsFile)
|
||||
|
||||
$tags.find(tagsFile, word) or []
|
||||
@@ -31,6 +31,7 @@ class WrapGuide extends View
|
||||
@updateGuide(@editor)
|
||||
@editor.on 'editor-path-change', => @updateGuide(@editor)
|
||||
config.on 'update', => @setFontSize(config.editor.fontSize)
|
||||
@editor.on 'before-remove', => @rootView.off('.wrap-guide')
|
||||
|
||||
setFontSize: (fontSize) ->
|
||||
return if fontSize == @fontSize
|
||||
|
||||
@@ -112,8 +112,8 @@ module.exports =
|
||||
@makeTree(@directory(path))
|
||||
@makeDirectory(path)
|
||||
|
||||
getAllPathsAsync: (rootPath, callback) ->
|
||||
$native.getAllPathsAsync(rootPath, callback)
|
||||
getAllFilePathsAsync: (rootPath, callback) ->
|
||||
$native.getAllFilePathsAsync(rootPath, callback)
|
||||
|
||||
traverseTree: (rootPath, onFile, onDirectory) ->
|
||||
$native.traverseTree(rootPath, onFile, onDirectory)
|
||||
|
||||
Reference in New Issue
Block a user