Merge remote-tracking branch 'origin/dev' into cefode

This commit is contained in:
Kevin Sawicki
2013-03-07 11:44:46 -08:00
88 changed files with 2744 additions and 2191 deletions

View File

@@ -17,8 +17,8 @@ describe "Autocomplete", ->
autocompletePackage = window.loadPackage("autocomplete")
expect(AutocompleteView.prototype.initialize).not.toHaveBeenCalled()
leftEditor = rootView.getActiveEditor()
rightEditor = rootView.getActiveEditor().splitRight()
leftEditor = rootView.getActiveView()
rightEditor = leftEditor.splitRight()
leftEditor.trigger 'autocomplete:attach'
expect(leftEditor.find('.autocomplete')).toExist()
@@ -40,7 +40,7 @@ describe "AutocompleteView", ->
beforeEach ->
window.rootView = new RootView
editor = new Editor(editSession: fixturesProject.buildEditSessionForPath('sample.js'))
editor = new Editor(editSession: project.buildEditSession('sample.js'))
window.loadPackage('autocomplete')
autocomplete = new AutocompleteView(editor)
miniEditor = autocomplete.miniEditor

View File

@@ -7,7 +7,7 @@ describe "Autoflow package", ->
window.rootView = new RootView
rootView.open()
window.loadPackage 'autoflow'
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
config.set('editor.preferredLineLength', 30)
describe "autoflow:reflow-paragraph", ->

View File

@@ -8,7 +8,7 @@ describe "bracket matching", ->
rootView.open('sample.js')
window.loadPackage('bracket-matcher')
rootView.attachToDom()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
editSession = editor.activeEditSession
buffer = editSession.buffer

View File

@@ -9,7 +9,7 @@ describe "CommandLogger", ->
rootView.open('sample.js')
commandLogger = window.loadPackage('command-logger').packageMain
commandLogger.eventLog = {}
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
describe "when a command is triggered", ->
it "records the number of times the command is triggered", ->

View File

@@ -19,8 +19,8 @@ describe "CommandPalette", ->
describe "when command-palette:toggle is triggered on the root view", ->
it "shows a list of all valid command descriptions, names, and keybindings for the previously focused element", ->
keyBindings = _.losslessInvert(keymap.bindingsForElement(rootView.getActiveEditor()))
for eventName, description of rootView.getActiveEditor().events()
keyBindings = _.losslessInvert(keymap.bindingsForElement(rootView.getActiveView()))
for eventName, description of rootView.getActiveView().events()
eventLi = palette.list.children("[data-event-name='#{eventName}']")
if description
expect(eventLi).toExist()
@@ -32,7 +32,7 @@ describe "CommandPalette", ->
expect(eventLi).not.toExist()
it "displays all commands registerd on the window", ->
editorEvents = rootView.getActiveEditor().events()
editorEvents = rootView.getActiveView().events()
windowEvents = $(window).events()
expect(_.isEmpty(windowEvents)).toBeFalsy()
for eventName, description of windowEvents
@@ -60,19 +60,19 @@ describe "CommandPalette", ->
expect(palette.hasParent()).toBeTruthy()
palette.trigger 'command-palette:toggle'
expect(palette.hasParent()).toBeFalsy()
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when the command palette is cancelled", ->
it "focuses the root view and detaches the command palette", ->
expect(palette.hasParent()).toBeTruthy()
palette.cancel()
expect(palette.hasParent()).toBeFalsy()
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when an command selection is confirmed", ->
it "detaches the palette, then focuses the previously focused element and emits the selected command on it", ->
eventHandler = jasmine.createSpy 'eventHandler'
activeEditor = rootView.getActiveEditor()
activeEditor = rootView.getActiveView()
{eventName} = palette.array[5]
activeEditor.preempt eventName, eventHandler

View File

@@ -120,7 +120,7 @@ class CommandPanelView extends View
@errorMessages.empty()
try
@commandInterpreter.eval(command, rootView.getActiveEditSession()).done ({operationsToPreview, errorMessages}) =>
@commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) =>
@loadingMessage.hide()
@history.push(command)
@historyIndex = @history.length
@@ -155,12 +155,12 @@ class CommandPanelView extends View
@miniEditor.setText(@history[@historyIndex] or '')
repeatRelativeAddress: ->
@commandInterpreter.repeatRelativeAddress(rootView.getActiveEditSession())
@commandInterpreter.repeatRelativeAddress(rootView.getActivePaneItem())
repeatRelativeAddressInReverse: ->
@commandInterpreter.repeatRelativeAddressInReverse(rootView.getActiveEditSession())
@commandInterpreter.repeatRelativeAddressInReverse(rootView.getActivePaneItem())
setSelectionAsLastRelativeAddress: ->
selection = rootView.getActiveEditor().getSelectedText()
selection = rootView.getActiveView().getSelectedText()
regex = _.escapeRegExp(selection)
@commandInterpreter.lastRelativeAddress = new CompositeCommand([new RegexAddress(regex)])

View File

@@ -6,12 +6,11 @@ EditSession = require 'edit-session'
_ = require 'underscore'
describe "CommandInterpreter", ->
[project, interpreter, editSession, buffer] = []
[interpreter, editSession, buffer] = []
beforeEach ->
project = new Project(fixturesProject.resolve('dir/'))
interpreter = new CommandInterpreter(fixturesProject)
editSession = fixturesProject.buildEditSessionForPath('sample.js')
interpreter = new CommandInterpreter(project)
editSession = project.buildEditSession('sample.js')
buffer = editSession.buffer
afterEach ->
@@ -418,7 +417,7 @@ describe "CommandInterpreter", ->
describe "X x/regex/", ->
it "returns selection operations for all regex matches in all the project's files", ->
editSession.destroy()
project = new Project(fixturesProject.resolve('dir/'))
project.setPath(project.resolve('dir'))
interpreter = new CommandInterpreter(project)
operationsToPreview = null
@@ -428,7 +427,7 @@ describe "CommandInterpreter", ->
runs ->
expect(operationsToPreview.length).toBeGreaterThan 3
for operation in operationsToPreview
editSession = project.buildEditSessionForPath(operation.getPath())
editSession = project.buildEditSession(operation.getPath())
editSession.setSelectedBufferRange(operation.execute(editSession))
expect(editSession.getSelectedText()).toMatch /a+/
editSession.destroy()

View File

@@ -3,14 +3,14 @@ CommandPanelView = require 'command-panel/lib/command-panel-view'
_ = require 'underscore'
describe "CommandPanel", ->
[editor, buffer, commandPanel] = []
[editSession, buffer, commandPanel] = []
beforeEach ->
window.rootView = new RootView
rootView.open('sample.js')
rootView.enableKeymap()
editor = rootView.getActiveEditor()
buffer = editor.activeEditSession.buffer
editSession = rootView.getActivePaneItem()
buffer = editSession.buffer
commandPanelMain = window.loadPackage('command-panel', activateImmediately: true).packageMain
commandPanel = commandPanelMain.commandPanelView
commandPanel.history = []
@@ -219,41 +219,41 @@ describe "CommandPanel", ->
it "repeats the last search command if there is one", ->
rootView.trigger 'command-panel:repeat-relative-address'
editor.setCursorScreenPosition([4, 0])
editSession.setCursorScreenPosition([4, 0])
commandPanel.execute("/current")
expect(editor.getSelection().getBufferRange()).toEqual [[5,6], [5,13]]
expect(editSession.getSelectedBufferRange()).toEqual [[5,6], [5,13]]
rootView.trigger 'command-panel:repeat-relative-address'
expect(editor.getSelection().getBufferRange()).toEqual [[6,6], [6,13]]
expect(editSession.getSelectedBufferRange()).toEqual [[6,6], [6,13]]
commandPanel.execute('s/r/R/g')
rootView.trigger 'command-panel:repeat-relative-address'
expect(editor.getSelection().getBufferRange()).toEqual [[6,34], [6,41]]
expect(editSession.getSelectedBufferRange()).toEqual [[6,34], [6,41]]
commandPanel.execute('0')
commandPanel.execute('/sort/ s/r/R/') # this contains a substitution... won't be repeated
rootView.trigger 'command-panel:repeat-relative-address'
expect(editor.getSelection().getBufferRange()).toEqual [[3,31], [3,38]]
expect(editSession.getSelectedBufferRange()).toEqual [[3,31], [3,38]]
describe "when command-panel:repeat-relative-address-in-reverse is triggered on the root view", ->
it "it repeats the last relative address in the reverse direction", ->
rootView.trigger 'command-panel:repeat-relative-address-in-reverse'
editor.setCursorScreenPosition([6, 0])
editSession.setCursorScreenPosition([6, 0])
commandPanel.execute("/current")
expect(editor.getSelection().getBufferRange()).toEqual [[6,6], [6,13]]
expect(editSession.getSelectedBufferRange()).toEqual [[6,6], [6,13]]
rootView.trigger 'command-panel:repeat-relative-address-in-reverse'
expect(editor.getSelection().getBufferRange()).toEqual [[5,6], [5,13]]
expect(editSession.getSelectedBufferRange()).toEqual [[5,6], [5,13]]
describe "when command-panel:set-selection-as-regex-address is triggered on the root view", ->
it "sets the @lastRelativeAddress to a RegexAddress of the current selection", ->
rootView.open(require.resolve('fixtures/sample.js'))
rootView.getActiveEditor().setSelectedBufferRange([[1,21],[1,28]])
rootView.getActivePaneItem().setSelectedBufferRange([[1,21],[1,28]])
commandInterpreter = commandPanel.commandInterpreter
expect(commandInterpreter.lastRelativeAddress).toBeUndefined()
@@ -267,7 +267,7 @@ describe "CommandPanel", ->
commandPanel.miniEditor.setText("foo")
commandPanel.miniEditor.setCursorBufferPosition([0, 0])
rootView.getActiveEditor().trigger "command-panel:find-in-file"
rootView.getActiveView().trigger "command-panel:find-in-file"
expect(commandPanel.attach).toHaveBeenCalled()
expect(commandPanel.parent).not.toBeEmpty()
expect(commandPanel.miniEditor.getText()).toBe "/"
@@ -297,8 +297,8 @@ describe "CommandPanel", ->
describe "when the command returns operations to be previewed", ->
beforeEach ->
rootView.getActivePane().remove()
rootView.attachToDom()
editor.remove()
rootView.trigger 'command-panel:toggle'
waitsForPromise -> commandPanel.execute('X x/quicksort/')
@@ -350,16 +350,14 @@ describe "CommandPanel", ->
expect(commandPanel).toBeVisible()
expect(commandPanel.errorMessages).not.toBeVisible()
describe "when the command contains an escaped character", ->
it "executes the command with the escaped character (instead of as a backslash followed by the character)", ->
rootView.trigger 'command-panel:toggle'
editSession = rootView.open(require.resolve 'fixtures/sample-with-tabs.coffee')
editor.edit(editSession)
commandPanel.miniEditor.setText "/\\tsell"
commandPanel.miniEditor.hiddenInput.trigger keydownEvent('enter')
expect(editor.getSelectedBufferRange()).toEqual [[3,1],[3,6]]
expect(editSession.getSelectedBufferRange()).toEqual [[3,1],[3,6]]
describe "when move-up and move-down are triggerred on the editor", ->
it "navigates forward and backward through the command history", ->
@@ -470,11 +468,11 @@ describe "CommandPanel", ->
previewList.trigger 'core:confirm'
editSession = rootView.getActiveEditSession()
editSession = rootView.getActivePaneItem()
expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath())
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(editor.isScreenRowVisible(editor.getCursorScreenRow())).toBeTruthy()
expect(rootView.getActiveView().isScreenRowVisible(editSession.getCursorScreenRow())).toBeTruthy()
expect(previewList.focus).toHaveBeenCalled()
expect(executeHandler).not.toHaveBeenCalled()
@@ -496,7 +494,7 @@ describe "CommandPanel", ->
previewList.find('li.operation:eq(4) span').mousedown()
expect(previewList.getSelectedOperation()).toBe operation
editSession = rootView.getActiveEditSession()
editSession = rootView.getActivePaneItem()
expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath())
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(previewList.focus).toHaveBeenCalled()

View File

@@ -22,19 +22,18 @@ class FuzzyFinderView extends SelectList
@subscribe $(window), 'focus', => @reloadProjectPaths = true
@observeConfig 'fuzzy-finder.ignoredNames', => @reloadProjectPaths = true
rootView.eachEditor (editor) ->
editor.activeEditSession.lastOpened = (new Date) - 1
editor.on 'editor:active-edit-session-changed', (e, editSession, index) ->
editSession.lastOpened = (new Date) - 1
rootView.eachPane (pane) ->
pane.activeItem.lastOpened = (new Date) - 1
pane.on 'pane:active-item-changed', (e, item) -> item.lastOpened = (new Date) - 1
@miniEditor.command 'editor:split-left', =>
@splitOpenPath (editor, session) -> editor.splitLeft(session)
@miniEditor.command 'editor:split-right', =>
@splitOpenPath (editor, session) -> editor.splitRight(session)
@miniEditor.command 'editor:split-down', =>
@splitOpenPath (editor, session) -> editor.splitDown(session)
@miniEditor.command 'editor:split-up', =>
@splitOpenPath (editor, session) -> editor.splitUp(session)
@miniEditor.command 'pane:split-left', =>
@splitOpenPath (pane, session) -> pane.splitLeft(session)
@miniEditor.command 'pane:split-right', =>
@splitOpenPath (pane, session) -> pane.splitRight(session)
@miniEditor.command 'pane:split-down', =>
@splitOpenPath (pane, session) -> pane.splitDown(session)
@miniEditor.command 'pane:split-up', =>
@splitOpenPath (pane, session) -> pane.splitUp(session)
itemForElement: (path) ->
$$ ->
@@ -70,10 +69,8 @@ class FuzzyFinderView extends SelectList
splitOpenPath: (fn) ->
path = @getSelectedElement()
return unless path
editor = rootView.getActiveEditor()
if editor
fn(editor, project.buildEditSessionForPath(path))
if pane = rootView.getActivePane()
fn(pane, project.buildEditSession(path))
else
@openPath(path)
@@ -118,7 +115,7 @@ class FuzzyFinderView extends SelectList
else
return unless project.getPath()?
@allowActiveEditorChange = false
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
currentWord = editor.getWordUnderCursor(wordRegex: @filenameRegex)
if currentWord.length == 0
@@ -177,7 +174,7 @@ class FuzzyFinderView extends SelectList
editSession.getPath()?
editSessions = _.sortBy editSessions, (editSession) =>
if editSession is rootView.getActiveEditSession()
if editSession is rootView.getActivePaneItem()
0
else
-(editSession.lastOpened or 1)

View File

@@ -21,8 +21,8 @@ describe 'FuzzyFinder', ->
it "shows the FuzzyFinder or hides it and returns focus to the active editor if it already showing", ->
rootView.attachToDom()
expect(rootView.find('.fuzzy-finder')).not.toExist()
rootView.find('.editor').trigger 'editor:split-right'
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
rootView.getActiveView().splitRight()
[editor1, editor2] = rootView.getEditors()
expect(rootView.find('.fuzzy-finder')).not.toExist()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
@@ -72,13 +72,13 @@ describe 'FuzzyFinder', ->
describe "when a path selection is confirmed", ->
it "opens the file associated with that path in the editor", ->
rootView.attachToDom()
editor1 = rootView.getActiveEditor()
editor1 = rootView.getActiveView()
editor2 = editor1.splitRight()
expect(rootView.getActiveEditor()).toBe editor2
expect(rootView.getActiveView()).toBe editor2
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finderView.confirmed('dir/a')
expectedPath = fixturesProject.resolve('dir/a')
expectedPath = project.resolve('dir/a')
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
@@ -88,26 +88,26 @@ describe 'FuzzyFinder', ->
describe "when the selected path isn't a file that exists", ->
it "leaves the the tree view open, doesn't open the path in the editor, and displays an error", ->
rootView.attachToDom()
path = rootView.getActiveEditor().getPath()
path = rootView.getActiveView().getPath()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finderView.confirmed('dir/this/is/not/a/file.txt')
expect(finderView.hasParent()).toBeTruthy()
expect(rootView.getActiveEditor().getPath()).toBe path
expect(rootView.getActiveView().getPath()).toBe path
expect(finderView.find('.error').text().length).toBeGreaterThan 0
advanceClock(2000)
expect(finderView.find('.error').text().length).toBe 0
describe "buffer-finder behavior", ->
describe "toggling", ->
describe "when the active editor contains edit sessions for buffers with paths", ->
describe "when there are pane items with paths", ->
beforeEach ->
rootView.open('sample.txt')
it "shows the FuzzyFinder or hides it, returning focus to the active editor if", ->
it "shows the FuzzyFinder if it isn't showing, or hides it and returns focus to the active editor", ->
rootView.attachToDom()
expect(rootView.find('.fuzzy-finder')).not.toExist()
rootView.find('.editor').trigger 'editor:split-right'
[editor1, editor2] = rootView.find('.editor').map -> $(this).view()
rootView.getActiveView().splitRight()
[editor1, editor2] = rootView.getEditors()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.find('.fuzzy-finder')).toExist()
@@ -122,26 +122,17 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(finderView.miniEditor.getText()).toBe ''
it "lists the paths of the current open buffers by most recently modified", ->
it "lists the paths of the current items, sorted by most recently opened but with the current item last", ->
rootView.attachToDom()
rootView.open 'sample-with-tabs.coffee'
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
children = finderView.list.children('li')
expect(children.get(0).outerText).toBe "sample.txt"
expect(children.get(1).outerText).toBe "sample.js"
expect(children.get(2).outerText).toBe "sample-with-tabs.coffee"
expect(_.pluck(finderView.list.children('li'), 'outerText')).toEqual ['sample.txt', 'sample.js', 'sample-with-tabs.coffee']
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
rootView.open 'sample.txt'
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
children = finderView.list.children('li')
expect(children.get(0).outerText).toBe "sample-with-tabs.coffee"
expect(children.get(1).outerText).toBe "sample.js"
expect(children.get(2).outerText).toBe "sample.txt"
expect(finderView.list.children('li').length).toBe 3
expect(finderView.list.find("li:contains(sample.js)")).toExist()
expect(finderView.list.find("li:contains(sample.txt)")).toExist()
expect(finderView.list.find("li:contains(sample-with-tabs.coffee)")).toExist()
expect(_.pluck(finderView.list.children('li'), 'outerText')).toEqual ['sample-with-tabs.coffee', 'sample.js', 'sample.txt']
expect(finderView.list.children().first()).toHaveClass 'selected'
it "serializes the list of paths and their last opened time", ->
@@ -151,29 +142,26 @@ describe 'FuzzyFinder', ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
rootView.open()
states = rootView.serialize().packageStates
states = rootView.serialize().packages
states = _.map states['fuzzy-finder'], (path, time) -> [ path, time ]
states = _.sortBy states, (path, time) -> -time
paths = [ 'sample-with-tabs.coffee', 'sample.txt', 'sample.js' ]
for [time, path] in states
expect(_.last path.split '/').toBe paths.shift()
expect(time).toBeGreaterThan 50000
describe "when the active editor only contains edit sessions for anonymous buffers", ->
describe "when there are only panes with anonymous items", ->
it "does not open", ->
editor = rootView.getActiveEditor()
editor.edit(project.buildEditSessionForPath())
editor.loadPreviousEditSession()
editor.destroyActiveEditSession()
expect(editor.getOpenBufferPaths().length).toBe 0
rootView.getActivePane().remove()
rootView.open()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.find('.fuzzy-finder')).not.toExist()
describe "when there is no active editor", ->
describe "when there are no pane items", ->
it "does not open", ->
rootView.getActiveEditor().destroyActiveEditSession()
expect(rootView.getActiveEditor()).toBeUndefined()
rootView.getActivePane().remove()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.find('.fuzzy-finder')).not.toExist()
@@ -182,16 +170,16 @@ describe 'FuzzyFinder', ->
beforeEach ->
rootView.attachToDom()
editor1 = rootView.getActiveEditor()
editor1 = rootView.getActiveView()
editor2 = editor1.splitRight()
expect(rootView.getActiveEditor()).toBe editor2
expect(rootView.getActiveView()).toBe editor2
rootView.open('sample.txt')
editor2.loadPreviousEditSession()
editor2.trigger 'pane:show-previous-item'
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
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')
describe "when the active pane has an item for the selected path", ->
it "switches to the item for the selected path", ->
expectedPath = project.resolve('sample.txt')
finderView.confirmed('sample.txt')
expect(finderView.hasParent()).toBeFalsy()
@@ -199,27 +187,26 @@ describe 'FuzzyFinder', ->
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", ->
describe "when the active pane does not have an item for the selected path", ->
it "adds a new item to the active pane for the selcted path", ->
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
editor1.focus()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
expect(rootView.getActiveEditor()).toBe editor1
expect(rootView.getActiveView()).toBe editor1
expectedPath = fixturesProject.resolve('sample.txt')
expectedPath = project.resolve('sample.txt')
finderView.confirmed('sample.txt')
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
expect(editor1.getPath()).toBe expectedPath
expect(editor1.isFocused).toBeTruthy()
describe "git-status-finder behavior", ->
[originalText, originalPath, newPath] = []
beforeEach ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
originalText = editor.getText()
originalPath = editor.getPath()
fs.write(originalPath, 'making a change for the better')
@@ -248,7 +235,7 @@ describe 'FuzzyFinder', ->
describe "when an editor is open", ->
it "detaches the finder and focuses the previously focused element", ->
rootView.attachToDom()
activeEditor = rootView.getActiveEditor()
activeEditor = rootView.getActiveView()
activeEditor.focus()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
@@ -265,7 +252,7 @@ describe 'FuzzyFinder', ->
describe "when no editors are open", ->
it "detaches the finder and focuses the previously focused element", ->
rootView.attachToDom()
rootView.getActiveEditor().destroyActiveEditSession()
rootView.getActivePane().remove()
inputView = $$ -> @input()
rootView.append(inputView)
@@ -351,7 +338,7 @@ describe 'FuzzyFinder', ->
editor = null
beforeEach ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
rootView.attachToDom()
it "opens the fuzzy finder window when there are multiple matches", ->
@@ -405,59 +392,63 @@ describe 'FuzzyFinder', ->
expect(finderView.find('.error').text().length).toBeGreaterThan 0
describe "opening a path into a split", ->
beforeEach ->
rootView.attachToDom()
it "opens the path by splitting the active editor left", ->
expect(rootView.getPanes().length).toBe 1
pane = rootView.getActivePane()
spyOn(pane, "splitLeft").andCallThrough()
describe "when an editor is active", ->
it "opens the path by splitting the active editor left", ->
editor = rootView.getActiveEditor()
spyOn(editor, "splitLeft").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finderView.miniEditor.trigger 'editor:split-left'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitLeft).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
expect(rootView.getActiveEditor().getPath()).toBe editor.getPath()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
path = finderView.getSelectedElement()
finderView.miniEditor.trigger 'pane:split-left'
it "opens the path by splitting the active editor right", ->
editor = rootView.getActiveEditor()
spyOn(editor, "splitRight").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finderView.miniEditor.trigger 'editor:split-right'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitRight).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
expect(rootView.getActiveEditor().getPath()).toBe editor.getPath()
expect(rootView.getPanes().length).toBe 2
expect(pane.splitLeft).toHaveBeenCalled()
expect(rootView.getActiveView().getPath()).toBe project.resolve(path)
it "opens the path by splitting the active editor down", ->
editor = rootView.getActiveEditor()
spyOn(editor, "splitDown").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finderView.miniEditor.trigger 'editor:split-down'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitDown).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
expect(rootView.getActiveEditor().getPath()).toBe editor.getPath()
it "opens the path by splitting the active editor right", ->
expect(rootView.getPanes().length).toBe 1
pane = rootView.getActivePane()
spyOn(pane, "splitRight").andCallThrough()
it "opens the path by splitting the active editor up", ->
editor = rootView.getActiveEditor()
spyOn(editor, "splitUp").andCallThrough()
expect(rootView.find('.editor').length).toBe 1
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
finderView.miniEditor.trigger 'editor:split-up'
expect(rootView.find('.editor').length).toBe 2
expect(editor.splitUp).toHaveBeenCalled()
expect(rootView.getActiveEditor()).not.toBe editor
expect(rootView.getActiveEditor().getPath()).toBe editor.getPath()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
path = finderView.getSelectedElement()
finderView.miniEditor.trigger 'pane:split-right'
expect(rootView.getPanes().length).toBe 2
expect(pane.splitRight).toHaveBeenCalled()
expect(rootView.getActiveView().getPath()).toBe project.resolve(path)
it "opens the path by splitting the active editor up", ->
expect(rootView.getPanes().length).toBe 1
pane = rootView.getActivePane()
spyOn(pane, "splitUp").andCallThrough()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
path = finderView.getSelectedElement()
finderView.miniEditor.trigger 'pane:split-up'
expect(rootView.getPanes().length).toBe 2
expect(pane.splitUp).toHaveBeenCalled()
expect(rootView.getActiveView().getPath()).toBe project.resolve(path)
it "opens the path by splitting the active editor down", ->
expect(rootView.getPanes().length).toBe 1
pane = rootView.getActivePane()
spyOn(pane, "splitDown").andCallThrough()
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
path = finderView.getSelectedElement()
finderView.miniEditor.trigger 'pane:split-down'
expect(rootView.getPanes().length).toBe 2
expect(pane.splitDown).toHaveBeenCalled()
expect(rootView.getActiveView().getPath()).toBe project.resolve(path)
describe "git status decorations", ->
[originalText, originalPath, editor, newPath] = []
beforeEach ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
originalText = editor.getText()
originalPath = editor.getPath()
newPath = project.resolve('newsample.js')
@@ -470,7 +461,7 @@ describe 'FuzzyFinder', ->
describe "when a modified file is shown in the list", ->
it "displays the modified icon", ->
editor.setText('modified')
editor.save()
editor.activeEditSession.save()
git.getPathStatus(editor.getPath())
rootView.trigger 'fuzzy-finder:toggle-buffer-finder'

View File

@@ -136,6 +136,6 @@ describe "GitHub Flavored Markdown grammar", ->
describe "auto indent", ->
it "indents newlines entered after list lines", ->
config.set('editor.autoIndent', true)
editSession = fixturesProject.buildEditSessionForPath('gfm.md')
editSession = project.buildEditSession('gfm.md')
editSession.insertNewlineBelow()
expect(editSession.buffer.lineForRow(1)).toBe ' '

View File

@@ -9,7 +9,7 @@ class Gists
rootView.command 'gist:create', '.editor', => @createGist()
createGist: (editor) ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
return unless editor?
gist = { public: false, files: {} }

View File

@@ -8,7 +8,7 @@ describe "Gists package", ->
window.rootView = new RootView
rootView.open('sample.js')
window.loadPackage('gists')
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
spyOn($, 'ajax')
describe "when gist:create is triggered on an editor", ->

View File

@@ -38,7 +38,7 @@ class GoToLineView extends View
confirm: ->
lineNumber = @miniEditor.getText()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
@detach()
@@ -51,5 +51,5 @@ class GoToLineView extends View
attach: ->
@previouslyFocusedElement = $(':focus')
rootView.append(this)
@message.text("Enter a line number 1-#{rootView.getActiveEditor().getLineCount()}")
@message.text("Enter a line number 1-#{rootView.getActiveView().getLineCount()}")
@miniEditor.focus()

View File

@@ -8,7 +8,7 @@ describe 'GoToLine', ->
window.rootView = new RootView
rootView.open('sample.js')
rootView.enableKeymap()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
goToLine = GoToLineView.activate()
editor.setCursorBufferPosition([1,0])

View File

@@ -40,7 +40,7 @@ class MarkdownPreviewView extends ScrollView
@detaching = false
getActiveText: ->
rootView.getActiveEditor()?.getText()
rootView.getActiveView()?.getText()
getErrorHtml: (error) ->
$$$ ->
@@ -74,7 +74,7 @@ class MarkdownPreviewView extends ScrollView
@markdownBody.html(html) if @hasParent()
isMarkdownEditor: (path) ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
return unless editor?
return true if editor.getGrammar().scopeName is 'source.gfm'
path and fs.isMarkdownExtension(fs.extension(path))

View File

@@ -13,7 +13,7 @@ describe "MarkdownPreview", ->
describe "markdown-preview:toggle event", ->
it "toggles on/off a preview for a .md file", ->
rootView.open('file.md')
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
@@ -25,7 +25,7 @@ describe "MarkdownPreview", ->
it "displays a preview for a .markdown file", ->
rootView.open('file.markdown')
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).toExist()
@@ -35,7 +35,7 @@ describe "MarkdownPreview", ->
it "displays a preview for a file with the source.gfm grammar scope", ->
gfmGrammar = _.find syntax.grammars, (grammar) -> grammar.scopeName is 'source.gfm'
rootView.open('file.js')
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
project.addGrammarOverrideForPath(editor.getPath(), gfmGrammar)
editor.reloadGrammar()
expect(rootView.find('.markdown-preview')).not.toExist()
@@ -46,39 +46,39 @@ describe "MarkdownPreview", ->
it "does not display a preview for non-markdown file", ->
rootView.open('file.js')
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).not.toExist()
expect(MarkdownPreview.prototype.loadHtml).not.toHaveBeenCalled()
describe "core:cancel event", ->
it "removes markdown preview", ->
rootView.open('file.md')
editor = rootView.getActiveEditor()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
describe "core:cancel event", ->
it "removes markdown preview", ->
rootView.open('file.md')
editor = rootView.getActiveView()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
markdownPreviewView = rootView.find('.markdown-preview')?.view()
expect(markdownPreviewView).toExist()
markdownPreviewView.trigger('core:cancel')
expect(rootView.find('.markdown-preview')).not.toExist()
markdownPreviewView = rootView.find('.markdown-preview')?.view()
expect(markdownPreviewView).toExist()
markdownPreviewView.trigger('core:cancel')
expect(rootView.find('.markdown-preview')).not.toExist()
describe "when the editor receives focus", ->
it "removes the markdown preview view", ->
rootView.attachToDom()
rootView.open('file.md')
editor = rootView.getActiveEditor()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
describe "when the editor receives focus", ->
it "removes the markdown preview view", ->
rootView.attachToDom()
rootView.open('file.md')
editor = rootView.getActiveView()
expect(rootView.find('.markdown-preview')).not.toExist()
editor.trigger('markdown-preview:toggle')
markdownPreviewView = rootView.find('.markdown-preview')
editor.focus()
expect(markdownPreviewView).toExist()
expect(rootView.find('.markdown-preview')).not.toExist()
markdownPreviewView = rootView.find('.markdown-preview')
editor.focus()
expect(markdownPreviewView).toExist()
expect(rootView.find('.markdown-preview')).not.toExist()
describe "when no editor is open", ->
it "does not attach", ->
expect(rootView.getActiveEditor()).toBeFalsy()
rootView.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).not.toExist()
describe "when no editor is open", ->
it "does not attach", ->
expect(rootView.getActiveView()).toBeFalsy()
rootView.trigger('markdown-preview:toggle')
expect(rootView.find('.markdown-preview')).not.toExist()

View File

@@ -21,11 +21,11 @@ describe 'Package Generator', ->
rootView.trigger("package-generator:generate")
packageGeneratorView = rootView.find(".package-generator").view()
expect(packageGeneratorView.miniEditor.isFocused).toBeTruthy()
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().isFocused).toBeFalsy()
packageGeneratorView.trigger("core:cancel")
expect(packageGeneratorView.hasParent()).toBeFalsy()
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when a package is generated", ->
[packageName, packagePath] = []
@@ -58,6 +58,7 @@ describe 'Package Generator', ->
expect(fs.join(fs.directory(packagePath), "camel-case-is-for-the-birds")).toExistOnDisk()
it "correctly lays out the package files and closes the package generator view", ->
rootView.attachToDom()
rootView.trigger("package-generator:generate")
packageGeneratorView = rootView.find(".package-generator").view()
expect(packageGeneratorView.hasParent()).toBeTruthy()
@@ -73,7 +74,7 @@ describe 'Package Generator', ->
expect("#{packagePath}/stylesheets/#{packageName}.css").toExistOnDisk()
expect(packageGeneratorView.hasParent()).toBeFalsy()
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
it "replaces instances of packageName placeholders in template files", ->
rootView.trigger("package-generator:generate")

View File

@@ -21,8 +21,8 @@ describe "Snippets extension", ->
window.loadPackage("snippets")
editor = rootView.getActiveEditor()
editSession = rootView.getActiveEditSession()
editor = rootView.getActiveView()
editSession = rootView.getActivePaneItem()
buffer = editor.getBuffer()
rootView.simulateDomAttachment()
rootView.enableKeymap()
@@ -300,7 +300,7 @@ describe "Snippets extension", ->
jasmine.unspy(LoadSnippetsTask.prototype, 'loadTextMateSnippets')
snippets.loaded = false
task = new LoadSnippetsTask(snippets)
task.packages = [Package.build(fixturesProject.resolve('packages/package-with-a-cson-grammar.tmbundle'))]
task.packages = [Package.build(project.resolve('packages/package-with-a-cson-grammar.tmbundle'))]
task.start()
waitsFor "CSON snippets to load", 5000, -> snippets.loaded

View File

@@ -9,7 +9,7 @@ describe "Spell check", ->
config.set('spell-check.grammars', [])
window.loadPackage('spell-check')
rootView.attachToDom()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
it "decorates all misspelled words", ->
editor.setText("This middle of thiss sentencts has issues.")
@@ -110,5 +110,5 @@ describe "Spell check", ->
view = editor.find('.misspelling').view()
buffer = editor.getBuffer()
expect(buffer.getMarkerPosition(view.marker)).not.toBeUndefined()
editor.destroyEditSessions()
editor.remove()
expect(buffer.getMarkerPosition(view.marker)).toBeUndefined()

View File

@@ -47,7 +47,7 @@ class StatusBarView extends View
subscribeToBuffer: ->
@buffer?.off '.status-bar'
@buffer = @editor.getBuffer()
@buffer.on 'contents-modified.status-bar', (e) => @updateBufferHasModifiedText(e.differsFromDisk)
@buffer.on 'modified-status-changed.status-bar', (isModified) => @updateBufferHasModifiedText(isModified)
@buffer.on 'saved.status-bar', => @updateStatusBar()
@updateStatusBar()
@@ -60,8 +60,8 @@ class StatusBarView extends View
updateGrammarText: ->
@grammarName.text(@editor.getGrammar().name)
updateBufferHasModifiedText: (differsFromDisk)->
if differsFromDisk
updateBufferHasModifiedText: (isModified)->
if isModified
@bufferModified.text('*') unless @isModified
@isModified = true
else

View File

@@ -12,7 +12,7 @@ describe "StatusBar", ->
rootView.open('sample.js')
rootView.simulateDomAttachment()
StatusBar.activate()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
statusBar = rootView.find('.status-bar').view()
buffer = editor.getBuffer()
@@ -63,7 +63,7 @@ describe "StatusBar", ->
editor.insertText("\n")
advanceClock(buffer.stoppedChangingDelay)
expect(statusBar.bufferModified.text()).toBe '*'
editor.save()
editor.getBuffer().save()
expect(statusBar.bufferModified.text()).toBe ''
it "disables the buffer modified indicator if the content matches again", ->

View File

@@ -12,7 +12,7 @@ describe "StripTrailingWhitespace", ->
window.loadPackage('strip-trailing-whitespace')
rootView.focus()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
afterEach ->
fs.remove(path) if fs.exists(path)
@@ -23,7 +23,7 @@ describe "StripTrailingWhitespace", ->
# works for buffers that are already open when extension is initialized
editor.insertText("foo \nbar\t \n\nbaz")
editor.save()
editor.getBuffer().save()
expect(editor.getText()).toBe "foo\nbar\n\nbaz"
# works for buffers that are opened after extension is initialized
@@ -47,25 +47,25 @@ describe "StripTrailingWhitespace", ->
it "adds a trailing newline when there is no trailing newline", ->
editor.insertText "foo"
editor.save()
editor.getBuffer().save()
expect(editor.getText()).toBe "foo\n"
it "removes extra trailing newlines and only keeps one", ->
editor.insertText "foo\n\n\n\n"
editor.save()
editor.getBuffer().save()
expect(editor.getText()).toBe "foo\n"
it "leaves a buffer with a single trailing newline untouched", ->
editor.insertText "foo\nbar\n"
editor.save()
editor.getBuffer().save()
expect(editor.getText()).toBe "foo\nbar\n"
it "leaves an empty buffer untouched", ->
editor.insertText ""
editor.save()
editor.getBuffer().save()
expect(editor.getText()).toBe ""
it "leaves a buffer that is a single newline untouched", ->
editor.insertText "\n"
editor.save()
editor.getBuffer().save()
expect(editor.getText()).toBe "\n"

View File

@@ -43,7 +43,7 @@ class SymbolsView extends SelectList
populateFileSymbols: ->
tags = []
callback = (tag) -> tags.push tag
path = rootView.getActiveEditor().getPath()
path = rootView.getActiveView().getPath()
@list.empty()
@setLoading("Generating symbols...")
new TagGenerator(path, callback).generate().done =>
@@ -91,7 +91,7 @@ class SymbolsView extends SelectList
@moveToPosition(position) if position
moveToPosition: (position) ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
editor.scrollToBufferPosition(position, center: true)
editor.setCursorBufferPosition(position)
editor.moveCursorToFirstCharacterOfLine()
@@ -111,7 +111,7 @@ class SymbolsView extends SelectList
return new Point(index, 0) if pattern is $.trim(line)
goToDeclaration: ->
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
matches = TagReader.find(editor)
return unless matches.length

View File

@@ -19,7 +19,7 @@ describe "SymbolsView", ->
describe "when tags can be generated for a file", ->
it "initially displays all JavaScript functions with line numbers", ->
rootView.open('sample.js')
rootView.getActiveEditor().trigger "symbols-view:toggle-file-symbols"
rootView.getActiveView().trigger "symbols-view:toggle-file-symbols"
symbolsView = rootView.find('.symbols-view').view()
expect(symbolsView.find('.loading')).toHaveText 'Generating symbols...'
@@ -39,7 +39,7 @@ describe "SymbolsView", ->
it "displays error when no tags match text in mini-editor", ->
rootView.open('sample.js')
rootView.getActiveEditor().trigger "symbols-view:toggle-file-symbols"
rootView.getActiveView().trigger "symbols-view:toggle-file-symbols"
symbolsView = rootView.find('.symbols-view').view()
waitsFor ->
@@ -66,7 +66,7 @@ describe "SymbolsView", ->
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.getActiveEditor().trigger "symbols-view:toggle-file-symbols"
rootView.getActiveView().trigger "symbols-view:toggle-file-symbols"
symbolsView = rootView.find('.symbols-view').view()
setErrorSpy = spyOn(symbolsView, "setError").andCallThrough()
@@ -93,14 +93,14 @@ describe "SymbolsView", ->
runs ->
rootView.open('sample.js')
expect(rootView.getActiveEditor().getCursorBufferPosition()).toEqual [0,0]
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.getActiveEditor().getCursorBufferPosition()).toEqual [1,2]
expect(rootView.getActiveView().getCursorBufferPosition()).toEqual [1,2]
describe "TagGenerator", ->
it "generates tags for all JavaScript functions", ->
@@ -136,29 +136,29 @@ describe "SymbolsView", ->
describe "go to declaration", ->
it "doesn't move the cursor when no declaration is found", ->
rootView.open("tagged.js")
editor = rootView.getActiveEditor()
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.getActiveEditor()
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.getActiveEditor()
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.getActiveEditor().getPath()).toBe project.resolve("tagged-duplicate.js")
expect(rootView.getActiveEditor().getCursorBufferPosition()).toEqual [0,4]
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
@@ -173,7 +173,7 @@ describe "SymbolsView", ->
it "doesn't display the tag", ->
rootView.open("tagged.js")
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
editor.setCursorBufferPosition([8,14])
editor.trigger 'symbols-view:go-to-declaration'
symbolsView = rootView.find('.symbols-view').view()

View File

@@ -0,0 +1,98 @@
$ = require 'jquery'
_ = require 'underscore'
SortableList = require 'sortable-list'
TabView = require './tab-view'
module.exports =
class TabBarView extends SortableList
@content: ->
@ul class: "tabs #{@viewClass()}"
initialize: (@pane) ->
super
@paneContainer = @pane.getContainer()
@addTabForItem(item) for item in @pane.getItems()
@pane.on 'pane:item-added', (e, item, index) => @addTabForItem(item, index)
@pane.on 'pane:item-moved', (e, item, index) => @moveItemTabToIndex(item, index)
@pane.on 'pane:item-removed', (e, item) => @removeTabForItem(item)
@pane.on 'pane:active-item-changed', => @updateActiveTab()
@updateActiveTab()
@on 'click', '.tab', (e) =>
tab = $(e.target).closest('.tab').view()
@pane.showItem(tab.item)
@pane.focus()
@on 'click', '.tab .close-icon', (e) =>
tab = $(e.target).closest('.tab').view()
@pane.destroyItem(tab.item)
false
@pane.prepend(this)
addTabForItem: (item, index) ->
@insertTabAtIndex(new TabView(item, @pane), index)
moveItemTabToIndex: (item, index) ->
tab = @tabForItem(item)
tab.detach()
@insertTabAtIndex(tab, index)
insertTabAtIndex: (tab, index) ->
followingTab = @tabAtIndex(index) if index?
if followingTab
tab.insertBefore(followingTab)
else
@append(tab)
removeTabForItem: (item) ->
@tabForItem(item).remove()
getTabs: ->
@children('.tab').toArray().map (elt) -> $(elt).view()
tabAtIndex: (index) ->
@children(".tab:eq(#{index})").view()
tabForItem: (item) ->
_.detect @getTabs(), (tab) -> tab.item is item
setActiveTab: (tabView) ->
unless tabView.hasClass('active')
@find(".tab.active").removeClass('active')
tabView.addClass('active')
updateActiveTab: ->
@setActiveTab(@tabForItem(@pane.activeItem))
shouldAllowDrag: ->
(@paneContainer.getPanes().length > 1) or (@pane.getItems().length > 1)
onDragStart: (event) =>
super
pane = $(event.target).closest('.pane')
paneIndex = @paneContainer.indexOfPane(pane)
event.originalEvent.dataTransfer.setData 'from-pane-index', paneIndex
onDrop: (event) =>
super
dataTransfer = event.originalEvent.dataTransfer
fromIndex = parseInt(dataTransfer.getData('sortable-index'))
fromPaneIndex = parseInt(dataTransfer.getData('from-pane-index'))
fromPane = @paneContainer.paneAtIndex(fromPaneIndex)
toIndex = @getSortableElement(event).index()
toPane = $(event.target).closest('.pane').view()
draggedTab = fromPane.find(".tabs .sortable:eq(#{fromIndex})").view()
item = draggedTab.item
if toPane is fromPane
toIndex++ if fromIndex > toIndex
toPane.moveItem(item, toIndex)
else
fromPane.moveItemToPane(item, toPane, toIndex)
toPane.showItem(item)
toPane.focus()

View File

@@ -1,100 +1,55 @@
$ = require 'jquery'
SortableList = require 'sortable-list'
Tab = require './tab'
{View} = require 'space-pen'
fs = require 'fs'
module.exports =
class TabView extends SortableList
@activate: ->
rootView.eachEditor (editor) =>
@prependToEditorPane(editor) if editor.attached
@prependToEditorPane: (editor) ->
if pane = editor.pane()
pane.prepend(new TabView(editor))
class TabView extends View
@content: ->
@ul class: "tabs #{@viewClass()}"
@li class: 'tab sortable', =>
@span class: 'title', outlet: 'title'
@span class: 'close-icon'
initialize: (@editor) ->
super
initialize: (@item, @pane) ->
@item.on? 'title-changed', => @updateTitle()
@item.on? 'modified-status-changed', => @updateModifiedStatus()
@updateTitle()
@updateModifiedStatus()
@addTabForEditSession(editSession) for editSession in @editor.editSessions
updateTitle: ->
return if @updatingTitle
@updatingTitle = true
@setActiveTab(@editor.getActiveEditSessionIndex())
@editor.on 'editor:active-edit-session-changed', (e, editSession, index) => @setActiveTab(index)
@editor.on 'editor:edit-session-added', (e, editSession) => @addTabForEditSession(editSession)
@editor.on 'editor:edit-session-removed', (e, editSession, index) => @removeTabAtIndex(index)
@editor.on 'editor:edit-session-order-changed', (e, editSession, fromIndex, toIndex) =>
fromTab = @find(".tab:eq(#{fromIndex})")
toTab = @find(".tab:eq(#{toIndex})")
fromTab.detach()
if fromIndex < toIndex
fromTab.insertAfter(toTab)
else
fromTab.insertBefore(toTab)
title = @item.getTitle()
useLongTitle = false
for tab in @getSiblingTabs()
if tab.item.getTitle() is title
tab.updateTitle()
useLongTitle = true
title = @item.getLongTitle?() ? title if useLongTitle
@on 'click', '.tab', (e) =>
@editor.setActiveEditSessionIndex($(e.target).closest('.tab').index())
@editor.focus()
@title.text(title)
@updatingTitle = false
@on 'click', '.tab .close-icon', (e) =>
index = $(e.target).closest('.tab').index()
@editor.destroyEditSessionIndex(index)
false
getSiblingTabs: ->
@siblings('.tab').views()
addTabForEditSession: (editSession) ->
@append(new Tab(editSession, @editor))
setActiveTab: (index) ->
@find(".tab.active").removeClass('active')
@find(".tab:eq(#{index})").addClass('active')
removeTabAtIndex: (index) ->
@find(".tab:eq(#{index})").remove()
containsEditSession: (editor, editSession) ->
for session in editor.editSessions
return true if editSession.getPath() is session.getPath()
shouldAllowDrag: (event) ->
panes = rootView.find('.pane')
!(panes.length == 1 && panes.find('.sortable').length == 1)
onDragStart: (event) =>
super
pane = $(event.target).closest('.pane')
paneIndex = rootView.indexOfPane(pane)
event.originalEvent.dataTransfer.setData 'from-pane-index', paneIndex
onDrop: (event) =>
super
droppedNearTab = @getSortableElement(event)
transfer = event.originalEvent.dataTransfer
previousDraggedTabIndex = transfer.getData 'sortable-index'
fromPaneIndex = ~~transfer.getData 'from-pane-index'
toPaneIndex = rootView.indexOfPane($(event.target).closest('.pane'))
fromPane = $(rootView.find('.pane')[fromPaneIndex])
fromEditor = fromPane.find('.editor').view()
draggedTab = fromPane.find(".#{TabView.viewClass()} .sortable:eq(#{previousDraggedTabIndex})")
if draggedTab.is(droppedNearTab)
fromEditor.focus()
return
if fromPaneIndex == toPaneIndex
droppedNearTab = @getSortableElement(event)
fromIndex = draggedTab.index()
toIndex = droppedNearTab.index()
toIndex++ if fromIndex > toIndex
fromEditor.moveEditSessionToIndex(fromIndex, toIndex)
fromEditor.focus()
updateModifiedStatus: ->
if @item.isModified?()
@addClass('modified') unless @isModified
@isModified = true
else
toEditor = rootView.find(".pane:eq(#{toPaneIndex}) > .editor").view()
if @containsEditSession(toEditor, fromEditor.editSessions[draggedTab.index()])
fromEditor.focus()
else
fromEditor.moveEditSessionToEditor(draggedTab.index(), toEditor, droppedNearTab.index() + 1)
toEditor.focus()
@removeClass('modified') if @isModified
@isModified = false
updateFileName: ->
fileNameText = @editSession.buffer.getBaseName()
if fileNameText?
duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName()
if duplicates.length > 1
directory = fs.base(fs.directory(@editSession.getPath()))
fileNameText = "#{fileNameText} - #{directory}" if directory
else
fileNameText = 'untitled'
@fileName.text(fileNameText)
@fileName.attr('title', @editSession.getPath())

View File

@@ -1,40 +0,0 @@
{View} = require 'space-pen'
fs = require 'fs'
module.exports =
class Tab extends View
@content: (editSession) ->
@li class: 'tab sortable', =>
@span class: 'file-name', outlet: 'fileName'
@span class: 'close-icon'
initialize: (@editSession, @editor) ->
@buffer = @editSession.buffer
@subscribe @buffer, 'path-changed', => @updateFileName()
@subscribe @buffer, 'contents-modified', => @updateModifiedStatus()
@subscribe @buffer, 'saved', => @updateModifiedStatus()
@subscribe @editor, 'editor:edit-session-added', => @updateFileName()
@subscribe @editor, 'editor:edit-session-removed', => @updateFileName()
@updateFileName()
@updateModifiedStatus()
updateModifiedStatus: ->
if @buffer.isModified()
@toggleClass('file-modified') unless @isModified
@isModified = true
else
@removeClass('file-modified') if @isModified
@isModified = false
updateFileName: ->
fileNameText = @editSession.buffer.getBaseName()
if fileNameText?
duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName()
if duplicates.length > 1
directory = fs.base(fs.directory(@editSession.getPath()))
fileNameText = "#{fileNameText} - #{directory}" if directory
else
fileNameText = 'untitled'
@fileName.text(fileNameText)
@fileName.attr('title', @editSession.getPath())

View File

@@ -0,0 +1,5 @@
TabBarView = require './tab-bar-view'
module.exports =
activate: ->
rootView.eachPane (pane) => new TabBarView(pane)

View File

@@ -1 +1 @@
'main': 'lib/tab-view'
'main': 'lib/tabs'

View File

@@ -1,231 +1,256 @@
$ = require 'jquery'
_ = require 'underscore'
RootView = require 'root-view'
Pane = require 'pane'
PaneContainer = require 'pane-container'
TabBarView = require 'tabs/lib/tab-bar-view'
fs = require 'fs'
{View} = require 'space-pen'
describe "TabView", ->
[editor, buffer, tabs] = []
describe "Tabs package main", ->
beforeEach ->
window.rootView = new RootView
rootView.open('sample.js')
rootView.open('sample.txt')
rootView.simulateDomAttachment()
window.loadPackage("tabs")
editor = rootView.getActiveEditor()
tabs = rootView.find('.tabs').view()
describe "@activate", ->
it "appends a status bear to all existing and new editors", ->
describe ".activate()", ->
it "appends a tab bar all existing and new panes", ->
expect(rootView.panes.find('.pane').length).toBe 1
expect(rootView.panes.find('.pane > .tabs').length).toBe 1
editor.splitRight()
rootView.getActivePane().splitRight()
expect(rootView.find('.pane').length).toBe 2
expect(rootView.panes.find('.pane > .tabs').length).toBe 2
describe ".initialize()", ->
it "creates a tab for each edit session on the editor to which the tab-strip belongs", ->
expect(editor.editSessions.length).toBe 2
expect(tabs.find('.tab').length).toBe 2
describe "TabBarView", ->
[item1, item2, editSession1, pane, tabBar] = []
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe editor.editSessions[0].buffer.getBaseName()
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe editor.editSessions[1].buffer.getBaseName()
class TestView extends View
@deserialize: ({title, longTitle}) -> new TestView(title, longTitle)
@content: (title) -> @div title
initialize: (@title, @longTitle) ->
getTitle: -> @title
getLongTitle: -> @longTitle
serialize: -> { deserializer: 'TestView', @title, @longTitle }
it "highlights the tab for the current active edit session", ->
expect(editor.getActiveEditSessionIndex()).toBe 1
expect(tabs.find('.tab:eq(1)')).toHaveClass 'active'
beforeEach ->
registerDeserializer(TestView)
item1 = new TestView('Item 1')
item2 = new TestView('Item 2')
editSession1 = project.buildEditSession('sample.js')
paneContainer = new PaneContainer
pane = new Pane(item1, editSession1, item2)
pane.showItem(item2)
paneContainer.append(pane)
tabBar = new TabBarView(pane)
it "sets the title on each tab to be the full path of the edit session", ->
expect(tabs.find('.tab:eq(0) .file-name').attr('title')).toBe editor.editSessions[0].getPath()
expect(tabs.find('.tab:eq(1) .file-name').attr('title')).toBe editor.editSessions[1].getPath()
afterEach ->
unregisterDeserializer(TestView)
describe "when the active edit session changes", ->
it "highlights the tab for the newly-active edit session", ->
editor.setActiveEditSessionIndex(0)
expect(tabs.find('.active').length).toBe 1
expect(tabs.find('.tab:eq(0)')).toHaveClass 'active'
describe ".initialize(pane)", ->
it "creates a tab for each item on the tab bar's parent pane", ->
expect(pane.getItems().length).toBe 3
expect(tabBar.find('.tab').length).toBe 3
editor.setActiveEditSessionIndex(1)
expect(tabs.find('.active').length).toBe 1
expect(tabs.find('.tab:eq(1)')).toHaveClass 'active'
expect(tabBar.find('.tab:eq(0) .title').text()).toBe item1.getTitle()
expect(tabBar.find('.tab:eq(1) .title').text()).toBe editSession1.getTitle()
expect(tabBar.find('.tab:eq(2) .title').text()).toBe item2.getTitle()
describe "when a new edit session is created", ->
it "adds a tab for the new edit session", ->
rootView.open('two-hundred.txt')
expect(tabs.find('.tab').length).toBe 3
expect(tabs.find('.tab:eq(2) .file-name').text()).toBe 'two-hundred.txt'
it "highlights the tab for the active pane item", ->
expect(tabBar.find('.tab:eq(2)')).toHaveClass 'active'
describe "when the edit session's buffer has an undefined path", ->
it "makes the tab text 'untitled'", ->
rootView.open()
expect(tabs.find('.tab').length).toBe 3
expect(tabs.find('.tab:eq(2) .file-name').text()).toBe 'untitled'
describe "when the active pane item changes", ->
it "highlights the tab for the new active pane item", ->
pane.showItem(item1)
expect(tabBar.find('.active').length).toBe 1
expect(tabBar.find('.tab:eq(0)')).toHaveClass 'active'
it "removes the tab's title", ->
rootView.open()
expect(tabs.find('.tab').length).toBe 3
expect(tabs.find('.tab:eq(2) .file-name').attr('title')).toBeUndefined()
pane.showItem(item2)
expect(tabBar.find('.active').length).toBe 1
expect(tabBar.find('.tab:eq(2)')).toHaveClass 'active'
describe "when an edit session is removed", ->
it "removes the tab for the removed edit session", ->
editor.setActiveEditSessionIndex(0)
editor.destroyActiveEditSession()
expect(tabs.find('.tab').length).toBe 1
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.txt'
describe "when a new item is added to the pane", ->
it "adds a tab for the new item at the same index as the item in the pane", ->
pane.showItem(item1)
item3 = new TestView('Item 3')
pane.showItem(item3)
expect(tabBar.find('.tab').length).toBe 4
expect(tabBar.tabAtIndex(1).find('.title')).toHaveText 'Item 3'
it "adds the 'modified' class to the new tab if the item is initially modified", ->
editSession2 = project.buildEditSession('sample.txt')
editSession2.insertText('x')
pane.showItem(editSession2)
expect(tabBar.tabForItem(editSession2)).toHaveClass 'modified'
describe "when an item is removed from the pane", ->
it "removes the item's tab from the tab bar", ->
pane.removeItem(item2)
expect(tabBar.getTabs().length).toBe 2
expect(tabBar.find('.tab:contains(Item 2)')).not.toExist()
describe "when a tab is clicked", ->
it "activates the associated edit session", ->
expect(editor.getActiveEditSessionIndex()).toBe 1
tabs.find('.tab:eq(0)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
tabs.find('.tab:eq(1)').click()
expect(editor.getActiveEditSessionIndex()).toBe 1
it "shows the associated item on the pane and focuses the pane", ->
spyOn(pane, 'focus')
it "focuses the associated editor", ->
rootView.attachToDom()
expect(editor).toMatchSelector ":has(:focus)"
editor.splitRight()
expect(editor).not.toMatchSelector ":has(:focus)"
tabs.find('.tab:eq(0)').click()
expect(editor).toMatchSelector ":has(:focus)"
tabBar.tabAtIndex(0).click()
expect(pane.activeItem).toBe pane.getItems()[0]
describe "when a file name associated with a tab changes", ->
[buffer, oldPath, newPath] = []
tabBar.tabAtIndex(2).click()
expect(pane.activeItem).toBe pane.getItems()[2]
beforeEach ->
buffer = editor.editSessions[0].buffer
oldPath = "/tmp/file-to-rename.txt"
newPath = "/tmp/renamed-file.txt"
fs.write(oldPath, "this old path")
rootView.open(oldPath)
expect(pane.focus.callCount).toBe 2
afterEach ->
fs.remove(newPath) if fs.exists(newPath)
describe "when a tab's close icon is clicked", ->
it "destroys the tab's item on the pane", ->
tabBar.tabForItem(editSession1).find('.close-icon').click()
expect(pane.getItems().length).toBe 2
expect(pane.getItems().indexOf(editSession1)).toBe -1
expect(editSession1.destroyed).toBeTruthy()
expect(tabBar.getTabs().length).toBe 2
expect(tabBar.find('.tab:contains(sample.js)')).not.toExist()
it "updates the file name in the tab", ->
tabFileName = tabs.find('.tab:eq(2) .file-name')
expect(tabFileName).toExist()
editor.setActiveEditSessionIndex(0)
fs.move(oldPath, newPath)
waitsFor "file to be renamed", ->
tabFileName.text() == "renamed-file.txt"
describe "when a tab item's title changes", ->
it "updates the title of the item's tab", ->
editSession1.buffer.setPath('/this/is-a/test.txt')
expect(tabBar.tabForItem(editSession1)).toHaveText 'test.txt'
describe "when the close icon is clicked", ->
it "closes the selected non-active edit session", ->
activeSession = editor.activeEditSession
expect(editor.getActiveEditSessionIndex()).toBe 1
tabs.find('.tab .close-icon:eq(0)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
expect(editor.activeEditSession).toBe activeSession
describe "when two tabs have the same title", ->
it "displays the long title on the tab if it's available from the item", ->
item1.title = "Old Man"
item1.longTitle = "Grumpy Old Man"
item1.trigger 'title-changed'
item2.title = "Old Man"
item2.longTitle = "Jolly Old Man"
item2.trigger 'title-changed'
it "closes the selected active edit session", ->
firstSession = editor.getEditSessions()[0]
expect(editor.getActiveEditSessionIndex()).toBe 1
tabs.find('.tab .close-icon:eq(1)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
expect(editor.activeEditSession).toBe firstSession
expect(tabBar.tabForItem(item1)).toHaveText "Grumpy Old Man"
expect(tabBar.tabForItem(item2)).toHaveText "Jolly Old Man"
describe "when two tabs have the same file name", ->
[tempPath] = []
item2.longTitle = undefined
item2.trigger 'title-changed'
beforeEach ->
tempPath = '/tmp/sample.js'
fs.write(tempPath, 'sample')
expect(tabBar.tabForItem(item1)).toHaveText "Grumpy Old Man"
expect(tabBar.tabForItem(item2)).toHaveText "Old Man"
afterEach ->
fs.remove(tempPath) if fs.exists(tempPath)
describe "when a tab item's modified status changes", ->
it "adds or removes the 'modified' class to the tab based on the status", ->
tab = tabBar.tabForItem(editSession1)
expect(editSession1.isModified()).toBeFalsy()
expect(tab).not.toHaveClass 'modified'
it "displays the parent folder name after the file name", ->
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.js'
rootView.open(tempPath)
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.js - fixtures'
expect(tabs.find('.tab:last .file-name').text()).toBe 'sample.js - tmp'
editor.destroyActiveEditSession()
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.js'
editSession1.insertText('x')
advanceClock(editSession1.buffer.stoppedChangingDelay)
expect(editSession1.isModified()).toBeTruthy()
expect(tab).toHaveClass 'modified'
describe "when an editor:edit-session-order-changed event is triggered", ->
it "updates the order of the tabs to match the new edit session order", ->
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.js"
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt"
editSession1.undo()
advanceClock(editSession1.buffer.stoppedChangingDelay)
expect(editSession1.isModified()).toBeFalsy()
expect(tab).not.toHaveClass 'modified'
editor.moveEditSessionToIndex(0, 1)
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.txt"
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.js"
editor.moveEditSessionToIndex(1, 0)
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.js"
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt"
describe "when a pane item moves to a new index", ->
it "updates the order of the tabs to match the new item order", ->
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"]
pane.moveItem(item2, 1)
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "Item 2", "sample.js"]
pane.moveItem(editSession1, 0)
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 1", "Item 2"]
pane.moveItem(item1, 2)
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 2", "Item 1"]
describe "dragging and dropping tabs", ->
describe "when the tab is dropped onto itself", ->
it "doesn't move the edit session and focuses the editor", ->
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt"
buildDragEvents = (dragged, dropTarget) ->
dataTransfer =
data: {}
setData: (key, value) -> @data[key] = value
getData: (key) -> @data[key]
sortableElement = [tabs.find('.tab:eq(0)')]
spyOn(tabs, 'getSortableElement').andCallFake -> sortableElement[0]
event = $.Event()
event.target = tabs[0]
event.originalEvent =
dataTransfer:
data: {}
setData: (key, value) -> @data[key] = value
getData: (key) -> @data[key]
dragStartEvent = $.Event()
dragStartEvent.target = dragged[0]
dragStartEvent.originalEvent = { dataTransfer }
editor.hiddenInput.focusout()
tabs.onDragStart(event)
tabs.onDrop(event)
dropEvent = $.Event()
dropEvent.target = dropTarget[0]
dropEvent.originalEvent = { dataTransfer }
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.js"
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt"
expect(editor.isFocused).toBeTruthy()
[dragStartEvent, dropEvent]
describe "when a tab is dragged from and dropped onto the same editor", ->
it "moves the edit session, updates the order of the tabs, and focuses the editor", ->
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.js"
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt"
describe "when a tab is dragged within the same pane", ->
describe "when it is dropped on tab that's later in the list", ->
it "moves the tab and its item, shows the tab's item, and focuses the pane", ->
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"]
expect(pane.getItems()).toEqual [item1, editSession1, item2]
expect(pane.activeItem).toBe item2
spyOn(pane, 'focus')
sortableElement = [tabs.find('.tab:eq(0)')]
spyOn(tabs, 'getSortableElement').andCallFake -> sortableElement[0]
event = $.Event()
event.target = tabs[0]
event.originalEvent =
dataTransfer:
data: {}
setData: (key, value) -> @data[key] = value
getData: (key) -> @data[key]
[dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar.tabAtIndex(1))
tabBar.onDragStart(dragStartEvent)
tabBar.onDrop(dropEvent)
editor.hiddenInput.focusout()
tabs.onDragStart(event)
sortableElement = [tabs.find('.tab:eq(1)')]
tabs.onDrop(event)
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 1", "Item 2"]
expect(pane.getItems()).toEqual [editSession1, item1, item2]
expect(pane.activeItem).toBe item1
expect(pane.focus).toHaveBeenCalled()
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.txt"
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.js"
expect(editor.isFocused).toBeTruthy()
describe "when it is dropped on a tab that's earlier in the list", ->
it "moves the tab and its item, shows the tab's item, and focuses the pane", ->
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"]
expect(pane.getItems()).toEqual [item1, editSession1, item2]
expect(pane.activeItem).toBe item2
spyOn(pane, 'focus')
describe "when a tab is dragged from one editor and dropped onto another editor", ->
it "moves the edit session, updates the order of the tabs, and focuses the destination editor", ->
leftTabs = tabs
rightEditor = editor.splitRight()
rightTabs = rootView.find('.tabs:last').view()
[dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(2), tabBar.tabAtIndex(0))
tabBar.onDragStart(dragStartEvent)
tabBar.onDrop(dropEvent)
sortableElement = [leftTabs.find('.tab:eq(0)')]
spyOn(tabs, 'getSortableElement').andCallFake -> sortableElement[0]
event = $.Event()
event.target = leftTabs
event.originalEvent =
dataTransfer:
data: {}
setData: (key, value) -> @data[key] = value
getData: (key) -> @data[key]
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "Item 2", "sample.js"]
expect(pane.getItems()).toEqual [item1, item2, editSession1]
expect(pane.activeItem).toBe item2
expect(pane.focus).toHaveBeenCalled()
rightEditor.hiddenInput.focusout()
tabs.onDragStart(event)
describe "when it is dropped on itself", ->
it "doesn't move the tab or item, but does make it the active item and focuses the pane", ->
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"]
expect(pane.getItems()).toEqual [item1, editSession1, item2]
expect(pane.activeItem).toBe item2
spyOn(pane, 'focus')
event.target = rightTabs
sortableElement = [rightTabs.find('.tab:eq(0)')]
tabs.onDrop(event)
[dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar.tabAtIndex(0))
tabBar.onDragStart(dragStartEvent)
tabBar.onDrop(dropEvent)
expect(rightTabs.find('.tab:eq(0) .file-name').text()).toBe "sample.txt"
expect(rightTabs.find('.tab:eq(1) .file-name').text()).toBe "sample.js"
expect(rightEditor.isFocused).toBeTruthy()
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"]
expect(pane.getItems()).toEqual [item1, editSession1, item2]
expect(pane.activeItem).toBe item1
expect(pane.focus).toHaveBeenCalled()
describe "when a tab is dragged to a different pane", ->
[pane2, tabBar2, item2b] = []
beforeEach ->
pane2 = pane.splitRight()
[item2b] = pane2.getItems()
tabBar2 = new TabBarView(pane2)
it "removes the tab and item from their original pane and moves them to the target pane", ->
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"]
expect(pane.getItems()).toEqual [item1, editSession1, item2]
expect(pane.activeItem).toBe item2
expect(tabBar2.getTabs().map (tab) -> tab.text()).toEqual ["Item 2"]
expect(pane2.getItems()).toEqual [item2b]
expect(pane2.activeItem).toBe item2b
spyOn(pane2, 'focus')
[dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar2.tabAtIndex(0))
tabBar.onDragStart(dragStartEvent)
tabBar.onDrop(dropEvent)
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 2"]
expect(pane.getItems()).toEqual [editSession1, item2]
expect(pane.activeItem).toBe item2
expect(tabBar2.getTabs().map (tab) -> tab.text()).toEqual ["Item 2", "Item 1"]
expect(pane2.getItems()).toEqual [item2b, item1]
expect(pane2.activeItem).toBe item1
expect(pane2.focus).toHaveBeenCalled()

View File

@@ -40,7 +40,7 @@ class TreeView extends ScrollView
else
@selectActiveFile()
rootView.on 'root-view:active-path-changed', => @selectActiveFile()
rootView.on 'pane:active-item-changed pane:became-active', => @selectActiveFile()
project.on 'path-changed', => @updateRoot()
@observeConfig 'core.hideGitIgnoredFiles', => @updateRoot()
@@ -98,7 +98,7 @@ class TreeView extends ScrollView
@openSelectedEntry(false) if entry instanceof FileView
when 2
if entry.is('.selected.file')
rootView.getActiveEditor().focus()
rootView.getActiveView().focus()
else if entry.is('.selected.directory')
entry.toggleExpansion()
@@ -119,6 +119,7 @@ class TreeView extends ScrollView
updateRoot: ->
@root?.remove()
if rootDirectory = project.getRootDirectory()
@root = new DirectoryView(directory: rootDirectory, isExpanded: true, project: project)
@treeViewList.append(@root)
@@ -126,14 +127,14 @@ class TreeView extends ScrollView
@root = null
selectActiveFile: ->
activeFilePath = rootView.getActiveEditor()?.getPath()
activeFilePath = rootView.getActiveView()?.getPath()
@selectEntryForPath(activeFilePath) if activeFilePath
revealActiveFile: ->
@attach()
@focus()
return unless activeFilePath = rootView.getActiveEditor()?.getPath()
return unless activeFilePath = rootView.getActiveView()?.getPath()
activePathComponents = project.relativize(activeFilePath).split('/')
currentPath = project.getPath().replace(/\/$/, '')

View File

@@ -2,7 +2,7 @@ module.exports =
treeView: null
activate: (@state) ->
@state.attached ?= true unless rootView.getActiveEditSession()
@state.attached ?= true unless rootView.getActivePaneItem()
@createView() if @state.attached
rootView.command 'tree-view:toggle', => @createView().toggle()

View File

@@ -65,7 +65,7 @@ describe "TreeView", ->
describe "when the project is assigned a path because a new buffer is saved", ->
it "creates a root directory view but does not attach to the root view", ->
rootView.getActiveEditSession().saveAs("/tmp/test.txt")
rootView.getActivePaneItem().saveAs("/tmp/test.txt")
expect(treeView.hasParent()).toBeFalsy()
expect(treeView.root.getPath()).toBe require.resolve('/tmp')
expect(treeView.root.parent()).toMatchSelector(".tree-view")
@@ -174,14 +174,14 @@ describe "TreeView", ->
describe "if the current file has no path", ->
it "shows and focuses the tree view, but does not attempt to select a specific file", ->
rootView.open()
expect(rootView.getActiveEditSession().getPath()).toBeUndefined()
expect(rootView.getActivePaneItem().getPath()).toBeUndefined()
rootView.trigger 'tree-view:reveal-active-file'
expect(treeView.hasParent()).toBeTruthy()
expect(treeView.focus).toHaveBeenCalled()
describe "if there is no editor open", ->
it "shows and focuses the tree view, but does not attempt to select a specific file", ->
expect(rootView.getActiveEditSession()).toBeUndefined()
expect(rootView.getActivePaneItem()).toBeUndefined()
rootView.trigger 'tree-view:reveal-active-file'
expect(treeView.hasParent()).toBeTruthy()
expect(treeView.focus).toHaveBeenCalled()
@@ -195,7 +195,7 @@ describe "TreeView", ->
treeView.trigger 'tool-panel:unfocus'
expect(treeView).toBeVisible()
expect(treeView.find(".tree-view")).not.toMatchSelector(':focus')
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when core:close is triggered on the tree view", ->
it "detaches the TreeView, focuses the RootView and does not bubble the core:close event", ->
@@ -262,28 +262,28 @@ describe "TreeView", ->
describe "when a file is single-clicked", ->
it "selects the files and opens it in the active editor, without changing focus", ->
expect(rootView.getActiveEditor()).toBeUndefined()
expect(rootView.getActiveView()).toBeUndefined()
sampleJs.trigger clickEvent(originalEvent: { detail: 1 })
expect(sampleJs).toHaveClass 'selected'
expect(rootView.getActiveEditor().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.js')
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.js')
expect(rootView.getActiveView().isFocused).toBeFalsy()
sampleTxt.trigger clickEvent(originalEvent: { detail: 1 })
expect(sampleTxt).toHaveClass 'selected'
expect(treeView.find('.selected').length).toBe 1
expect(rootView.getActiveEditor().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.txt')
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.txt')
expect(rootView.getActiveView().isFocused).toBeFalsy()
describe "when a file is double-clicked", ->
it "selects the file and opens it in the active editor on the first click, then changes focus to the active editor on the second", ->
sampleJs.trigger clickEvent(originalEvent: { detail: 1 })
expect(sampleJs).toHaveClass 'selected'
expect(rootView.getActiveEditor().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.js')
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.js')
expect(rootView.getActiveView().isFocused).toBeFalsy()
sampleJs.trigger clickEvent(originalEvent: { detail: 2 })
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when a directory is single-clicked", ->
it "is selected", ->
@@ -299,26 +299,25 @@ describe "TreeView", ->
expect(subdir).toHaveClass 'selected'
subdir.trigger clickEvent(originalEvent: { detail: 2 })
expect(subdir).toHaveClass 'expanded'
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().isFocused).toBeFalsy()
describe "when a new file is opened in the active editor", ->
it "is selected in the tree view if the file's entry visible", ->
it "selects the file in the tree view if the file's entry visible", ->
sampleJs.click()
rootView.open(require.resolve('fixtures/tree-view/tree-view.txt'))
expect(sampleTxt).toHaveClass 'selected'
expect(treeView.find('.selected').length).toBe 1
it "selected a file's parent dir if the file's entry is not visible", ->
rootView.open(require.resolve('fixtures/tree-view/dir1/sub-dir1/sub-file1'))
it "selects the file's parent dir if the file's entry is not visible", ->
rootView.open('dir1/sub-dir1/sub-file1')
dirView = treeView.root.find('.directory:contains(dir1)').view()
expect(dirView).toHaveClass 'selected'
describe "when a different editor becomes active", ->
it "selects the file in that is open in that editor", ->
sampleJs.click()
leftEditor = rootView.getActiveEditor()
leftEditor = rootView.getActiveView()
rightEditor = leftEditor.splitRight()
sampleTxt.click()
@@ -569,8 +568,8 @@ describe "TreeView", ->
it "opens the file in the editor and focuses it", ->
treeView.root.find('.file:contains(tree-view.js)').click()
treeView.root.trigger 'tree-view:open-selected-entry'
expect(rootView.getActiveEditor().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.js')
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().getPath()).toBe require.resolve('fixtures/tree-view/tree-view.js')
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when a directory is selected", ->
it "expands or collapses the directory", ->
@@ -586,7 +585,7 @@ describe "TreeView", ->
describe "when nothing is selected", ->
it "does nothing", ->
treeView.root.trigger 'tree-view:open-selected-entry'
expect(rootView.getActiveEditor()).toBeUndefined()
expect(rootView.getActiveView()).toBeUndefined()
describe "file modification", ->
[dirView, fileView, rootDirPath, dirPath, filePath] = []
@@ -650,7 +649,7 @@ describe "TreeView", ->
expect(fs.exists(newPath)).toBeTruthy()
expect(fs.isFile(newPath)).toBeTruthy()
expect(addDialog.parent()).not.toExist()
expect(rootView.getActiveEditor().getPath()).toBe newPath
expect(rootView.getActiveView().getPath()).toBe newPath
waitsFor "tree view to be updated", ->
dirView.entries.find("> .file").length > 1
@@ -680,9 +679,9 @@ describe "TreeView", ->
expect(fs.exists(newPath)).toBeTruthy()
expect(fs.isDirectory(newPath)).toBeTruthy()
expect(addDialog.parent()).not.toExist()
expect(rootView.getActiveEditor().getPath()).not.toBe newPath
expect(rootView.getActiveView().getPath()).not.toBe newPath
expect(treeView.find(".tree-view")).toMatchSelector(':focus')
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().isFocused).toBeFalsy()
expect(dirView.find('.directory.selected:contains(new)').length).toBe(1)
it "selects the created directory", ->
@@ -693,9 +692,9 @@ describe "TreeView", ->
expect(fs.exists(newPath)).toBeTruthy()
expect(fs.isDirectory(newPath)).toBeTruthy()
expect(addDialog.parent()).not.toExist()
expect(rootView.getActiveEditor().getPath()).not.toBe newPath
expect(rootView.getActiveView().getPath()).not.toBe newPath
expect(treeView.find(".tree-view")).toMatchSelector(':focus')
expect(rootView.getActiveEditor().isFocused).toBeFalsy()
expect(rootView.getActiveView().isFocused).toBeFalsy()
expect(dirView.find('.directory.selected:contains(new2)').length).toBe(1)
describe "when a file or directory already exists at the given path", ->
@@ -722,7 +721,7 @@ describe "TreeView", ->
rootView.attachToDom()
rootView.focus()
expect(addDialog.parent()).not.toExist()
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when a directory is selected", ->
it "opens an add dialog with the directory's path populated", ->
@@ -839,7 +838,7 @@ describe "TreeView", ->
rootView.attachToDom()
rootView.focus()
expect(moveDialog.parent()).not.toExist()
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
expect(rootView.getActiveView().isFocused).toBeTruthy()
describe "when a file is selected that's name starts with a '.'", ->
[dotFilePath, dotFileView, moveDialog] = []

View File

@@ -8,7 +8,7 @@ describe "WrapGuide", ->
rootView.open('sample.js')
window.loadPackage('wrap-guide')
rootView.attachToDom()
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
wrapGuide = rootView.find('.wrap-guide').view()
editor.width(editor.charWidth * wrapGuide.getDefaultColumn() * 2)
editor.trigger 'resize'