mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Pull out symbols-view package into a separate repo
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"coffee-script": "1.6.2",
|
||||
"ctags": "0.5.0",
|
||||
"oniguruma": "0.16.0",
|
||||
"mkdirp": "0.3.5",
|
||||
"git-utils": "0.19.0",
|
||||
@@ -77,6 +76,7 @@
|
||||
"grammar-selector": "0.1.0",
|
||||
"image-view": "0.1.0",
|
||||
"spell-check": "0.1.0",
|
||||
"symbols-view": "0.1.0",
|
||||
"terminal": "0.3.0",
|
||||
"toml": "0.1.0",
|
||||
"wrap-guide": "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
'.editor':
|
||||
'meta-j': 'symbols-view:toggle-file-symbols'
|
||||
'meta-.': 'symbols-view:go-to-declaration'
|
||||
|
||||
'body':
|
||||
'meta-J': 'symbols-view:toggle-project-symbols'
|
||||
@@ -1,17 +0,0 @@
|
||||
ctags = require 'ctags'
|
||||
fsUtils = require 'fs-utils'
|
||||
path = require 'path'
|
||||
|
||||
getTagsFile = (directoryPath) ->
|
||||
tagsFile = path.join(directoryPath, "tags")
|
||||
return tagsFile if fsUtils.isFileSync(tagsFile)
|
||||
|
||||
tagsFile = path.join(directoryPath, "TAGS")
|
||||
return tagsFile if fsUtils.isFileSync(tagsFile)
|
||||
|
||||
module.exports = (directoryPath) ->
|
||||
tagsFilePath = getTagsFile(directoryPath)
|
||||
if tagsFilePath
|
||||
ctags.getTags(tagsFilePath)
|
||||
else
|
||||
[]
|
||||
@@ -1,124 +0,0 @@
|
||||
{$$} = require 'space-pen'
|
||||
SelectList = require 'select-list'
|
||||
TagGenerator = require './tag-generator'
|
||||
TagReader = require './tag-reader'
|
||||
Point = require 'point'
|
||||
fsUtils = require 'fs-utils'
|
||||
path = require 'path'
|
||||
$ = require 'jquery'
|
||||
|
||||
module.exports =
|
||||
class SymbolsView extends SelectList
|
||||
@activate: ->
|
||||
new SymbolsView
|
||||
|
||||
@viewClass: -> "#{super} symbols-view overlay from-top"
|
||||
|
||||
filterKey: 'name'
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
|
||||
rootView.command 'symbols-view:toggle-file-symbols', => @toggleFileSymbols()
|
||||
rootView.command 'symbols-view:toggle-project-symbols', => @toggleProjectSymbols()
|
||||
rootView.command 'symbols-view:go-to-declaration', => @goToDeclaration()
|
||||
|
||||
itemForElement: ({position, name, file}) ->
|
||||
$$ ->
|
||||
@li class: 'two-lines', =>
|
||||
@div name, class: 'primary-line'
|
||||
if position
|
||||
text = "Line #{position.row + 1}"
|
||||
else
|
||||
text = path.basename(file)
|
||||
@div text, class: 'secondary-line'
|
||||
|
||||
getEmptyMessage: (itemCount) ->
|
||||
if itemCount is 0
|
||||
'No symbols found'
|
||||
else
|
||||
super
|
||||
|
||||
toggleFileSymbols: ->
|
||||
if @hasParent()
|
||||
@cancel()
|
||||
else
|
||||
@populateFileSymbols()
|
||||
@attach()
|
||||
|
||||
populateFileSymbols: ->
|
||||
filePath = rootView.getActiveView().getPath()
|
||||
@list.empty()
|
||||
@setLoading("Generating symbols...")
|
||||
new TagGenerator(filePath).generate().done (tags) =>
|
||||
@maxItem = Infinity
|
||||
@setArray(tags)
|
||||
|
||||
toggleProjectSymbols: ->
|
||||
if @hasParent()
|
||||
@cancel()
|
||||
else
|
||||
@populateProjectSymbols()
|
||||
@attach()
|
||||
|
||||
populateProjectSymbols: ->
|
||||
@list.empty()
|
||||
@setLoading("Loading symbols...")
|
||||
TagReader.getAllTags(project).done (tags) =>
|
||||
@maxItems = 10
|
||||
@setArray(tags)
|
||||
|
||||
confirmed : (tag) ->
|
||||
if tag.file and not fsUtils.isFileSync(project.resolve(tag.file))
|
||||
@setError('Selected file does not exist')
|
||||
setTimeout((=> @setError()), 2000)
|
||||
else
|
||||
@cancel()
|
||||
@openTag(tag)
|
||||
|
||||
openTag: (tag) ->
|
||||
position = tag.position
|
||||
position = @getTagLine(tag) unless position
|
||||
rootView.open(tag.file, {changeFocus: true, allowActiveEditorChange:true}) if tag.file
|
||||
@moveToPosition(position) if position
|
||||
|
||||
moveToPosition: (position) ->
|
||||
editor = rootView.getActiveView()
|
||||
editor.scrollToBufferPosition(position, center: true)
|
||||
editor.setCursorBufferPosition(position)
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
|
||||
attach: ->
|
||||
super
|
||||
|
||||
rootView.append(this)
|
||||
@miniEditor.focus()
|
||||
|
||||
getTagLine: (tag) ->
|
||||
pattern = $.trim(tag.pattern?.replace(/(^^\/\^)|(\$\/$)/g, '')) # Remove leading /^ and trailing $/
|
||||
return unless pattern
|
||||
file = project.resolve(tag.file)
|
||||
return unless fsUtils.isFileSync(file)
|
||||
for line, index in fsUtils.read(file).split('\n')
|
||||
return new Point(index, 0) if pattern is $.trim(line)
|
||||
|
||||
goToDeclaration: ->
|
||||
editor = rootView.getActiveView()
|
||||
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: path.basename(match.file)
|
||||
position: position
|
||||
@miniEditor.show()
|
||||
@setArray(tags)
|
||||
@attach()
|
||||
@@ -1,30 +0,0 @@
|
||||
Point = require 'point'
|
||||
$ = require 'jquery'
|
||||
BufferedProcess = require 'buffered-process'
|
||||
fsUtils = require 'fs-utils'
|
||||
|
||||
module.exports =
|
||||
class TagGenerator
|
||||
constructor: (@path) ->
|
||||
|
||||
parseTagLine: (line) ->
|
||||
sections = line.split('\t')
|
||||
if sections.length > 3
|
||||
position: new Point(parseInt(sections[2]) - 1)
|
||||
name: sections[0]
|
||||
else
|
||||
null
|
||||
|
||||
generate: ->
|
||||
deferred = $.Deferred()
|
||||
tags = []
|
||||
command = fsUtils.resolveOnLoadPath('ctags')
|
||||
args = ['--fields=+KS', '-nf', '-', @path]
|
||||
stdout = (lines) =>
|
||||
for line in lines.split('\n')
|
||||
tag = @parseTagLine(line)
|
||||
tags.push(tag) if tag
|
||||
exit = ->
|
||||
deferred.resolve(tags)
|
||||
new BufferedProcess({command, args, stdout, exit})
|
||||
deferred
|
||||
@@ -1,30 +0,0 @@
|
||||
fsUtils = require 'fs-utils'
|
||||
$ = require 'jquery'
|
||||
Task = require 'task'
|
||||
ctags = require 'ctags'
|
||||
|
||||
handlerPath = require.resolve('./load-tags-handler')
|
||||
|
||||
module.exports =
|
||||
getTagsFile: (project) ->
|
||||
tagsFile = project.resolve("tags") or project.resolve("TAGS")
|
||||
return tagsFile if fsUtils.isFileSync(tagsFile)
|
||||
|
||||
find: (editor) ->
|
||||
word = editor.getTextInRange(editor.getCursor().getCurrentWordBufferRange())
|
||||
return [] unless word.length > 0
|
||||
|
||||
tagsFile = @getTagsFile(project)
|
||||
return [] unless tagsFile
|
||||
|
||||
ctags.findTags(tagsFile, word)
|
||||
|
||||
getAllTags: (project, callback) ->
|
||||
deferred = $.Deferred()
|
||||
|
||||
task = new Task(handlerPath)
|
||||
task.start project.getPath(), (tags) ->
|
||||
deferred.resolve(tags)
|
||||
task.terminate()
|
||||
|
||||
deferred.promise()
|
||||
@@ -1,6 +0,0 @@
|
||||
'main': './lib/symbols-view'
|
||||
'description': 'Jump to a function or method in the current editor with `meta-j`.'
|
||||
'activationEvents':
|
||||
'symbols-view:toggle-file-symbols': '.editor'
|
||||
'symbols-view:toggle-project-symbols': null
|
||||
'symbols-view:go-to-declaration': '.editor'
|
||||
@@ -1,220 +0,0 @@
|
||||
RootView = require 'root-view'
|
||||
SymbolsView = require 'symbols-view/lib/symbols-view'
|
||||
TagGenerator = require 'symbols-view/lib/tag-generator'
|
||||
fsUtils = require 'fs-utils'
|
||||
|
||||
describe "SymbolsView", ->
|
||||
[symbolsView, setArraySpy] = []
|
||||
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
atom.activatePackage("symbols-view")
|
||||
|
||||
rootView.attachToDom()
|
||||
setArraySpy = spyOn(SymbolsView.prototype, 'setArray').andCallThrough()
|
||||
|
||||
afterEach ->
|
||||
setArraySpy.reset()
|
||||
|
||||
describe "when tags can be generated for a file", ->
|
||||
it "initially displays all JavaScript functions with line numbers", ->
|
||||
rootView.open('sample.js')
|
||||
rootView.getActiveView().trigger "symbols-view:toggle-file-symbols"
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
expect(symbolsView.loading).toHaveText 'Generating symbols...'
|
||||
|
||||
waitsFor ->
|
||||
setArraySpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(symbolsView.loading).toBeEmpty()
|
||||
expect(rootView.find('.symbols-view')).toExist()
|
||||
expect(symbolsView.list.children('li').length).toBe 2
|
||||
expect(symbolsView.list.children('li:first').find('.primary-line')).toHaveText 'quicksort'
|
||||
expect(symbolsView.list.children('li:first').find('.secondary-line')).toHaveText 'Line 1'
|
||||
expect(symbolsView.list.children('li:last').find('.primary-line')).toHaveText 'quicksort.sort'
|
||||
expect(symbolsView.list.children('li:last').find('.secondary-line')).toHaveText 'Line 2'
|
||||
expect(symbolsView.error).not.toBeVisible()
|
||||
|
||||
it "displays error when no tags match text in mini-editor", ->
|
||||
rootView.open('sample.js')
|
||||
rootView.getActiveView().trigger "symbols-view:toggle-file-symbols"
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
|
||||
waitsFor ->
|
||||
setArraySpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
symbolsView.miniEditor.setText("nothing will match this")
|
||||
window.advanceClock(symbolsView.inputThrottle)
|
||||
|
||||
expect(rootView.find('.symbols-view')).toExist()
|
||||
expect(symbolsView.list.children('li').length).toBe 0
|
||||
expect(symbolsView.error).toBeVisible()
|
||||
expect(symbolsView.error.text().length).toBeGreaterThan 0
|
||||
|
||||
# Should remove error
|
||||
symbolsView.miniEditor.setText("")
|
||||
window.advanceClock(symbolsView.inputThrottle)
|
||||
|
||||
expect(symbolsView.list.children('li').length).toBe 2
|
||||
expect(symbolsView.error).not.toBeVisible()
|
||||
|
||||
describe "when tags can't be generated for a file", ->
|
||||
it "shows an error message when no matching tags are found", ->
|
||||
rootView.open('sample.txt')
|
||||
rootView.getActiveView().trigger "symbols-view:toggle-file-symbols"
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
setErrorSpy = spyOn(symbolsView, "setError").andCallThrough()
|
||||
|
||||
waitsFor ->
|
||||
setErrorSpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(symbolsView).toExist()
|
||||
expect(symbolsView.list.children('li').length).toBe 0
|
||||
expect(symbolsView.error).toBeVisible()
|
||||
expect(symbolsView.error.text().length).toBeGreaterThan 0
|
||||
expect(symbolsView.loadingArea).not.toBeVisible()
|
||||
|
||||
it "moves the cursor to the selected function", ->
|
||||
tags = []
|
||||
|
||||
waitsForPromise ->
|
||||
path = require.resolve('fixtures/sample.js')
|
||||
generator = new TagGenerator(path)
|
||||
generator.generate().done (generatedTags) ->
|
||||
tags = generatedTags
|
||||
|
||||
runs ->
|
||||
rootView.open('sample.js')
|
||||
expect(rootView.getActiveView().getCursorBufferPosition()).toEqual [0,0]
|
||||
expect(rootView.find('.symbols-view')).not.toExist()
|
||||
symbolsView = SymbolsView.activate()
|
||||
symbolsView.setArray(tags)
|
||||
symbolsView.attach()
|
||||
expect(rootView.find('.symbols-view')).toExist()
|
||||
symbolsView.confirmed(tags[1])
|
||||
expect(rootView.getActiveView().getCursorBufferPosition()).toEqual [1,2]
|
||||
|
||||
describe "TagGenerator", ->
|
||||
it "generates tags for all JavaScript functions", ->
|
||||
tags = []
|
||||
|
||||
waitsForPromise ->
|
||||
path = require.resolve('fixtures/sample.js')
|
||||
generator = new TagGenerator(path)
|
||||
generator.generate().done (generatedTags) ->
|
||||
tags = generatedTags
|
||||
|
||||
runs ->
|
||||
expect(tags.length).toBe 2
|
||||
expect(tags[0].name).toBe "quicksort"
|
||||
expect(tags[0].position.row).toBe 0
|
||||
expect(tags[1].name).toBe "quicksort.sort"
|
||||
expect(tags[1].position.row).toBe 1
|
||||
|
||||
it "generates no tags for text file", ->
|
||||
tags = []
|
||||
|
||||
waitsForPromise ->
|
||||
path = require.resolve('fixtures/sample.txt')
|
||||
generator = new TagGenerator(path)
|
||||
generator.generate().done (generatedTags) ->
|
||||
tags = generatedTags
|
||||
|
||||
runs ->
|
||||
expect(tags.length).toBe 0
|
||||
|
||||
describe "go to declaration", ->
|
||||
it "doesn't move the cursor when no declaration is found", ->
|
||||
rootView.open("tagged.js")
|
||||
editor = rootView.getActiveView()
|
||||
editor.setCursorBufferPosition([0,2])
|
||||
editor.trigger 'symbols-view:go-to-declaration'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0,2]
|
||||
|
||||
it "moves the cursor to the declaration", ->
|
||||
rootView.open("tagged.js")
|
||||
editor = rootView.getActiveView()
|
||||
editor.setCursorBufferPosition([6,24])
|
||||
editor.trigger 'symbols-view:go-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.getActiveView()
|
||||
editor.setCursorBufferPosition([8,14])
|
||||
editor.trigger 'symbols-view:go-to-declaration'
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
expect(symbolsView.list.children('li').length).toBe 2
|
||||
expect(symbolsView).toBeVisible()
|
||||
symbolsView.confirmed(symbolsView.array[0])
|
||||
expect(rootView.getActiveView().getPath()).toBe project.resolve("tagged-duplicate.js")
|
||||
expect(rootView.getActiveView().getCursorBufferPosition()).toEqual [0,4]
|
||||
|
||||
describe "when the tag is in a file that doesn't exist", ->
|
||||
renamedPath = null
|
||||
|
||||
beforeEach ->
|
||||
renamedPath = project.resolve("tagged-duplicate-renamed.js")
|
||||
fsUtils.remove(renamedPath) if fsUtils.exists(renamedPath)
|
||||
fsUtils.move(project.resolve("tagged-duplicate.js"), renamedPath)
|
||||
|
||||
afterEach ->
|
||||
fsUtils.move(renamedPath, project.resolve("tagged-duplicate.js"))
|
||||
|
||||
it "doesn't display the tag", ->
|
||||
rootView.open("tagged.js")
|
||||
editor = rootView.getActiveView()
|
||||
editor.setCursorBufferPosition([8,14])
|
||||
editor.trigger 'symbols-view:go-to-declaration'
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
expect(symbolsView.list.children('li').length).toBe 1
|
||||
expect(symbolsView.list.children('li:first').find('.primary-line')).toHaveText 'tagged.js'
|
||||
|
||||
describe "project symbols", ->
|
||||
it "displays all tags", ->
|
||||
rootView.open("tagged.js")
|
||||
expect(rootView.find('.symbols-view')).not.toExist()
|
||||
rootView.trigger "symbols-view:toggle-project-symbols"
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
expect(symbolsView.loading).toHaveText 'Loading symbols...'
|
||||
|
||||
waitsFor ->
|
||||
setArraySpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(symbolsView.loading).toBeEmpty()
|
||||
expect(rootView.find('.symbols-view')).toExist()
|
||||
expect(symbolsView.list.children('li').length).toBe 4
|
||||
expect(symbolsView.list.children('li:first').find('.primary-line')).toHaveText 'callMeMaybe'
|
||||
expect(symbolsView.list.children('li:first').find('.secondary-line')).toHaveText 'tagged.js'
|
||||
expect(symbolsView.list.children('li:last').find('.primary-line')).toHaveText 'thisIsCrazy'
|
||||
expect(symbolsView.list.children('li:last').find('.secondary-line')).toHaveText 'tagged.js'
|
||||
expect(symbolsView.error).not.toBeVisible()
|
||||
|
||||
describe "when selecting a tag", ->
|
||||
describe "when the file doesn't exist", ->
|
||||
renamedPath = null
|
||||
|
||||
beforeEach ->
|
||||
renamedPath = project.resolve("tagged-renamed.js")
|
||||
fsUtils.remove(renamedPath) if fsUtils.exists(renamedPath)
|
||||
fsUtils.move(project.resolve("tagged.js"), renamedPath)
|
||||
|
||||
afterEach ->
|
||||
fsUtils.move(renamedPath, project.resolve("tagged.js"))
|
||||
|
||||
it "doesn't open the editor", ->
|
||||
rootView.trigger "symbols-view:toggle-project-symbols"
|
||||
symbolsView = rootView.find('.symbols-view').view()
|
||||
|
||||
waitsFor ->
|
||||
setArraySpy.callCount > 0
|
||||
|
||||
runs ->
|
||||
spyOn(rootView, 'open').andCallThrough()
|
||||
symbolsView.list.children('li:first').mousedown().mouseup()
|
||||
expect(rootView.open).not.toHaveBeenCalled()
|
||||
expect(symbolsView.error.text().length).toBeGreaterThan 0
|
||||
BIN
vendor/ctags
vendored
BIN
vendor/ctags
vendored
Binary file not shown.
Reference in New Issue
Block a user