Merge master

This commit is contained in:
Garen Torikian
2013-04-02 14:12:20 -07:00
21 changed files with 153 additions and 129 deletions

View File

@@ -75,6 +75,7 @@ class Project
fs.absolute filePath
relativize: (fullPath) ->
return fullPath unless fullPath.lastIndexOf(@getPath()) is 0
fullPath.replace(@getPath(), "").replace(/^\//, '')
getSoftTabs: -> @softTabs

View File

@@ -45,7 +45,9 @@ class SelectList extends View
schedulePopulateList: ->
clearTimeout(@scheduleTimeout)
@scheduleTimeout = setTimeout((=> @populateList()), @inputThrottle)
populateCallback = =>
@populateList() if @isOnDom()
@scheduleTimeout = setTimeout(populateCallback, @inputThrottle)
setArray: (@array) ->
@populateList()

View File

@@ -1,54 +0,0 @@
{View} = require 'space-pen'
$ = require 'jquery'
module.exports =
class SortableList extends View
@viewClass: -> 'sortable-list'
initialize: ->
@on 'dragstart', '.sortable', @onDragStart
@on 'dragend', '.sortable', @onDragEnd
@on 'dragover', '.sortable', @onDragOver
@on 'dragenter', '.sortable', @onDragEnter
@on 'dragleave', '.sortable', @onDragLeave
@on 'drop', '.sortable', @onDrop
onDragStart: (event) =>
unless @shouldAllowDrag(event)
event.preventDefault()
return
el = @getSortableElement(event)
el.addClass 'is-dragging'
event.originalEvent.dataTransfer.setData 'sortable-index', el.index()
onDragEnd: (event) =>
@getSortableElement(event).removeClass 'is-dragging'
onDragEnter: (event) =>
event.preventDefault()
onDragOver: (event) =>
event.preventDefault()
@getSortableElement(event).addClass 'is-drop-target'
onDragLeave: (event) =>
@getSortableElement(event).removeClass 'is-drop-target'
onDrop: (event) =>
return false if !@shouldAllowDrop(event)
event.stopPropagation()
@find('.is-drop-target').removeClass 'is-drop-target'
shouldAllowDrag: (event) ->
true
shouldAllowDrop: (event) ->
true
getDroppedElement: (event) ->
index = event.originalEvent.dataTransfer.getData('sortable-index')
@find(".sortable:eq(#{index})")
getSortableElement: (event) ->
$(event.target).closest('.sortable')

View File

@@ -288,6 +288,9 @@ describe "AutocompleteView", ->
expect(editor.lineForBufferRow(10)).toBe matchToSelect.text()
describe "when the mini-editor receives keyboard input", ->
beforeEach ->
editor.attachToDom()
describe "when text is removed from the mini-editor", ->
it "reloads the match list based on the mini-editor's text", ->
editor.getBuffer().insert([10,0] ,"t")

View File

@@ -39,7 +39,7 @@ class FuzzyFinderView extends SelectList
$$ ->
@li =>
if git?
status = git.statuses[project.resolve(path)]
status = git.statuses[path]
if git.isStatusNew(status)
@div class: 'status new'
else if git.isStatusModified(status)
@@ -60,7 +60,7 @@ class FuzzyFinderView extends SelectList
typeClass = 'text-name'
@span fs.base(path), class: "file label #{typeClass}"
if folder = fs.directory(project.relativize(path))
if folder = project.relativize(fs.directory(path))
@span " - #{folder}/", class: 'directory'
openPath: (path) ->
@@ -76,7 +76,7 @@ class FuzzyFinderView extends SelectList
confirmed : (path) ->
return unless path.length
if fs.isFile(project.resolve(path))
if fs.isFile(path)
@cancel()
@openPath(path)
else
@@ -133,11 +133,10 @@ class FuzzyFinderView extends SelectList
@miniEditor.setText(currentWord)
populateGitStatusPaths: ->
projectRelativePaths = []
for path, status of git.statuses
continue unless fs.isFile(path)
projectRelativePaths.push(project.relativize(path))
@setArray(projectRelativePaths)
paths = []
paths.push(path) for path, status of git.statuses when fs.isFile(path)
@setArray(paths)
populateProjectPaths: (options = {}) ->
if @projectPaths?
@@ -147,7 +146,6 @@ class FuzzyFinderView extends SelectList
path.indexOf(options.filter) >= 0
else
@projectPaths
@setArray(listedItems)
options.done(listedItems) if options.done?
else
@@ -165,8 +163,6 @@ class FuzzyFinderView extends SelectList
populateOpenBufferPaths: ->
editSessions = project.getEditSessions().filter (editSession) ->
editSession.getPath()?
editSessions = _.uniq editSessions, (editSession) ->
editSession.getPath()
editSessions = _.sortBy editSessions, (editSession) =>
if editSession is rootView.getActivePaneItem()
@@ -174,17 +170,10 @@ class FuzzyFinderView extends SelectList
else
-(editSession.lastOpened or 1)
@paths = _.map editSessions, (editSession) ->
project.relativize editSession.getPath()
@paths = []
@paths.push(editSession.getPath()) for editSession in editSessions
@setArray(@paths)
getOpenedPaths: ->
paths = {}
for editSession in project.getEditSessions()
path = editSession.getPath()
paths[path] = editSession.lastOpened if path?
paths
@setArray(_.uniq(@paths))
detach: ->
super

View File

@@ -31,7 +31,12 @@ module.exports =
@projectPaths = null
serialize: ->
@fuzzyFinderView?.getOpenedPaths()
if @fuzzyFinderView?
paths = {}
for editSession in project.getEditSessions()
path = editSession.getPath()
paths[path] = editSession.lastOpened if path?
paths
createView: ->
unless @fuzzyFinderView

View File

@@ -77,8 +77,8 @@ describe 'FuzzyFinder', ->
expect(rootView.getActiveView()).toBe editor2
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finderView.confirmed('dir/a')
expectedPath = project.resolve('dir/a')
finderView.confirmed(expectedPath)
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
@@ -144,6 +144,7 @@ describe 'FuzzyFinder', ->
atom.deactivatePackage('fuzzy-finder')
states = _.map atom.getPackageState('fuzzy-finder'), (path, time) -> [ path, time ]
expect(states.length).toBe 3
states = _.sortBy states, (path, time) -> -time
paths = [ 'sample-with-tabs.coffee', 'sample.txt', 'sample.js' ]
@@ -187,7 +188,7 @@ describe 'FuzzyFinder', ->
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')
finderView.confirmed(expectedPath)
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).not.toBe expectedPath
@@ -203,7 +204,7 @@ describe 'FuzzyFinder', ->
expect(rootView.getActiveView()).toBe editor1
expectedPath = project.resolve('sample.txt')
finderView.confirmed('sample.txt')
finderView.confirmed(expectedPath)
expect(finderView.hasParent()).toBeFalsy()
expect(editor1.getPath()).toBe expectedPath
@@ -372,7 +373,7 @@ describe 'FuzzyFinder', ->
runs ->
expect(finderView).not.toBeVisible()
expect(openedPath).toBe "#{project.getPath()}/sample.txt"
expect(openedPath).toBe project.resolve("sample.txt")
it "displays an error when the word under the cursor doesn't match any files", ->
editor.setText("moogoogaipan")

View File

@@ -1,3 +0,0 @@
'.source.gfm':
'editor':
'increaseIndentPattern': '^\\s*([\\*\\+-])[ \\t]+'

View File

@@ -132,10 +132,3 @@ describe "GitHub Flavored Markdown grammar", ->
{tokens} = grammar.tokenizeLine("> Quotation")
expect(tokens[0]).toEqual value: ">", scopes: ["source.gfm", "support.quote.gfm"]
expect(tokens[1]).toEqual value: " Quotation", scopes: ["source.gfm", "comment.quote.gfm"]
describe "auto indent", ->
it "indents newlines entered after list lines", ->
config.set('editor.autoIndent', true)
editSession = project.buildEditSession('gfm.md')
editSession.insertNewlineBelow()
expect(editSession.buffer.lineForRow(1)).toBe ' '

View File

@@ -1 +0,0 @@
'main': './lib/strip-trailing-whitespace'

View File

@@ -1,15 +1,18 @@
$ = require 'jquery'
{View} = require 'space-pen'
_ = require 'underscore'
SortableList = require 'sortable-list'
TabView = require './tab-view'
module.exports =
class TabBarView extends SortableList
class TabBarView extends View
@content: ->
@ul class: "tabs #{@viewClass()}"
@ul class: "tabs sortable-list"
initialize: (@pane) ->
super
@on 'dragstart', '.sortable', @onDragStart
@on 'dragend', '.sortable', @onDragEnd
@on 'dragover', @onDragOver
@on 'drop', @onDrop
@paneContainer = @pane.getContainer()
@addTabForItem(item) for item in @pane.getItems()
@@ -74,27 +77,66 @@ class TabBarView extends SortableList
(@paneContainer.getPanes().length > 1) or (@pane.getItems().length > 1)
onDragStart: (event) =>
super
unless @shouldAllowDrag(event)
event.preventDefault()
return
el = $(event.target).closest('.sortable')
el.addClass 'is-dragging'
event.originalEvent.dataTransfer.setData 'sortable-index', el.index()
pane = $(event.target).closest('.pane')
paneIndex = @paneContainer.indexOfPane(pane)
event.originalEvent.dataTransfer.setData 'from-pane-index', paneIndex
onDragEnd: (event) =>
@find(".is-dragging").removeClass 'is-dragging'
onDragOver: (event) =>
event.preventDefault()
currentDropTargetIndex = @find(".is-drop-target").index()
newDropTargetIndex = @getDropTargetIndex(event)
if newDropTargetIndex != currentDropTargetIndex
@children().removeClass 'is-drop-target drop-target-is-after'
sortableObjects = @find(".sortable")
if newDropTargetIndex < sortableObjects.length
sortableObjects.eq(newDropTargetIndex).addClass 'is-drop-target'
else
sortableObjects.eq(newDropTargetIndex - 1).addClass 'drop-target-is-after'
onDrop: (event) =>
super
event.stopPropagation()
@children('.is-drop-target').removeClass 'is-drop-target'
@children('.drop-target-is-after').removeClass 'drop-target-is-after'
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()
toIndex = @getDropTargetIndex(event)
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
toIndex-- if fromIndex < toIndex
toPane.moveItem(item, toIndex)
else
fromPane.moveItemToPane(item, toPane, toIndex)
fromPane.moveItemToPane(item, toPane, toIndex--)
toPane.showItem(item)
toPane.focus()
getDropTargetIndex: (event) ->
el = $(event.target).closest('.sortable')
el = $(event.target).find('.sortable').last() if el.length == 0
elementCenter = el.offset().left + el.width() / 2
if event.originalEvent.pageX < elementCenter
el.index()
else if el.next().length > 0
el.next().index()
else
el.index() + 1

View File

@@ -235,6 +235,20 @@ describe "TabBarView", ->
expect(pane.activeItem).toBe item1
expect(pane.focus).toHaveBeenCalled()
describe "when it is dropped on the tab bar", ->
it "moves the tab and its item to the end", ->
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')
[dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar)
tabBar.onDragStart(dragStartEvent)
tabBar.onDrop(dropEvent)
expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 2", "Item 1"]
expect(pane.getItems()).toEqual [editSession1, item2, item1]
describe "when a tab is dragged to a different pane", ->
[pane2, tabBar2, item2b] = []

View File

@@ -83,11 +83,10 @@
}
.tab.is-drop-target:after {
.tab.is-drop-target:before, .tab.drop-target-is-after:after {
content: "";
position: absolute;
top: 0;
right: -2px;
content: "";
z-index: 999;
display: inline-block;
width: 2px;
@@ -96,15 +95,30 @@
background: #0098ff;
}
.tab.is-drop-target:before {
.tab.is-drop-target:after, .tab.drop-target-is-after:before {
content: "";
position: absolute;
top: 30px;
z-index: 9999;
width: 4px;
height: 4px;
background: #0098ff;
right: -4px;
top: 30px;
border-radius: 4px;
z-index: 9999;
border: 1px solid transparent;
}
}
.tab.is-drop-target:before {
left: -2px;
}
.tab.is-drop-target:after {
left: -4px;
}
.tab.drop-target-is-after:before {
right: -4px;
}
.tab.drop-target-is-after:after {
right: -2px;
}

View File

@@ -1,13 +1,16 @@
module.exports =
activate: ->
rootView.eachBuffer (buffer) => @stripTrailingWhitespaceBeforeSave(buffer)
rootView.eachBuffer (buffer) => @whitespaceBeforeSave(buffer)
stripTrailingWhitespaceBeforeSave: (buffer) ->
configDefaults:
ensureSingleTrailingNewline: true
whitespaceBeforeSave: (buffer) ->
buffer.on 'will-be-saved', ->
buffer.transact ->
buffer.scan /[ \t]+$/g, (match, range, { replace }) ->
replace('')
if config.get('stripTrailingWhitespace.singleTrailingNewline')
buffer.scan /[ \t]+$/g, (match, range, { replace }) -> replace('')
if config.get('whitespace.ensureSingleTrailingNewline')
if buffer.getLastLine() is ''
row = buffer.getLastRow() - 1
while row and buffer.lineForRow(row) is ''

View File

@@ -0,0 +1 @@
'main': './lib/whitespace'

View File

@@ -1,7 +1,7 @@
RootView = require 'root-view'
fs = require 'fs-utils'
describe "StripTrailingWhitespace", ->
describe "Whitespace", ->
[editor, path] = []
beforeEach ->
@@ -10,17 +10,20 @@ describe "StripTrailingWhitespace", ->
window.rootView = new RootView
rootView.open(path)
atom.activatePackage('strip-trailing-whitespace')
atom.activatePackage('whitespace')
rootView.focus()
editor = rootView.getActiveView()
afterEach ->
fs.remove(path) if fs.exists(path)
rootView.remove()
it "strips trailing whitespace before an editor saves a buffer", ->
spyOn(fs, 'write')
config.set("whitespace.ensureSingleTrailingNewline", false)
config.update()
# works for buffers that are already open when extension is initialized
editor.insertText("foo \nbar\t \n\nbaz")
editor.getBuffer().save()
@@ -34,15 +37,14 @@ describe "StripTrailingWhitespace", ->
editor.getBuffer().save()
expect(editor.getText()).toBe 'Some text.\n'
describe "stripTrailingWhitespace.singleTrailingNewline config", ->
describe "whitespace.ensureSingleTrailingNewline config", ->
[originalConfigValue] = []
beforeEach ->
originalConfigValue = config.get("stripTrailingWhitespace.singleTrailingNewline")
config.set("stripTrailingWhitespace.singleTrailingNewline", true)
config.update()
originalConfigValue = config.get("whitespace.ensureSingleTrailingNewline")
expect(originalConfigValue).toBe true
afterEach ->
config.set("stripTrailingWhitespace.singleTrailingNewline", originalConfigValue)
config.set("whitespace.ensureSingleTrailingNewline", originalConfigValue)
config.update()
it "adds a trailing newline when there is no trailing newline", ->
@@ -69,3 +71,12 @@ describe "StripTrailingWhitespace", ->
editor.insertText "\n"
editor.getBuffer().save()
expect(editor.getText()).toBe "\n"
it "does not add trailing newline if ensureSingleTrailingNewline is false", ->
config.set("whitespace.ensureSingleTrailingNewline", false)
config.update()
editor.insertText "no trailing newline"
editor.getBuffer().save()
expect(editor.getText()).toBe "no trailing newline"