Merge branch 'master' into chrome41

Conflicts:
	apm/package.json
This commit is contained in:
Cheng Zhao
2015-03-23 18:24:26 +08:00
45 changed files with 225 additions and 65 deletions

View File

@@ -48,7 +48,7 @@ For more information on how to work with Atom's official packages, see
[JavaScript](https://github.com/styleguide/javascript),
and [CSS](https://github.com/styleguide/css) styleguides.
* Include thoughtfully-worded, well-structured
[Jasmine](http://jasmine.github.io/) specs.
[Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. Run them using `apm test`.
* Document new code based on the
[Documentation Styleguide](#documentation-styleguide)
* End files with a newline.
@@ -104,6 +104,9 @@ For more information on how to work with Atom's official packages, see
should be lower-case:
* `getURI` instead of `getUri`
* `uriToOpen` instead of `URIToOpen`
* Use `slice()` to copy an array
* Add an explicit `return` when your function ends with a `for`/`while` loop and
you don't want it to return a collected array.
## Documentation Styleguide

View File

@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.146.0"
"atom-package-manager": "0.147.0"
}
}

View File

@@ -0,0 +1,22 @@
path = require 'path'
module.exports = (grunt) ->
grunt.registerTask 'output-for-loop-returns', 'Log methods that end with a for loop', ->
appDir = grunt.config.get('atom.appDir')
jsPaths = []
grunt.file.recurse path.join(appDir, 'src'), (absolutePath, rootPath, relativePath, fileName) ->
jsPaths.push(absolutePath) if path.extname(fileName) is '.js'
jsPaths.forEach (jsPath) ->
js = grunt.file.read(jsPath)
method = null
for line, index in js.split('\n')
[match, className, methodName] = /^\s*([a-zA-Z]+)\.(?:prototype\.)?([a-zA-Z]+)\s*=\s*function\(/.exec(line) ? []
if className and methodName
method = "#{className}::#{methodName}"
else
[match, ctorName] = /^\s*function\s+([a-zA-Z]+)\(/.exec(line) ? []
if /^\s*return\s+_results;\s*$/.test(line)
console.log(method ? "#{path.basename(jsPath)}:#{index}")

View File

@@ -64,7 +64,7 @@
"space-pen": "3.8.2",
"stacktrace-parser": "0.1.1",
"temp": "0.8.1",
"text-buffer": "^5",
"text-buffer": "^5.0.2",
"theorist": "^1.0.2",
"underscore-plus": "^1.6.6"
},
@@ -87,13 +87,13 @@
"autosave": "0.20.0",
"background-tips": "0.23.0",
"bookmarks": "0.35.0",
"bracket-matcher": "0.72.0",
"bracket-matcher": "0.73.0",
"command-palette": "0.34.0",
"deprecation-cop": "0.37.0",
"dev-live-reload": "0.45.0",
"encoding-selector": "0.19.0",
"exception-reporting": "0.24.0",
"feedback": "0.34.0",
"feedback": "0.35.0",
"find-and-replace": "0.159.0",
"fuzzy-finder": "0.72.0",
"git-diff": "0.54.0",
@@ -144,7 +144,7 @@
"language-property-list": "0.8.0",
"language-python": "0.32.0",
"language-ruby": "0.49.0",
"language-ruby-on-rails": "0.20.0",
"language-ruby-on-rails": "0.21.0",
"language-sass": "0.36.0",
"language-shellscript": "0.13.0",
"language-source": "0.9.0",

View File

@@ -115,6 +115,24 @@ describe "DisplayBuffer", ->
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], '
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' right = [];'
describe "when the only whitespace characters are at the beginning of the line", ->
beforeEach ->
displayBuffer.setEditorWidthInChars(10)
it "wraps the line at the max length when indented with tabs", ->
buffer.setTextInRange([[0, 0], [1, 0]], '\t\tabcdefghijklmnopqrstuvwxyz')
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr'
it "wraps the line at the max length when indented with spaces", ->
buffer.setTextInRange([[0, 0], [1, 0]], ' abcdefghijklmnopqrstuvwxyz')
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr'
describe "when there are hard tabs", ->
beforeEach ->
buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t'))

View File

@@ -0,0 +1,4 @@
module.exports =
activate: ->
deactivate: ->

View File

@@ -0,0 +1,11 @@
{
"name": "package-with-missing-consumed-services",
"consumedServices": {
"service-1": {
"versions": {
">=0.1": "consumeMissingService"
}
}
}
}

View File

@@ -0,0 +1,4 @@
module.exports =
activate: ->
deactivate: ->

View File

@@ -0,0 +1,12 @@
{
"name": "package-with-missing-provided-services",
"providedServices": {
"service-1": {
"description": "The first service",
"versions": {
"0.2.9": "provideMissingService"
}
}
}
}

View File

@@ -547,6 +547,21 @@ describe "PackageManager", ->
expect(consumerModule.consumeFirstServiceV4).not.toHaveBeenCalled()
expect(consumerModule.consumeSecondService).not.toHaveBeenCalled()
it "ignores provided and consumed services that do not exist", ->
addErrorHandler = jasmine.createSpy()
atom.notifications.onDidAddNotification(addErrorHandler)
waitsForPromise ->
atom.packages.activatePackage("package-with-missing-consumed-services")
waitsForPromise ->
atom.packages.activatePackage("package-with-missing-provided-services")
runs ->
expect(atom.packages.isPackageActive("package-with-missing-consumed-services")).toBe true
expect(atom.packages.isPackageActive("package-with-missing-provided-services")).toBe true
expect(addErrorHandler.callCount).toBe 0
describe "::deactivatePackage(id)", ->
afterEach ->
atom.packages.unloadPackages()

View File

@@ -4,7 +4,7 @@ TextBuffer = require 'text-buffer'
TextEditor = require '../src/text-editor'
describe "TextEditor", ->
[editor, tokenizedBuffer, buffer, steps, previousSteps] = []
[editor, tokenizedBuffer, buffer, steps] = []
softWrapColumn = 80
@@ -13,8 +13,6 @@ describe "TextEditor", ->
atom.config.set('editor.preferredLineLength', softWrapColumn)
it "properly renders soft-wrapped lines when randomly mutated", ->
previousSteps = JSON.parse(localStorage.steps ? '[]')
times 10, (i) ->
buffer = new TextBuffer
editor = new TextEditor({buffer})
@@ -47,6 +45,9 @@ describe "TextEditor", ->
{bufferRows, screenLines} = getReferenceScreenLines()
for bufferRow, screenRow in bufferRows
console.log screenRow, bufferRow, screenLines[screenRow].text
console.log "==== steps to reproduce this failure: ==="
for step in steps
console.log 'editor.' + step[0] + '('+ step[1..].map((a) -> JSON.stringify(a)).join(', ') + ')'
randomlyMutateEditor = ->
if Math.random() < .2
@@ -79,34 +80,11 @@ describe "TextEditor", ->
text
getReferenceScreenLines = ->
if editor.isSoftWrapped()
screenLines = []
bufferRows = []
for bufferRow in [0..tokenizedBuffer.getLastRow()]
for screenLine in softWrapLine(tokenizedBuffer.tokenizedLineForRow(bufferRow))
screenLines.push(screenLine)
bufferRows.push(bufferRow)
else
screenLines = tokenizedBuffer.tokenizedLines.slice()
bufferRows = [0..tokenizedBuffer.getLastRow()]
referenceEditor = new TextEditor({})
referenceEditor.setEditorWidthInChars(80)
referenceEditor.setText(editor.getText())
referenceEditor.setSoftWrapped(editor.isSoftWrapped())
screenLines = referenceEditor.tokenizedLinesForScreenRows(0, referenceEditor.getLastScreenRow())
bufferRows = referenceEditor.bufferRowsForScreenRows(0, referenceEditor.getLastScreenRow())
{screenLines, bufferRows}
softWrapLine = (tokenizedLine) ->
wrappedLines = []
while tokenizedLine.text.length > softWrapColumn and wrapScreenColumn = findWrapColumn(tokenizedLine.text)
[wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn)
wrappedLines.push(wrappedLine)
wrappedLines.push(tokenizedLine)
wrappedLines
findWrapColumn = (line) ->
if /\s/.test(line[softWrapColumn])
# search forward for the start of a word past the boundary
for column in [softWrapColumn..line.length]
return column if /\S/.test(line[column])
return line.length
else
# search backward for the start of the word on the boundary
for column in [softWrapColumn..0]
return column + 1 if /\s/.test(line[column])
return softWrapColumn

View File

@@ -1937,14 +1937,14 @@ describe "TextEditorComponent", ->
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(11), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 0]]]
expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [19, 0]]]
it "merges overlapping selections", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(9), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(9), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]]
expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [19, 0]]]
describe "when the gutter is shift-clicked and dragged", ->
describe "when the shift-click is below the existing selection's tail", ->

View File

@@ -825,6 +825,7 @@ class Atom extends Model
delete window[key]
else
window[key] = value
return
onUpdateAvailable: (callback) ->
@emitter.on 'update-available', callback

View File

@@ -82,7 +82,8 @@ class ApplicationMenu
# window specific items.
enableWindowSpecificItems: (enable) ->
for item in @flattenMenuItems(@menu)
item.enabled = enable if item.metadata?['windowSpecific']
item.enabled = enable if item.metadata?.windowSpecific
return
# Replaces VERSION with the current version.
substituteVersion: (template) ->
@@ -145,7 +146,7 @@ class ApplicationMenu
if item.command
item.accelerator = @acceleratorForCommand(item.command, keystrokesByCommand)
item.click = -> global.atomApplication.sendCommand(item.command)
item.metadata['windowSpecific'] = true unless /^application:/.test(item.command)
item.metadata.windowSpecific = true unless /^application:/.test(item.command)
@translateTemplate(item.submenu, keystrokesByCommand) if item.submenu
template

View File

@@ -388,11 +388,13 @@ class AtomApplication
# Kill all processes associated with opened windows.
killAllProcesses: ->
@killProcess(pid) for pid of @pidsToOpenWindows
return
# Kill process associated with the given opened window.
killProcessForWindow: (openedWindow) ->
for pid, trackedWindow of @pidsToOpenWindows
@killProcess(pid) if trackedWindow is openedWindow
return
# Kill the process with the given pid.
killProcess: (pid) ->

View File

@@ -65,6 +65,7 @@ class AutoUpdateManager
return unless @releaseVersion?
for atomWindow in windows
atomWindow.sendMessage('update-available', {@releaseVersion})
return
setState: (state) ->
return if @state is state

View File

@@ -50,6 +50,7 @@ class CommandRegistry
destroy: ->
for commandName of @registeredCommands
window.removeEventListener(commandName, @handleCommandEvent, true)
return
# Public: Add one or more command listeners associated with a selector.
#
@@ -187,6 +188,7 @@ class CommandRegistry
@selectorBasedListenersByCommandName = {}
for commandName, listeners of snapshot
@selectorBasedListenersByCommandName[commandName] = listeners.slice()
return
handleCommandEvent: (originalEvent) =>
propagationStopped = false

View File

@@ -301,6 +301,7 @@ class Config
for typeName, functions of filters
for name, enforcerFunction of functions
@addSchemaEnforcer(typeName, enforcerFunction)
return
@executeSchemaEnforcers: (keyPath, value, schema) ->
error = null
@@ -898,6 +899,7 @@ class Config
@transact =>
@settings = {}
@set(key, value, save: false) for key, value of newSettings
return
getRawValue: (keyPath, options) ->
unless options?.excludeSources?.indexOf(@getUserConfigPath()) >= 0
@@ -958,6 +960,7 @@ class Config
@setRawDefault(keyPath, defaults)
catch e
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
return
deepClone: (object) ->
if object instanceof Color

View File

@@ -132,6 +132,7 @@ class ContextMenuManager
new Disposable =>
for itemSet in addedItemSets
@itemSets.splice(@itemSets.indexOf(itemSet), 1)
return
templateForElement: (target) ->
@templateForEvent({target})

View File

@@ -35,6 +35,8 @@ class CursorsComponent
@domNode.appendChild(cursorNode)
@updateCursorNode(id, cursorState)
return
updateCursorNode: (id, newCursorState) ->
cursorNode = @cursorNodesById[id]
oldCursorState = (@oldState.cursors[id] ?= {})

View File

@@ -7,9 +7,11 @@ CustomEventMixin =
for name, listeners in @customEventListeners
for listener in listeners
@getDOMNode().removeEventListener(name, listener)
return
addCustomEventListeners: (customEventListeners) ->
for name, listener of customEventListeners
@customEventListeners[name] ?= []
@customEventListeners[name].push(listener)
@getDOMNode().addEventListener(name, listener)
return

View File

@@ -35,10 +35,12 @@ class DeserializerManager
@deserializers[deserializer.name] = deserializer for deserializer in deserializers
new Disposable =>
delete @deserializers[deserializer.name] for deserializer in deserializers
return
remove: (classes...) ->
Grim.deprecate("Call .dispose() on the Disposable return from ::add instead")
delete @deserializers[name] for {name} in classes
return
# Public: Deserialize the state and params.
#

View File

@@ -538,6 +538,7 @@ class DisplayBuffer extends Model
# bufferRow - The buffer row {Number} to check against
unfoldBufferRow: (bufferRow) ->
fold.destroy() for fold in @foldsContainingBufferRow(bufferRow)
return
# Given a buffer row, this returns the largest fold that starts there.
#
@@ -1082,6 +1083,7 @@ class DisplayBuffer extends Model
pauseMarkerChangeEvents: ->
marker.pauseChangeEvents() for marker in @getMarkers()
return
resumeMarkerChangeEvents: ->
marker.resumeChangeEvents() for marker in @getMarkers()
@@ -1091,6 +1093,7 @@ class DisplayBuffer extends Model
refreshMarkerScreenPositions: ->
for marker in @getMarkers()
marker.notifyObservers(textChanged: false)
return
destroyed: ->
marker.unsubscribe() for id, marker of @markers
@@ -1102,6 +1105,7 @@ class DisplayBuffer extends Model
for row in [start..end]
line = @tokenizedLineForScreenRow(row).text
console.log row, @bufferRowForScreenRow(row), line, line.length
return
getRootScopeDescriptor: ->
@tokenizedBuffer.rootScopeDescriptor

View File

@@ -84,6 +84,8 @@ class GutterComponent
delete @lineNumberNodesById[id]
delete @oldState.lineNumbers[id]
return
buildLineNumberHTML: (lineNumberState) ->
{screenRow, bufferRow, softWrapped, top, decorationClasses} = lineNumberState
if screenRow?

View File

@@ -39,6 +39,8 @@ class HighlightsComponent
@domNode.appendChild(highlightNode)
@updateHighlightNode(id, highlightState)
return
updateHighlightNode: (id, newHighlightState) ->
highlightNode = @highlightNodesById[id]
oldHighlightState = (@oldState[id] ?= {regions: [], flashCount: 0})
@@ -92,6 +94,8 @@ class HighlightsComponent
else
regionNode.style[property] = ''
return
flashHighlightNodeIfRequested: (id, newHighlightState) ->
oldHighlightState = @oldState[id]
return unless newHighlightState.flashCount > oldHighlightState.flashCount

View File

@@ -104,11 +104,13 @@ class LanguageMode
[startRow, endRow] = @rowRangeForFoldAtBufferRow(currentRow) ? []
continue unless startRow?
@editor.createFold(startRow, endRow)
return
# Unfolds all the foldable lines in the buffer.
unfoldAll: ->
for row in [@buffer.getLastRow()..0]
fold.destroy() for fold in @editor.displayBuffer.foldsStartingAtBufferRow(row)
return
# Fold all comment and code blocks at a given indentLevel
#
@@ -122,6 +124,7 @@ class LanguageMode
# assumption: startRow will always be the min indent level for the entire range
if @editor.indentationForBufferRow(startRow) == indentLevel
@editor.createFold(startRow, endRow)
return
# Given a buffer row, creates a fold at it.
#
@@ -276,6 +279,7 @@ class LanguageMode
# endRow - The row {Number} to end at
autoIndentBufferRows: (startRow, endRow) ->
@autoIndentBufferRow(row) for row in [startRow..endRow]
return
# Given a buffer row, this indents it.
#

View File

@@ -89,6 +89,7 @@ class LinesComponent
removeLineNodes: ->
@removeLineNode(id) for id of @oldState.lines
return
removeLineNode: (id) ->
@lineNodesByLineId[id].remove()
@@ -126,6 +127,8 @@ class LinesComponent
@lineNodesByLineId[id] = lineNode
@domNode.appendChild(lineNode)
return
buildLineHTML: (id) ->
{scrollWidth} = @newState
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id]

View File

@@ -396,6 +396,7 @@ class Marker
for event in deferredChangeEvents
@emit 'changed', event
@emitter.emit 'did-change', event
return
getPixelRange: ->
@displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false)

View File

@@ -17,6 +17,8 @@ merge = (menu, item, itemSpecificity=Infinity) ->
else unless item.type is 'separator' and _.last(menu)?.type is 'separator'
menu.push(item)
return
unmerge = (menu, item) ->
matchingItemIndex = findMatchingItemIndex(menu, item)
matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1

View File

@@ -394,6 +394,7 @@ class PackageManager
for pack in packages
promise = @activatePackage(pack.name)
promises.push(promise) unless pack.hasActivationCommands()
return
@observeDisabledPackages()
promises
@@ -413,6 +414,7 @@ class PackageManager
deactivatePackages: ->
atom.config.transact =>
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
return
@unobserveDisabledPackages()
# Deactivate the package with the given name

View File

@@ -225,12 +225,14 @@ class Package
for name, {versions} of @metadata.providedServices
servicesByVersion = {}
for version, methodName of versions
servicesByVersion[version] = @mainModule[methodName]()
if typeof @mainModule[methodName] is 'function'
servicesByVersion[version] = @mainModule[methodName]()
@activationDisposables.add atom.packages.serviceHub.provide(name, servicesByVersion)
for name, {versions} of @metadata.consumedServices
for version, methodName of versions
@activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule))
if typeof @mainModule[methodName] is 'function'
@activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule))
return
loadKeymaps: ->
@@ -238,12 +240,14 @@ class Package
@keymaps = (["#{atom.packages.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of packagesCache[@name].keymaps)
else
@keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath) ? {}]
return
loadMenus: ->
if @bundledPackage and packagesCache[@name]?
@menus = (["#{atom.packages.resourcePath}#{path.sep}#{menuPath}", menuObject] for menuPath, menuObject of packagesCache[@name].menus)
else
@menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath) ? {}]
return
getKeymapPaths: ->
keymapsDirPath = path.join(@path, 'keymaps')
@@ -447,6 +451,8 @@ class Package
@activateNow()
break
currentTarget = currentTarget.parentElement
return
return
getActivationCommands: ->
return @activationCommands if @activationCommands?
@@ -505,6 +511,7 @@ class Package
for modulePath in fs.listSync(nodeModulesPath)
nativeModulePaths.push(modulePath) if @isNativeModule(modulePath)
traversePath(path.join(modulePath, 'node_modules'))
return
traversePath(path.join(@path, 'node_modules'))
nativeModulePaths

View File

@@ -151,6 +151,7 @@ class PaneContainer extends Model
saveAll: ->
pane.saveItems() for pane in @getPanes()
return
confirmClose: (options) ->
allSaved = true
@@ -186,6 +187,7 @@ class PaneContainer extends Model
destroyEmptyPanes: ->
pane.destroy() for pane in @getPanes() when pane.items.length is 0
return
willDestroyPaneItem: (event) ->
@emitter.emit 'will-destroy-pane-item', event

View File

@@ -440,10 +440,12 @@ class Pane extends Model
# Public: Destroy all items.
destroyItems: ->
@destroyItem(item) for item in @getItems()
return
# Public: Destroy all items except for the active item.
destroyInactiveItems: ->
@destroyItem(item) for item in @getItems() when item isnt @activeItem
return
promptToSaveItem: (item, options={}) ->
return true unless item.shouldPromptToSave?(options)
@@ -518,6 +520,7 @@ class Pane extends Model
# Public: Save all items.
saveItems: ->
@saveItem(item) for item in @getItems()
return
# Public: Return the first item that matches the given URI or undefined if
# none exists.

View File

@@ -83,6 +83,7 @@ class Project extends Model
destroyUnretainedBuffers: ->
buffer.destroy() for buffer in @getBuffers() when not buffer.isRetained()
return
###
Section: Serialization

View File

@@ -112,6 +112,7 @@ class RowMap
@regions.splice index - 1, 2,
bufferRows: leftRegion.bufferRows + rightRegion.bufferRows
screenRows: leftRegion.screenRows + rightRegion.screenRows
return
# Public: Returns an array of strings describing the map's regions.
inspect: ->

View File

@@ -538,6 +538,7 @@ class Selection extends Model
for row in [start..end]
if matchLength = buffer.lineForRow(row).match(leadingTabRegex)?[0].length
buffer.delete [[row, 0], [row, matchLength]]
return
# Public: Sets the indentation level of all selected rows to values suggested
# by the relevant grammars.
@@ -620,6 +621,7 @@ class Selection extends Model
currentIndentLevel = @editor.indentLevelForLine(lines[i])
indentLevel = Math.max(0, currentIndentLevel + indentAdjustment)
lines[i] = line.replace(/^[\t ]+/, @editor.buildIndentString(indentLevel))
return
# Indent the current line(s).
#
@@ -651,6 +653,7 @@ class Selection extends Model
[start, end] = @getBufferRowRange()
for row in [start..end]
@editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0
return
###
Section: Managing multiple selections
@@ -674,6 +677,8 @@ class Selection extends Model
@editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range)
break
return
# Public: Moves the selection up one row.
addSelectionAbove: ->
range = (@getGoalScreenRange() ? @getScreenRange()).copy()
@@ -692,6 +697,8 @@ class Selection extends Model
@editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range)
break
return
# Public: Combines the given selection into this selection and then destroys
# the given selection.
#

View File

@@ -152,6 +152,8 @@ class StyleManager
for styleElement in styleElementsToRestore
@addStyleElement(styleElement) unless styleElement in existingStyleElements
return
###
Section: Paths
###

View File

@@ -46,6 +46,7 @@ class StylesElement extends HTMLElement
@styleElementRemoved(child) for child in Array::slice.call(@children)
@context = @getAttribute('context')
@styleElementAdded(styleElement) for styleElement in atom.styles.getStyleElements()
return
styleElementAdded: (styleElement) ->
return unless @styleElementMatchesContext(styleElement)

View File

@@ -124,6 +124,7 @@ class TextEditorPresenter
@disposables.add @model.onDidChangeScrollLeft(@setScrollLeft.bind(this))
@observeDecoration(decoration) for decoration in @model.getDecorations()
@observeCursor(cursor) for cursor in @model.getCursors()
return
observeConfig: ->
configParams = {scope: @model.getRootScopeDescriptor()}
@@ -273,6 +274,7 @@ class TextEditorPresenter
for id, line of @state.content.lines
unless visibleLineIds.hasOwnProperty(id)
delete @state.content.lines[id]
return
updateLineState: (row, line) ->
lineState = @state.content.lines[line.id]
@@ -296,6 +298,7 @@ class TextEditorPresenter
updateCursorsState: -> @batch "shouldUpdateCursorsState", ->
@state.content.cursors = {}
@updateCursorState(cursor) for cursor in @model.cursors # using property directly to avoid allocation
return
updateCursorState: (cursor, destroyOnly = false) ->
delete @state.content.cursors[cursor.id]
@@ -331,6 +334,8 @@ class TextEditorPresenter
for id of @state.content.overlays
delete @state.content.overlays[id] unless visibleDecorationIds[id]
return
updateGutterState: -> @batch "shouldUpdateGutterState", ->
@state.gutter.visible = not @model.isMini() and (@model.isGutterVisible() ? true) and @showLineNumbers
@state.gutter.maxLineNumberDigits = @model.getLineCount().toString().length
@@ -382,6 +387,8 @@ class TextEditorPresenter
for id of @state.gutter.lineNumbers
delete @state.gutter.lineNumbers[id] unless visibleLineNumberIds[id]
return
updateStartRow: ->
return unless @scrollTop? and @lineHeight?
@@ -873,11 +880,13 @@ class TextEditorPresenter
unless visibleHighlights[id]
delete @state.content.highlights[id]
return
removeFromLineDecorationCaches: (decoration, range) ->
for row in [range.start.row..range.end.row] by 1
delete @lineDecorationsByScreenRow[row]?[decoration.id]
delete @lineNumberDecorationsByScreenRow[row]?[decoration.id]
return
addToLineDecorationCaches: (decoration, range) ->
marker = decoration.getMarker()
@@ -903,6 +912,8 @@ class TextEditorPresenter
@lineNumberDecorationsByScreenRow[row] ?= {}
@lineNumberDecorationsByScreenRow[row][decoration.id] = decoration
return
updateHighlightState: (decoration) ->
return unless @startRow? and @endRow? and @lineHeight? and @hasPixelPositionRequirements()

View File

@@ -842,7 +842,8 @@ class TextEditor extends Model
# {Number} index of that selection.
mutateSelectedText: (fn) ->
@mergeIntersectingSelections =>
@transact => fn(selection, index) for selection, index in @getSelections()
@transact =>
fn(selection, index) for selection, index in @getSelections()
# Move lines intersection the most recent selection up by one row in screen
# coordinates.
@@ -978,6 +979,7 @@ class TextEditor extends Model
selection.setBufferRange(selectedBufferRange.translate([delta, 0]))
for [foldStartRow, foldEndRow] in foldedRowRanges
@createFold(foldStartRow + delta, foldEndRow + delta)
return
# Deprecated: Use {::duplicateLines} instead.
duplicateLine: ->
@@ -1013,6 +1015,7 @@ class TextEditor extends Model
while ++row < end.row
@addSelectionForBufferRange([[row, 0], [row, Infinity]])
@addSelectionForBufferRange([[end.row, 0], [end.row, end.column]]) unless end.column is 0
return
# Extended: For each selection, transpose the selected text.
#
@@ -1779,7 +1782,7 @@ class TextEditor extends Model
# Extended: Get an Array of all {Cursor}s.
getCursors: ->
cursor for cursor in @cursors
@cursors.slice()
# Extended: Get all {Cursors}s, ordered by their position in the buffer
# instead of the order in which they were added.
@@ -1822,6 +1825,7 @@ class TextEditor extends Model
cursor.destroy()
else
positions[position] = true
return
preserveCursorPositionOnBufferReload: ->
cursorPosition = null
@@ -1886,6 +1890,7 @@ class TextEditor extends Model
selections[i].setBufferRange(bufferRange, options)
else
@addSelectionForBufferRange(bufferRange, options)
return
# Essential: Get the {Range} of the most recently added selection in screen
# coordinates.
@@ -1932,6 +1937,7 @@ class TextEditor extends Model
selections[i].setScreenRange(screenRange, options)
else
@addSelectionForScreenRange(screenRange, options)
return
# Essential: Add a selection for the given range in buffer coordinates.
#
@@ -2159,7 +2165,7 @@ class TextEditor extends Model
#
# Returns: An {Array} of {Selection}s.
getSelections: ->
selection for selection in @selections
@selections.slice()
# Extended: Get all {Selection}s, ordered by their position in the buffer
# instead of the order in which they were added.
@@ -2206,15 +2212,18 @@ class TextEditor extends Model
expandSelectionsForward: (fn) ->
@mergeIntersectingSelections =>
fn(selection) for selection in @getSelections()
return
# Calls the given function with each selection, then merges selections in the
# reversed orientation
expandSelectionsBackward: (fn) ->
@mergeIntersectingSelections reversed: true, =>
fn(selection) for selection in @getSelections()
return
finalizeSelections: ->
selection.finalize() for selection in @getSelections()
return
selectionsForScreenRows: (startRow, endRow) ->
@getSelections().filter (selection) -> selection.intersectsScreenRowRange(startRow, endRow)
@@ -2620,6 +2629,7 @@ class TextEditor extends Model
else
selection.copy(maintainClipboard, false)
maintainClipboard = true
return
# Essential: For each selection, cut the selected text.
cutSelectedText: ->
@@ -2714,6 +2724,7 @@ class TextEditor extends Model
# Extended: For each selection, fold the rows it intersects.
foldSelectedLines: ->
selection.fold() for selection in @getSelections()
return
# Extended: Fold all foldable lines.
foldAll: ->
@@ -2796,6 +2807,8 @@ class TextEditor extends Model
for row in [bufferRange.end.row..bufferRange.start.row]
fold.destroy() for fold in @displayBuffer.foldsStartingAtBufferRow(row)
return
# Remove any {Fold}s found that contain the given buffer range.
destroyFoldsContainingBufferRange: (bufferRange) ->
@unfoldBufferRow(bufferRange.start.row)

View File

@@ -197,6 +197,7 @@ class TokenizedBuffer extends Model
validateRow: (row) ->
@invalidRows.shift() while @invalidRows[0] <= row
return
invalidateRow: (row) ->
@invalidRows.push(row)
@@ -468,3 +469,4 @@ class TokenizedBuffer extends Model
for row in [start..end]
line = @tokenizedLineForRow(row).text
console.log row, line, line.length
return

View File

@@ -11,6 +11,7 @@ module.exports =
class TokenizedLine
endOfLineInvisibles: null
lineIsWhitespaceOnly: false
firstNonWhitespaceIndex: 0
foldable: false
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) ->
@@ -96,6 +97,7 @@ class TokenizedLine
# Returns a {Number} representing the `line` position where the wrap would take place.
# Returns `null` if a wrap wouldn't occur.
findWrapColumn: (maxColumn) ->
return unless maxColumn?
return unless @text.length > maxColumn
if /\s/.test(@text[maxColumn])
@@ -106,7 +108,7 @@ class TokenizedLine
return @text.length
else
# search backward for the start of the word on the boundary
for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column)
for column in [maxColumn..@firstNonWhitespaceIndex]
return column + 1 if /\s/.test(@text[column])
return maxColumn
@@ -127,12 +129,13 @@ class TokenizedLine
rightTokens = new Array(@tokens...)
leftTokens = []
leftTextLength = 0
while leftTextLength < column
if leftTextLength + rightTokens[0].value.length > column
rightTokens[0..0] = rightTokens[0].splitAt(column - leftTextLength)
leftScreenColumn = 0
while leftScreenColumn < column
if leftScreenColumn + rightTokens[0].screenDelta > column
rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn)
nextToken = rightTokens.shift()
leftTextLength += nextToken.value.length
leftScreenColumn += nextToken.screenDelta
leftTokens.push nextToken
indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent)
@@ -160,11 +163,6 @@ class TokenizedLine
isSoftWrapped: ->
@lineEnding is null
isColumnOutsideSoftWrapIndentation: (column) ->
return true if @softWrapIndentationTokens.length == 0
column > @softWrapIndentationDelta
isColumnInsideSoftWrapIndentation: (column) ->
return false if @softWrapIndentationTokens.length == 0
@@ -209,19 +207,20 @@ class TokenizedLine
outputTokens
markLeadingAndTrailingWhitespaceTokens: ->
firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex)
if firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, firstNonWhitespaceIndex - 1)
firstNonWhitespaceIndex--
@firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex)
if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1)
@firstNonWhitespaceIndex--
firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex)
@lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0
index = 0
for token in @tokens
if index < firstNonWhitespaceIndex
token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index)
if index < @firstNonWhitespaceIndex
token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index)
# Only the *last* segment of a soft-wrapped line can have trailing whitespace
if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex)
token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index)
index += token.value.length
return
substituteInvisibleCharacters: ->
invisibles = @invisibles
@@ -309,6 +308,8 @@ class TokenizedLine
for j in [i...desiredScopeDescriptor.length]
scopeStack.push(new Scope(desiredScopeDescriptor[j]))
return
class Scope
constructor: (@scope) ->
@children = []

View File

@@ -32,6 +32,8 @@ class WindowEventHandler
unless fs.isDirectorySync(pathToOpen)
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
return
when 'update-available'
atom.updateAvailable(detail)
@@ -156,6 +158,7 @@ class WindowEventHandler
continue unless tabIndex >= 0
callback(element, tabIndex)
return
focusNext: =>
focusedTabIndex = parseInt($(':focus').attr('tabindex')) or -Infinity

View File

@@ -222,7 +222,6 @@ class WorkspaceView extends View
for editorElement in @panes.element.querySelectorAll('atom-pane > .item-views > atom-text-editor')
$(editorElement).view()
###
Section: Deprecated
###

View File

@@ -110,6 +110,7 @@ class Workspace extends Model
packageNames.push(packageName)
for scopeName in includedGrammarScopes ? []
addGrammar(atom.grammars.grammarForScopeName(scopeName))
return
editors = @getTextEditors()
addGrammar(editor.getGrammar()) for editor in editors