Merge branch 'dev' into web-workers

This commit is contained in:
Nathan Sobo
2013-01-27 18:53:59 -07:00
43 changed files with 635 additions and 92 deletions

View File

@@ -180,17 +180,19 @@ describe "CommandPanel", ->
expect(commandPanel.hasParent()).toBeTruthy()
describe "when the mini editor is focused", ->
it "retains focus on the mini editor and does not show the preview list", ->
it "retains focus on the mini editor and does not show the preview list or preview count", ->
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
rootView.trigger 'command-panel:toggle-preview'
expect(commandPanel.previewList).toBeHidden()
expect(commandPanel.previewCount).toBeHidden()
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
describe "when the mini editor is not focused", ->
it "focuses the mini editor and does not show the preview list", ->
it "focuses the mini editor and does not show the preview list or preview count", ->
rootView.focus()
rootView.trigger 'command-panel:toggle-preview'
expect(commandPanel.previewList).toBeHidden()
expect(commandPanel.previewCount).toBeHidden()
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
describe "when the command panel is not visible", ->
@@ -297,7 +299,7 @@ describe "CommandPanel", ->
expect(commandPanel.previewList).toBeVisible()
expect(commandPanel.previewList).toMatchSelector ':focus'
previewItem = commandPanel.previewList.find("li:contains(sample.js):first")
expect(previewItem.text()).toBe "sample.js"
expect(previewItem.text()).toBe "sample.js(1)"
expect(previewItem.next().find('.preview').text()).toBe "var quicksort = function () {"
expect(previewItem.next().find('.preview > .match').text()).toBe "quicksort"
@@ -377,6 +379,10 @@ describe "CommandPanel", ->
rootView.trigger 'command-panel:toggle'
waitsForPromise -> commandPanel.execute('X x/sort/')
it "displays the number of files and operations", ->
rootView.attachToDom()
expect(commandPanel.previewCount.text()).toBe '17 matches in 4 files'
describe "when move-down and move-up are triggered on the preview list", ->
it "selects the next/previous operation (if there is one), and scrolls the list if needed", ->
rootView.attachToDom()
@@ -405,28 +411,15 @@ describe "CommandPanel", ->
previewList.trigger 'core:move-down'
expect(previewList.scrollTop()).toBe 0
it "wraps around when the list is at the beginning or end", ->
rootView.attachToDom()
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0]
previewList.trigger 'core:move-up'
expect(previewList.find('li.operation:last')).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBe _.last(previewList.getOperations())
previewList.trigger 'core:move-down'
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0]
it "doesn't bubble up the event and the command panel text doesn't change", ->
rootView.attachToDom()
commandPanel.miniEditor.setText "command"
previewList.focus()
previewList.trigger 'core:move-up'
expect(previewList.find('li.operation:last')).toHaveClass 'selected'
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(commandPanel.miniEditor.getText()).toBe 'command'
previewList.trigger 'core:move-down'
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected'
expect(commandPanel.miniEditor.getText()).toBe 'command'
describe "when move-to-top and move-to-bottom are triggered on the preview list", ->

View File

@@ -24,6 +24,7 @@ class CommandPanelView extends View
@content: (rootView) ->
@div class: 'command-panel tool-panel', =>
@div outlet: 'previewCount', class: 'preview-count'
@subview 'previewList', new PreviewList(rootView)
@ul class: 'error-messages', outlet: 'errorMessages'
@div class: 'prompt-and-editor', =>
@@ -48,6 +49,7 @@ class CommandPanelView extends View
@command 'core:move-down', => @navigateForwardInHistory()
@previewList.hide()
@previewCount.hide()
@errorMessages.hide()
@prompt.iconSize(@miniEditor.fontSize)
@@ -73,12 +75,14 @@ class CommandPanelView extends View
togglePreview: ->
if @previewList.is(':focus')
@previewList.hide()
@previewCount.hide()
@detach()
@rootView.focus()
else
@attach() unless @hasParent()
if @previewList.hasOperations()
@previewList.show().focus()
@previewCount.show()
else
@miniEditor.focus()
@@ -94,6 +98,7 @@ class CommandPanelView extends View
detach: ->
@rootView.focus()
@previewList.hide()
@previewCount.hide()
super
escapedCommand: ->
@@ -115,6 +120,7 @@ class CommandPanelView extends View
else if operationsToPreview?.length
@previewList.populate(operationsToPreview)
@previewList.focus()
@previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show()
else
@detach()
catch error

View File

@@ -34,7 +34,9 @@ class PreviewList extends ScrollView
operation.index = index for operation, index in operations
operationsByPath = _.groupBy(operations, (operation) -> operation.getPath())
for path, ops of operationsByPath
@li path, class: 'path'
@li class: 'path', =>
@span path
@span "(#{ops.length})", class: 'path-match-number'
for operation in ops
{prefix, suffix, match, range} = operation.preview()
@li 'data-index': operation.index, class: 'operation', =>
@@ -56,16 +58,10 @@ class PreviewList extends ScrollView
lineNumbers.width(maxWidth)
selectNextOperation: ->
if @selectedOperationIndex is @operations.length - 1
@setSelectedOperationIndex(0)
else
@setSelectedOperationIndex(@selectedOperationIndex + 1)
@setSelectedOperationIndex(@selectedOperationIndex + 1)
selectPreviousOperation: ->
if @selectedOperationIndex is 0
@setSelectedOperationIndex(@operations.length - 1)
else
@setSelectedOperationIndex(@selectedOperationIndex - 1)
@setSelectedOperationIndex(@selectedOperationIndex - 1)
setSelectedOperationIndex: (index, scrollToOperation=true) ->
index = Math.max(0, index)
@@ -90,6 +86,9 @@ class PreviewList extends ScrollView
@rootView.focus()
false
getPathCount: ->
_.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length
getOperations: ->
new Array(@operations...)

View File

@@ -0,0 +1,12 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class GistsPackage extends DeferredAtomPackage
loadEvents:
'gist:create': '.editor'
instanceClass: 'gists/lib/gists'
onLoadEvent: (event, instance) ->
instance.createGist(event.currentTargetView())

View File

@@ -0,0 +1,2 @@
'body':
'alt-meta-g': 'gist:create'

View File

@@ -0,0 +1,31 @@
$ = require 'jquery'
{$$} = require 'space-pen'
module.exports =
class Gists
@activate: (rootView) -> new Gists(rootView)
constructor: (@rootView) ->
createGist: (editor) ->
gist = { public: false, files: {} }
gist.files[editor.getBuffer().getBaseName()] =
content: editor.getSelectedText() or editor.getText()
$.ajax
url: 'https://api.github.com/gists'
type: 'POST'
dataType: 'json'
contentType: 'application/json; charset=UTF-8'
data: JSON.stringify(gist)
success: (response) =>
pasteboard.write(response.html_url)
notification = $$ ->
@div class: 'gist-notification', =>
@div class: 'message-area', =>
@span "Gist #{response.id} created", class: 'message'
@br()
@span "The url is on your clipboard", class: 'clipboard'
@rootView.append(notification.hide())
notification.fadeIn().delay(2000).fadeOut(complete: -> $(this).remove())

View File

@@ -0,0 +1,61 @@
RootView = require 'root-view'
$ = require 'jquery'
describe "Gists package", ->
[rootView, editor] = []
beforeEach ->
rootView = new RootView(fixturesProject.resolve('sample.js'))
atom.loadPackage('gists').getInstance()
editor = rootView.getActiveEditor()
spyOn($, 'ajax')
afterEach ->
rootView.deactivate()
describe "when gist:create is triggered on an editor", ->
describe "when the editor has no selection", ->
[request, originalFxOffValue] = []
beforeEach ->
originalFxOffValue = $.fx.off
$.fx.off = true
editor.trigger 'gist:create'
expect($.ajax).toHaveBeenCalled()
request = $.ajax.argsForCall[0][0]
afterEach ->
$.fx.off = originalFxOffValue
it "creates an Ajax request to api.github.com with the entire buffer contents as the Gist's content", ->
expect(request.url).toBe 'https://api.github.com/gists'
expect(request.type).toBe 'POST'
requestData = JSON.parse(request.data)
expect(requestData.public).toBeFalsy()
expect(requestData.files).toEqual 'sample.js': content: editor.getText()
describe "when the server responds successfully", ->
beforeEach ->
request.success(html_url: 'https://gist.github.com/1', id: '1')
it "places the created Gist's URL on the clipboard", ->
expect(pasteboard.read()[0]).toBe 'https://gist.github.com/1'
it "flashes that the Gist was created", ->
expect(rootView.find('.gist-notification')).toExist()
expect(rootView.find('.gist-notification .message').text()).toBe 'Gist 1 created'
advanceClock(2000)
expect(rootView.find('.gist-notification')).not.toExist()
describe "when the editor has a selection", ->
beforeEach ->
editor.setSelectedBufferRange [[4, 0], [8, 0]]
it "creates an Ajax with the selected text as the Gist's content", ->
editor.trigger 'gist:create'
expect($.ajax).toHaveBeenCalled()
request = $.ajax.argsForCall[0][0]
requestData = JSON.parse(request.data)
expect(requestData.files).toEqual 'sample.js': content: editor.getSelectedText()

View File

@@ -0,0 +1,12 @@
DeferredAtomPackage = require 'deferred-atom-package'
module.exports =
class GoToLinePackage extends DeferredAtomPackage
loadEvents:
'editor:go-to-line': '.editor'
instanceClass: 'go-to-line/lib/go-to-line-view'
onLoadEvent: (event, instance) ->
instance.toggle(event.currentTargetView())

View File

@@ -0,0 +1,6 @@
'body':
'meta-l': 'editor:go-to-line'
'.go-to-line .mini.editor input':
'enter': 'core:confirm',
'escape': 'core:cancel'
'meta-w': 'core:cancel'

View File

@@ -0,0 +1,54 @@
{View} = require 'space-pen'
Editor = require 'editor'
$ = require 'jquery'
Point = require 'point'
module.exports =
class GoToLineView extends View
@activate: (rootView) -> new GoToLineView(rootView)
@content: ->
@div class: 'go-to-line', =>
@subview 'miniEditor', new Editor(mini: true)
@div class: 'message', outlet: 'message'
initialize: (@rootView) ->
@miniEditor.on 'focusout', => @detach()
@on 'core:confirm', => @confirm()
@on 'core:cancel', => @detach()
@miniEditor.preempt 'textInput', (e) =>
false unless e.originalEvent.data.match(/[0-9]/)
toggle: ->
if @hasParent()
@detach()
else
@attach()
detach: ->
return unless @hasParent()
@miniEditor.setText('')
@previouslyFocusedElement?.focus()
super
confirm: ->
lineNumber = @miniEditor.getText()
editor = rootView.getActiveEditor()
@detach()
return unless editor and lineNumber.length
position = new Point(parseInt(lineNumber - 1, 0))
editor.scrollToBufferPosition(position, center: true)
editor.setCursorBufferPosition(position)
editor.moveCursorToFirstCharacterOfLine()
attach: ->
@previouslyFocusedElement = $(':focus')
@rootView.append(this)
@message.text("Enter a line number 1-#{@rootView.getActiveEditor().getLineCount()}")
@miniEditor.focus()

View File

@@ -0,0 +1,51 @@
RootView = require 'root-view'
describe 'GoToLine', ->
[rootView, goToLine, editor] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
rootView.enableKeymap()
goToLine = atom.loadPackage("go-to-line").getInstance()
editor = rootView.getActiveEditor()
editor.setCursorBufferPosition([1,0])
afterEach ->
rootView.remove()
describe "when editor:go-to-line is triggered", ->
it "attaches to the root view", ->
expect(goToLine.hasParent()).toBeFalsy()
editor.trigger 'editor:go-to-line'
expect(goToLine.hasParent()).toBeTruthy()
describe "when entering a line number", ->
it "only allows 0-9 to be entered in the mini editor", ->
expect(goToLine.miniEditor.getText()).toBe ''
goToLine.miniEditor.textInput 'a'
expect(goToLine.miniEditor.getText()).toBe ''
goToLine.miniEditor.textInput '40'
expect(goToLine.miniEditor.getText()).toBe '40'
describe "when core:confirm is triggered", ->
describe "when a line number has been entered", ->
it "moves the cursor to the first character of the line", ->
goToLine.miniEditor.textInput '3'
goToLine.miniEditor.trigger 'core:confirm'
expect(editor.getCursorBufferPosition()).toEqual [2, 4]
describe "when no line number has been entered", ->
it "closes the view and does not update the cursor position", ->
editor.trigger 'editor:go-to-line'
expect(goToLine.hasParent()).toBeTruthy()
goToLine.miniEditor.trigger 'core:confirm'
expect(goToLine.hasParent()).toBeFalsy()
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
describe "when core:cancel is triggered", ->
it "closes the view and does not update the cursor position", ->
editor.trigger 'editor:go-to-line'
expect(goToLine.hasParent()).toBeTruthy()
goToLine.miniEditor.trigger 'core:cancel'
expect(goToLine.hasParent()).toBeFalsy()
expect(editor.getCursorBufferPosition()).toEqual [1, 0]

View File

@@ -57,3 +57,16 @@ describe "MarkdownPreview", ->
expect(markdownPreviewView).toExist()
markdownPreviewView.trigger('core:cancel')
expect(rootView.find('.markdown-preview')).not.toExist()
describe "when focus is lost", ->
it "removes the markdown preview view", ->
rootView.open('file.md')
editor = rootView.getActiveEditor()
expect(rootView.find('.markdown-preview')).not.toExist()
spyOn(markdownPreview, 'loadHtml')
editor.trigger('markdown-preview:toggle')
markdownPreviewView = rootView.find('.markdown-preview')
expect(markdownPreviewView).toExist()
markdownPreviewView.blur()
expect(rootView.find('.markdown-preview')).not.toExist()

View File

@@ -14,7 +14,9 @@ class MarkdownPreviewView extends ScrollView
initialize: (@rootView) ->
super
@command 'core:cancel', => @detach()
@command 'core:cancel', => @detach() unless @detaching
@on 'focusout', => @detach() unless @detaching
toggle: ->
if @hasParent()
@@ -30,8 +32,10 @@ class MarkdownPreviewView extends ScrollView
@focus()
detach: ->
super()
@detaching = true
super
@rootView.focus()
@detaching = false
getActivePath: ->
@rootView.getActiveEditor()?.getPath()

View File

@@ -6,7 +6,7 @@ class Symbols extends DeferredAtomPackage
loadEvents: [
'symbols-view:toggle-file-symbols'
'symbols-view:toggle-project-symbols'
'symbols-view:jump-to-declaration'
'symbols-view:go-to-declaration'
]
instanceClass: 'symbols-view/src/symbols-view'
@@ -17,5 +17,5 @@ class Symbols extends DeferredAtomPackage
instance.toggleFileSymbols()
when 'symbols-view:toggle-project-symbols'
instance.toggleProjectSymbols()
when 'symbols-view:jump-to-declaration'
instance.jumpToDeclaration()
when 'symbols-view:go-to-declaration'
instance.goToDeclaration()

View File

@@ -1,6 +1,6 @@
'.editor':
'meta-j': 'symbols-view:toggle-file-symbols'
'meta-.': 'symbols-view:jump-to-declaration'
'meta-.': 'symbols-view:go-to-declaration'
'body':
'meta-J': 'symbols-view:toggle-project-symbols'

View File

@@ -126,26 +126,26 @@ describe "SymbolsView", ->
generator.generate().done ->
expect(tags.length).toBe 0
describe "jump to declaration", ->
describe "go to declaration", ->
it "doesn't move the cursor when no declaration is found", ->
rootView.open("tagged.js")
editor = rootView.getActiveEditor()
editor.setCursorBufferPosition([0,2])
editor.trigger 'symbols-view:jump-to-declaration'
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.setCursorBufferPosition([6,24])
editor.trigger 'symbols-view:jump-to-declaration'
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.setCursorBufferPosition([8,14])
editor.trigger 'symbols-view:jump-to-declaration'
editor.trigger 'symbols-view:go-to-declaration'
expect(symbolsView.list.children('li').length).toBe 2
expect(symbolsView).toBeVisible()
symbolsView.confirmed(symbolsView.array[0])
@@ -163,7 +163,7 @@ describe "SymbolsView", ->
rootView.open("tagged.js")
editor = rootView.getActiveEditor()
editor.setCursorBufferPosition([8,14])
editor.trigger 'symbols-view:jump-to-declaration'
editor.trigger 'symbols-view:go-to-declaration'
expect(symbolsView.list.children('li').length).toBe 1
expect(symbolsView.list.children('li:first').find('.function-name')).toHaveText 'tagged.js'

View File

@@ -102,7 +102,7 @@ class SymbolsView extends SelectList
for line, index in fs.read(file).split('\n')
return new Point(index, 0) if pattern is $.trim(line)
jumpToDeclaration: ->
goToDeclaration: ->
editor = @rootView.getActiveEditor()
matches = TagReader.find(editor)
return unless matches.length

View File

@@ -1,14 +1,20 @@
.tabs {
-webkit-user-select: none;
display: -webkit-box;
-webkit-box-align: center;
}
.tab {
display: table-cell;
-webkit-box-flex: 2;
position: relative;
width:175px;
width: 175px;
max-width: 175px;
min-width: 40px;
box-sizing: border-box;
height: 24px;
}
.tab.active {
-webkit-box-flex: 1;
}
.tab.file-modified .close-icon {
@@ -23,9 +29,5 @@
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
position: absolute;
left: 9px;
top:4px;
bottom:4px;
right: 21px;
padding: 3px 5px;
}