mirror of
https://github.com/atom/atom.git
synced 2026-02-08 13:45:09 -05:00
Merge branch 'master' into absolute-paths-in-fuzzy-finder
Conflicts: src/packages/fuzzy-finder/lib/load-paths-handler.coffee
This commit is contained in:
@@ -1,20 +1,29 @@
|
||||
TextMateGrammar = require 'text-mate-grammar'
|
||||
Package = require 'package'
|
||||
fs = require 'fs'
|
||||
fsUtils = require 'fs-utils'
|
||||
_ = require 'underscore'
|
||||
$ = require 'jquery'
|
||||
CSON = require 'cson'
|
||||
|
||||
module.exports =
|
||||
class AtomPackage extends Package
|
||||
metadata: null
|
||||
keymaps: null
|
||||
stylesheets: null
|
||||
grammars: null
|
||||
scopedProperties: null
|
||||
mainModulePath: null
|
||||
resolvedMainModulePath: false
|
||||
mainModule: null
|
||||
deferActivation: false
|
||||
|
||||
load: ->
|
||||
try
|
||||
@loadMetadata()
|
||||
@loadKeymaps()
|
||||
@loadStylesheets()
|
||||
if @deferActivation = @metadata.activationEvents?
|
||||
@loadGrammars()
|
||||
@loadScopedProperties()
|
||||
if @metadata.activationEvents?
|
||||
@registerDeferredDeserializers()
|
||||
else
|
||||
@requireMainModule()
|
||||
@@ -22,43 +31,91 @@ class AtomPackage extends Package
|
||||
console.warn "Failed to load package named '#{@name}'", e.stack
|
||||
this
|
||||
|
||||
activate: ({immediate}={}) ->
|
||||
keymap.add(path, map) for [path, map] in @keymaps
|
||||
applyStylesheet(path, content) for [path, content] in @stylesheets
|
||||
syntax.addGrammar(grammar) for grammar in @grammars
|
||||
syntax.addProperties(path, selector, properties) for [path, selector, properties] in @scopedProperties
|
||||
|
||||
if @metadata.activationEvents? and not immediate
|
||||
@subscribeToActivationEvents()
|
||||
else
|
||||
@activateNow()
|
||||
|
||||
activateNow: ->
|
||||
try
|
||||
if @requireMainModule()
|
||||
config.setDefaults(@name, @mainModule.configDefaults)
|
||||
@mainModule.activate(atom.getPackageState(@name) ? {})
|
||||
catch e
|
||||
console.warn "Failed to activate package named '#{@name}'", e.stack
|
||||
|
||||
loadMetadata: ->
|
||||
if metadataPath = fs.resolveExtension(fs.join(@path, 'package'), ['cson', 'json'])
|
||||
@metadata = fs.readObject(metadataPath)
|
||||
if metadataPath = fsUtils.resolveExtension(fsUtils.join(@path, 'package'), ['cson', 'json'])
|
||||
@metadata = CSON.readObject(metadataPath)
|
||||
@metadata ?= {}
|
||||
|
||||
loadKeymaps: ->
|
||||
keymapsDirPath = fs.join(@path, 'keymaps')
|
||||
@keymaps = @getKeymapPaths().map (path) -> [path, CSON.readObject(path)]
|
||||
|
||||
getKeymapPaths: ->
|
||||
keymapsDirPath = fsUtils.join(@path, 'keymaps')
|
||||
if @metadata.keymaps
|
||||
for path in @metadata.keymaps
|
||||
keymapPath = fs.resolve(keymapsDirPath, path, ['cson', 'json', ''])
|
||||
keymap.load(keymapPath)
|
||||
@metadata.keymaps.map (name) -> fsUtils.resolve(keymapsDirPath, name, ['cson', 'json', ''])
|
||||
else
|
||||
keymap.loadDirectory(keymapsDirPath)
|
||||
fsUtils.list(keymapsDirPath, ['cson', 'json']) ? []
|
||||
|
||||
loadStylesheets: ->
|
||||
stylesheetDirPath = fs.join(@path, 'stylesheets')
|
||||
for stylesheetPath in fs.list(stylesheetDirPath)
|
||||
requireStylesheet(stylesheetPath)
|
||||
@stylesheets = @getStylesheetPaths().map (path) -> [path, loadStylesheet(path)]
|
||||
|
||||
activate: ->
|
||||
if @deferActivation
|
||||
@subscribeToActivationEvents()
|
||||
getStylesheetPaths: ->
|
||||
stylesheetDirPath = fsUtils.join(@path, 'stylesheets')
|
||||
if @metadata.stylesheets
|
||||
@metadata.stylesheets.map (name) -> fsUtils.resolve(stylesheetDirPath, name, ['css', 'less', ''])
|
||||
else
|
||||
try
|
||||
if @requireMainModule()
|
||||
config.setDefaults(@name, @mainModule.configDefaults)
|
||||
atom.activateAtomPackage(this)
|
||||
catch e
|
||||
console.warn "Failed to activate package named '#{@name}'", e.stack
|
||||
fsUtils.list(stylesheetDirPath, ['css', 'less']) ? []
|
||||
|
||||
loadGrammars: ->
|
||||
@grammars = []
|
||||
grammarsDirPath = fsUtils.join(@path, 'grammars')
|
||||
for grammarPath in fsUtils.list(grammarsDirPath, ['.cson', '.json']) ? []
|
||||
@grammars.push(TextMateGrammar.loadSync(grammarPath))
|
||||
|
||||
loadScopedProperties: ->
|
||||
@scopedProperties = []
|
||||
scopedPropertiessDirPath = fsUtils.join(@path, 'scoped-properties')
|
||||
for scopedPropertiesPath in fsUtils.list(scopedPropertiessDirPath, ['.cson', '.json']) ? []
|
||||
for selector, properties of fsUtils.readObject(scopedPropertiesPath)
|
||||
@scopedProperties.push([scopedPropertiesPath, selector, properties])
|
||||
|
||||
serialize: ->
|
||||
try
|
||||
@mainModule?.serialize?()
|
||||
catch e
|
||||
console.error "Error serializing package '#{@name}'", e.stack
|
||||
|
||||
deactivate: ->
|
||||
@unsubscribeFromActivationEvents()
|
||||
syntax.removeGrammar(grammar) for grammar in @grammars
|
||||
syntax.removeProperties(path) for [path] in @scopedProperties
|
||||
keymap.remove(path) for [path] in @keymaps
|
||||
removeStylesheet(path) for [path] in @stylesheets
|
||||
@mainModule?.deactivate?()
|
||||
|
||||
requireMainModule: ->
|
||||
return @mainModule if @mainModule
|
||||
mainPath = @path
|
||||
mainPath = fs.join(mainPath, @metadata.main) if @metadata.main
|
||||
mainPath = require.resolve(mainPath)
|
||||
@mainModule = require(mainPath) if fs.isFile(mainPath)
|
||||
mainModulePath = @getMainModulePath()
|
||||
@mainModule = require(mainModulePath) if fsUtils.isFile(mainModulePath)
|
||||
|
||||
getMainModulePath: ->
|
||||
return @mainModulePath if @resolvedMainModulePath
|
||||
@resolvedMainModulePath = true
|
||||
mainModulePath =
|
||||
if @metadata.main
|
||||
fsUtils.join(@path, @metadata.main)
|
||||
else
|
||||
fsUtils.join(@path, 'index')
|
||||
@mainModulePath = fsUtils.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
|
||||
|
||||
registerDeferredDeserializers: ->
|
||||
for deserializerName in @metadata.deferredDeserializers ? []
|
||||
@@ -66,25 +123,23 @@ class AtomPackage extends Package
|
||||
|
||||
subscribeToActivationEvents: () ->
|
||||
return unless @metadata.activationEvents?
|
||||
|
||||
activateHandler = (event) =>
|
||||
bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event)
|
||||
@deferActivation = false
|
||||
@activate()
|
||||
$(event.target).trigger(event)
|
||||
@restoreEventHandlersOnBubblePath(bubblePathEventHandlers)
|
||||
@unsubscribeFromActivationEvents(activateHandler)
|
||||
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
rootView.command(event, activateHandler) for event in @metadata.activationEvents
|
||||
rootView.command(event, @handleActivationEvent) for event in @metadata.activationEvents
|
||||
else
|
||||
rootView.command(event, selector, activateHandler) for event, selector of @metadata.activationEvents
|
||||
rootView.command(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
|
||||
|
||||
unsubscribeFromActivationEvents: (activateHandler) ->
|
||||
handleActivationEvent: (event) =>
|
||||
bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event)
|
||||
@activateNow()
|
||||
$(event.target).trigger(event)
|
||||
@restoreEventHandlersOnBubblePath(bubblePathEventHandlers)
|
||||
@unsubscribeFromActivationEvents()
|
||||
|
||||
unsubscribeFromActivationEvents: ->
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
rootView.off(event, activateHandler) for event in @metadata.activationEvents
|
||||
rootView.off(event, @handleActivationEvent) for event in @metadata.activationEvents
|
||||
else
|
||||
rootView.off(event, selector, activateHandler) for event, selector of @metadata.activationEvents
|
||||
rootView.off(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
|
||||
|
||||
disableEventHandlersOnBubblePath: (event) ->
|
||||
bubblePathEventHandlers = []
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
Theme = require 'theme'
|
||||
CSON = require 'cson'
|
||||
|
||||
module.exports =
|
||||
class AtomTheme extends Theme
|
||||
@@ -13,7 +14,7 @@ class AtomTheme extends Theme
|
||||
else
|
||||
metadataPath = fs.resolveExtension(fs.join(@path, 'package'), ['cson', 'json'])
|
||||
if fs.isFile(metadataPath)
|
||||
stylesheetNames = fs.readObject(metadataPath)?.stylesheets
|
||||
stylesheetNames = CSON.readObject(metadataPath)?.stylesheets
|
||||
if stylesheetNames
|
||||
@loadStylesheet(fs.join(@path, name)) for name in stylesheetNames
|
||||
else
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
_ = require 'underscore'
|
||||
Package = require 'package'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
Theme = require 'theme'
|
||||
LoadTextMatePackagesTask = require 'load-text-mate-packages-task'
|
||||
|
||||
messageIdCounter = 1
|
||||
originalSendMessageToBrowserProcess = atom.sendMessageToBrowserProcess
|
||||
@@ -14,70 +13,91 @@ _.extend atom,
|
||||
loadedThemes: []
|
||||
pendingBrowserProcessCallbacks: {}
|
||||
loadedPackages: []
|
||||
activatedAtomPackages: []
|
||||
atomPackageStates: {}
|
||||
activePackages: []
|
||||
packageStates: {}
|
||||
presentingModal: false
|
||||
pendingModals: [[]]
|
||||
|
||||
getPathToOpen: ->
|
||||
@getWindowState('pathToOpen') ? window.location.params.pathToOpen
|
||||
|
||||
activateAtomPackage: (pack) ->
|
||||
@activatedAtomPackages.push(pack)
|
||||
pack.mainModule.activate(@atomPackageStates[pack.name] ? {})
|
||||
getPackageState: (name) ->
|
||||
@packageStates[name]
|
||||
|
||||
deactivateAtomPackages: ->
|
||||
pack.mainModule.deactivate?() for pack in @activatedAtomPackages
|
||||
@activatedAtomPackages = []
|
||||
|
||||
serializeAtomPackages: ->
|
||||
packageStates = {}
|
||||
for pack in @loadedPackages
|
||||
if pack in @activatedAtomPackages
|
||||
try
|
||||
packageStates[pack.name] = pack.mainModule.serialize?()
|
||||
catch e
|
||||
console?.error("Exception serializing '#{pack.name}' package's module\n", e.stack)
|
||||
else
|
||||
packageStates[pack.name] = @atomPackageStates[pack.name]
|
||||
packageStates
|
||||
|
||||
loadTextPackage: ->
|
||||
textPackagePath = _.find @getPackagePaths(), (path) -> fs.base(path) is 'text.tmbundle'
|
||||
pack = Package.build(textPackagePath)
|
||||
@loadedPackages.push(pack)
|
||||
pack.load()
|
||||
|
||||
loadPackages: ->
|
||||
textMatePackages = []
|
||||
paths = @getPackagePaths().filter (path) -> fs.base(path) isnt 'text.tmbundle'
|
||||
for path in paths
|
||||
pack = Package.build(path)
|
||||
@loadedPackages.push(pack)
|
||||
if pack instanceof TextMatePackage
|
||||
textMatePackages.push(pack)
|
||||
else
|
||||
pack.load()
|
||||
|
||||
new LoadTextMatePackagesTask(textMatePackages).start() if textMatePackages.length > 0
|
||||
setPackageState: (name, state) ->
|
||||
@packageStates[name] = state
|
||||
|
||||
activatePackages: ->
|
||||
pack.activate() for pack in @loadedPackages
|
||||
@activatePackage(pack.path) for pack in @getLoadedPackages()
|
||||
|
||||
activatePackage: (id, options) ->
|
||||
if pack = @loadPackage(id, options)
|
||||
@activePackages.push(pack)
|
||||
pack.activate(options)
|
||||
pack
|
||||
|
||||
deactivatePackages: ->
|
||||
@deactivatePackage(pack.path) for pack in @getActivePackages()
|
||||
|
||||
deactivatePackage: (id) ->
|
||||
if pack = @getActivePackage(id)
|
||||
@setPackageState(pack.name, state) if state = pack.serialize?()
|
||||
pack.deactivate()
|
||||
_.remove(@activePackages, pack)
|
||||
else
|
||||
throw new Error("No active package for id '#{id}'")
|
||||
|
||||
getActivePackage: (id) ->
|
||||
if path = @resolvePackagePath(id)
|
||||
_.detect @activePackages, (pack) -> pack.path is path
|
||||
|
||||
isPackageActive: (id) ->
|
||||
if path = @resolvePackagePath(id)
|
||||
_.detect @activePackages, (pack) -> pack.path is path
|
||||
|
||||
getActivePackages: ->
|
||||
_.clone(@activePackages)
|
||||
|
||||
loadPackages: ->
|
||||
@loadPackage(path) for path in @getPackagePaths() when not @isPackageDisabled(path)
|
||||
|
||||
loadPackage: (id, options) ->
|
||||
if @isPackageDisabled(id)
|
||||
return console.warn("Tried to load disabled packaged '#{id}'")
|
||||
|
||||
if path = @resolvePackagePath(id)
|
||||
return pack if pack = @getLoadedPackage(id)
|
||||
pack = Package.load(path, options)
|
||||
@loadedPackages.push(pack)
|
||||
pack
|
||||
else
|
||||
throw new Error("Could not resolve '#{id}' to a package path")
|
||||
|
||||
resolvePackagePath: _.memoize (id) ->
|
||||
return id if fs.isDirectory(id)
|
||||
path = fs.resolve(config.packageDirPaths..., id)
|
||||
path if fs.isDirectory(path)
|
||||
|
||||
getLoadedPackage: (id) ->
|
||||
if path = @resolvePackagePath(id)
|
||||
_.detect @loadedPackages, (pack) -> pack.path is path
|
||||
|
||||
isPackageLoaded: (id) ->
|
||||
@getLoadedPackage(id)?
|
||||
|
||||
getLoadedPackages: ->
|
||||
_.clone(@loadedPackages)
|
||||
|
||||
isPackageDisabled: (id) ->
|
||||
if path = @resolvePackagePath(id)
|
||||
_.include(config.get('core.disabledPackages') ? [], fs.base(path))
|
||||
|
||||
getPackagePaths: ->
|
||||
disabledPackages = config.get("core.disabledPackages") ? []
|
||||
packagePaths = []
|
||||
for packageDirPath in config.packageDirPaths
|
||||
for packagePath in fs.list(packageDirPath)
|
||||
continue if not fs.isDirectory(packagePath)
|
||||
continue if fs.base(packagePath) in disabledPackages
|
||||
continue if packagePath in packagePaths
|
||||
packagePaths.push(packagePath)
|
||||
|
||||
packagePaths
|
||||
packagePaths.push(packagePath) if fs.isDirectory(packagePath)
|
||||
_.uniq(packagePaths)
|
||||
|
||||
loadThemes: ->
|
||||
themeNames = config.get("core.themes") ? ['atom-dark-ui', 'atom-dark-syntax']
|
||||
@@ -179,17 +199,6 @@ _.extend atom,
|
||||
toggleFullScreen: ->
|
||||
@sendMessageToBrowserProcess('toggleFullScreen')
|
||||
|
||||
getRootViewStateForPath: (path) ->
|
||||
if json = localStorage[path]
|
||||
JSON.parse(json)
|
||||
|
||||
setRootViewStateForPath: (path, state) ->
|
||||
return unless path
|
||||
if state?
|
||||
localStorage[path] = JSON.stringify(state)
|
||||
else
|
||||
delete localStorage[path]
|
||||
|
||||
sendMessageToBrowserProcess: (name, data=[], callbacks) ->
|
||||
messageId = messageIdCounter++
|
||||
data.unshift(messageId)
|
||||
@@ -209,12 +218,25 @@ _.extend atom,
|
||||
windowState
|
||||
|
||||
getWindowState: (keyPath) ->
|
||||
windowState = JSON.parse($native.getWindowState())
|
||||
windowState = JSON.parse(@getInMemoryWindowState() ? @getSavedWindowState() ? '{}')
|
||||
if keyPath
|
||||
_.valueForKeyPath(windowState, keyPath)
|
||||
else
|
||||
windowState
|
||||
|
||||
getInMemoryWindowState: ->
|
||||
inMemoryState = $native.getWindowState()
|
||||
if inMemoryState.length > 0
|
||||
inMemoryState
|
||||
else
|
||||
null
|
||||
|
||||
getSavedWindowState: ->
|
||||
localStorage[window.location.params.pathToOpen]
|
||||
|
||||
saveWindowState: ->
|
||||
localStorage[@getPathToOpen()] = JSON.stringify(@getWindowState())
|
||||
|
||||
update: ->
|
||||
@sendMessageToBrowserProcess('update')
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
|
||||
Specificity = require 'specificity'
|
||||
PEG = require 'pegjs'
|
||||
@@ -14,8 +14,9 @@ class BindingSet
|
||||
commandsByKeystrokes: null
|
||||
commandForEvent: null
|
||||
parser: null
|
||||
name: null
|
||||
|
||||
constructor: (@selector, commandsByKeystrokes, @index) ->
|
||||
constructor: (@selector, commandsByKeystrokes, @index, @name) ->
|
||||
BindingSet.parser ?= PEG.buildParser(fs.read(require.resolve 'keystroke-pattern.pegjs'))
|
||||
@specificity = Specificity(@selector)
|
||||
@commandsByKeystrokes = @normalizeCommandsByKeystrokes(commandsByKeystrokes)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
CSON = require 'cson'
|
||||
|
||||
configDirPath = fs.absolute("~/.atom")
|
||||
bundledPackagesDirPath = fs.join(resourcePath, "src/packages")
|
||||
@@ -10,8 +11,6 @@ vendoredThemesDirPath = fs.join(resourcePath, "vendor/themes")
|
||||
userThemesDirPath = fs.join(configDirPath, "themes")
|
||||
userPackagesDirPath = fs.join(configDirPath, "packages")
|
||||
|
||||
require.paths.unshift userPackagesDirPath
|
||||
|
||||
module.exports =
|
||||
class Config
|
||||
configDirPath: configDirPath
|
||||
@@ -36,19 +35,18 @@ class Config
|
||||
fs.makeDirectory(@configDirPath)
|
||||
|
||||
templateConfigDirPath = fs.resolve(window.resourcePath, 'dot-atom')
|
||||
|
||||
onConfigDirFile = (path) =>
|
||||
relativePath = path.substring(templateConfigDirPath.length + 1)
|
||||
configPath = fs.join(@configDirPath, relativePath)
|
||||
fs.write(configPath, fs.read(path))
|
||||
fs.traverseTree(templateConfigDirPath, onConfigDirFile, (path) -> true)
|
||||
fs.traverseTreeSync(templateConfigDirPath, onConfigDirFile, (path) -> true)
|
||||
|
||||
configThemeDirPath = fs.join(@configDirPath, 'themes')
|
||||
onThemeDirFile = (path) ->
|
||||
relativePath = path.substring(bundledThemesDirPath.length + 1)
|
||||
configPath = fs.join(configThemeDirPath, relativePath)
|
||||
fs.write(configPath, fs.read(path))
|
||||
fs.traverseTree(bundledThemesDirPath, onThemeDirFile, (path) -> true)
|
||||
fs.traverseTreeSync(bundledThemesDirPath, onThemeDirFile, (path) -> true)
|
||||
|
||||
load: ->
|
||||
@initializeConfigDirectory()
|
||||
@@ -57,7 +55,7 @@ class Config
|
||||
loadUserConfig: ->
|
||||
if fs.exists(@configFilePath)
|
||||
try
|
||||
userConfig = fs.readObject(@configFilePath)
|
||||
userConfig = CSON.readObject(@configFilePath)
|
||||
_.extend(@settings, userConfig)
|
||||
catch e
|
||||
@configFileHasErrors = true
|
||||
@@ -103,6 +101,6 @@ class Config
|
||||
@trigger 'updated'
|
||||
|
||||
save: ->
|
||||
fs.writeObject(@configFilePath, @settings)
|
||||
CSON.writeObject(@configFilePath, @settings)
|
||||
|
||||
_.extend Config.prototype, EventEmitter
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fsUtils = require 'fs-utils'
|
||||
File = require 'file'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
@@ -7,23 +8,27 @@ module.exports =
|
||||
class Directory
|
||||
path: null
|
||||
|
||||
constructor: (@path) ->
|
||||
constructor: (@path, @symlink=false) ->
|
||||
|
||||
getBaseName: ->
|
||||
fs.base(@path)
|
||||
fsUtils.base(@path)
|
||||
|
||||
getPath: -> @path
|
||||
|
||||
getEntries: ->
|
||||
directories = []
|
||||
files = []
|
||||
for path in fs.list(@path)
|
||||
if fs.isDirectory(path)
|
||||
directories.push(new Directory(path))
|
||||
else if fs.isFile(path)
|
||||
files.push(new File(path))
|
||||
else
|
||||
console.error "#{path} is neither a file nor a directory."
|
||||
for path in fsUtils.list(@path)
|
||||
try
|
||||
stat = fs.lstatSync(path)
|
||||
symlink = stat.isSymbolicLink()
|
||||
stat = fs.statSync(path) if symlink
|
||||
catch e
|
||||
continue
|
||||
if stat.isDirectory()
|
||||
directories.push(new Directory(path, symlink))
|
||||
else if stat.isFile()
|
||||
files.push(new File(path, symlink))
|
||||
|
||||
directories.concat(files)
|
||||
|
||||
@@ -34,10 +39,12 @@ class Directory
|
||||
@unsubscribeFromNativeChangeEvents() if @subscriptionCount() == 0
|
||||
|
||||
subscribeToNativeChangeEvents: ->
|
||||
@watchId = $native.watchPath @path, (eventType) =>
|
||||
@watchSubscription = fsUtils.watchPath @path, (eventType) =>
|
||||
@trigger "contents-changed" if eventType is "contents-change"
|
||||
|
||||
unsubscribeFromNativeChangeEvents: ->
|
||||
$native.unwatchPath(@path, @watchId)
|
||||
if @watchSubscription?
|
||||
@watchSubscription.unwatch()
|
||||
@watchSubscription = null
|
||||
|
||||
_.extend Directory.prototype, EventEmitter
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Point = require 'point'
|
||||
Buffer = require 'buffer'
|
||||
Buffer = require 'text-buffer'
|
||||
LanguageMode = require 'language-mode'
|
||||
DisplayBuffer = require 'display-buffer'
|
||||
Cursor = require 'cursor'
|
||||
@@ -8,7 +8,7 @@ EventEmitter = require 'event-emitter'
|
||||
Subscriber = require 'subscriber'
|
||||
Range = require 'range'
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
|
||||
module.exports =
|
||||
class EditSession
|
||||
@@ -25,11 +25,6 @@ class EditSession
|
||||
session.setCursorScreenPosition(state.cursorScreenPosition)
|
||||
session
|
||||
|
||||
@identifiedBy: 'path'
|
||||
|
||||
@deserializesToSameObject: (state, editSession) ->
|
||||
state.path
|
||||
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
languageMode: null
|
||||
@@ -589,9 +584,15 @@ class EditSession
|
||||
cursor = @addCursor(marker)
|
||||
selection = new Selection({editSession: this, marker, cursor})
|
||||
@selections.push(selection)
|
||||
selectionBufferRange = selection.getBufferRange()
|
||||
@mergeIntersectingSelections()
|
||||
@trigger 'selection-added', selection
|
||||
selection
|
||||
if selection.destroyed
|
||||
for selection in @getSelections()
|
||||
if selection.intersectsBufferRange(selectionBufferRange)
|
||||
return selection
|
||||
else
|
||||
@trigger 'selection-added', selection
|
||||
selection
|
||||
|
||||
addSelectionForBufferRange: (bufferRange, options={}) ->
|
||||
options = _.defaults({invalidationStrategy: 'never'}, options)
|
||||
@@ -842,11 +843,18 @@ class EditSession
|
||||
|
||||
getGrammar: -> @languageMode.grammar
|
||||
|
||||
setGrammar: (grammar) ->
|
||||
@languageMode.grammar = grammar
|
||||
@handleGrammarChange()
|
||||
|
||||
reloadGrammar: ->
|
||||
if @languageMode.reloadGrammar()
|
||||
@unfoldAll()
|
||||
@displayBuffer.tokenizedBuffer.resetScreenLines()
|
||||
true
|
||||
@handleGrammarChange() if @languageMode.reloadGrammar()
|
||||
|
||||
handleGrammarChange: ->
|
||||
@unfoldAll()
|
||||
@displayBuffer.tokenizedBuffer.resetScreenLines()
|
||||
@trigger 'grammar-changed'
|
||||
true
|
||||
|
||||
getDebugSnapshot: ->
|
||||
[
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{View, $$} = require 'space-pen'
|
||||
Buffer = require 'buffer'
|
||||
Buffer = require 'text-buffer'
|
||||
Gutter = require 'gutter'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
EditSession = require 'edit-session'
|
||||
CursorView = require 'cursor-view'
|
||||
SelectionView = require 'selection-view'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
|
||||
@@ -16,6 +16,7 @@ class Editor extends View
|
||||
fontSize: 20
|
||||
showInvisibles: false
|
||||
showIndentGuide: false
|
||||
showLineNumbers: true
|
||||
autoIndent: true
|
||||
autoIndentOnPaste: false
|
||||
nonWordCharacters: "./\\()\"':,.;<>~!@#$%^&*|+=[]{}`~?-"
|
||||
@@ -61,7 +62,7 @@ class Editor extends View
|
||||
else
|
||||
{editSession, @mini} = (editSessionOrOptions ? {})
|
||||
|
||||
requireStylesheet 'editor.less'
|
||||
requireStylesheet 'editor'
|
||||
|
||||
@id = Editor.nextEditorId++
|
||||
@lineCache = []
|
||||
@@ -149,13 +150,13 @@ class Editor extends View
|
||||
'editor:toggle-line-comments': @toggleLineCommentsInSelection
|
||||
'editor:log-cursor-scope': @logCursorScope
|
||||
'editor:checkout-head-revision': @checkoutHead
|
||||
'editor:select-grammar': @selectGrammar
|
||||
'editor:copy-path': @copyPathToPasteboard
|
||||
'editor:move-line-up': @moveLineUp
|
||||
'editor:move-line-down': @moveLineDown
|
||||
'editor:duplicate-line': @duplicateLine
|
||||
'editor:toggle-indent-guide': => config.set('editor.showIndentGuide', !config.get('editor.showIndentGuide'))
|
||||
'editor:save-debug-snapshot': @saveDebugSnapshot
|
||||
'editor:toggle-line-numbers': => config.set('editor.showLineNumbers', !config.get('editor.showLineNumbers'))
|
||||
|
||||
documentation = {}
|
||||
for name, method of editorBindings
|
||||
@@ -316,6 +317,7 @@ class Editor extends View
|
||||
backwardsScanInRange: (args...) -> @getBuffer().backwardsScanInRange(args...)
|
||||
|
||||
configure: ->
|
||||
@observeConfig 'editor.showLineNumbers', (showLineNumbers) => @gutter.setShowLineNumbers(showLineNumbers)
|
||||
@observeConfig 'editor.showInvisibles', (showInvisibles) => @setShowInvisibles(showInvisibles)
|
||||
@observeConfig 'editor.showIndentGuide', (showIndentGuide) => @setShowIndentGuide(showIndentGuide)
|
||||
@observeConfig 'editor.invisibles', (invisibles) => @setInvisibles(invisibles)
|
||||
@@ -371,7 +373,7 @@ class Editor extends View
|
||||
else if clickCount == 3
|
||||
@activeEditSession.selectLine() unless e.shiftKey
|
||||
|
||||
@selectOnMousemoveUntilMouseup()
|
||||
@selectOnMousemoveUntilMouseup() unless e.originalEvent.which > 1
|
||||
|
||||
@renderedLines.on 'mousedown', onMouseDown
|
||||
|
||||
@@ -395,8 +397,6 @@ class Editor extends View
|
||||
e.pageX = @renderedLines.offset().left
|
||||
onMouseDown(e)
|
||||
|
||||
@subscribe syntax, 'grammars-loaded', => @reloadGrammar()
|
||||
|
||||
@scrollView.on 'scroll', =>
|
||||
if @scrollView.scrollLeft() == 0
|
||||
@gutter.removeClass('drop-shadow')
|
||||
@@ -456,6 +456,9 @@ class Editor extends View
|
||||
@reloadGrammar()
|
||||
@trigger 'editor:path-changed'
|
||||
|
||||
@activeEditSession.on "grammar-changed.editor", =>
|
||||
@trigger 'editor:grammar-changed'
|
||||
|
||||
@trigger 'editor:path-changed'
|
||||
@resetDisplay()
|
||||
|
||||
@@ -586,6 +589,7 @@ class Editor extends View
|
||||
@setSoftWrapColumn(softWrapColumn) if @attached
|
||||
if @activeEditSession.getSoftWrap()
|
||||
@addClass 'soft-wrap'
|
||||
@scrollView.scrollLeft(0)
|
||||
@_setSoftWrapColumn = => @setSoftWrapColumn()
|
||||
$(window).on "resize.editor-#{@id}", @_setSoftWrapColumn
|
||||
else
|
||||
@@ -635,19 +639,19 @@ class Editor extends View
|
||||
@requestDisplayUpdate()
|
||||
|
||||
splitLeft: (items...) ->
|
||||
@pane()?.splitLeft(items...).activeView
|
||||
@getPane()?.splitLeft(items...).activeView
|
||||
|
||||
splitRight: (items...) ->
|
||||
@pane()?.splitRight(items...).activeView
|
||||
@getPane()?.splitRight(items...).activeView
|
||||
|
||||
splitUp: (items...) ->
|
||||
@pane()?.splitUp(items...).activeView
|
||||
@getPane()?.splitUp(items...).activeView
|
||||
|
||||
splitDown: (items...) ->
|
||||
@pane()?.splitDown(items...).activeView
|
||||
@getPane()?.splitDown(items...).activeView
|
||||
|
||||
pane: ->
|
||||
@closest('.pane').view()
|
||||
getPane: ->
|
||||
@parent('.item-views').parent('.pane').view()
|
||||
|
||||
remove: (selector, keepData) ->
|
||||
return super if keepData or @removed
|
||||
@@ -655,7 +659,7 @@ class Editor extends View
|
||||
super
|
||||
rootView?.focus()
|
||||
|
||||
afterRemove: ->
|
||||
beforeRemove: ->
|
||||
@removed = true
|
||||
@activeEditSession?.destroy()
|
||||
$(window).off(".editor-#{@id}")
|
||||
@@ -713,8 +717,6 @@ class Editor extends View
|
||||
fragment.remove()
|
||||
|
||||
updateLayerDimensions: ->
|
||||
@gutter.calculateWidth()
|
||||
|
||||
height = @lineHeight * @screenLineCount()
|
||||
unless @layerHeight == height
|
||||
@renderedLines.height(height)
|
||||
@@ -1141,20 +1143,23 @@ class Editor extends View
|
||||
else
|
||||
@highlightedLine = null
|
||||
|
||||
getGrammar: -> @activeEditSession.getGrammar()
|
||||
getGrammar: ->
|
||||
@activeEditSession.getGrammar()
|
||||
|
||||
selectGrammar: ->
|
||||
GrammarView = require 'grammar-view'
|
||||
new GrammarView(this)
|
||||
setGrammar: (grammar) ->
|
||||
throw new Error("Only mini-editors can explicity set their grammar") unless @mini
|
||||
@activeEditSession.setGrammar(grammar)
|
||||
@handleGrammarChange()
|
||||
|
||||
reloadGrammar: ->
|
||||
grammarChanged = @activeEditSession.reloadGrammar()
|
||||
if grammarChanged
|
||||
@clearRenderedLines()
|
||||
@updateDisplay()
|
||||
@trigger 'editor:grammar-changed'
|
||||
grammarChanged = @activeEditSession.reloadGrammar()
|
||||
@handleGrammarChange() if grammarChanged
|
||||
grammarChanged
|
||||
|
||||
handleGrammarChange: ->
|
||||
@clearRenderedLines()
|
||||
@updateDisplay()
|
||||
|
||||
bindToKeyedEvent: (key, event, callback) ->
|
||||
binding = {}
|
||||
binding[key] = event
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
fs = require 'fs'
|
||||
fsUtils = require 'fs-utils'
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
@@ -8,33 +9,34 @@ class File
|
||||
path: null
|
||||
cachedContents: null
|
||||
|
||||
constructor: (@path) ->
|
||||
if @exists() and not fs.isFile(@path)
|
||||
throw new Error(@path + " is a directory")
|
||||
constructor: (@path, @symlink=false) ->
|
||||
try
|
||||
if fs.statSync(@path).isDirectory()
|
||||
throw new Error("#{@path} is a directory")
|
||||
|
||||
setPath: (@path) ->
|
||||
|
||||
getPath: -> @path
|
||||
|
||||
getBaseName: ->
|
||||
fs.base(@path)
|
||||
fsUtils.base(@path)
|
||||
|
||||
write: (text) ->
|
||||
previouslyExisted = @exists()
|
||||
@cachedContents = text
|
||||
fs.write(@getPath(), text)
|
||||
fsUtils.write(@getPath(), text)
|
||||
@subscribeToNativeChangeEvents() if not previouslyExisted and @subscriptionCount() > 0
|
||||
|
||||
read: (flushCache)->
|
||||
if not @exists()
|
||||
@cachedContents = null
|
||||
else if not @cachedContents? or flushCache
|
||||
@cachedContents = fs.read(@getPath())
|
||||
@cachedContents = fsUtils.read(@getPath())
|
||||
else
|
||||
@cachedContents
|
||||
|
||||
exists: ->
|
||||
fs.exists(@getPath())
|
||||
fsUtils.exists(@getPath())
|
||||
|
||||
afterSubscribe: ->
|
||||
@subscribeToNativeChangeEvents() if @exists() and @subscriptionCount() == 1
|
||||
@@ -67,10 +69,12 @@ class File
|
||||
@trigger "removed"
|
||||
|
||||
subscribeToNativeChangeEvents: ->
|
||||
@watchId = $native.watchPath @path, (eventType, path) =>
|
||||
@watchSubscription = fsUtils.watchPath @path, (eventType, path) =>
|
||||
@handleNativeChangeEvent(eventType, path)
|
||||
|
||||
unsubscribeFromNativeChangeEvents: ->
|
||||
$native.unwatchPath(@path, @watchId)
|
||||
if @watchSubscription
|
||||
@watchSubscription.unwatch()
|
||||
@watchSubscription = null
|
||||
|
||||
_.extend File.prototype, EventEmitter
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
Subscriber = require 'subscriber'
|
||||
EventEmitter = require 'event-emitter'
|
||||
GitRepository = require 'git-repository'
|
||||
RepositoryStatusTask = require 'repository-status-task'
|
||||
GitUtils = require 'git-utils'
|
||||
|
||||
module.exports =
|
||||
class Git
|
||||
@@ -14,26 +14,18 @@ class Git
|
||||
catch e
|
||||
null
|
||||
|
||||
statusFlags:
|
||||
index_new: 1 << 0
|
||||
index_modified: 1 << 1
|
||||
index_deleted: 1 << 2
|
||||
index_renamed: 1 << 3
|
||||
index_typechange: 1 << 4
|
||||
working_dir_new: 1 << 7
|
||||
working_dir_modified: 1 << 8
|
||||
working_dir_delete: 1 << 9
|
||||
working_dir_typechange: 1 << 10
|
||||
ignore: 1 << 14
|
||||
|
||||
statuses: null
|
||||
upstream: null
|
||||
statusTask: null
|
||||
|
||||
constructor: (path, options={}) ->
|
||||
@repo = GitUtils.open(path)
|
||||
unless @repo?
|
||||
throw new Error("No Git repository found searching path: #{path}")
|
||||
|
||||
@statuses = {}
|
||||
@upstream = {ahead: 0, behind: 0}
|
||||
@repo = GitRepository.open(path)
|
||||
|
||||
refreshOnWindowFocus = options.refreshOnWindowFocus ? true
|
||||
if refreshOnWindowFocus
|
||||
$ = require 'jquery'
|
||||
@@ -64,12 +56,14 @@ class Git
|
||||
@statusTask.off()
|
||||
@statusTask = null
|
||||
|
||||
@getRepo().destroy()
|
||||
@repo = null
|
||||
if @repo?
|
||||
@repo.release()
|
||||
@repo = null
|
||||
|
||||
@unsubscribe()
|
||||
|
||||
getWorkingDirectory: ->
|
||||
@getPath()?.replace(/\/\.git\/?$/, '')
|
||||
@getRepo().getWorkingDirectory()
|
||||
|
||||
getHead: ->
|
||||
@getRepo().getHead() ? ''
|
||||
@@ -88,22 +82,14 @@ class Git
|
||||
isPathIgnored: (path) ->
|
||||
@getRepo().isIgnored(@relativize(path))
|
||||
|
||||
isStatusModified: (status=0) ->
|
||||
modifiedFlags = @statusFlags.working_dir_modified |
|
||||
@statusFlags.working_dir_delete |
|
||||
@statusFlags.working_dir_typechange |
|
||||
@statusFlags.index_modified |
|
||||
@statusFlags.index_deleted |
|
||||
@statusFlags.index_typechange
|
||||
(status & modifiedFlags) > 0
|
||||
isStatusModified: (status) ->
|
||||
@getRepo().isStatusModified(status)
|
||||
|
||||
isPathModified: (path) ->
|
||||
@isStatusModified(@getPathStatus(path))
|
||||
|
||||
isStatusNew: (status=0) ->
|
||||
newFlags = @statusFlags.working_dir_new |
|
||||
@statusFlags.index_new
|
||||
(status & newFlags) > 0
|
||||
isStatusNew: (status) ->
|
||||
@getRepo().isStatusNew(status)
|
||||
|
||||
isPathNew: (path) ->
|
||||
@isStatusNew(@getPathStatus(path))
|
||||
@@ -116,12 +102,7 @@ class Git
|
||||
path
|
||||
|
||||
getShortHead: ->
|
||||
head = @getHead()
|
||||
return head.substring(11) if head.indexOf('refs/heads/') is 0
|
||||
return head.substring(10) if head.indexOf('refs/tags/') is 0
|
||||
return head.substring(13) if head.indexOf('refs/remotes/') is 0
|
||||
return head.substring(0, 7) if head.match(/[a-fA-F0-9]{40}/)
|
||||
return head
|
||||
@getRepo().getShortHead()
|
||||
|
||||
checkoutHead: (path) ->
|
||||
headCheckedOut = @getRepo().checkoutHead(@relativize(path))
|
||||
@@ -129,7 +110,7 @@ class Git
|
||||
headCheckedOut
|
||||
|
||||
getDiffStats: (path) ->
|
||||
@getRepo().getDiffStats(@relativize(path)) ? added: 0, deleted: 0
|
||||
@getRepo().getDiffStats(@relativize(path))
|
||||
|
||||
isSubmodule: (path) ->
|
||||
@getRepo().isSubmodule(@relativize(path))
|
||||
@@ -154,10 +135,7 @@ class Git
|
||||
directoryStatus
|
||||
|
||||
getAheadBehindCounts: ->
|
||||
@getRepo().getAheadBehindCounts() ? ahead: 0, behind: 0
|
||||
|
||||
getLineDiffs: (path, text) ->
|
||||
@getRepo().getLineDiffs(@relativize(path), text) ? []
|
||||
@getRepo().getAheadBehindCount()
|
||||
|
||||
_.extend Git.prototype, Subscriber
|
||||
_.extend Git.prototype, EventEmitter
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
SelectList = require 'select-list'
|
||||
{$$} = require 'space-pen'
|
||||
|
||||
module.exports =
|
||||
class GrammarView extends SelectList
|
||||
|
||||
@viewClass: -> "#{super} grammar-view from-top overlay mini"
|
||||
|
||||
filterKey: 'name'
|
||||
|
||||
initialize: (@editor) ->
|
||||
@currentGrammar = @editor.getGrammar()
|
||||
@path = @editor.getPath()
|
||||
@autoDetect = name: 'Auto Detect'
|
||||
@command 'editor:select-grammar', =>
|
||||
@cancel()
|
||||
false
|
||||
super
|
||||
|
||||
@populate()
|
||||
@attach()
|
||||
|
||||
itemForElement: (grammar) ->
|
||||
if grammar is @currentGrammar
|
||||
grammarClass = 'active-item'
|
||||
else
|
||||
grammarClass = 'inactive-item'
|
||||
|
||||
$$ ->
|
||||
@li grammar.name, class: grammarClass
|
||||
|
||||
populate: ->
|
||||
grammars = new Array(syntax.grammars...)
|
||||
grammars.sort (grammarA, grammarB) ->
|
||||
if grammarA.scopeName is 'text.plain'
|
||||
-1
|
||||
else if grammarB.scopeName is 'text.plain'
|
||||
1
|
||||
else if grammarA.name < grammarB.name
|
||||
-1
|
||||
else if grammarA.name > grammarB.name
|
||||
1
|
||||
else
|
||||
0
|
||||
grammars.unshift(@autoDetect)
|
||||
@setArray(grammars)
|
||||
|
||||
confirmed: (grammar) ->
|
||||
@cancel()
|
||||
if grammar is @autoDetect
|
||||
project.removeGrammarOverrideForPath(@path)
|
||||
else
|
||||
project.addGrammarOverrideForPath(@path, grammar)
|
||||
@editor.reloadGrammar()
|
||||
|
||||
attach: ->
|
||||
super
|
||||
|
||||
rootView.append(this)
|
||||
@miniEditor.focus()
|
||||
@@ -1,5 +1,6 @@
|
||||
{View, $$, $$$} = require 'space-pen'
|
||||
Range = require 'range'
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class Gutter extends View
|
||||
@@ -20,18 +21,11 @@ class Gutter extends View
|
||||
editor.on 'cursor:moved', highlightLines
|
||||
editor.on 'selection:changed', highlightLines
|
||||
|
||||
@calculateWidth()
|
||||
|
||||
editor: ->
|
||||
@parentView
|
||||
|
||||
calculateLineNumberPadding: ->
|
||||
widthTesterElement = $$ -> @div {class: 'line-number'}, ""
|
||||
widthTesterElement.width(0)
|
||||
@append(widthTesterElement)
|
||||
lineNumberPadding = widthTesterElement.outerWidth()
|
||||
widthTesterElement.remove()
|
||||
lineNumberPadding
|
||||
setShowLineNumbers: (showLineNumbers) ->
|
||||
if showLineNumbers then @lineNumbers.show() else @lineNumbers.hide()
|
||||
|
||||
updateLineNumbers: (changes, renderFrom, renderTo) ->
|
||||
if renderFrom < @firstScreenRow or renderTo > @lastScreenRow
|
||||
@@ -48,6 +42,7 @@ class Gutter extends View
|
||||
|
||||
renderLineNumbers: (startScreenRow, endScreenRow) ->
|
||||
editor = @editor()
|
||||
maxDigits = editor.getLineCount().toString().length
|
||||
rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow)
|
||||
|
||||
cursorScreenRow = editor.getCursorScreenPosition().row
|
||||
@@ -56,25 +51,20 @@ class Gutter extends View
|
||||
if row == lastScreenRow
|
||||
rowValue = '•'
|
||||
else
|
||||
rowValue = row + 1
|
||||
rowValue = (row + 1).toString()
|
||||
classes = ['line-number']
|
||||
classes.push('fold') if editor.isFoldedAtBufferRow(row)
|
||||
@div rowValue, class: classes.join(' ')
|
||||
@div class: classes.join(' '), =>
|
||||
rowValuePadding = _.multiplyString(' ', maxDigits - rowValue.length)
|
||||
@raw("#{rowValuePadding}#{rowValue}")
|
||||
|
||||
lastScreenRow = row
|
||||
|
||||
@calculateWidth()
|
||||
@firstScreenRow = startScreenRow
|
||||
@lastScreenRow = endScreenRow
|
||||
@highlightedRows = null
|
||||
@highlightLines()
|
||||
|
||||
calculateWidth: ->
|
||||
highestNumberWidth = @editor().getLineCount().toString().length * @editor().charWidth
|
||||
if highestNumberWidth != @highestNumberWidth
|
||||
@highestNumberWidth = highestNumberWidth
|
||||
@lineNumbers.width(highestNumberWidth + @calculateLineNumberPadding())
|
||||
@widthChanged?(@outerWidth())
|
||||
|
||||
removeLineHighlights: ->
|
||||
return unless @highlightedLineNumbers
|
||||
for line in @highlightedLineNumbers
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
CSON = require 'cson'
|
||||
|
||||
BindingSet = require 'binding-set'
|
||||
|
||||
module.exports =
|
||||
class Keymap
|
||||
bindingSets: null
|
||||
nextBindingSetIndex: 0
|
||||
bindingSetsByFirstKeystroke: null
|
||||
queuedKeystrokes: null
|
||||
|
||||
@@ -30,29 +32,48 @@ class Keymap
|
||||
$(document).command 'open-dev', => atom.openDev()
|
||||
|
||||
loadBundledKeymaps: ->
|
||||
@loadDirectory(require.resolve('keymaps'))
|
||||
@loadDirectory(fs.resolveOnLoadPath('keymaps'))
|
||||
|
||||
loadUserKeymaps: ->
|
||||
@loadDirectory(fs.join(config.configDirPath, 'keymaps'))
|
||||
|
||||
loadDirectory: (directoryPath) ->
|
||||
@load(filePath) for filePath in fs.list(directoryPath, ['.cson', '.json'])
|
||||
@load(filePath) for filePath in fs.list(directoryPath, ['.cson', '.json']) ? []
|
||||
|
||||
load: (path) ->
|
||||
@add(fs.readObject(path))
|
||||
@add(path, CSON.readObject(path))
|
||||
|
||||
add: (keymap) ->
|
||||
add: (args...) ->
|
||||
name = args.shift() if args.length > 1
|
||||
keymap = args.shift()
|
||||
for selector, bindings of keymap
|
||||
@bindKeys(selector, bindings)
|
||||
@bindKeys(name, selector, bindings)
|
||||
|
||||
bindKeys: (selector, bindings) ->
|
||||
bindingSet = new BindingSet(selector, bindings, @bindingSets.length)
|
||||
remove: (name) ->
|
||||
for bindingSet in @bindingSets.filter((bindingSet) -> bindingSet.name is name)
|
||||
_.remove(@bindingSets, bindingSet)
|
||||
for keystrokes of bindingSet.commandsByKeystrokes
|
||||
keystroke = keystrokes.split(' ')[0]
|
||||
_.remove(@bindingSetsByFirstKeystroke[keystroke], bindingSet)
|
||||
|
||||
bindKeys: (args...) ->
|
||||
name = args.shift() if args.length > 2
|
||||
[selector, bindings] = args
|
||||
bindingSet = new BindingSet(selector, bindings, @nextBindingSetIndex++, name)
|
||||
@bindingSets.unshift(bindingSet)
|
||||
for keystrokes of bindingSet.commandsByKeystrokes
|
||||
keystroke = keystrokes.split(' ')[0] # only index by first keystroke
|
||||
@bindingSetsByFirstKeystroke[keystroke] ?= []
|
||||
@bindingSetsByFirstKeystroke[keystroke].push(bindingSet)
|
||||
|
||||
unbindKeys: (selector, bindings) ->
|
||||
bindingSet = _.detect @bindingSets, (bindingSet) ->
|
||||
bindingSet.selector is selector and bindingSet.bindings is bindings
|
||||
|
||||
if bindingSet
|
||||
console.log "binding set", bindingSet
|
||||
_.remove(@bindingSets, bindingSet)
|
||||
|
||||
bindingsForElement: (element) ->
|
||||
keystrokeMap = {}
|
||||
currentNode = $(element)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
'meta-U': 'editor:lower-case'
|
||||
'alt-meta-w': 'editor:close-other-edit-sessions'
|
||||
'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'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Range = require 'range'
|
||||
_ = require 'underscore'
|
||||
require 'underscore-extensions'
|
||||
OnigRegExp = require 'onig-reg-exp'
|
||||
{OnigRegExp} = require 'oniguruma'
|
||||
|
||||
module.exports =
|
||||
class LanguageMode
|
||||
@@ -17,10 +17,7 @@ class LanguageMode
|
||||
path = @buffer.getPath()
|
||||
pathContents = @buffer.cachedDiskContents
|
||||
previousGrammar = @grammar
|
||||
if @buffer.project?
|
||||
@grammar = @buffer.project.grammarForFilePath(path, pathContents)
|
||||
else
|
||||
@grammar = syntax.grammarForFilePath(path, pathContents)
|
||||
@grammar = syntax.selectGrammar(path, pathContents)
|
||||
throw new Error("No grammar found for path: #{path}") unless @grammar
|
||||
previousGrammar isnt @grammar
|
||||
|
||||
@@ -30,13 +27,13 @@ class LanguageMode
|
||||
|
||||
buffer = @editSession.buffer
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '($1)?')
|
||||
commentStartRegex = OnigRegExp.create("^(\\s*)(#{commentStartRegexString})")
|
||||
commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})")
|
||||
shouldUncomment = commentStartRegex.test(buffer.lineForRow(start))
|
||||
|
||||
if commentEndString = syntax.getProperty(scopes, "editor.commentEnd")
|
||||
if shouldUncomment
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '($1)?')
|
||||
commentEndRegex = OnigRegExp.create("(#{commentEndRegexString})(\\s*)$")
|
||||
commentEndRegex = new OnigRegExp("(#{commentEndRegexString})(\\s*)$")
|
||||
startMatch = commentStartRegex.search(buffer.lineForRow(start))
|
||||
endMatch = commentEndRegex.search(buffer.lineForRow(end))
|
||||
if startMatch and endMatch
|
||||
@@ -152,12 +149,12 @@ class LanguageMode
|
||||
|
||||
increaseIndentRegexForScopes: (scopes) ->
|
||||
if increaseIndentPattern = syntax.getProperty(scopes, 'editor.increaseIndentPattern')
|
||||
OnigRegExp.create(increaseIndentPattern)
|
||||
new OnigRegExp(increaseIndentPattern)
|
||||
|
||||
decreaseIndentRegexForScopes: (scopes) ->
|
||||
if decreaseIndentPattern = syntax.getProperty(scopes, 'editor.decreaseIndentPattern')
|
||||
OnigRegExp.create(decreaseIndentPattern)
|
||||
new OnigRegExp(decreaseIndentPattern)
|
||||
|
||||
foldEndRegexForScopes: (scopes) ->
|
||||
if foldEndPattern = syntax.getProperty(scopes, 'editor.foldEndPattern')
|
||||
OnigRegExp.create(foldEndPattern)
|
||||
new OnigRegExp(foldEndPattern)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
module.exports =
|
||||
loadPackage: (path) ->
|
||||
callTaskMethod('packageLoaded', new TextMatePackage(path).readGrammars())
|
||||
@@ -1,26 +0,0 @@
|
||||
Task = require 'task'
|
||||
|
||||
module.exports =
|
||||
class LoadTextMatePackagesTask extends Task
|
||||
|
||||
constructor: (@packages) ->
|
||||
super('load-text-mate-packages-handler')
|
||||
|
||||
started: ->
|
||||
@loadNextPackage()
|
||||
|
||||
loadNextPackage: ->
|
||||
unless @packages.length
|
||||
@done()
|
||||
syntax.trigger 'grammars-loaded'
|
||||
return
|
||||
|
||||
@package = @packages.shift()
|
||||
@loadPackage(@package.path)
|
||||
|
||||
loadPackage: (path) ->
|
||||
@callWorkerMethod('loadPackage', path)
|
||||
|
||||
packageLoaded: (grammars) ->
|
||||
@package.loadGrammars(grammars)
|
||||
@loadNextPackage()
|
||||
9
src/app/null-grammar.coffee
Normal file
9
src/app/null-grammar.coffee
Normal file
@@ -0,0 +1,9 @@
|
||||
Token = require 'token'
|
||||
|
||||
module.exports =
|
||||
class NullGrammar
|
||||
name: 'Null Grammar'
|
||||
scopeName: 'text.plain.null-grammar'
|
||||
|
||||
tokenizeLine: (line) ->
|
||||
{ tokens: [new Token(value: line, scopes: ['null-grammar.text.plain'])] }
|
||||
@@ -1,4 +1,4 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
|
||||
module.exports =
|
||||
class Package
|
||||
@@ -11,6 +11,11 @@ class Package
|
||||
else
|
||||
new AtomPackage(path)
|
||||
|
||||
@load: (path, options) ->
|
||||
pack = @build(path)
|
||||
pack.load(options)
|
||||
pack
|
||||
|
||||
name: null
|
||||
path: null
|
||||
|
||||
|
||||
@@ -324,5 +324,5 @@ class Pane extends View
|
||||
container.adjustPaneDimensions()
|
||||
container.trigger 'pane:removed', [this]
|
||||
|
||||
afterRemove: ->
|
||||
beforeRemove: ->
|
||||
item.destroy?() for item in @getItems()
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
{hex_md5} = require 'md5'
|
||||
crypto = require 'crypto'
|
||||
|
||||
module.exports =
|
||||
class Pasteboard
|
||||
signatureForMetadata: null
|
||||
|
||||
md5: (text) ->
|
||||
crypto.createHash('md5').update(text, 'utf8').digest('hex')
|
||||
|
||||
write: (text, metadata) ->
|
||||
@signatureForMetadata = hex_md5(text)
|
||||
@signatureForMetadata = @md5(text)
|
||||
@metadata = metadata
|
||||
$native.writeToPasteboard(text)
|
||||
|
||||
read: ->
|
||||
text = $native.readFromPasteboard()
|
||||
value = [text]
|
||||
value.push(@metadata) if @signatureForMetadata == hex_md5(text)
|
||||
value.push(@metadata) if @signatureForMetadata == @md5(text)
|
||||
value
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class Point
|
||||
@fromObject: (object) ->
|
||||
if object instanceof Point
|
||||
object
|
||||
else
|
||||
if object instanceof Array
|
||||
if _.isArray(object)
|
||||
[row, column] = object
|
||||
else
|
||||
{ row, column } = object
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
_ = require 'underscore'
|
||||
$ = require 'jquery'
|
||||
Range = require 'range'
|
||||
Buffer = require 'buffer'
|
||||
Buffer = require 'text-buffer'
|
||||
EditSession = require 'edit-session'
|
||||
EventEmitter = require 'event-emitter'
|
||||
Directory = require 'directory'
|
||||
ChildProcess = require 'child-process'
|
||||
BufferedProcess = require 'buffered-process'
|
||||
|
||||
module.exports =
|
||||
class Project
|
||||
registerDeserializer(this)
|
||||
|
||||
@deserialize: (state) ->
|
||||
new Project(state.path, state.grammarOverridesByPath)
|
||||
new Project(state.path)
|
||||
|
||||
tabLength: 2
|
||||
softTabs: true
|
||||
@@ -21,9 +21,8 @@ class Project
|
||||
rootDirectory: null
|
||||
editSessions: null
|
||||
ignoredPathRegexes: null
|
||||
grammarOverridesByPath: null
|
||||
|
||||
constructor: (path, @grammarOverridesByPath={}) ->
|
||||
constructor: (path) ->
|
||||
@setPath(path)
|
||||
@editSessions = []
|
||||
@buffers = []
|
||||
@@ -31,23 +30,10 @@ class Project
|
||||
serialize: ->
|
||||
deserializer: 'Project'
|
||||
path: @getPath()
|
||||
grammarOverridesByPath: @grammarOverridesByPath
|
||||
|
||||
destroy: ->
|
||||
editSession.destroy() for editSession in @getEditSessions()
|
||||
|
||||
addGrammarOverrideForPath: (path, grammar) ->
|
||||
@grammarOverridesByPath[path] = grammar.scopeName
|
||||
|
||||
removeGrammarOverrideForPath: (path) ->
|
||||
delete @grammarOverridesByPath[path]
|
||||
|
||||
grammarOverrideForPath: (path) ->
|
||||
syntax.grammarForScopeName(@grammarOverridesByPath[path])
|
||||
|
||||
grammarForFilePath: (path, contents) ->
|
||||
@grammarOverrideForPath(path) or syntax.grammarForFilePath(path, contents)
|
||||
|
||||
getPath: ->
|
||||
@rootDirectory?.path
|
||||
|
||||
@@ -67,9 +53,11 @@ class Project
|
||||
|
||||
getFilePaths: ->
|
||||
deferred = $.Deferred()
|
||||
fs.getAllFilePathsAsync @getPath(), (paths) =>
|
||||
paths = paths.filter (path) => not @isPathIgnored(path)
|
||||
deferred.resolve(paths)
|
||||
paths = []
|
||||
onFile = (path) => paths.push(path) unless @isPathIgnored(path)
|
||||
onDirectory = -> true
|
||||
fs.traverseTreeSync(@getPath(), onFile, onDirectory)
|
||||
deferred.resolve(paths)
|
||||
deferred.promise()
|
||||
|
||||
isPathIgnored: (path) ->
|
||||
@@ -160,9 +148,7 @@ class Project
|
||||
_.remove(@buffers, buffer)
|
||||
|
||||
scan: (regex, iterator) ->
|
||||
command = "#{require.resolve('ag')} --ackmate '#{regex.source}' '#{@getPath()}'"
|
||||
bufferedData = ""
|
||||
|
||||
state = 'readingPath'
|
||||
path = null
|
||||
|
||||
@@ -194,11 +180,22 @@ class Project
|
||||
match = lineText.substr(column, length)
|
||||
iterator({path, range, match})
|
||||
|
||||
ChildProcess.exec command , bufferLines: true, stdout: (data) ->
|
||||
deferred = $.Deferred()
|
||||
exit = (code) ->
|
||||
if code is -1
|
||||
deferred.reject({command, code})
|
||||
else
|
||||
deferred.resolve()
|
||||
stdout = (data) ->
|
||||
lines = data.split('\n')
|
||||
lines.pop() # the last segment is a spurious '' because data always ends in \n due to bufferLines: true
|
||||
for line in lines
|
||||
readPath(line) if state is 'readingPath'
|
||||
readLine(line) if state is 'readingLines'
|
||||
|
||||
command = require.resolve('ag')
|
||||
args = ['--ackmate', regex.source, @getPath()]
|
||||
new BufferedProcess({command, args, stdout, exit})
|
||||
deferred
|
||||
|
||||
_.extend Project.prototype, EventEmitter
|
||||
|
||||
@@ -31,7 +31,7 @@ class Range
|
||||
new Range(@start.copy(), @end.copy())
|
||||
|
||||
isEqual: (other) ->
|
||||
if other instanceof Array and other.length == 2
|
||||
if _.isArray(other) and other.length == 2
|
||||
other = new Range(other...)
|
||||
|
||||
other.start.isEqual(@start) and other.end.isEqual(@end)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Git = require 'git'
|
||||
fs = require 'fs'
|
||||
Git = require 'git-utils'
|
||||
fs = require 'fs-utils'
|
||||
|
||||
module.exports =
|
||||
loadStatuses: (path) ->
|
||||
@@ -7,10 +7,10 @@ module.exports =
|
||||
if repo?
|
||||
workingDirectoryPath = repo.getWorkingDirectory()
|
||||
statuses = {}
|
||||
for path, status of repo.getRepo().getStatuses()
|
||||
for path, status of repo.getStatus()
|
||||
statuses[fs.join(workingDirectoryPath, path)] = status
|
||||
upstream = repo.getAheadBehindCounts()
|
||||
repo.destroy()
|
||||
upstream = repo.getAheadBehindCount()
|
||||
repo.release()
|
||||
else
|
||||
upstream = {}
|
||||
statuses = {}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
$ = require 'jquery'
|
||||
{$$} = require 'space-pen'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
_ = require 'underscore'
|
||||
|
||||
{View} = require 'space-pen'
|
||||
Buffer = require 'buffer'
|
||||
Buffer = require 'text-buffer'
|
||||
Editor = require 'editor'
|
||||
Project = require 'project'
|
||||
Pane = require 'pane'
|
||||
@@ -29,8 +29,7 @@ class RootView extends View
|
||||
@div id: 'vertical', outlet: 'vertical', =>
|
||||
@subview 'panes', panes ? new PaneContainer
|
||||
|
||||
@deserialize: ({ panes, packages, projectPath }) ->
|
||||
atom.atomPackageStates = packages ? {}
|
||||
@deserialize: ({ panes }) ->
|
||||
panes = deserialize(panes) if panes?.deserializer is 'PaneContainer'
|
||||
new RootView({panes})
|
||||
|
||||
@@ -73,7 +72,6 @@ class RootView extends View
|
||||
version: RootView.version
|
||||
deserializer: 'RootView'
|
||||
panes: @panes.serialize()
|
||||
packages: atom.serializeAtomPackages()
|
||||
|
||||
confirmClose: ->
|
||||
@panes.confirmClose()
|
||||
@@ -94,10 +92,6 @@ class RootView extends View
|
||||
afterAttach: (onDom) ->
|
||||
@focus() if onDom
|
||||
|
||||
deactivate: ->
|
||||
atom.deactivateAtomPackages()
|
||||
@remove()
|
||||
|
||||
open: (path, options = {}) ->
|
||||
changeFocus = options.changeFocus ? true
|
||||
path = project.resolve(path) if path?
|
||||
|
||||
@@ -20,7 +20,7 @@ class SelectList extends View
|
||||
cancelling: false
|
||||
|
||||
initialize: ->
|
||||
requireStylesheet 'select-list.less'
|
||||
requireStylesheet 'select-list'
|
||||
|
||||
@miniEditor.getBuffer().on 'changed', => @schedulePopulateList()
|
||||
@miniEditor.on 'focusout', => @cancel() unless @cancelling
|
||||
|
||||
@@ -271,7 +271,7 @@ class Selection
|
||||
if @isEmpty()
|
||||
start = @cursor.getScreenRow()
|
||||
range = @editSession.bufferRowsForScreenRows(start, start + 1)
|
||||
if range[1]
|
||||
if range[1] > range[0]
|
||||
@editSession.buffer.deleteRows(range[0], range[1] - 1)
|
||||
else
|
||||
@editSession.buffer.deleteRow(range[0])
|
||||
|
||||
@@ -2,40 +2,72 @@ _ = require 'underscore'
|
||||
jQuery = require 'jquery'
|
||||
Specificity = require 'specificity'
|
||||
{$$} = require 'space-pen'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
EventEmitter = require 'event-emitter'
|
||||
NullGrammar = require 'null-grammar'
|
||||
nodePath = require 'path'
|
||||
pathSplitRegex = new RegExp("[#{nodePath.sep}.]")
|
||||
|
||||
module.exports =
|
||||
class Syntax
|
||||
registerDeserializer(this)
|
||||
|
||||
@deserialize: ({grammarOverridesByPath}) ->
|
||||
syntax = new Syntax()
|
||||
syntax.grammarOverridesByPath = grammarOverridesByPath
|
||||
syntax
|
||||
|
||||
constructor: ->
|
||||
@grammars = []
|
||||
@grammarsByFileType = {}
|
||||
@grammarsByScopeName = {}
|
||||
@globalProperties = {}
|
||||
@grammarOverridesByPath = {}
|
||||
@scopedPropertiesIndex = 0
|
||||
@scopedProperties = []
|
||||
@nullGrammar = new NullGrammar
|
||||
|
||||
serialize: ->
|
||||
{ deserializer: @constructor.name, @grammarOverridesByPath }
|
||||
|
||||
addGrammar: (grammar) ->
|
||||
@grammars.push(grammar)
|
||||
for fileType in grammar.fileTypes
|
||||
@grammarsByFileType[fileType] = grammar
|
||||
@grammarsByScopeName[grammar.scopeName] = grammar
|
||||
@grammarsByFileType[fileType] = grammar for fileType in grammar.fileTypes
|
||||
@grammarsByScopeName[grammar.scopeName] = grammar
|
||||
|
||||
grammarForFilePath: (filePath, fileContents) ->
|
||||
return @grammarsByFileType["txt"] unless filePath
|
||||
removeGrammar: (grammar) ->
|
||||
if _.include(@grammars, grammar)
|
||||
_.remove(@grammars, grammar)
|
||||
delete @grammarsByFileType[fileType] for fileType in grammar.fileTypes
|
||||
delete @grammarsByScopeName[grammar.scopeName]
|
||||
|
||||
extension = fs.extension(filePath)?[1..]
|
||||
if filePath and extension.length == 0
|
||||
extension = fs.base(filePath)
|
||||
setGrammarOverrideForPath: (path, scopeName) ->
|
||||
@grammarOverridesByPath[path] = scopeName
|
||||
|
||||
@grammarByFirstLineRegex(filePath, fileContents) or
|
||||
@grammarsByFileType[extension] or
|
||||
@grammarByFileTypeSuffix(filePath) or
|
||||
@grammarsByFileType["txt"]
|
||||
clearGrammarOverrideForPath: (path) ->
|
||||
delete @grammarOverridesByPath[path]
|
||||
|
||||
grammarByFileTypeSuffix: (filePath) ->
|
||||
clearGrammarOverrides: ->
|
||||
@grammarOverridesByPath = {}
|
||||
|
||||
selectGrammar: (filePath, fileContents) ->
|
||||
|
||||
return @grammarsByFileType["txt"] ? @nullGrammar unless filePath
|
||||
|
||||
@grammarOverrideForPath(filePath) ?
|
||||
@grammarByFirstLineRegex(filePath, fileContents) ?
|
||||
@grammarByPath(filePath) ?
|
||||
@grammarsByFileType["txt"] ?
|
||||
@nullGrammar
|
||||
|
||||
grammarOverrideForPath: (path) ->
|
||||
@grammarsByScopeName[@grammarOverridesByPath[path]]
|
||||
|
||||
grammarByPath: (path) ->
|
||||
pathComponents = path.split(pathSplitRegex)
|
||||
for fileType, grammar of @grammarsByFileType
|
||||
return grammar if _.endsWith(filePath, fileType)
|
||||
fileTypeComponents = fileType.split(pathSplitRegex)
|
||||
pathSuffix = pathComponents[-fileTypeComponents.length..-1]
|
||||
return grammar if _.isEqual(pathSuffix, fileTypeComponents)
|
||||
|
||||
grammarByFirstLineRegex: (filePath, fileContents) ->
|
||||
try
|
||||
@@ -68,18 +100,24 @@ class Syntax
|
||||
@grammarsByScopeName[scopeName]
|
||||
|
||||
addProperties: (args...) ->
|
||||
selector = args.shift() if args.length > 1
|
||||
properties = args.shift()
|
||||
name = args.shift() if args.length > 2
|
||||
[selector, properties] = args
|
||||
|
||||
if selector
|
||||
@scopedProperties.unshift(
|
||||
selector: selector,
|
||||
properties: properties,
|
||||
specificity: Specificity(selector),
|
||||
index: @scopedPropertiesIndex++
|
||||
)
|
||||
else
|
||||
_.extend(@globalProperties, properties)
|
||||
@scopedProperties.unshift(
|
||||
name: name
|
||||
selector: selector,
|
||||
properties: properties,
|
||||
specificity: Specificity(selector),
|
||||
index: @scopedPropertiesIndex++
|
||||
)
|
||||
|
||||
removeProperties: (name) ->
|
||||
for properties in @scopedProperties.filter((properties) -> properties.name is name)
|
||||
_.remove(@scopedProperties, properties)
|
||||
|
||||
clearProperties: ->
|
||||
@scopedProperties = []
|
||||
@scopedPropertiesIndex = 0
|
||||
|
||||
getProperty: (scope, keyPath) ->
|
||||
for object in @propertiesForScope(scope, keyPath)
|
||||
@@ -95,7 +133,7 @@ class Syntax
|
||||
while element
|
||||
matchingProperties.push(@matchingPropertiesForElement(element, candidates)...)
|
||||
element = element.parentNode
|
||||
matchingProperties.concat([@globalProperties])
|
||||
matchingProperties
|
||||
|
||||
matchingPropertiesForElement: (element, candidates) ->
|
||||
matchingScopedProperties = candidates.filter ({selector}) ->
|
||||
@@ -125,4 +163,13 @@ class Syntax
|
||||
else
|
||||
element[0]
|
||||
|
||||
cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
scopeSelector.split(', ').map((commaFragment) ->
|
||||
commaFragment.split(' ').map((spaceFragment) ->
|
||||
spaceFragment.split('.').map((dotFragment) ->
|
||||
'.' + dotFragment.replace(/\+/g, '\\+')
|
||||
).join('')
|
||||
).join(' ')
|
||||
).join(', ')
|
||||
|
||||
_.extend(Syntax.prototype, EventEmitter)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
File = require 'file'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
@@ -1,22 +1,24 @@
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
plist = require 'plist'
|
||||
Token = require 'token'
|
||||
OnigRegExp = require 'onig-reg-exp'
|
||||
OnigScanner = require 'onig-scanner'
|
||||
CSON = require 'cson'
|
||||
{OnigRegExp, OnigScanner} = require 'oniguruma'
|
||||
|
||||
module.exports =
|
||||
class TextMateGrammar
|
||||
@readFromPath: (path) ->
|
||||
grammarContent = null
|
||||
if fs.isObjectPath(path)
|
||||
grammarContent = fs.readObject(path)
|
||||
else
|
||||
plist.parseString fs.read(path), (e, data) ->
|
||||
throw new Error(e) if e
|
||||
grammarContent = data[0]
|
||||
throw new Error("Failed to load grammar at path `#{path}`") unless grammarContent
|
||||
grammarContent
|
||||
fs.readPlist(path)
|
||||
|
||||
@load: (path, done) ->
|
||||
fs.readObjectAsync path, (err, object) ->
|
||||
if err
|
||||
done(err)
|
||||
else
|
||||
done(null, new TextMateGrammar(object))
|
||||
|
||||
@loadSync: (path) ->
|
||||
new TextMateGrammar(fs.readObject(path))
|
||||
|
||||
name: null
|
||||
fileTypes: null
|
||||
@@ -28,7 +30,7 @@ class TextMateGrammar
|
||||
constructor: ({ @name, @fileTypes, @scopeName, patterns, repository, @foldingStopMarker, firstLineMatch}) ->
|
||||
@initialRule = new Rule(this, {@scopeName, patterns})
|
||||
@repository = {}
|
||||
@firstLineRegex = OnigRegExp.create(firstLineMatch) if firstLineMatch
|
||||
@firstLineRegex = new OnigRegExp(firstLineMatch) if firstLineMatch
|
||||
@fileTypes ?= []
|
||||
|
||||
for name, data of repository
|
||||
@@ -39,9 +41,10 @@ class TextMateGrammar
|
||||
ruleStack = new Array(ruleStack...) # clone ruleStack
|
||||
tokens = []
|
||||
position = 0
|
||||
|
||||
loop
|
||||
scopes = scopesFromStack(ruleStack)
|
||||
previousRuleStackLength = ruleStack.length
|
||||
previousPosition = position
|
||||
|
||||
if line.length == 0
|
||||
tokens = [new Token(value: "", scopes: scopes)]
|
||||
@@ -69,6 +72,10 @@ class TextMateGrammar
|
||||
))
|
||||
break
|
||||
|
||||
if position == previousPosition and ruleStack.length == previousRuleStackLength
|
||||
console.error("Popping rule because it loops at column #{position} of line '#{line}'", _.clone(ruleStack))
|
||||
ruleStack.pop()
|
||||
|
||||
ruleStack.forEach (rule) -> rule.clearAnchorPosition()
|
||||
{ tokens, ruleStack }
|
||||
|
||||
@@ -111,7 +118,7 @@ class Rule
|
||||
regex = pattern.regexSource
|
||||
regexes.push regex if regex
|
||||
|
||||
regexScanner = OnigScanner.create(regexes)
|
||||
regexScanner = new OnigScanner(regexes)
|
||||
regexScanner.patterns = patterns
|
||||
@scannersByBaseGrammarName[baseGrammar.name] = regexScanner unless anchored
|
||||
regexScanner
|
||||
@@ -152,10 +159,10 @@ class Pattern
|
||||
backReferences: null
|
||||
anchored: false
|
||||
|
||||
constructor: (@grammar, { name, contentName, @include, match, begin, end, captures, beginCaptures, endCaptures, patterns, @popRule, hasBackReferences}) ->
|
||||
constructor: (@grammar, { name, contentName, @include, match, begin, end, captures, beginCaptures, endCaptures, patterns, @popRule, @hasBackReferences}) ->
|
||||
@scopeName = name ? contentName # TODO: We need special treatment of contentName
|
||||
if match
|
||||
if @hasBackReferences = hasBackReferences ? /\\\d+/.test(match)
|
||||
if (end or @popRule) and @hasBackReferences ?= /\\\d+/.test(match)
|
||||
@match = match
|
||||
else
|
||||
@regexSource = match
|
||||
|
||||
@@ -1,101 +1,89 @@
|
||||
Package = require 'package'
|
||||
fs = require 'fs'
|
||||
fsUtils = require 'fs-utils'
|
||||
plist = require 'plist'
|
||||
_ = require 'underscore'
|
||||
TextMateGrammar = require 'text-mate-grammar'
|
||||
async = require 'async'
|
||||
|
||||
module.exports =
|
||||
class TextMatePackage extends Package
|
||||
@testName: (packageName) ->
|
||||
/(\.|_|-)tmbundle$/.test(packageName)
|
||||
|
||||
@cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
scopeSelector.split(', ').map((commaFragment) ->
|
||||
commaFragment.split(' ').map((spaceFragment) ->
|
||||
spaceFragment.split('.').map((dotFragment) ->
|
||||
'.' + dotFragment.replace(/\+/g, '\\+')
|
||||
).join('')
|
||||
).join(' ')
|
||||
).join(', ')
|
||||
@getLoadQueue: ->
|
||||
return @loadQueue if @loadQueue
|
||||
@loadQueue = async.queue (pack, done) -> pack.loadGrammars(done)
|
||||
@loadQueue.drain = -> syntax.trigger 'grammars-loaded'
|
||||
@loadQueue
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@preferencesPath = fs.join(@path, "Preferences")
|
||||
@syntaxesPath = fs.join(@path, "Syntaxes")
|
||||
@preferencesPath = fsUtils.join(@path, "Preferences")
|
||||
@syntaxesPath = fsUtils.join(@path, "Syntaxes")
|
||||
@grammars = []
|
||||
|
||||
load: ->
|
||||
try
|
||||
@loadGrammars()
|
||||
catch e
|
||||
console.warn "Failed to load package at '#{@path}'", e.stack
|
||||
this
|
||||
load: ({sync}={}) ->
|
||||
if sync
|
||||
@loadGrammarsSync()
|
||||
else
|
||||
TextMatePackage.getLoadQueue().push(this)
|
||||
@loadScopedProperties()
|
||||
|
||||
activate: -> # no-op
|
||||
activate: ->
|
||||
syntax.addGrammar(grammar) for grammar in @grammars
|
||||
for { selector, properties } in @scopedProperties
|
||||
syntax.addProperties(@path, selector, properties)
|
||||
|
||||
deactivate: ->
|
||||
syntax.removeGrammar(grammar) for grammar in @grammars
|
||||
syntax.removeProperties(@path)
|
||||
|
||||
legalGrammarExtensions: ['plist', 'tmLanguage', 'tmlanguage']
|
||||
|
||||
loadGrammars: (done) ->
|
||||
fsUtils.isDirectoryAsync @syntaxesPath, (isDirectory) =>
|
||||
if isDirectory
|
||||
fsUtils.listAsync @syntaxesPath, @legalGrammarExtensions, (err, paths) =>
|
||||
return console.log("Error loading grammars of TextMate package '#{@path}':", err.stack, err) if err
|
||||
async.eachSeries paths, @loadGrammarAtPath, done
|
||||
|
||||
loadGrammarAtPath: (path, done) =>
|
||||
TextMateGrammar.load path, (err, grammar) =>
|
||||
return console.log("Error loading grammar at path '#{path}':", err.stack ? err) if err
|
||||
@addGrammar(grammar)
|
||||
done()
|
||||
|
||||
loadGrammarsSync: ->
|
||||
for path in fsUtils.list(@syntaxesPath, @legalGrammarExtensions) ? []
|
||||
@addGrammar(TextMateGrammar.loadSync(path))
|
||||
|
||||
addGrammar: (grammar) ->
|
||||
@grammars.push(grammar)
|
||||
syntax.addGrammar(grammar) if atom.isPackageActive(@path)
|
||||
|
||||
getGrammars: -> @grammars
|
||||
|
||||
readGrammars: ->
|
||||
grammars = []
|
||||
for grammarPath in fs.list(@syntaxesPath)
|
||||
try
|
||||
grammars.push(TextMateGrammar.readFromPath(grammarPath))
|
||||
catch e
|
||||
console.warn "Failed to load grammar at path '#{grammarPath}'", e.stack
|
||||
grammars
|
||||
|
||||
addGrammar: (rawGrammar) ->
|
||||
grammar = new TextMateGrammar(rawGrammar)
|
||||
@grammars.push(grammar)
|
||||
syntax.addGrammar(grammar)
|
||||
|
||||
loadGrammars: (rawGrammars) ->
|
||||
rawGrammars = @readGrammars() unless rawGrammars?
|
||||
|
||||
@grammars = []
|
||||
@addGrammar(rawGrammar) for rawGrammar in rawGrammars
|
||||
@loadScopedProperties()
|
||||
|
||||
loadScopedProperties: ->
|
||||
for { selector, properties } in @getScopedProperties()
|
||||
syntax.addProperties(selector, properties)
|
||||
|
||||
getScopedProperties: ->
|
||||
scopedProperties = []
|
||||
@scopedProperties = []
|
||||
|
||||
for grammar in @getGrammars()
|
||||
if properties = @propertiesFromTextMateSettings(grammar)
|
||||
selector = @cssSelectorFromScopeSelector(grammar.scopeName)
|
||||
scopedProperties.push({selector, properties})
|
||||
selector = syntax.cssSelectorFromScopeSelector(grammar.scopeName)
|
||||
@scopedProperties.push({selector, properties})
|
||||
|
||||
for {scope, settings} in @getTextMatePreferenceObjects()
|
||||
if properties = @propertiesFromTextMateSettings(settings)
|
||||
selector = @cssSelectorFromScopeSelector(scope) if scope?
|
||||
scopedProperties.push({selector, properties})
|
||||
|
||||
scopedProperties
|
||||
|
||||
readObjectFromPath: (path, callback) ->
|
||||
object = null
|
||||
error = null
|
||||
if fs.isObjectPath(path)
|
||||
object = fs.readObject(path)
|
||||
else
|
||||
plist.parseString fs.read(path), (e, data) ->
|
||||
error = e
|
||||
object = data[0]
|
||||
error = throw new Error("Failed to load object at path `#{path}`") unless object
|
||||
callback(error, object)
|
||||
selector = syntax.cssSelectorFromScopeSelector(scope) if scope?
|
||||
@scopedProperties.push({selector, properties})
|
||||
|
||||
getTextMatePreferenceObjects: ->
|
||||
preferenceObjects = []
|
||||
if fs.exists(@preferencesPath)
|
||||
for preferencePath in fs.list(@preferencesPath)
|
||||
@readObjectFromPath preferencePath, (e, object) =>
|
||||
if e
|
||||
console.warn "Failed to parse preference at path '#{preferencePath}'", e.stack
|
||||
else
|
||||
preferenceObjects.push(object)
|
||||
if fsUtils.exists(@preferencesPath)
|
||||
for preferencePath in fsUtils.list(@preferencesPath)
|
||||
try
|
||||
preferenceObjects.push(fsUtils.readObject(preferencePath))
|
||||
catch e
|
||||
console.warn "Failed to parse preference at path '#{preferencePath}'", e.stack
|
||||
preferenceObjects
|
||||
|
||||
propertiesFromTextMateSettings: (textMateSettings) ->
|
||||
@@ -113,6 +101,3 @@ class TextMatePackage extends Package
|
||||
foldEndPattern: textMateSettings.foldingStopMarker
|
||||
)
|
||||
{ editor: editorProperties } if _.size(editorProperties) > 0
|
||||
|
||||
cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
@constructor.cssSelectorFromScopeSelector(scopeSelector)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
plist = require 'plist'
|
||||
Theme = require 'theme'
|
||||
|
||||
@@ -18,10 +18,9 @@ class TextMateTheme extends Theme
|
||||
super
|
||||
|
||||
buildRulesets: ->
|
||||
plist.parseString fs.read(@path), (error, [{settings}]) =>
|
||||
throw new Error("Error loading theme at '#{@path}': #{error}") if error
|
||||
@buildGlobalSettingsRulesets(settings[0])
|
||||
@buildScopeSelectorRulesets(settings[1..])
|
||||
{settings} = plist.parseFileSync(@path)
|
||||
@buildGlobalSettingsRulesets(settings[0])
|
||||
@buildScopeSelectorRulesets(settings[1..])
|
||||
|
||||
getStylesheet: ->
|
||||
lines = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
|
||||
module.exports =
|
||||
class Theme
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-utils'
|
||||
$ = require 'jquery'
|
||||
ChildProcess = require 'child-process'
|
||||
{less} = require 'less'
|
||||
{spawn} = require 'child_process'
|
||||
require 'jquery-extensions'
|
||||
require 'underscore-extensions'
|
||||
require 'space-pen-extensions'
|
||||
@@ -17,27 +17,21 @@ window.setUpEnvironment = ->
|
||||
Keymap = require 'keymap'
|
||||
|
||||
window.rootViewParentSelector = 'body'
|
||||
window.platform = $native.getPlatform()
|
||||
window.config = new Config
|
||||
window.syntax = new Syntax
|
||||
window.syntax = deserialize(atom.getWindowState('syntax')) ? new Syntax
|
||||
window.pasteboard = new Pasteboard
|
||||
window.keymap = new Keymap()
|
||||
$(document).on 'keydown', keymap.handleKeyEvent
|
||||
keymap.bindDefaultKeys()
|
||||
|
||||
requireStylesheet 'reset.less'
|
||||
requireStylesheet 'atom.less'
|
||||
requireStylesheet 'tabs.less'
|
||||
requireStylesheet 'tree-view.less'
|
||||
requireStylesheet 'status-bar.less'
|
||||
requireStylesheet 'command-panel.less'
|
||||
requireStylesheet 'fuzzy-finder.less'
|
||||
requireStylesheet 'overlay.less'
|
||||
requireStylesheet 'popover-list.less'
|
||||
requireStylesheet 'notification.less'
|
||||
requireStylesheet 'markdown.less'
|
||||
requireStylesheet 'reset'
|
||||
requireStylesheet 'atom'
|
||||
requireStylesheet 'overlay'
|
||||
requireStylesheet 'popover-list'
|
||||
requireStylesheet 'notification'
|
||||
requireStylesheet 'markdown'
|
||||
|
||||
if nativeStylesheetPath = require.resolve("#{platform}.css")
|
||||
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
|
||||
requireStylesheet(nativeStylesheetPath)
|
||||
|
||||
# This method is only called when opening a real application window
|
||||
@@ -53,11 +47,10 @@ window.startup = ->
|
||||
|
||||
handleWindowEvents()
|
||||
config.load()
|
||||
atom.loadTextPackage()
|
||||
keymap.loadBundledKeymaps()
|
||||
atom.loadThemes()
|
||||
atom.loadPackages()
|
||||
buildProjectAndRootView()
|
||||
deserializeWindowState()
|
||||
atom.activatePackages()
|
||||
keymap.loadUserKeymaps()
|
||||
atom.requireUserInitScript()
|
||||
@@ -67,10 +60,13 @@ window.startup = ->
|
||||
window.shutdown = ->
|
||||
return if not project and not rootView
|
||||
atom.setWindowState('pathToOpen', project.getPath())
|
||||
atom.setRootViewStateForPath project.getPath(),
|
||||
project: project.serialize()
|
||||
rootView: rootView.serialize()
|
||||
rootView.deactivate()
|
||||
atom.setWindowState('project', project.serialize())
|
||||
atom.setWindowState('syntax', syntax.serialize())
|
||||
atom.setWindowState('rootView', rootView.serialize())
|
||||
atom.deactivatePackages()
|
||||
atom.setWindowState('packageStates', atom.packageStates)
|
||||
rootView.remove()
|
||||
atom.saveWindowState()
|
||||
project.destroy()
|
||||
git?.destroy()
|
||||
$(window).off('focus blur before')
|
||||
@@ -84,7 +80,7 @@ window.installAtomCommand = (commandPath) ->
|
||||
bundledCommandPath = fs.resolve(window.resourcePath, 'atom.sh')
|
||||
if bundledCommandPath?
|
||||
fs.write(commandPath, fs.read(bundledCommandPath))
|
||||
ChildProcess.exec("chmod u+x '#{commandPath}'")
|
||||
spawn('chmod', ['u+x', commandPath])
|
||||
|
||||
window.handleWindowEvents = ->
|
||||
$(window).command 'window:toggle-full-screen', => atom.toggleFullScreen()
|
||||
@@ -92,13 +88,16 @@ window.handleWindowEvents = ->
|
||||
$(window).on 'blur', -> $("body").addClass('is-blurred')
|
||||
$(window).command 'window:close', => confirmClose()
|
||||
|
||||
window.buildProjectAndRootView = ->
|
||||
window.deserializeWindowState = ->
|
||||
RootView = require 'root-view'
|
||||
Project = require 'project'
|
||||
Git = require 'git'
|
||||
|
||||
pathToOpen = atom.getPathToOpen()
|
||||
windowState = atom.getRootViewStateForPath(pathToOpen) ? {}
|
||||
|
||||
windowState = atom.getWindowState()
|
||||
|
||||
atom.packageStates = windowState.packageStates ? {}
|
||||
window.project = deserialize(windowState.project) ? new Project(pathToOpen)
|
||||
window.rootView = deserialize(windowState.rootView) ? new RootView
|
||||
|
||||
@@ -115,25 +114,30 @@ window.buildProjectAndRootView = ->
|
||||
window.stylesheetElementForId = (id) ->
|
||||
$("head style[id='#{id}']")
|
||||
|
||||
window.resolveStylesheet = (path) ->
|
||||
if fs.extension(path).length > 0
|
||||
fs.resolveOnLoadPath(path)
|
||||
else
|
||||
fs.resolveOnLoadPath(path, ['css', 'less'])
|
||||
|
||||
window.requireStylesheet = (path) ->
|
||||
if fullPath = require.resolve(path)
|
||||
if fullPath = window.resolveStylesheet(path)
|
||||
content = window.loadStylesheet(fullPath)
|
||||
window.applyStylesheet(fullPath, content)
|
||||
else
|
||||
console.log "bad", path
|
||||
throw new Error("Could not find a file at path '#{path}'")
|
||||
|
||||
window.loadStylesheet = (path) ->
|
||||
content = fs.read(path)
|
||||
if fs.extension(path) == '.less'
|
||||
(new less.Parser).parse content, (e, tree) ->
|
||||
throw new Error(e.message, file, e.line) if e
|
||||
throw new Error(e.message, path, e.line) if e
|
||||
content = tree.toCSS()
|
||||
|
||||
content
|
||||
|
||||
window.removeStylesheet = (path) ->
|
||||
unless fullPath = require.resolve(path)
|
||||
unless fullPath = window.resolveStylesheet(path)
|
||||
throw new Error("Could not find a file at path '#{path}'")
|
||||
window.stylesheetElementForId(fullPath).remove()
|
||||
|
||||
@@ -189,6 +193,12 @@ window.measure = (description, fn) ->
|
||||
console.log description, result
|
||||
value
|
||||
|
||||
window.profile = (description, fn) ->
|
||||
measure description, ->
|
||||
console.profile(description)
|
||||
value = fn()
|
||||
console.profileEnd(description)
|
||||
value
|
||||
|
||||
confirmClose = ->
|
||||
rootView.confirmClose().done -> window.close()
|
||||
rootView.confirmClose().done -> window.close()
|
||||
|
||||
Reference in New Issue
Block a user