Merge branch 'dev' into editor-stats

This commit is contained in:
Justin Palmer
2013-02-01 07:47:36 -08:00
61 changed files with 843 additions and 183 deletions

View File

@@ -26,15 +26,12 @@ class AtomPackage extends Package
@metadata = fs.readObject(metadataPath)
loadKeymaps: ->
for keymapPath in @getKeymapPaths()
keymap.load(keymapPath)
getKeymapPaths: ->
if keymaps = @metadata?.keymaps
keymaps.map (relativePath) =>
keymaps = keymaps.map (relativePath) =>
fs.resolve(@keymapsDirPath, relativePath, ['cson', 'json', ''])
keymap.load(keymapPath) for keymapPath in keymaps
else
fs.list(@keymapsDirPath)
keymap.loadDirectory(@keymapsDirPath)
loadStylesheets: ->
for stylesheetPath in @getStylesheetPaths()

View File

@@ -53,10 +53,16 @@ _.extend atom,
themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black']
themeNames = [themeNames] unless _.isArray(themeNames)
@loadTheme(themeName) for themeName in themeNames
@loadUserStylesheet()
loadTheme: (name) ->
@loadedThemes.push Theme.load(name)
loadUserStylesheet: ->
userStylesheetPath = fs.join(config.configDirPath, 'user.css')
if fs.isFile(userStylesheetPath)
applyStylesheet(userStylesheetPath, fs.read(userStylesheetPath), 'userTheme')
getAtomThemeStylesheets: ->
themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black']
themeNames = [themeNames] unless _.isArray(themeNames)

View File

@@ -115,9 +115,9 @@ class Buffer
new Range([0, 0], [@getLastRow(), @getLastLine().length])
getTextInRange: (range) ->
range = Range.fromObject(range)
range = @clipRange(range)
if range.start.row == range.end.row
return @lines[range.start.row][range.start.column...range.end.column]
return @lineForRow(range.start.row)[range.start.column...range.end.column]
multipleLines = []
multipleLines.push @lineForRow(range.start.row)[range.start.column..] # first line
@@ -194,7 +194,7 @@ class Buffer
startPoint = [start, 0]
endPoint = [end + 1, 0]
@change(new Range(startPoint, endPoint), '')
@delete(new Range(startPoint, endPoint))
append: (text) ->
@insert(@getEofPosition(), text)
@@ -220,6 +220,10 @@ class Buffer
new Point(row, column)
clipRange: (range) ->
range = Range.fromObject(range)
new Range(@clipPosition(range.start), @clipPosition(range.end))
prefixAndSuffixForRange: (range) ->
prefix: @lines[range.start.row][0...range.start.column]
suffix: @lines[range.end.row][range.end.column..]

View File

@@ -4,7 +4,7 @@ EventEmitter = require 'event-emitter'
configDirPath = fs.absolute("~/.atom")
configJsonPath = fs.join(configDirPath, "config.json")
userInitScriptPath = fs.join(configDirPath, "atom.coffee")
userInitScriptPath = fs.join(configDirPath, "user.coffee")
bundledPackagesDirPath = fs.join(resourcePath, "src/packages")
bundledThemesDirPath = fs.join(resourcePath, "themes")
vendoredPackagesDirPath = fs.join(resourcePath, "vendor/packages")

View File

@@ -9,7 +9,6 @@ class Cursor
screenPosition: null
bufferPosition: null
goalColumn: null
wordRegex: /(\w+)|([^\w\n]+)/g
visible: true
needsAutoscroll: false
@@ -56,9 +55,18 @@ class Cursor
isVisible: -> @visible
wordRegExp: ->
nonWordCharacters = config.get("editor.nonWordCharacters")
new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "g")
isLastCursor: ->
this == @editSession.getCursor()
isSurroundedByWhitespace: ->
{row, column} = @getBufferPosition()
range = [[row, Math.min(0, column - 1)], [row, Math.max(0, column + 1)]]
/^\s+$/.test @editSession.getTextInBufferRange(range)
autoscrolled: ->
@needsAutoscroll = false
@@ -147,14 +155,16 @@ class Cursor
allowPrevious = options.allowPrevious ? true
currentBufferPosition = @getBufferPosition()
previousNonBlankRow = @editSession.buffer.previousNonBlankRow(currentBufferPosition.row)
previousLinesRange = [[previousNonBlankRow, 0], currentBufferPosition]
range = [[previousNonBlankRow, 0], currentBufferPosition]
beginningOfWordPosition = currentBufferPosition
@editSession.backwardsScanInRange (options.wordRegex || @wordRegex), previousLinesRange, (match, matchRange, { stop }) =>
beginningOfWordPosition = null
@editSession.backwardsScanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) =>
if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious
beginningOfWordPosition = matchRange.start
stop()
beginningOfWordPosition
if not beginningOfWordPosition?.isEqual(currentBufferPosition)
stop()
beginningOfWordPosition or currentBufferPosition
getEndOfCurrentWordBufferPosition: (options = {}) ->
allowNext = options.allowNext ? true
@@ -162,11 +172,12 @@ class Cursor
range = [currentBufferPosition, @editSession.getEofBufferPosition()]
endOfWordPosition = null
@editSession.scanInRange (options.wordRegex || @wordRegex), range, (match, matchRange, { stop }) =>
endOfWordPosition = matchRange.end
if not allowNext and matchRange.start.isGreaterThan(currentBufferPosition)
endOfWordPosition = currentBufferPosition
stop()
@editSession.scanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) =>
if matchRange.start.isLessThanOrEqual(currentBufferPosition) or allowNext
endOfWordPosition = matchRange.end
if not endOfWordPosition?.isEqual(currentBufferPosition)
stop()
endOfWordPosition or currentBufferPosition
getCurrentWordBufferRange: (options={}) ->

View File

@@ -18,7 +18,7 @@ class EditSession
if fs.exists(state.buffer)
session = project.buildEditSessionForPath(state.buffer)
else
console.warn "Could not build edit session for path '#{state.buffer}' because that file no longer exists"
console.warn "Could not build edit session for path '#{state.buffer}' because that file no longer exists" if state.buffer
session = project.buildEditSessionForPath(null)
session.setScrollTop(state.scrollTop)
session.setScrollLeft(state.scrollLeft)
@@ -307,6 +307,10 @@ class EditSession
fold.destroy()
@setCursorBufferPosition([fold.startRow, 0])
isFoldedAtBufferRow: (bufferRow) ->
screenRow = @screenPositionForBufferPosition([bufferRow]).row
@isFoldedAtScreenRow(screenRow)
isFoldedAtScreenRow: (screenRow) ->
@lineForScreenRow(screenRow)?.fold?
@@ -334,6 +338,77 @@ class EditSession
toggleLineCommentsForBufferRows: (start, end) ->
@languageMode.toggleLineCommentsForBufferRows(start, end)
moveLineUp: ->
selection = @getSelectedBufferRange()
return if selection.start.row is 0
lastRow = @buffer.getLastRow()
return if selection.isEmpty() and selection.start.row is lastRow and @buffer.getLastLine() is ''
@transact =>
foldedRows = []
rows = [selection.start.row..selection.end.row]
if selection.start.row isnt selection.end.row and selection.end.column is 0
rows.pop() unless @isFoldedAtBufferRow(selection.end.row)
for row in rows
screenRow = @screenPositionForBufferPosition([row]).row
if @isFoldedAtScreenRow(screenRow)
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
startRow = bufferRange.start.row
endRow = bufferRange.end.row - 1
foldedRows.push(endRow - 1)
else
startRow = row
endRow = row
endPosition = Point.min([endRow + 1], @buffer.getEofPosition())
lines = @buffer.getTextInRange([[startRow], endPosition])
if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row)
lines = "#{lines}\n"
@buffer.deleteRows(startRow, endRow)
@buffer.insert([startRow - 1], lines)
@foldBufferRow(foldedRow) for foldedRow in foldedRows
@setSelectedBufferRange(selection.translate([-1]), preserveFolds: true)
moveLineDown: ->
selection = @getSelectedBufferRange()
lastRow = @buffer.getLastRow()
return if selection.end.row is lastRow
return if selection.end.row is lastRow - 1 and @buffer.getLastLine() is ''
@transact =>
foldedRows = []
rows = [selection.end.row..selection.start.row]
if selection.start.row isnt selection.end.row and selection.end.column is 0
rows.shift() unless @isFoldedAtBufferRow(selection.end.row)
for row in rows
screenRow = @screenPositionForBufferPosition([row]).row
if @isFoldedAtScreenRow(screenRow)
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
startRow = bufferRange.start.row
endRow = bufferRange.end.row - 1
foldedRows.push(endRow + 1)
else
startRow = row
endRow = row
if endRow + 1 is lastRow
endPosition = [endRow, @buffer.lineLengthForRow(endRow)]
else
endPosition = [endRow + 1]
lines = @buffer.getTextInRange([[startRow], endPosition])
@buffer.deleteRows(startRow, endRow)
insertPosition = Point.min([startRow + 1], @buffer.getEofPosition())
if insertPosition.row is @buffer.getLastRow() and insertPosition.column > 0
lines = "\n#{lines}"
@buffer.insert(insertPosition, lines)
@foldBufferRow(foldedRow) for foldedRow in foldedRows
@setSelectedBufferRange(selection.translate([1]), preserveFolds: true)
mutateSelectedText: (fn) ->
@transact => fn(selection) for selection in @getSelections()

View File

@@ -19,6 +19,7 @@ class Editor extends View
autosave: false
autoIndent: true
autoIndentOnPaste: false
nonWordCharacters: "./\\()\"'-_:,.;<>~!@#$%^&*|+=[]{}`~?"
@content: (params) ->
@div class: @classes(params), tabindex: -1, =>
@@ -183,6 +184,8 @@ class Editor extends View
'editor:close-all-edit-sessions': @destroyAllEditSessions
'editor:select-grammar': @selectGrammar
'editor:copy-path': @copyPathToPasteboard
'editor:move-line-up': @moveLineUp
'editor:move-line-down': @moveLineDown
documentation = {}
for name, method of editorBindings
@@ -204,6 +207,8 @@ class Editor extends View
moveCursorToBeginningOfLine: -> @activeEditSession.moveCursorToBeginningOfLine()
moveCursorToFirstCharacterOfLine: -> @activeEditSession.moveCursorToFirstCharacterOfLine()
moveCursorToEndOfLine: -> @activeEditSession.moveCursorToEndOfLine()
moveLineUp: -> @activeEditSession.moveLineUp()
moveLineDown: -> @activeEditSession.moveLineDown()
setCursorScreenPosition: (position) -> @activeEditSession.setCursorScreenPosition(position)
getCursorScreenPosition: -> @activeEditSession.getCursorScreenPosition()
getCursorScreenRow: -> @activeEditSession.getCursorScreenRow()
@@ -271,6 +276,7 @@ class Editor extends View
destroyFold: (foldId) -> @activeEditSession.destroyFold(foldId)
destroyFoldsContainingBufferRow: (bufferRow) -> @activeEditSession.destroyFoldsContainingBufferRow(bufferRow)
isFoldedAtScreenRow: (screenRow) -> @activeEditSession.isFoldedAtScreenRow(screenRow)
isFoldedAtBufferRow: (bufferRow) -> @activeEditSession.isFoldedAtBufferRow(bufferRow)
lineForScreenRow: (screenRow) -> @activeEditSession.lineForScreenRow(screenRow)
linesForScreenRows: (start, end) -> @activeEditSession.linesForScreenRows(start, end)
@@ -312,7 +318,7 @@ class Editor extends View
setInvisibles: (@invisibles={}) ->
_.defaults @invisibles,
eol: '\u00ac'
space: '\u2022'
space: '\u00b7'
tab: '\u00bb'
cr: '\u00a4'
@resetDisplay()
@@ -335,6 +341,7 @@ class Editor extends View
@observeConfig 'editor.showInvisibles', (showInvisibles) => @setShowInvisibles(showInvisibles)
@observeConfig 'editor.invisibles', (invisibles) => @setInvisibles(invisibles)
@observeConfig 'editor.fontSize', (fontSize) => @setFontSize(fontSize)
@observeConfig 'editor.fontFamily', (fontFamily) => @setFontFamily(fontFamily)
handleEvents: ->
@on 'focus', =>
@@ -675,16 +682,38 @@ class Editor extends View
autosave: ->
@save() if @getPath()?
setFontSize: (@fontSize) ->
if fontSize?
@css('font-size', fontSize + 'px')
return unless @attached
@calculateDimensions()
@updatePaddingOfRenderedLines()
@updateLayerDimensions()
@requestDisplayUpdate()
setFontSize: (fontSize) ->
headTag = $("head")
styleTag = headTag.find("style.font-size")
if styleTag.length == 0
styleTag = $$ -> @style class: 'font-size'
headTag.append styleTag
getFontSize: -> @fontSize
styleTag.text(".editor {font-size: #{fontSize}px}")
@redraw()
getFontSize: ->
parseInt(@css("font-size"))
setFontFamily: (fontFamily) ->
return if fontFamily == undefined
headTag = $("head")
styleTag = headTag.find("style.font-family")
if styleTag.length == 0
styleTag = $$ -> @style class: 'font-family'
headTag.append styleTag
styleTag.text(".editor {font-family: #{fontFamily}}")
@redraw()
getFontFamily: -> @css("font-family")
redraw: ->
return unless @attached
@calculateDimensions()
@updatePaddingOfRenderedLines()
@updateLayerDimensions()
@requestDisplayUpdate()
newSplitEditor: (editSession) ->
new Editor { editSession: editSession ? @activeEditSession.copy() }
@@ -775,6 +804,10 @@ class Editor extends View
@overlayer.append(view)
calculateDimensions: ->
if not @isOnDom()
detachedEditorParent = _.last(@parents()) ? this
$(document.body).append(detachedEditorParent)
fragment = $('<pre class="line" style="position: absolute; visibility: hidden;"><span>x</span></div>')
@renderedLines.append(fragment)
@@ -786,6 +819,8 @@ class Editor extends View
@height(@lineHeight) if @mini
fragment.remove()
$(detachedEditorParent).detach()
updateLayerDimensions: ->
@gutter.calculateWidth()
@@ -1053,8 +1088,6 @@ class Editor extends View
if fold = screenLine.fold
lineAttributes = { class: 'fold line', 'fold-id': fold.id }
if @activeEditSession.selectionIntersectsBufferRange(fold.getBufferRange())
lineAttributes.class += ' selected'
else
lineAttributes = { class: 'line' }
@@ -1087,6 +1120,8 @@ class Editor extends View
if invisibles.eol
line.push("<span class='invisible'>#{invisibles.eol}</span>")
line.push("<span class='fold-marker'/>") if fold
line.push('</pre>')
line.join('')

View File

@@ -36,8 +36,8 @@ class Fold
@displayBuffer.unregisterFold(@startRow, this)
return
@updateStartRow(event)
@updateEndRow(event)
@startRow += @getRowDelta(event, @startRow)
@endRow += @getRowDelta(event, @endRow)
if @startRow != oldStartRow
@displayBuffer.unregisterFold(oldStartRow, this)
@@ -49,26 +49,12 @@ class Fold
isContainedByFold: (fold) ->
@isContainedByRange(fold.getBufferRange())
updateStartRow: (event) ->
getRowDelta: (event, row) ->
{ newRange, oldRange } = event
if oldRange.end.row < @startRow
delta = newRange.end.row - oldRange.end.row
else if newRange.end.row < @startRow
delta = newRange.end.row - @startRow
if oldRange.end.row <= row
newRange.end.row - oldRange.end.row
else if newRange.end.row < row
newRange.end.row - row
else
delta = 0
@startRow += delta
updateEndRow: (event) ->
{ newRange, oldRange } = event
if oldRange.end.row <= @endRow
delta = newRange.end.row - oldRange.end.row
else if newRange.end.row <= @endRow
delta = newRange.end.row - @endRow
else
delta = 0
@endRow += delta
0

View File

@@ -58,16 +58,19 @@ class Gutter extends View
@renderLineNumbers(renderFrom, renderTo) if performUpdate
renderLineNumbers: (startScreenRow, endScreenRow) ->
rows = @editor().bufferRowsForScreenRows(startScreenRow, endScreenRow)
editor = @editor()
rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow)
cursorScreenRow = @editor().getCursorScreenPosition().row
cursorScreenRow = editor.getCursorScreenPosition().row
@lineNumbers[0].innerHTML = $$$ ->
for row in rows
if row == lastScreenRow
rowValue = ''
else
rowValue = row + 1
@div {class: 'line-number'}, rowValue
classes = ['line-number']
classes.push('fold') if editor.isFoldedAtBufferRow(row)
@div rowValue, class: classes.join(' ')
lastScreenRow = row
@calculateWidth()

View File

@@ -35,7 +35,7 @@ class Keymap
@loadDirectory(fs.join(config.configDirPath, 'keymaps'))
loadDirectory: (directoryPath) ->
@load(filePath) for filePath in fs.list(directoryPath)
@load(filePath) for filePath in fs.list(directoryPath, ['.cson', '.json'])
load: (path) ->
@add(fs.readObject(path))

View File

@@ -38,3 +38,5 @@
'meta-P': 'editor:close-all-edit-sessions'
'meta-L': 'editor:select-grammar'
'ctrl-C': 'editor:copy-path'
'ctrl-meta-up': 'editor:move-line-up'
'ctrl-meta-down': 'editor:move-line-down'

View File

@@ -133,6 +133,7 @@ class LineMap
new Range(start, end)
bufferRangeForScreenRange: (screenRange) ->
screenRange = Range.fromObject(screenRange)
start = @bufferPositionForScreenPosition(screenRange.start)
end = @bufferPositionForScreenPosition(screenRange.end)
new Range(start, end)
@@ -141,4 +142,3 @@ class LineMap
for row in [start..end]
line = @lineForScreenRow(row).text
console.log row, line, line.length

View File

@@ -1,4 +1,4 @@
Task = require 'Task'
Task = require 'task'
module.exports =
class LoadTextMatePackagesTask extends Task

View File

@@ -11,6 +11,14 @@ class Point
new Point(row, column)
@min: (point1, point2) ->
point1 = @fromObject(point1)
point2 = @fromObject(point2)
if point1.isLessThanOrEqual(point2)
point1
else
point2
constructor: (@row=0, @column=0) ->
copy: ->
@@ -26,6 +34,10 @@ class Point
new Point(row, column)
translate: (other) ->
other = Point.fromObject(other)
new Point(@row + other.row, @column + other.column)
splitAt: (column) ->
if @row == 0
rightColumn = @column - column

View File

@@ -48,6 +48,9 @@ class Range
add: (point) ->
new Range(@start.add(point), @end.add(point))
translate: (startPoint, endPoint=startPoint) ->
new Range(@start.translate(startPoint), @end.translate(endPoint))
intersectsWith: (otherRange) ->
if @start.isLessThanOrEqual(otherRange.start)
@end.isGreaterThanOrEqual(otherRange.start)

View File

@@ -96,7 +96,10 @@ class Selection
@screenRangeChanged()
selectWord: ->
@setBufferRange(@cursor.getCurrentWordBufferRange())
options = {}
options.wordRegex = /[\t ]*/ if @cursor.isSurroundedByWhitespace()
@setBufferRange(@cursor.getCurrentWordBufferRange(options))
@wordwise = true
@initialScreenRange = @getScreenRange()

View File

@@ -1,4 +1,5 @@
DeferredAtomPackage = require 'deferred-atom-package'
$ = require 'jquery'
module.exports =
class CommandLogger extends DeferredAtomPackage
@@ -7,4 +8,25 @@ class CommandLogger extends DeferredAtomPackage
instanceClass: 'command-logger/src/command-logger-view'
onLoadEvent: (event, instance) -> instance.toggle()
activate: (rootView, state={})->
super
@eventLog = state.eventLog ? {}
rootView.command 'command-logger:clear-data', => @eventLog = {}
registerTriggeredEvent = (eventName) =>
eventNameLog = @eventLog[eventName]
unless eventNameLog
eventNameLog =
count: 0
name: eventName
@eventLog[eventName] = eventNameLog
eventNameLog.count++
eventNameLog.lastRun = new Date().getTime()
originalTrigger = $.fn.trigger
$.fn.trigger = (eventName) ->
eventName = eventName.type if eventName.type
registerTriggeredEvent(eventName) if $(this).events()[eventName]
originalTrigger.apply(this, arguments)
onLoadEvent: (event, instance) -> instance.toggle(@eventLog)

View File

@@ -6,9 +6,8 @@ describe "CommandLogger", ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
atom.loadPackage('command-logger').getInstance()
commandLogger = atom.loadPackage('command-logger')
editor = rootView.getActiveEditor()
commandLogger = CommandLogger.instance
afterEach ->
rootView.deactivate()
@@ -44,9 +43,11 @@ describe "CommandLogger", ->
describe "when an event is ignored", ->
it "does not create a node for that event", ->
commandLogger.ignoredEvents.push 'editor:delete-line'
commandLoggerView = commandLogger.getInstance()
commandLoggerView.ignoredEvents.push 'editor:delete-line'
editor.trigger 'editor:delete-line'
nodes = commandLogger.createNodes()
commandLoggerView.eventLog = commandLogger.eventLog
nodes = commandLoggerView.createNodes()
for node in nodes
continue unless node.name is 'Editor'
for child in node.children

View File

@@ -1,12 +1,11 @@
{$$$} = require 'space-pen'
ScrollView = require 'scroll-view'
$ = require 'jquery'
_ = require 'underscore'
module.exports =
class CommandLoggerView extends ScrollView
@activate: (rootView, state) ->
@instance = new CommandLoggerView(rootView, state?.eventLog)
@instance = new CommandLoggerView(rootView)
@content: (rootView) ->
@div class: 'command-logger', tabindex: -1, =>
@@ -31,29 +30,13 @@ class CommandLoggerView extends ScrollView
'tree-view:directory-modified'
]
initialize: (@rootView, @eventLog={}) ->
initialize: (@rootView) ->
super
@rootView.command 'command-logger:clear-data', => @eventLog = {}
@command 'core:cancel', => @detach()
@on 'blur', => @detach() unless document.activeElement is this[0]
registerEvent = (eventName) =>
eventNameLog = @eventLog[eventName]
unless eventNameLog
eventNameLog =
count: 0
name: eventName
@eventLog[eventName] = eventNameLog
eventNameLog.count++
eventNameLog.lastRun = new Date().getTime()
originalTrigger = $.fn.trigger
$.fn.trigger = (eventName) ->
eventName = eventName.type if eventName.type
registerEvent(eventName) if $(this).events()[eventName]
originalTrigger.apply(this, arguments)
toggle: ->
toggle: (@eventLog={}) ->
if @hasParent()
@detach()
else
@@ -198,8 +181,11 @@ class CommandLoggerView extends ScrollView
@focus()
detach: ->
super()
return if @detaching
@detaching = true
super
@rootView.focus()
@detaching = false
serialize: ->
eventLog: @eventLog

View File

@@ -438,13 +438,13 @@ describe "CommandPanel", ->
expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0]
describe "when core:confirm is triggered on the preview list", ->
it "opens the operation's buffer, selects and scrolls to the search result, and focuses the active editor", ->
it "opens the operation's buffer, selects and scrolls to the search result, and refocuses the preview list", ->
rootView.height(200)
rootView.attachToDom()
waitsForPromise -> commandPanel.execute('X x/apply/') # use apply because it is at the end of the file
runs ->
spyOn(rootView, 'focus')
spyOn(previewList, 'focus')
executeHandler = jasmine.createSpy('executeHandler')
commandPanel.on 'core:confirm', executeHandler
@@ -458,13 +458,13 @@ describe "CommandPanel", ->
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(editor.isScreenRowVisible(editor.getCursorScreenRow())).toBeTruthy()
expect(rootView.focus).toHaveBeenCalled()
expect(previewList.focus).toHaveBeenCalled()
expect(executeHandler).not.toHaveBeenCalled()
describe "when an operation in the preview list is clicked", ->
it "opens the operation's buffer, selects the search result, and focuses the active editor", ->
spyOn(rootView, 'focus')
it "opens the operation's buffer, selects the search result, and refocuses the preview list", ->
spyOn(previewList, 'focus')
operation = previewList.getOperations()[4]
previewList.find('li.operation:eq(4) span').mousedown()
@@ -473,4 +473,4 @@ describe "CommandPanel", ->
editSession = rootView.getActiveEditSession()
expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath())
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(rootView.focus).toHaveBeenCalled()
expect(previewList.focus).toHaveBeenCalled()

View File

@@ -51,7 +51,7 @@ class CommandPanelView extends View
@previewList.hide()
@previewCount.hide()
@errorMessages.hide()
@prompt.iconSize(@miniEditor.fontSize)
@prompt.iconSize(@miniEditor.getFontSize())
serialize: ->
text: @miniEditor.getText()

View File

@@ -83,7 +83,7 @@ class PreviewList extends ScrollView
editSession = @rootView.open(operation.getPath())
bufferRange = operation.execute(editSession)
editSession.setSelectedBufferRange(bufferRange, autoscroll: true) if bufferRange
@rootView.focus()
@focus()
false
getPathCount: ->

View File

@@ -1,2 +1,2 @@
window.keymap.bindKeys '.editor'
'.editor':
'tab': 'snippets:expand'

View File

@@ -1,6 +1,6 @@
# it's critical that these bindings be loaded after those snippets-1 so they
# are later in the cascade, hence breaking the keymap into 2 files
window.keymap.bindKeys '.editor'
'.editor':
'tab': 'snippets:next-tab-stop'
'shift-tab': 'snippets:previous-tab-stop'

View File

@@ -277,6 +277,7 @@ describe "Snippets extension", ->
it "terminates the worker when loading completes", ->
jasmine.unspy(LoadSnippetsTask.prototype, 'loadAtomSnippets')
spyOn(console, "warn")
spyOn(Worker.prototype, 'terminate').andCallThrough()
snippets.loaded = false
snippets.loadAll()
@@ -284,6 +285,8 @@ describe "Snippets extension", ->
waitsFor "all snippets to load", 5000, -> snippets.loaded
runs ->
expect(console.warn).toHaveBeenCalled()
expect(console.warn.argsForCall[0]).toMatch /Error reading snippets file '.*?\/spec\/fixtures\/packages\/package-with-snippets\/snippets\/junk-file'/
expect(Worker.prototype.terminate).toHaveBeenCalled()
expect(Worker.prototype.terminate.calls.length).toBe 1

View File

@@ -1,4 +1,4 @@
Task = require 'Task'
Task = require 'task'
TextMatePackage = require 'text-mate-package'
module.exports =

View File

@@ -5,7 +5,7 @@ Tabs = require 'tabs'
fs = require 'fs'
describe "Tabs", ->
[rootView, editor, statusBar, buffer, tabs] = []
[rootView, editor, buffer, tabs] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
@@ -118,3 +118,21 @@ describe "Tabs", ->
tabs.find('.tab .close-icon:eq(1)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
expect(editor.activeEditSession).toBe firstSession
describe "when two tabs have the same file name", ->
[tempPath] = []
beforeEach ->
tempPath = '/tmp/sample.js'
fs.write(tempPath, 'sample')
afterEach ->
fs.remove(tempPath) if fs.exists(tempPath)
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'

View File

@@ -1,4 +1,5 @@
{View} = require 'space-pen'
fs = require 'fs'
module.exports =
class Tab extends View
@@ -7,12 +8,14 @@ class Tab extends View
@span class: 'file-name', outlet: 'fileName'
@span class: 'close-icon'
initialize: (@editSession) ->
initialize: (@editSession, @editor) ->
@buffer = @editSession.buffer
@subscribe @buffer, 'path-changed', => @updateFileName()
@subscribe @buffer, 'contents-modified', => @updateModifiedStatus()
@subscribe @buffer, 'saved', => @updateModifiedStatus()
@subscribe @buffer, 'git-status-changed', => @updateModifiedStatus()
@subscribe @editor, 'editor:edit-session-added', => @updateFileName()
@subscribe @editor, 'editor:edit-session-removed', => @updateFileName()
@updateFileName()
@updateModifiedStatus()
@@ -25,4 +28,14 @@ class Tab extends View
@isModified = false
updateFileName: ->
@fileName.text(@editSession.buffer.getBaseName() ? 'untitled')
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

@@ -34,7 +34,7 @@ class Tabs extends View
false
addTabForEditSession: (editSession) ->
@append(new Tab(editSession))
@append(new Tab(editSession, @editor))
setActiveTab: (index) ->
@find(".tab.active").removeClass('active')

View File

@@ -761,7 +761,7 @@ describe "TreeView", ->
expect(addDialog.miniEditor.getText().length).toBe 0
describe "tree-view:move", ->
fdescribe "tree-view:move", ->
describe "when a file is selected", ->
moveDialog = null
@@ -770,6 +770,9 @@ describe "TreeView", ->
treeView.trigger "tree-view:move"
moveDialog = rootView.find(".tree-view-dialog").view()
afterEach ->
waits 50 # The move specs cause too many false positives because of their async nature, so wait a little bit before we cleanup
it "opens a move dialog with the file's current path (excluding extension) populated", ->
extension = fs.extension(filePath)
fileNameWithoutExtension = fs.base(filePath, extension)

View File

@@ -59,11 +59,16 @@ module.exports =
# Returns an array with all the names of files contained
# in the directory path.
list: (rootPath) ->
list: (rootPath, extensions) ->
paths = []
onPath = (path) =>
paths.push(@join(rootPath, path))
false
if extensions
onPath = (path) =>
paths.push(@join(rootPath, path)) if _.contains(extensions, @extension(path))
false
else
onPath = (path) =>
paths.push(@join(rootPath, path))
false
@traverseTree(rootPath, onPath, onPath)
paths

View File

@@ -25,6 +25,9 @@ $.fn.pageUp = ->
$.fn.pageDown = ->
@scrollTop(@scrollTop() + @height())
$.fn.isOnDom = ->
@closest(document.body).length is 1
$.fn.containsElement = (element) ->
(element[0].compareDocumentPosition(this[0]) & 8) == 8