mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
Merge branch 'master' into as-cjk-soft-wrap
# Conflicts: # spec/display-buffer-spec.coffee
This commit is contained in:
165
src/application-delegate.coffee
Normal file
165
src/application-delegate.coffee
Normal file
@@ -0,0 +1,165 @@
|
||||
_ = require 'underscore-plus'
|
||||
ipc = require 'ipc'
|
||||
remote = require 'remote'
|
||||
shell = require 'shell'
|
||||
{Disposable} = require 'event-kit'
|
||||
{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers'
|
||||
|
||||
module.exports =
|
||||
class ApplicationDelegate
|
||||
open: (params) ->
|
||||
ipc.send('open', params)
|
||||
|
||||
pickFolder: (callback) ->
|
||||
responseChannel = "atom-pick-folder-response"
|
||||
ipc.on responseChannel, (path) ->
|
||||
ipc.removeAllListeners(responseChannel)
|
||||
callback(path)
|
||||
ipc.send("pick-folder", responseChannel)
|
||||
|
||||
getCurrentWindow: ->
|
||||
remote.getCurrentWindow()
|
||||
|
||||
closeWindow: ->
|
||||
ipc.send("call-window-method", "close")
|
||||
|
||||
getWindowSize: ->
|
||||
[width, height] = remote.getCurrentWindow().getSize()
|
||||
{width, height}
|
||||
|
||||
setWindowSize: (width, height) ->
|
||||
remote.getCurrentWindow().setSize(width, height)
|
||||
|
||||
getWindowPosition: ->
|
||||
[x, y] = remote.getCurrentWindow().getPosition()
|
||||
{x, y}
|
||||
|
||||
setWindowPosition: (x, y) ->
|
||||
ipc.send("call-window-method", "setPosition", x, y)
|
||||
|
||||
centerWindow: ->
|
||||
ipc.send("call-window-method", "center")
|
||||
|
||||
focusWindow: ->
|
||||
ipc.send("call-window-method", "focus")
|
||||
|
||||
showWindow: ->
|
||||
ipc.send("call-window-method", "show")
|
||||
|
||||
hideWindow: ->
|
||||
ipc.send("call-window-method", "hide")
|
||||
|
||||
restartWindow: ->
|
||||
ipc.send("call-window-method", "restart")
|
||||
|
||||
isWindowMaximized: ->
|
||||
remote.getCurrentWindow().isMaximized()
|
||||
|
||||
maximizeWindow: ->
|
||||
ipc.send("call-window-method", "maximize")
|
||||
|
||||
isWindowFullScreen: ->
|
||||
remote.getCurrentWindow().isFullScreen()
|
||||
|
||||
setWindowFullScreen: (fullScreen=false) ->
|
||||
ipc.send("call-window-method", "setFullScreen", fullScreen)
|
||||
|
||||
openWindowDevTools: ->
|
||||
remote.getCurrentWindow().openDevTools()
|
||||
|
||||
toggleWindowDevTools: ->
|
||||
remote.getCurrentWindow().toggleDevTools()
|
||||
|
||||
executeJavaScriptInWindowDevTools: (code) ->
|
||||
remote.getCurrentWindow().executeJavaScriptInDevTools(code)
|
||||
|
||||
setWindowDocumentEdited: (edited) ->
|
||||
ipc.send("call-window-method", "setDocumentEdited", edited)
|
||||
|
||||
setRepresentedFilename: (filename) ->
|
||||
ipc.send("call-window-method", "setRepresentedFilename", filename)
|
||||
|
||||
setRepresentedDirectoryPaths: (paths) ->
|
||||
loadSettings = getWindowLoadSettings()
|
||||
loadSettings['initialPaths'] = paths
|
||||
setWindowLoadSettings(loadSettings)
|
||||
|
||||
setAutoHideWindowMenuBar: (autoHide) ->
|
||||
ipc.send("call-window-method", "setAutoHideMenuBar", autoHide)
|
||||
|
||||
setWindowMenuBarVisibility: (visible) ->
|
||||
remote.getCurrentWindow().setMenuBarVisibility(visible)
|
||||
|
||||
getPrimaryDisplayWorkAreaSize: ->
|
||||
screen = remote.require 'screen'
|
||||
screen.getPrimaryDisplay().workAreaSize
|
||||
|
||||
confirm: ({message, detailedMessage, buttons}) ->
|
||||
buttons ?= {}
|
||||
if _.isArray(buttons)
|
||||
buttonLabels = buttons
|
||||
else
|
||||
buttonLabels = Object.keys(buttons)
|
||||
|
||||
dialog = remote.require('dialog')
|
||||
chosen = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info'
|
||||
message: message
|
||||
detail: detailedMessage
|
||||
buttons: buttonLabels
|
||||
})
|
||||
|
||||
if _.isArray(buttons)
|
||||
chosen
|
||||
else
|
||||
callback = buttons[buttonLabels[chosen]]
|
||||
callback?()
|
||||
|
||||
showMessageDialog: (params) ->
|
||||
|
||||
showSaveDialog: (params) ->
|
||||
if _.isString(params)
|
||||
params = defaultPath: params
|
||||
else
|
||||
params = _.clone(params)
|
||||
params.title ?= 'Save File'
|
||||
params.defaultPath ?= getWindowLoadSettings().initialPaths[0]
|
||||
dialog = remote.require('dialog')
|
||||
dialog.showSaveDialog remote.getCurrentWindow(), params
|
||||
|
||||
playBeepSound: ->
|
||||
shell.beep()
|
||||
|
||||
onDidOpenLocations: (callback) ->
|
||||
outerCallback = (message, detail) ->
|
||||
if message is 'open-locations'
|
||||
callback(detail)
|
||||
|
||||
ipc.on('message', outerCallback)
|
||||
new Disposable ->
|
||||
ipc.removeEventListener('message', outerCallback)
|
||||
|
||||
onUpdateAvailable: (callback) ->
|
||||
outerCallback = (message, detail) ->
|
||||
if message is 'update-available'
|
||||
callback(detail)
|
||||
|
||||
ipc.on('message', outerCallback)
|
||||
new Disposable ->
|
||||
ipc.removeEventListener('message', outerCallback)
|
||||
|
||||
onApplicationMenuCommand: (callback) ->
|
||||
ipc.on('command', callback)
|
||||
new Disposable ->
|
||||
ipc.removeEventListener('command', callback)
|
||||
|
||||
onContextMenuCommand: (callback) ->
|
||||
ipc.on('context-command', callback)
|
||||
new Disposable ->
|
||||
ipc.removeEventListener('context-command', callback)
|
||||
|
||||
didCancelWindowUnload: ->
|
||||
ipc.send('did-cancel-window-unload')
|
||||
|
||||
openExternal: (url) ->
|
||||
shell.openExternal(url)
|
||||
@@ -1,9 +1,5 @@
|
||||
crypto = require 'crypto'
|
||||
ipc = require 'ipc'
|
||||
os = require 'os'
|
||||
path = require 'path'
|
||||
remote = require 'remote'
|
||||
shell = require 'shell'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{deprecate} = require 'grim'
|
||||
@@ -14,83 +10,52 @@ Model = require './model'
|
||||
WindowEventHandler = require './window-event-handler'
|
||||
StylesElement = require './styles-element'
|
||||
StorageFolder = require './storage-folder'
|
||||
{getWindowLoadSettings} = require './window-load-settings-helpers'
|
||||
registerDefaultCommands = require './register-default-commands'
|
||||
|
||||
DeserializerManager = require './deserializer-manager'
|
||||
ViewRegistry = require './view-registry'
|
||||
NotificationManager = require './notification-manager'
|
||||
Config = require './config'
|
||||
KeymapManager = require './keymap-extensions'
|
||||
TooltipManager = require './tooltip-manager'
|
||||
CommandRegistry = require './command-registry'
|
||||
GrammarRegistry = require './grammar-registry'
|
||||
StyleManager = require './style-manager'
|
||||
PackageManager = require './package-manager'
|
||||
ThemeManager = require './theme-manager'
|
||||
MenuManager = require './menu-manager'
|
||||
ContextMenuManager = require './context-menu-manager'
|
||||
CommandInstaller = require './command-installer'
|
||||
Clipboard = require './clipboard'
|
||||
Project = require './project'
|
||||
Workspace = require './workspace'
|
||||
PanelContainer = require './panel-container'
|
||||
Panel = require './panel'
|
||||
PaneContainer = require './pane-container'
|
||||
PaneAxis = require './pane-axis'
|
||||
Pane = require './pane'
|
||||
Project = require './project'
|
||||
TextEditor = require './text-editor'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Gutter = require './gutter'
|
||||
|
||||
WorkspaceElement = require './workspace-element'
|
||||
PanelContainerElement = require './panel-container-element'
|
||||
PanelElement = require './panel-element'
|
||||
PaneContainerElement = require './pane-container-element'
|
||||
PaneAxisElement = require './pane-axis-element'
|
||||
PaneElement = require './pane-element'
|
||||
TextEditorElement = require './text-editor-element'
|
||||
{createGutterView} = require './gutter-component-helpers'
|
||||
|
||||
# Essential: Atom global for dealing with packages, themes, menus, and the window.
|
||||
#
|
||||
# An instance of this class is always available as the `atom` global.
|
||||
module.exports =
|
||||
class Atom extends Model
|
||||
class AtomEnvironment extends Model
|
||||
@version: 1 # Increment this when the serialization format changes
|
||||
|
||||
# Load or create the Atom environment in the given mode.
|
||||
#
|
||||
# * `mode` A {String} mode that is either 'editor' or 'spec' depending on the
|
||||
# kind of environment you want to build.
|
||||
#
|
||||
# Returns an Atom instance, fully initialized
|
||||
@loadOrCreate: (mode) ->
|
||||
startTime = Date.now()
|
||||
atom = @deserialize(@loadState(mode)) ? new this({mode, @version})
|
||||
atom.deserializeTimings.atom = Date.now() - startTime
|
||||
atom
|
||||
|
||||
# Deserializes the Atom environment from a state object
|
||||
@deserialize: (state) ->
|
||||
new this(state) if state?.version is @version
|
||||
|
||||
# Loads and returns the serialized state corresponding to this window
|
||||
# if it exists; otherwise returns undefined.
|
||||
@loadState: (mode) ->
|
||||
if stateKey = @getStateKey(@getLoadSettings().initialPaths, mode)
|
||||
if state = @getStorageFolder().load(stateKey)
|
||||
return state
|
||||
|
||||
if windowState = @getLoadSettings().windowState
|
||||
try
|
||||
JSON.parse(@getLoadSettings().windowState)
|
||||
catch error
|
||||
console.warn "Error parsing window state: #{statePath} #{error.stack}", error
|
||||
|
||||
# Returns the path where the state for the current window will be
|
||||
# located if it exists.
|
||||
@getStateKey: (paths, mode) ->
|
||||
if mode is 'spec'
|
||||
'spec'
|
||||
else if mode is 'editor' and paths?.length > 0
|
||||
sha1 = crypto.createHash('sha1').update(paths.slice().sort().join("\n")).digest('hex')
|
||||
"editor-#{sha1}"
|
||||
else
|
||||
null
|
||||
|
||||
# Get the directory path to Atom's configuration area.
|
||||
#
|
||||
# Returns the absolute path to ~/.atom
|
||||
@getConfigDirPath: ->
|
||||
@configDirPath ?= process.env.ATOM_HOME
|
||||
|
||||
@getStorageFolder: ->
|
||||
@storageFolder ?= new StorageFolder(@getConfigDirPath())
|
||||
|
||||
# Returns the load settings hash associated with the current window.
|
||||
@getLoadSettings: ->
|
||||
@loadSettings ?= JSON.parse(decodeURIComponent(location.hash.substr(1)))
|
||||
cloned = _.deepClone(@loadSettings)
|
||||
# The loadSettings.windowState could be large, request it only when needed.
|
||||
cloned.__defineGetter__ 'windowState', =>
|
||||
@getCurrentWindow().loadSettings.windowState
|
||||
cloned.__defineSetter__ 'windowState', (value) =>
|
||||
@getCurrentWindow().loadSettings.windowState = value
|
||||
cloned
|
||||
|
||||
@updateLoadSetting: (key, value) ->
|
||||
@getLoadSettings()
|
||||
@loadSettings[key] = value
|
||||
location.hash = encodeURIComponent(JSON.stringify(@loadSettings))
|
||||
|
||||
@getCurrentWindow: ->
|
||||
remote.getCurrentWindow()
|
||||
|
||||
workspaceParentSelectorctor: 'body'
|
||||
lastUncaughtError: null
|
||||
|
||||
###
|
||||
@@ -150,122 +115,197 @@ class Atom extends Model
|
||||
###
|
||||
|
||||
# Call .loadOrCreate instead
|
||||
constructor: (@state) ->
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
{@mode} = @state
|
||||
DeserializerManager = require './deserializer-manager'
|
||||
@deserializers = new DeserializerManager()
|
||||
@deserializeTimings = {}
|
||||
constructor: (params={}) ->
|
||||
{@applicationDelegate, @window, @document, configDirPath, @enablePersistence} = params
|
||||
|
||||
# Sets up the basic services that should be available in all modes
|
||||
# (both spec and application).
|
||||
#
|
||||
# Call after this instance has been assigned to the `atom` global.
|
||||
initialize: ->
|
||||
window.onerror = =>
|
||||
@lastUncaughtError = Array::slice.call(arguments)
|
||||
[message, url, line, column, originalError] = @lastUncaughtError
|
||||
|
||||
{line, column} = mapSourcePosition({source: url, line, column})
|
||||
|
||||
eventObject = {message, url, line, column, originalError}
|
||||
|
||||
openDevTools = true
|
||||
eventObject.preventDefault = -> openDevTools = false
|
||||
|
||||
@emitter.emit 'will-throw-error', eventObject
|
||||
|
||||
if openDevTools
|
||||
@openDevTools()
|
||||
@executeJavaScriptInDevTools('DevToolsAPI.showConsole()')
|
||||
|
||||
@emitter.emit 'did-throw-error', {message, url, line, column, originalError}
|
||||
|
||||
@disposables?.dispose()
|
||||
@disposables = new CompositeDisposable
|
||||
|
||||
@displayWindow() unless @inSpecMode()
|
||||
|
||||
@setBodyPlatformClass()
|
||||
@state = {version: @constructor.version}
|
||||
|
||||
@loadTime = null
|
||||
|
||||
Config = require './config'
|
||||
KeymapManager = require './keymap-extensions'
|
||||
ViewRegistry = require './view-registry'
|
||||
CommandRegistry = require './command-registry'
|
||||
TooltipManager = require './tooltip-manager'
|
||||
NotificationManager = require './notification-manager'
|
||||
PackageManager = require './package-manager'
|
||||
Clipboard = require './clipboard'
|
||||
GrammarRegistry = require './grammar-registry'
|
||||
ThemeManager = require './theme-manager'
|
||||
StyleManager = require './style-manager'
|
||||
ContextMenuManager = require './context-menu-manager'
|
||||
MenuManager = require './menu-manager'
|
||||
{devMode, safeMode, resourcePath} = @getLoadSettings()
|
||||
configDirPath = @getConfigDirPath()
|
||||
|
||||
# Add 'exports' to module search path.
|
||||
exportsPath = path.join(resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
|
||||
# Make react.js faster
|
||||
process.env.NODE_ENV ?= 'production' unless devMode
|
||||
@deserializers = new DeserializerManager(this)
|
||||
@deserializeTimings = {}
|
||||
|
||||
@views = new ViewRegistry(this)
|
||||
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@keymaps.subscribeToFileReadFailure()
|
||||
@tooltips = new TooltipManager
|
||||
@notifications = new NotificationManager
|
||||
|
||||
@config = new Config({configDirPath, resourcePath, notificationManager: @notifications, @enablePersistence})
|
||||
@setConfigSchema()
|
||||
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath, notificationManager: @notifications})
|
||||
|
||||
@tooltips = new TooltipManager(keymapManager: @keymaps)
|
||||
|
||||
@commands = new CommandRegistry
|
||||
@views = new ViewRegistry
|
||||
@registerViewProviders()
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
|
||||
@styles = new StyleManager
|
||||
document.head.appendChild(new StylesElement)
|
||||
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath, safeMode})
|
||||
@contextMenu = new ContextMenuManager({resourcePath, devMode})
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@commands.attach(@window)
|
||||
|
||||
@grammars = new GrammarRegistry({@config})
|
||||
|
||||
@styles = new StyleManager({configDirPath})
|
||||
|
||||
@packages = new PackageManager({
|
||||
devMode, configDirPath, resourcePath, safeMode, @config, styleManager: @styles,
|
||||
commandRegistry: @commands, keymapManager: @keymaps, notificationManager: @notifications,
|
||||
grammarRegistry: @grammars
|
||||
})
|
||||
|
||||
@themes = new ThemeManager({
|
||||
packageManager: @packages, configDirPath, resourcePath, safeMode, @config,
|
||||
styleManager: @styles, notificationManager: @notifications, viewRegistry: @views
|
||||
})
|
||||
|
||||
@menu = new MenuManager({resourcePath, keymapManager: @keymaps, packageManager: @packages})
|
||||
|
||||
@contextMenu = new ContextMenuManager({resourcePath, devMode, keymapManager: @keymaps})
|
||||
|
||||
@packages.setMenuManager(@menu)
|
||||
@packages.setContextMenuManager(@contextMenu)
|
||||
@packages.setThemeManager(@themes)
|
||||
|
||||
@clipboard = new Clipboard()
|
||||
@grammars = @deserializers.deserialize(@state.grammars ? @state.syntax) ? new GrammarRegistry()
|
||||
@disposables.add @packages.onDidActivateInitialPackages => @watchThemes()
|
||||
|
||||
Project = require './project'
|
||||
TextBuffer = require 'text-buffer'
|
||||
@project = new Project({notificationManager: @notifications, packageManager: @packages, @config})
|
||||
|
||||
@commandInstaller = new CommandInstaller(@getVersion(), @applicationDelegate)
|
||||
|
||||
@workspace = new Workspace({
|
||||
@config, @project, packageManager: @packages, grammarRegistry: @grammars, deserializerManager: @deserializers,
|
||||
notificationManager: @notifications, @applicationDelegate, @clipboard, viewRegistry: @views, assert: @assert.bind(this)
|
||||
})
|
||||
@themes.workspace = @workspace
|
||||
|
||||
@config.load()
|
||||
|
||||
@themes.loadBaseStylesheets()
|
||||
@initialStyleElements = @styles.getSnapshot()
|
||||
@themes.initialLoadComplete = true
|
||||
@setBodyPlatformClass()
|
||||
|
||||
@stylesElement = @styles.buildStylesElement()
|
||||
@document.head.appendChild(@stylesElement)
|
||||
|
||||
@keymaps.subscribeToFileReadFailure()
|
||||
@keymaps.loadBundledKeymaps()
|
||||
|
||||
@registerDefaultCommands()
|
||||
@registerDefaultOpeners()
|
||||
@registerDefaultDeserializers()
|
||||
@registerDefaultViewProviders()
|
||||
|
||||
@installUncaughtErrorHandler()
|
||||
@installWindowEventHandler()
|
||||
|
||||
@observeAutoHideMenuBar()
|
||||
|
||||
setConfigSchema: ->
|
||||
@config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))}
|
||||
|
||||
registerDefaultDeserializers: ->
|
||||
@deserializers.add(Workspace)
|
||||
@deserializers.add(PaneContainer)
|
||||
@deserializers.add(PaneAxis)
|
||||
@deserializers.add(Pane)
|
||||
@deserializers.add(Project)
|
||||
@deserializers.add(TextEditor)
|
||||
@deserializers.add(TextBuffer)
|
||||
TokenizedBuffer = require './tokenized-buffer'
|
||||
DisplayBuffer = require './display-buffer'
|
||||
TextEditor = require './text-editor'
|
||||
|
||||
@windowEventHandler = new WindowEventHandler
|
||||
registerDefaultCommands: ->
|
||||
registerDefaultCommands({commandRegistry: @commands, @config, @commandInstaller})
|
||||
|
||||
# Register the core views as early as possible in case they are needed for
|
||||
# package deserialization.
|
||||
registerViewProviders: ->
|
||||
Gutter = require './gutter'
|
||||
Pane = require './pane'
|
||||
PaneElement = require './pane-element'
|
||||
PaneContainer = require './pane-container'
|
||||
PaneContainerElement = require './pane-container-element'
|
||||
PaneAxis = require './pane-axis'
|
||||
PaneAxisElement = require './pane-axis-element'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorElement = require './text-editor-element'
|
||||
{createGutterView} = require './gutter-component-helpers'
|
||||
registerDefaultViewProviders: ->
|
||||
@views.addViewProvider Workspace, (model, env) ->
|
||||
new WorkspaceElement().initialize(model, env)
|
||||
@views.addViewProvider PanelContainer, (model, env) ->
|
||||
new PanelContainerElement().initialize(model, env)
|
||||
@views.addViewProvider Panel, (model, env) ->
|
||||
new PanelElement().initialize(model, env)
|
||||
@views.addViewProvider PaneContainer, (model, env) ->
|
||||
new PaneContainerElement().initialize(model, env)
|
||||
@views.addViewProvider PaneAxis, (model, env) ->
|
||||
new PaneAxisElement().initialize(model, env)
|
||||
@views.addViewProvider Pane, (model, env) ->
|
||||
new PaneElement().initialize(model, env)
|
||||
@views.addViewProvider TextEditor, (model, env) ->
|
||||
new TextEditorElement().initialize(model, env)
|
||||
@views.addViewProvider(Gutter, createGutterView)
|
||||
|
||||
atom.views.addViewProvider PaneContainer, (model) ->
|
||||
new PaneContainerElement().initialize(model)
|
||||
atom.views.addViewProvider PaneAxis, (model) ->
|
||||
new PaneAxisElement().initialize(model)
|
||||
atom.views.addViewProvider Pane, (model) ->
|
||||
new PaneElement().initialize(model)
|
||||
atom.views.addViewProvider TextEditor, (model) ->
|
||||
new TextEditorElement().initialize(model)
|
||||
atom.views.addViewProvider(Gutter, createGutterView)
|
||||
registerDefaultOpeners: ->
|
||||
@workspace.addOpener (uri) =>
|
||||
switch uri
|
||||
when 'atom://.atom/stylesheet'
|
||||
@workspace.open(@styles.getUserStyleSheetPath())
|
||||
when 'atom://.atom/keymap'
|
||||
@workspace.open(@keymaps.getUserKeymapPath())
|
||||
when 'atom://.atom/config'
|
||||
@workspace.open(@config.getUserConfigPath())
|
||||
when 'atom://.atom/init-script'
|
||||
@workspace.open(@getUserInitScriptPath())
|
||||
|
||||
registerDefaultTargetForKeymaps: ->
|
||||
@keymaps.defaultTarget = @views.getView(@workspace)
|
||||
|
||||
observeAutoHideMenuBar: ->
|
||||
@disposables.add @config.onDidChange 'core.autoHideMenuBar', ({newValue}) =>
|
||||
@setAutoHideMenuBar(newValue)
|
||||
@setAutoHideMenuBar(true) if @config.get('core.autoHideMenuBar')
|
||||
|
||||
reset: ->
|
||||
@deserializers.clear()
|
||||
@registerDefaultDeserializers()
|
||||
|
||||
@config.clear()
|
||||
@setConfigSchema()
|
||||
|
||||
@keymaps.clear()
|
||||
@keymaps.loadBundledKeymaps()
|
||||
|
||||
@commands.clear()
|
||||
@registerDefaultCommands()
|
||||
|
||||
@styles.restoreSnapshot(@initialStyleElements)
|
||||
|
||||
@menu.clear()
|
||||
|
||||
@clipboard.reset()
|
||||
|
||||
@notifications.clear()
|
||||
|
||||
@contextMenu.clear()
|
||||
|
||||
@packages.reset()
|
||||
|
||||
@workspace.reset(@packages)
|
||||
@registerDefaultOpeners()
|
||||
|
||||
@project.reset(@packages)
|
||||
|
||||
@workspace.subscribeToEvents()
|
||||
|
||||
@grammars.clear()
|
||||
|
||||
@views.clear()
|
||||
@registerDefaultViewProviders()
|
||||
|
||||
@state.packageStates = {}
|
||||
delete @state.workspace
|
||||
|
||||
destroy: ->
|
||||
return if not @project
|
||||
|
||||
@disposables.dispose()
|
||||
@workspace?.destroy()
|
||||
@workspace = null
|
||||
@themes.workspace = null
|
||||
@project?.destroy()
|
||||
@project = null
|
||||
@commands.clear()
|
||||
@stylesElement.remove()
|
||||
|
||||
@uninstallWindowEventHandler()
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
@@ -341,12 +381,6 @@ class Atom extends Model
|
||||
isReleasedVersion: ->
|
||||
not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix
|
||||
|
||||
# Public: Get the directory path to Atom's configuration area.
|
||||
#
|
||||
# Returns the absolute path to `~/.atom`.
|
||||
getConfigDirPath: ->
|
||||
@constructor.getConfigDirPath()
|
||||
|
||||
# Public: Get the time taken to completely load the current window.
|
||||
#
|
||||
# This time include things like loading and activating packages, creating
|
||||
@@ -361,7 +395,7 @@ class Atom extends Model
|
||||
#
|
||||
# Returns an {Object} containing all the load setting key/value pairs.
|
||||
getLoadSettings: ->
|
||||
@constructor.getLoadSettings()
|
||||
getWindowLoadSettings()
|
||||
|
||||
###
|
||||
Section: Managing The Atom Window
|
||||
@@ -372,7 +406,7 @@ class Atom extends Model
|
||||
# Calling this method without an options parameter will open a prompt to pick
|
||||
# a file/folder to open in the new window.
|
||||
#
|
||||
# * `options` An {Object} with the following keys:
|
||||
# * `params` An {Object} with the following keys:
|
||||
# * `pathsToOpen` An {Array} of {String} paths to open.
|
||||
# * `newWindow` A {Boolean}, true to always open a new window instead of
|
||||
# reusing existing windows depending on the paths to open.
|
||||
@@ -381,8 +415,8 @@ class Atom extends Model
|
||||
# repository and also loads all the packages in ~/.atom/dev/packages
|
||||
# * `safeMode` A {Boolean}, true to open the window in safe mode. Safe
|
||||
# mode prevents all packages installed to ~/.atom/packages from loading.
|
||||
open: (options) ->
|
||||
ipc.send('open', options)
|
||||
open: (params) ->
|
||||
@applicationDelegate.open(params)
|
||||
|
||||
# Extended: Prompt the user to select one or more folders.
|
||||
#
|
||||
@@ -390,87 +424,81 @@ class Atom extends Model
|
||||
# * `paths` An {Array} of {String} paths that the user selected, or `null`
|
||||
# if the user dismissed the dialog.
|
||||
pickFolder: (callback) ->
|
||||
responseChannel = "atom-pick-folder-response"
|
||||
ipc.on responseChannel, (path) ->
|
||||
ipc.removeAllListeners(responseChannel)
|
||||
callback(path)
|
||||
ipc.send("pick-folder", responseChannel)
|
||||
@applicationDelegate.pickFolder(callback)
|
||||
|
||||
# Essential: Close the current window.
|
||||
close: ->
|
||||
@getCurrentWindow().close()
|
||||
@applicationDelegate.closeWindow()
|
||||
|
||||
# Essential: Get the size of current window.
|
||||
#
|
||||
# Returns an {Object} in the format `{width: 1000, height: 700}`
|
||||
getSize: ->
|
||||
[width, height] = @getCurrentWindow().getSize()
|
||||
{width, height}
|
||||
@applicationDelegate.getWindowSize()
|
||||
|
||||
# Essential: Set the size of current window.
|
||||
#
|
||||
# * `width` The {Number} of pixels.
|
||||
# * `height` The {Number} of pixels.
|
||||
setSize: (width, height) ->
|
||||
@getCurrentWindow().setSize(width, height)
|
||||
@applicationDelegate.setWindowSize(width, height)
|
||||
|
||||
# Essential: Get the position of current window.
|
||||
#
|
||||
# Returns an {Object} in the format `{x: 10, y: 20}`
|
||||
getPosition: ->
|
||||
[x, y] = @getCurrentWindow().getPosition()
|
||||
{x, y}
|
||||
@applicationDelegate.getWindowPosition()
|
||||
|
||||
# Essential: Set the position of current window.
|
||||
#
|
||||
# * `x` The {Number} of pixels.
|
||||
# * `y` The {Number} of pixels.
|
||||
setPosition: (x, y) ->
|
||||
ipc.send('call-window-method', 'setPosition', x, y)
|
||||
@applicationDelegate.setWindowPosition(x, y)
|
||||
|
||||
# Extended: Get the current window
|
||||
getCurrentWindow: ->
|
||||
@constructor.getCurrentWindow()
|
||||
@applicationDelegate.getCurrentWindow()
|
||||
|
||||
# Extended: Move current window to the center of the screen.
|
||||
center: ->
|
||||
ipc.send('call-window-method', 'center')
|
||||
@applicationDelegate.centerWindow()
|
||||
|
||||
# Extended: Focus the current window.
|
||||
focus: ->
|
||||
ipc.send('call-window-method', 'focus')
|
||||
window.focus()
|
||||
@applicationDelegate.focusWindow()
|
||||
@window.focus()
|
||||
|
||||
# Extended: Show the current window.
|
||||
show: ->
|
||||
ipc.send('call-window-method', 'show')
|
||||
@applicationDelegate.showWindow()
|
||||
|
||||
# Extended: Hide the current window.
|
||||
hide: ->
|
||||
ipc.send('call-window-method', 'hide')
|
||||
@applicationDelegate.hideWindow()
|
||||
|
||||
# Extended: Reload the current window.
|
||||
reload: ->
|
||||
ipc.send('call-window-method', 'restart')
|
||||
@applicationDelegate.restartWindow()
|
||||
|
||||
# Extended: Returns a {Boolean} that is `true` if the current window is maximized.
|
||||
isMaximized: ->
|
||||
@getCurrentWindow().isMaximized()
|
||||
@applicationDelegate.isWindowMaximized()
|
||||
|
||||
maximize: ->
|
||||
ipc.send('call-window-method', 'maximize')
|
||||
@applicationDelegate.maximizeWindow()
|
||||
|
||||
# Extended: Returns a {Boolean} that is `true` if the current window is in full screen mode.
|
||||
isFullScreen: ->
|
||||
@getCurrentWindow().isFullScreen()
|
||||
@applicationDelegate.isWindowFullScreen()
|
||||
|
||||
# Extended: Set the full screen state of the current window.
|
||||
setFullScreen: (fullScreen=false) ->
|
||||
ipc.send('call-window-method', 'setFullScreen', fullScreen)
|
||||
@applicationDelegate.setWindowFullScreen(fullScreen)
|
||||
if fullScreen
|
||||
document.body.classList.add("fullscreen")
|
||||
@document.body.classList.add("fullscreen")
|
||||
else
|
||||
document.body.classList.remove("fullscreen")
|
||||
@document.body.classList.remove("fullscreen")
|
||||
|
||||
# Extended: Toggle the full screen state of the current window.
|
||||
toggleFullScreen: ->
|
||||
@@ -546,8 +574,7 @@ class Atom extends Model
|
||||
if @isValidDimensions(dimensions)
|
||||
dimensions
|
||||
else
|
||||
screen = remote.require 'screen'
|
||||
{width, height} = screen.getPrimaryDisplay().workAreaSize
|
||||
{width, height} = @applicationDelegate.getPrimaryDisplayWorkAreaSize()
|
||||
{x: 0, y: 0, width: Math.min(1024, width), height}
|
||||
|
||||
restoreWindowDimensions: ->
|
||||
@@ -565,37 +592,34 @@ class Atom extends Model
|
||||
return if @inSpecMode()
|
||||
|
||||
workspaceElement = @views.getView(@workspace)
|
||||
backgroundColor = window.getComputedStyle(workspaceElement)['background-color']
|
||||
window.localStorage.setItem('atom:window-background-color', backgroundColor)
|
||||
backgroundColor = @window.getComputedStyle(workspaceElement)['background-color']
|
||||
@window.localStorage.setItem('atom:window-background-color', backgroundColor)
|
||||
|
||||
# Call this method when establishing a real application window.
|
||||
startEditorWindow: ->
|
||||
{safeMode} = @getLoadSettings()
|
||||
|
||||
CommandInstaller = require './command-installer'
|
||||
|
||||
commandInstaller = new CommandInstaller(@getVersion())
|
||||
commandInstaller.installAtomCommand false, (error) ->
|
||||
@commandInstaller.installAtomCommand false, (error) ->
|
||||
console.warn error.message if error?
|
||||
commandInstaller.installApmCommand false, (error) ->
|
||||
@commandInstaller.installApmCommand false, (error) ->
|
||||
console.warn error.message if error?
|
||||
|
||||
@loadConfig()
|
||||
@keymaps.loadBundledKeymaps()
|
||||
@themes.loadBaseStylesheets()
|
||||
@disposables.add(@applicationDelegate.onDidOpenLocations(@openLocations.bind(this)))
|
||||
@disposables.add(@applicationDelegate.onApplicationMenuCommand(@dispatchApplicationMenuCommand.bind(this)))
|
||||
@disposables.add(@applicationDelegate.onContextMenuCommand(@dispatchContextMenuCommand.bind(this)))
|
||||
@listenForUpdates()
|
||||
|
||||
@registerDefaultTargetForKeymaps()
|
||||
|
||||
@packages.loadPackages()
|
||||
@deserializeEditorWindow()
|
||||
|
||||
@document.body.appendChild(@views.getView(@workspace))
|
||||
|
||||
@watchProjectPath()
|
||||
|
||||
@packages.activate()
|
||||
@keymaps.loadUserKeymap()
|
||||
@requireUserInitScript() unless safeMode
|
||||
@requireUserInitScript() unless @getLoadSettings().safeMode
|
||||
|
||||
@menu.update()
|
||||
@disposables.add @config.onDidChange 'core.autoHideMenuBar', ({newValue}) =>
|
||||
@setAutoHideMenuBar(newValue)
|
||||
@setAutoHideMenuBar(true) if @config.get('core.autoHideMenuBar')
|
||||
|
||||
@openInitialEmptyEditorIfNecessary()
|
||||
|
||||
@@ -603,36 +627,56 @@ class Atom extends Model
|
||||
return if not @project
|
||||
|
||||
@storeWindowBackground()
|
||||
@state.grammars = @grammars.serialize()
|
||||
@state.grammars = {grammarOverridesByPath: @grammars.grammarOverridesByPath}
|
||||
@state.project = @project.serialize()
|
||||
@state.workspace = @workspace.serialize()
|
||||
@packages.deactivatePackages()
|
||||
@state.packageStates = @packages.packageStates
|
||||
@saveSync()
|
||||
@windowState = null
|
||||
|
||||
removeEditorWindow: ->
|
||||
return if not @project
|
||||
|
||||
@workspace?.destroy()
|
||||
@workspace = null
|
||||
@project?.destroy()
|
||||
@project = null
|
||||
|
||||
@windowEventHandler?.unsubscribe()
|
||||
@state.fullScreen = @isFullScreen()
|
||||
@saveStateSync()
|
||||
|
||||
openInitialEmptyEditorIfNecessary: ->
|
||||
return unless @config.get('core.openEmptyEditorOnStart')
|
||||
if @getLoadSettings().initialPaths?.length is 0 and @workspace.getPaneItems().length is 0
|
||||
@workspace.open(null)
|
||||
|
||||
installUncaughtErrorHandler: ->
|
||||
@previousWindowErrorHandler = @window.onerror
|
||||
@window.onerror = =>
|
||||
@lastUncaughtError = Array::slice.call(arguments)
|
||||
[message, url, line, column, originalError] = @lastUncaughtError
|
||||
|
||||
{line, column} = mapSourcePosition({source: url, line, column})
|
||||
|
||||
eventObject = {message, url, line, column, originalError}
|
||||
|
||||
openDevTools = true
|
||||
eventObject.preventDefault = -> openDevTools = false
|
||||
|
||||
@emitter.emit 'will-throw-error', eventObject
|
||||
|
||||
if openDevTools
|
||||
@openDevTools()
|
||||
@executeJavaScriptInDevTools('DevToolsAPI.showConsole()')
|
||||
|
||||
@emitter.emit 'did-throw-error', {message, url, line, column, originalError}
|
||||
|
||||
uninstallUncaughtErrorHandler: ->
|
||||
@window.onerror = @previousWindowErrorHandler
|
||||
|
||||
installWindowEventHandler: ->
|
||||
@windowEventHandler = new WindowEventHandler({atomEnvironment: this, @applicationDelegate, @window, @document})
|
||||
|
||||
uninstallWindowEventHandler: ->
|
||||
@windowEventHandler?.unsubscribe()
|
||||
|
||||
###
|
||||
Section: Messaging the User
|
||||
###
|
||||
|
||||
# Essential: Visually and audibly trigger a beep.
|
||||
beep: ->
|
||||
shell.beep() if @config.get('core.audioBeep')
|
||||
@applicationDelegate.playBeepSound() if @config.get('core.audioBeep')
|
||||
@emitter.emit 'did-beep'
|
||||
|
||||
# Essential: A flexible way to open a dialog akin to an alert dialog.
|
||||
@@ -655,25 +699,8 @@ class Atom extends Model
|
||||
# button names and the values are callbacks to invoke when clicked.
|
||||
#
|
||||
# Returns the chosen button index {Number} if the buttons option was an array.
|
||||
confirm: ({message, detailedMessage, buttons}={}) ->
|
||||
buttons ?= {}
|
||||
if _.isArray(buttons)
|
||||
buttonLabels = buttons
|
||||
else
|
||||
buttonLabels = Object.keys(buttons)
|
||||
|
||||
dialog = remote.require('dialog')
|
||||
chosen = dialog.showMessageBox @getCurrentWindow(),
|
||||
type: 'info'
|
||||
message: message
|
||||
detail: detailedMessage
|
||||
buttons: buttonLabels
|
||||
|
||||
if _.isArray(buttons)
|
||||
chosen
|
||||
else
|
||||
callback = buttons[buttonLabels[chosen]]
|
||||
callback?()
|
||||
confirm: (params={}) ->
|
||||
@applicationDelegate.confirm(params)
|
||||
|
||||
###
|
||||
Section: Managing the Dev Tools
|
||||
@@ -681,15 +708,15 @@ class Atom extends Model
|
||||
|
||||
# Extended: Open the dev tools for the current window.
|
||||
openDevTools: ->
|
||||
ipc.send('call-window-method', 'openDevTools')
|
||||
@applicationDelegate.openWindowDevTools()
|
||||
|
||||
# Extended: Toggle the visibility of the dev tools for the current window.
|
||||
toggleDevTools: ->
|
||||
ipc.send('call-window-method', 'toggleDevTools')
|
||||
@applicationDelegate.toggleWindowDevTools()
|
||||
|
||||
# Extended: Execute code in dev tools.
|
||||
executeJavaScriptInDevTools: (code) ->
|
||||
ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
|
||||
@applicationDelegate.executeJavaScriptInWindowDevTools(code)
|
||||
|
||||
###
|
||||
Section: Private
|
||||
@@ -706,62 +733,19 @@ class Atom extends Model
|
||||
|
||||
false
|
||||
|
||||
deserializeProject: ->
|
||||
Project = require './project'
|
||||
|
||||
startTime = Date.now()
|
||||
@project ?= @deserializers.deserialize(@state.project) ? new Project()
|
||||
@deserializeTimings.project = Date.now() - startTime
|
||||
|
||||
deserializeWorkspace: ->
|
||||
Workspace = require './workspace'
|
||||
|
||||
startTime = Date.now()
|
||||
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
|
||||
@deserializeTimings.workspace = Date.now() - startTime
|
||||
|
||||
workspaceElement = @views.getView(@workspace)
|
||||
@keymaps.defaultTarget = workspaceElement
|
||||
document.querySelector(@workspaceParentSelectorctor).appendChild(workspaceElement)
|
||||
|
||||
deserializePackageStates: ->
|
||||
@packages.packageStates = @state.packageStates ? {}
|
||||
delete @state.packageStates
|
||||
|
||||
deserializeEditorWindow: ->
|
||||
@deserializePackageStates()
|
||||
@deserializeProject()
|
||||
@deserializeWorkspace()
|
||||
|
||||
loadConfig: ->
|
||||
@config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))}
|
||||
@config.load()
|
||||
|
||||
loadThemes: ->
|
||||
@themes.load()
|
||||
|
||||
watchThemes: ->
|
||||
@themes.onDidChangeActiveThemes =>
|
||||
# Only reload stylesheets from non-theme packages
|
||||
for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
|
||||
pack.reloadStylesheets?()
|
||||
return
|
||||
|
||||
# Notify the browser project of the window's current project path
|
||||
watchProjectPath: ->
|
||||
@disposables.add @project.onDidChangePaths =>
|
||||
@constructor.updateLoadSetting('initialPaths', @project.getPaths())
|
||||
|
||||
exit: (status) ->
|
||||
app = remote.require('app')
|
||||
app.emit('will-exit')
|
||||
remote.process.exit(status)
|
||||
@applicationDelegate.setRepresentedDirectoryPaths(@project.getPaths())
|
||||
|
||||
setDocumentEdited: (edited) ->
|
||||
ipc.send('call-window-method', 'setDocumentEdited', edited)
|
||||
@applicationDelegate.setWindowDocumentEdited?(edited)
|
||||
|
||||
setRepresentedFilename: (filename) ->
|
||||
ipc.send('call-window-method', 'setRepresentedFilename', filename)
|
||||
@applicationDelegate.setWindowRepresentedFilename?(filename)
|
||||
|
||||
addProjectFolder: ->
|
||||
@pickFolder (selectedPaths = []) =>
|
||||
@@ -771,27 +755,61 @@ class Atom extends Model
|
||||
callback(showSaveDialogSync())
|
||||
|
||||
showSaveDialogSync: (options={}) ->
|
||||
if _.isString(options)
|
||||
options = defaultPath: options
|
||||
else
|
||||
options = _.clone(options)
|
||||
currentWindow = @getCurrentWindow()
|
||||
dialog = remote.require('dialog')
|
||||
options.title ?= 'Save File'
|
||||
options.defaultPath ?= @project?.getPaths()[0]
|
||||
dialog.showSaveDialog currentWindow, options
|
||||
@applicationDelegate.showSaveDialog(options)
|
||||
|
||||
saveSync: ->
|
||||
if storageKey = @constructor.getStateKey(@project?.getPaths(), @mode)
|
||||
@constructor.getStorageFolder().store(storageKey, @state)
|
||||
saveStateSync: ->
|
||||
return unless @enablePersistence
|
||||
|
||||
if storageKey = @getStateKey(@project?.getPaths())
|
||||
@getStorageFolder().store(storageKey, @state)
|
||||
else
|
||||
@getCurrentWindow().loadSettings.windowState = JSON.stringify(@state)
|
||||
|
||||
crashMainProcess: ->
|
||||
remote.process.crash()
|
||||
loadStateSync: ->
|
||||
return unless @enablePersistence
|
||||
|
||||
crashRenderProcess: ->
|
||||
process.crash()
|
||||
startTime = Date.now()
|
||||
|
||||
if stateKey = @getStateKey(@getLoadSettings().initialPaths)
|
||||
if state = @getStorageFolder().load(stateKey)
|
||||
@state = state
|
||||
|
||||
if not @state? and windowState = @getLoadSettings().windowState
|
||||
try
|
||||
if state = JSON.parse(@getLoadSettings().windowState)
|
||||
@state = state
|
||||
catch error
|
||||
console.warn "Error parsing window state: #{statePath} #{error.stack}", error
|
||||
|
||||
@deserializeTimings.atom = Date.now() - startTime
|
||||
|
||||
if grammarOverridesByPath = @state.grammars?.grammarOverridesByPath
|
||||
@grammars.grammarOverridesByPath = grammarOverridesByPath
|
||||
|
||||
@setFullScreen(@state.fullScreen)
|
||||
|
||||
@packages.packageStates = @state.packageStates ? {}
|
||||
|
||||
startTime = Date.now()
|
||||
@project.deserialize(@state.project, @deserializers) if @state.project?
|
||||
@deserializeTimings.project = Date.now() - startTime
|
||||
|
||||
startTime = Date.now()
|
||||
@workspace.deserialize(@state.workspace, @deserializers) if @state.workspace?
|
||||
@deserializeTimings.workspace = Date.now() - startTime
|
||||
|
||||
getStateKey: (paths) ->
|
||||
if paths?.length > 0
|
||||
sha1 = crypto.createHash('sha1').update(paths.slice().sort().join("\n")).digest('hex')
|
||||
"editor-#{sha1}"
|
||||
else
|
||||
null
|
||||
|
||||
getConfigDirPath: ->
|
||||
@configDirPath ?= process.env.ATOM_HOME
|
||||
|
||||
getStorageFolder: ->
|
||||
@storageFolder ?= new StorageFolder(@getConfigDirPath())
|
||||
|
||||
getUserInitScriptPath: ->
|
||||
initScriptPath = fs.resolve(@getConfigDirPath(), 'init', ['js', 'coffee'])
|
||||
@@ -802,44 +820,52 @@ class Atom extends Model
|
||||
try
|
||||
require(userInitScriptPath) if fs.isFileSync(userInitScriptPath)
|
||||
catch error
|
||||
atom.notifications.addError "Failed to load `#{userInitScriptPath}`",
|
||||
@notifications.addError "Failed to load `#{userInitScriptPath}`",
|
||||
detail: error.message
|
||||
dismissable: true
|
||||
|
||||
# Require the module with the given globals.
|
||||
#
|
||||
# The globals will be set on the `window` object and removed after the
|
||||
# require completes.
|
||||
#
|
||||
# * `id` The {String} module name or path.
|
||||
# * `globals` An optional {Object} to set as globals during require.
|
||||
requireWithGlobals: (id, globals={}) ->
|
||||
existingGlobals = {}
|
||||
for key, value of globals
|
||||
existingGlobals[key] = window[key]
|
||||
window[key] = value
|
||||
|
||||
require(id)
|
||||
|
||||
for key, value of existingGlobals
|
||||
if value is undefined
|
||||
delete window[key]
|
||||
else
|
||||
window[key] = value
|
||||
return
|
||||
|
||||
onUpdateAvailable: (callback) ->
|
||||
@emitter.on 'update-available', callback
|
||||
|
||||
updateAvailable: (details) ->
|
||||
@emitter.emit 'update-available', details
|
||||
|
||||
listenForUpdates: ->
|
||||
@disposables.add(@applicationDelegate.onUpdateAvailable(@updateAvailable.bind(this)))
|
||||
|
||||
setBodyPlatformClass: ->
|
||||
document.body.classList.add("platform-#{process.platform}")
|
||||
@document.body.classList.add("platform-#{process.platform}")
|
||||
|
||||
setAutoHideMenuBar: (autoHide) ->
|
||||
ipc.send('call-window-method', 'setAutoHideMenuBar', autoHide)
|
||||
ipc.send('call-window-method', 'setMenuBarVisibility', not autoHide)
|
||||
@applicationDelegate.setAutoHideWindowMenuBar(autoHide)
|
||||
@applicationDelegate.setWindowMenuBarVisibility(not autoHide)
|
||||
|
||||
dispatchApplicationMenuCommand: (command, arg) ->
|
||||
activeElement = @document.activeElement
|
||||
# Use the workspace element if body has focus
|
||||
if activeElement is @document.body and workspaceElement = @views.getView(@workspace)
|
||||
activeElement = workspaceElement
|
||||
@commands.dispatch(activeElement, command, arg)
|
||||
|
||||
dispatchContextMenuCommand: (command, args...) ->
|
||||
@commands.dispatch(@contextMenu.activeElement, command, args)
|
||||
|
||||
openLocations: (locations) ->
|
||||
needsProjectPaths = @project?.getPaths().length is 0
|
||||
|
||||
for {pathToOpen, initialLine, initialColumn} in locations
|
||||
if pathToOpen? and needsProjectPaths
|
||||
if fs.existsSync(pathToOpen)
|
||||
@project.addPath(pathToOpen)
|
||||
else if fs.existsSync(path.dirname(pathToOpen))
|
||||
@project.addPath(path.dirname(pathToOpen))
|
||||
else
|
||||
@project.addPath(pathToOpen)
|
||||
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
@workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
return
|
||||
|
||||
# Preserve this deprecation until 2.0. Sorry. Should have removed Q sooner.
|
||||
Promise.prototype.done = (callback) ->
|
||||
@@ -16,6 +16,8 @@ net = require 'net'
|
||||
url = require 'url'
|
||||
{EventEmitter} = require 'events'
|
||||
_ = require 'underscore-plus'
|
||||
FindParentDir = null
|
||||
Resolve = null
|
||||
|
||||
LocationSuffixRegExp = /(:\d+)(:\d+)?$/
|
||||
|
||||
@@ -63,7 +65,7 @@ class AtomApplication
|
||||
exit: (status) -> app.exit(status)
|
||||
|
||||
constructor: (options) ->
|
||||
{@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath} = options
|
||||
{@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout} = options
|
||||
|
||||
@socketPath = null if options.test
|
||||
|
||||
@@ -87,9 +89,9 @@ class AtomApplication
|
||||
else
|
||||
@loadState() or @openPath(options)
|
||||
|
||||
openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile, profileStartup}) ->
|
||||
openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout}) ->
|
||||
if test
|
||||
@runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile})
|
||||
@runTests({headless: true, @resourcePath, executedFrom, pathsToOpen, logFile, timeout})
|
||||
else if pathsToOpen.length > 0
|
||||
@openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup})
|
||||
else if urlsToOpen.length > 0
|
||||
@@ -163,7 +165,6 @@ class AtomApplication
|
||||
devMode: @focusedWindow()?.devMode
|
||||
safeMode: @focusedWindow()?.safeMode
|
||||
|
||||
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: @devResourcePath, safeMode: @focusedWindow()?.safeMode)
|
||||
@on 'application:quit', -> app.quit()
|
||||
@on 'application:new-window', -> @openPath(_.extend(windowDimensions: @focusedWindow()?.getDimensions(), getLoadSettings()))
|
||||
@on 'application:new-file', -> (@focusedWindow() ? this).openPath()
|
||||
@@ -218,11 +219,6 @@ class AtomApplication
|
||||
@killAllProcesses()
|
||||
@deleteSocketFile()
|
||||
|
||||
app.on 'will-exit', =>
|
||||
@saveState(false)
|
||||
@killAllProcesses()
|
||||
@deleteSocketFile()
|
||||
|
||||
app.on 'open-file', (event, pathToOpen) =>
|
||||
event.preventDefault()
|
||||
@openPath({pathToOpen})
|
||||
@@ -253,8 +249,8 @@ class AtomApplication
|
||||
win = BrowserWindow.fromWebContents(event.sender)
|
||||
@applicationMenu.update(win, template, keystrokesByCommand)
|
||||
|
||||
ipc.on 'run-package-specs', (event, specDirectory) =>
|
||||
@runSpecs({resourcePath: @devResourcePath, specDirectory: specDirectory, exitWhenDone: false})
|
||||
ipc.on 'run-package-specs', (event, packageSpecPath) =>
|
||||
@runTests({resourcePath: @devResourcePath, pathsToOpen: [packageSpecPath], headless: false})
|
||||
|
||||
ipc.on 'command', (event, command) =>
|
||||
@emit(command)
|
||||
@@ -271,13 +267,19 @@ class AtomApplication
|
||||
@promptForPath "folder", (selectedPaths) ->
|
||||
event.sender.send(responseChannel, selectedPaths)
|
||||
|
||||
ipc.on 'cancel-window-close', =>
|
||||
ipc.on 'did-cancel-window-unload', =>
|
||||
@quitting = false
|
||||
|
||||
clipboard = require '../safe-clipboard'
|
||||
ipc.on 'write-text-to-selection-clipboard', (event, selectedText) ->
|
||||
clipboard.writeText(selectedText, 'selection')
|
||||
|
||||
ipc.on 'write-to-stdout', (event, output) ->
|
||||
process.stdout.write(output)
|
||||
|
||||
ipc.on 'write-to-stderr', (event, output) ->
|
||||
process.stderr.write(output)
|
||||
|
||||
# Public: Executes the given command.
|
||||
#
|
||||
# If it isn't handled globally, delegate to the currently focused window.
|
||||
@@ -395,12 +397,12 @@ class AtomApplication
|
||||
else
|
||||
if devMode
|
||||
try
|
||||
bootstrapScript = require.resolve(path.join(@devResourcePath, 'src', 'window-bootstrap'))
|
||||
windowInitializationScript = require.resolve(path.join(@devResourcePath, 'src', 'initialize-application-window'))
|
||||
resourcePath = @devResourcePath
|
||||
|
||||
bootstrapScript ?= require.resolve('../window-bootstrap')
|
||||
windowInitializationScript ?= require.resolve('../initialize-application-window')
|
||||
resourcePath ?= @resourcePath
|
||||
openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup})
|
||||
openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup})
|
||||
|
||||
if pidToKillWhenClosed?
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
@@ -475,9 +477,9 @@ class AtomApplication
|
||||
if pack?
|
||||
if pack.urlMain
|
||||
packagePath = @packages.resolvePackagePath(packageName)
|
||||
bootstrapScript = path.resolve(packagePath, pack.urlMain)
|
||||
windowInitializationScript = path.resolve(packagePath, pack.urlMain)
|
||||
windowDimensions = @focusedWindow()?.getDimensions()
|
||||
new AtomWindow({bootstrapScript, @resourcePath, devMode, safeMode, urlToOpen, windowDimensions})
|
||||
new AtomWindow({windowInitializationScript, @resourcePath, devMode, safeMode, urlToOpen, windowDimensions})
|
||||
else
|
||||
console.log "Package '#{pack.name}' does not have a url main: #{urlToOpen}"
|
||||
else
|
||||
@@ -486,25 +488,64 @@ class AtomApplication
|
||||
# Opens up a new {AtomWindow} to run specs within.
|
||||
#
|
||||
# options -
|
||||
# :exitWhenDone - A Boolean that, if true, will close the window upon
|
||||
# :headless - A Boolean that, if true, will close the window upon
|
||||
# completion.
|
||||
# :resourcePath - The path to include specs from.
|
||||
# :specPath - The directory to load specs from.
|
||||
# :safeMode - A Boolean that, if true, won't run specs from ~/.atom/packages
|
||||
# and ~/.atom/dev/packages, defaults to false.
|
||||
runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode}) ->
|
||||
runTests: ({headless, resourcePath, executedFrom, pathsToOpen, logFile, safeMode, timeout}) ->
|
||||
if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath)
|
||||
resourcePath = @resourcePath
|
||||
|
||||
try
|
||||
bootstrapScript = require.resolve(path.resolve(@devResourcePath, 'spec', 'spec-bootstrap'))
|
||||
catch error
|
||||
bootstrapScript = require.resolve(path.resolve(__dirname, '..', '..', 'spec', 'spec-bootstrap'))
|
||||
timeoutInSeconds = Number.parseFloat(timeout)
|
||||
unless Number.isNaN(timeoutInSeconds)
|
||||
timeoutHandler = ->
|
||||
console.log "The test suite has timed out because it has been running for more than #{timeoutInSeconds} seconds."
|
||||
process.exit(124) # Use the same exit code as the UNIX timeout util.
|
||||
setTimeout(timeoutHandler, timeoutInSeconds * 1000)
|
||||
|
||||
try
|
||||
windowInitializationScript = require.resolve(path.resolve(@devResourcePath, 'src', 'initialize-test-window'))
|
||||
catch error
|
||||
windowInitializationScript = require.resolve(path.resolve(__dirname, '..', '..', 'src', 'initialize-test-window'))
|
||||
|
||||
testPaths = []
|
||||
if pathsToOpen?
|
||||
for pathToOpen in pathsToOpen
|
||||
testPaths.push(path.resolve(executedFrom, fs.normalize(pathToOpen)))
|
||||
|
||||
if testPaths.length is 0
|
||||
process.stderr.write 'Error: Specify at least one test path\n\n'
|
||||
process.exit(1)
|
||||
|
||||
legacyTestRunnerPath = @resolveLegacyTestRunnerPath()
|
||||
testRunnerPath = @resolveTestRunnerPath(testPaths[0])
|
||||
isSpec = true
|
||||
devMode = true
|
||||
safeMode ?= false
|
||||
new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode})
|
||||
new AtomWindow({windowInitializationScript, resourcePath, headless, isSpec, devMode, testRunnerPath, legacyTestRunnerPath, testPaths, logFile, safeMode})
|
||||
|
||||
resolveTestRunnerPath: (testPath) ->
|
||||
FindParentDir ?= require 'find-parent-dir'
|
||||
|
||||
if packageRoot = FindParentDir.sync(testPath, 'package.json')
|
||||
packageMetadata = require(path.join(packageRoot, 'package.json'))
|
||||
if packageMetadata.atomTestRunner
|
||||
Resolve ?= require('resolve')
|
||||
if testRunnerPath = Resolve.sync(packageMetadata.atomTestRunner, basedir: packageRoot, extensions: Object.keys(require.extensions))
|
||||
return testRunnerPath
|
||||
else
|
||||
process.stderr.write "Error: Could not resolve test runner path '#{packageMetadata.atomTestRunner}'"
|
||||
process.exit(1)
|
||||
|
||||
@resolveLegacyTestRunnerPath()
|
||||
|
||||
resolveLegacyTestRunnerPath: ->
|
||||
try
|
||||
require.resolve(path.resolve(@devResourcePath, 'spec', 'jasmine-test-runner'))
|
||||
catch error
|
||||
require.resolve(path.resolve(__dirname, '..', '..', 'spec', 'jasmine-test-runner'))
|
||||
|
||||
locationForPathToOpen: (pathToOpen, executedFrom='') ->
|
||||
return {pathToOpen} unless pathToOpen
|
||||
|
||||
@@ -19,7 +19,7 @@ class AtomWindow
|
||||
isSpec: null
|
||||
|
||||
constructor: (settings={}) ->
|
||||
{@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings
|
||||
{@resourcePath, pathToOpen, locationsToOpen, @isSpec, @headless, @safeMode, @devMode} = settings
|
||||
locationsToOpen ?= [{pathToOpen}] if pathToOpen
|
||||
locationsToOpen ?= []
|
||||
|
||||
@@ -29,6 +29,10 @@ class AtomWindow
|
||||
'web-preferences':
|
||||
'direct-write': true
|
||||
'subpixel-font-scaling': true
|
||||
|
||||
if @isSpec
|
||||
options['web-preferences']['page-visibility'] = true
|
||||
|
||||
# Don't set icon on Windows so the exe's ico will be used as window and
|
||||
# taskbar's icon. See https://github.com/atom/atom/issues/4811 for more.
|
||||
if process.platform is 'linux'
|
||||
@@ -131,7 +135,7 @@ class AtomWindow
|
||||
@browserWindow.destroy() if chosen is 0
|
||||
|
||||
@browserWindow.webContents.on 'crashed', =>
|
||||
global.atomApplication.exit(100) if @exitWhenDone
|
||||
global.atomApplication.exit(100) if @headless
|
||||
|
||||
chosen = dialog.showMessageBox @browserWindow,
|
||||
type: 'warning'
|
||||
|
||||
@@ -99,9 +99,9 @@ parseCommandLine = ->
|
||||
options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.')
|
||||
options.boolean('profile-startup').describe('profile-startup', 'Create a profile of the startup execution time.')
|
||||
options.alias('r', 'resource-path').string('r').describe('r', 'Set the path to the Atom source directory and enable dev-mode.')
|
||||
options.alias('s', 'spec-directory').string('s').describe('s', 'Set the directory from which to run package specs (default: Atom\'s spec directory).')
|
||||
options.boolean('safe').describe('safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.')
|
||||
options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.')
|
||||
options.string('timeout').describe('timeout', 'When in test mode, waits until the specified time (in minutes) and kills the process (exit code: 130).')
|
||||
options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
|
||||
options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.')
|
||||
options.string('socket-path')
|
||||
@@ -121,7 +121,7 @@ parseCommandLine = ->
|
||||
safeMode = args['safe']
|
||||
pathsToOpen = args._
|
||||
test = args['test']
|
||||
specDirectory = args['spec-directory']
|
||||
timeout = args['timeout']
|
||||
newWindow = args['new-window']
|
||||
pidToKillWhenClosed = args['pid'] if args['wait']
|
||||
logFile = args['log-file']
|
||||
@@ -133,18 +133,7 @@ parseCommandLine = ->
|
||||
if args['resource-path']
|
||||
devMode = true
|
||||
resourcePath = args['resource-path']
|
||||
else
|
||||
# Set resourcePath based on the specDirectory if running specs on atom core
|
||||
if specDirectory?
|
||||
packageDirectoryPath = path.join(specDirectory, '..')
|
||||
packageManifestPath = path.join(packageDirectoryPath, 'package.json')
|
||||
if fs.statSyncNoException(packageManifestPath)
|
||||
try
|
||||
packageManifest = JSON.parse(fs.readFileSync(packageManifestPath))
|
||||
resourcePath = packageDirectoryPath if packageManifest.name is 'atom'
|
||||
|
||||
if devMode
|
||||
resourcePath ?= devResourcePath
|
||||
resourcePath ?= devResourcePath if devMode
|
||||
|
||||
unless fs.statSyncNoException(resourcePath)
|
||||
resourcePath = path.dirname(path.dirname(__dirname))
|
||||
@@ -157,7 +146,7 @@ parseCommandLine = ->
|
||||
devResourcePath = normalizeDriveLetterName(devResourcePath)
|
||||
|
||||
{resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test,
|
||||
version, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory,
|
||||
logFile, socketPath, profileStartup}
|
||||
version, pidToKillWhenClosed, devMode, safeMode, newWindow,
|
||||
logFile, socketPath, profileStartup, timeout}
|
||||
|
||||
start()
|
||||
|
||||
@@ -14,8 +14,12 @@ clipboard = require './safe-clipboard'
|
||||
# ```
|
||||
module.exports =
|
||||
class Clipboard
|
||||
metadata: null
|
||||
signatureForMetadata: null
|
||||
constructor: ->
|
||||
@reset()
|
||||
|
||||
reset: ->
|
||||
@metadata = null
|
||||
@signatureForMetadata = null
|
||||
|
||||
# Creates an `md5` hash of some text.
|
||||
#
|
||||
|
||||
@@ -26,7 +26,7 @@ symlinkCommandWithPrivilegeSync = (sourcePath, destinationPath) ->
|
||||
|
||||
module.exports =
|
||||
class CommandInstaller
|
||||
constructor: (@appVersion) ->
|
||||
constructor: (@appVersion, @applicationDelegate) ->
|
||||
|
||||
getInstallDirectory: ->
|
||||
"/usr/local/bin"
|
||||
@@ -36,7 +36,7 @@ class CommandInstaller
|
||||
|
||||
installShellCommandsInteractively: ->
|
||||
showErrorDialog = (error) ->
|
||||
atom.confirm
|
||||
@applicationDelegate.confirm
|
||||
message: "Failed to install shell commands"
|
||||
detailedMessage: error.message
|
||||
|
||||
@@ -48,7 +48,7 @@ class CommandInstaller
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
atom.confirm
|
||||
@applicationDelegate.confirm
|
||||
message: "Commands installed."
|
||||
detailedMessage: "The shell commands `atom` and `apm` are installed."
|
||||
|
||||
|
||||
@@ -44,15 +44,23 @@ SequenceCount = 0
|
||||
# ```
|
||||
module.exports =
|
||||
class CommandRegistry
|
||||
constructor: (@rootNode) ->
|
||||
constructor: ->
|
||||
@rootNode = null
|
||||
@clear()
|
||||
|
||||
clear: ->
|
||||
@registeredCommands = {}
|
||||
@selectorBasedListenersByCommandName = {}
|
||||
@inlineListenersByCommandName = {}
|
||||
@emitter = new Emitter
|
||||
|
||||
attach: (@rootNode) ->
|
||||
@commandRegistered(command) for command of @selectorBasedListenersByCommandName
|
||||
@commandRegistered(command) for command of @inlineListenersByCommandName
|
||||
|
||||
destroy: ->
|
||||
for commandName of @registeredCommands
|
||||
window.removeEventListener(commandName, @handleCommandEvent, true)
|
||||
@rootNode.removeEventListener(commandName, @handleCommandEvent, true)
|
||||
return
|
||||
|
||||
# Public: Add one or more command listeners associated with a selector.
|
||||
@@ -253,8 +261,8 @@ class CommandRegistry
|
||||
matched
|
||||
|
||||
commandRegistered: (commandName) ->
|
||||
unless @registeredCommands[commandName]
|
||||
window.addEventListener(commandName, @handleCommandEvent, true)
|
||||
if @rootNode? and not @registeredCommands[commandName]
|
||||
@rootNode.addEventListener(commandName, @handleCommandEvent, true)
|
||||
@registeredCommands[commandName] = true
|
||||
|
||||
class SelectorBasedListener
|
||||
|
||||
@@ -334,7 +334,13 @@ class Config
|
||||
value
|
||||
|
||||
# Created during initialization, available as `atom.config`
|
||||
constructor: ({@configDirPath, @resourcePath}={}) ->
|
||||
constructor: ({@configDirPath, @resourcePath, @notificationManager, @enablePersistence}={}) ->
|
||||
if @enablePersistence?
|
||||
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
|
||||
@configFilePath ?= path.join(@configDirPath, 'config.cson')
|
||||
@clear()
|
||||
|
||||
clear: ->
|
||||
@emitter = new Emitter
|
||||
@schema =
|
||||
type: 'object'
|
||||
@@ -343,11 +349,8 @@ class Config
|
||||
@settings = {}
|
||||
@scopedSettingsStore = new ScopedPropertyStore
|
||||
@configFileHasErrors = false
|
||||
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
|
||||
@configFilePath ?= path.join(@configDirPath, 'config.cson')
|
||||
@transactDepth = 0
|
||||
@savePending = false
|
||||
|
||||
@requestLoad = _.debounce(@loadUserConfig, 100)
|
||||
@requestSave = =>
|
||||
@savePending = true
|
||||
@@ -357,6 +360,8 @@ class Config
|
||||
@save()
|
||||
debouncedSave = _.debounce(save, 100)
|
||||
|
||||
shouldNotAccessFileSystem: -> not @enablePersistence
|
||||
|
||||
###
|
||||
Section: Config Subscription
|
||||
###
|
||||
@@ -727,7 +732,7 @@ class Config
|
||||
###
|
||||
|
||||
initializeConfigDirectory: (done) ->
|
||||
return if fs.existsSync(@configDirPath)
|
||||
return if fs.existsSync(@configDirPath) or @shouldNotAccessFileSystem()
|
||||
|
||||
fs.makeTreeSync(@configDirPath)
|
||||
|
||||
@@ -743,6 +748,8 @@ class Config
|
||||
fs.traverseTree(templateConfigDirPath, onConfigDirFile, (path) -> true)
|
||||
|
||||
loadUserConfig: ->
|
||||
return if @shouldNotAccessFileSystem()
|
||||
|
||||
unless fs.existsSync(@configFilePath)
|
||||
fs.makeTreeSync(path.dirname(@configFilePath))
|
||||
CSON.writeFileSync(@configFilePath, {})
|
||||
@@ -766,6 +773,8 @@ class Config
|
||||
@notifyFailure(message, detail)
|
||||
|
||||
observeUserConfig: ->
|
||||
return if @shouldNotAccessFileSystem()
|
||||
|
||||
try
|
||||
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
||||
@requestLoad() if eventType is 'change' and @watchSubscription?
|
||||
@@ -782,9 +791,11 @@ class Config
|
||||
@watchSubscription = null
|
||||
|
||||
notifyFailure: (errorMessage, detail) ->
|
||||
atom.notifications.addError(errorMessage, {detail, dismissable: true})
|
||||
@notificationManager.addError(errorMessage, {detail, dismissable: true})
|
||||
|
||||
save: ->
|
||||
return if @shouldNotAccessFileSystem()
|
||||
|
||||
allSettings = {'*': @settings}
|
||||
allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath())
|
||||
try
|
||||
|
||||
@@ -4,6 +4,7 @@ CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
{calculateSpecificity, validateSelector} = require 'clear-cut'
|
||||
{Disposable} = require 'event-kit'
|
||||
remote = require 'remote'
|
||||
MenuHelpers = require './menu-helpers'
|
||||
|
||||
platformContextMenu = require('../package.json')?._atomMenu?['context-menu']
|
||||
@@ -40,11 +41,11 @@ platformContextMenu = require('../package.json')?._atomMenu?['context-menu']
|
||||
# {::add} for more information.
|
||||
module.exports =
|
||||
class ContextMenuManager
|
||||
constructor: ({@resourcePath, @devMode}) ->
|
||||
constructor: ({@resourcePath, @devMode, @keymapManager}) ->
|
||||
@definitions = {'.overlayer': []} # TODO: Remove once color picker package stops touching private data
|
||||
@clear()
|
||||
|
||||
atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()
|
||||
@keymapManager.onDidLoadBundledKeymaps => @loadPlatformItems()
|
||||
|
||||
loadPlatformItems: ->
|
||||
if platformContextMenu?
|
||||
@@ -175,7 +176,7 @@ class ContextMenuManager
|
||||
menuTemplate = @templateForEvent(event)
|
||||
|
||||
return unless menuTemplate?.length > 0
|
||||
atom.getCurrentWindow().emit('context-menu', menuTemplate)
|
||||
remote.getCurrentWindow().emit('context-menu', menuTemplate)
|
||||
return
|
||||
|
||||
clear: ->
|
||||
|
||||
@@ -16,7 +16,7 @@ class Cursor extends Model
|
||||
visible: true
|
||||
|
||||
# Instantiated by a {TextEditor}
|
||||
constructor: ({@editor, @marker, id}) ->
|
||||
constructor: ({@editor, @marker, @config, id}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@assignId(id)
|
||||
@@ -158,7 +158,7 @@ class Cursor extends Model
|
||||
[before, after] = @editor.getTextInBufferRange(range)
|
||||
return false if /\s/.test(before) or /\s/.test(after)
|
||||
|
||||
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()).split('')
|
||||
nonWordCharacters = @config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()).split('')
|
||||
_.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after)
|
||||
|
||||
# Public: Returns whether this cursor is between a word's start and end.
|
||||
@@ -605,7 +605,7 @@ class Cursor extends Model
|
||||
# Returns a {RegExp}.
|
||||
wordRegExp: ({includeNonWordCharacters}={}) ->
|
||||
includeNonWordCharacters ?= true
|
||||
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
|
||||
nonWordCharacters = @config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
|
||||
segments = ["^[\t ]*$"]
|
||||
segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
|
||||
if includeNonWordCharacters
|
||||
@@ -620,7 +620,7 @@ class Cursor extends Model
|
||||
#
|
||||
# Returns a {RegExp}.
|
||||
subwordRegExp: (options={}) ->
|
||||
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
|
||||
nonWordCharacters = @config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
|
||||
lowercaseLetters = 'a-z\\u00DF-\\u00F6\\u00F8-\\u00FF'
|
||||
uppercaseLetters = 'A-Z\\u00C0-\\u00D6\\u00D8-\\u00DE'
|
||||
snakeCamelSegment = "[#{uppercaseLetters}]?[#{lowercaseLetters}]+"
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
module.exports =
|
||||
class CustomGutterComponent
|
||||
|
||||
constructor: ({@gutter}) ->
|
||||
constructor: ({@gutter, @views}) ->
|
||||
@decorationNodesById = {}
|
||||
@decorationItemsById = {}
|
||||
@visible = true
|
||||
|
||||
@domNode = atom.views.getView(@gutter)
|
||||
@domNode = @views.getView(@gutter)
|
||||
@decorationsNode = @domNode.firstChild
|
||||
# Clear the contents in case the domNode is being reused.
|
||||
@decorationsNode.innerHTML = ''
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# ```
|
||||
module.exports =
|
||||
class DeserializerManager
|
||||
constructor: ->
|
||||
constructor: (@atomEnvironment) ->
|
||||
@deserializers = {}
|
||||
|
||||
# Public: Register the given class(es) as deserializers.
|
||||
@@ -29,7 +29,10 @@ class DeserializerManager
|
||||
# * `deserializers` One or more deserializers to register. A deserializer can
|
||||
# be any object with a `.name` property and a `.deserialize()` method. A
|
||||
# common approach is to register a *constructor* as the deserializer for its
|
||||
# instances by adding a `.deserialize()` class method.
|
||||
# instances by adding a `.deserialize()` class method. When your method is
|
||||
# called, it will be passed serialized state as the first argument and the
|
||||
# {Atom} environment object as the second argument, which is useful if you
|
||||
# wish to avoid referencing the `atom` global.
|
||||
add: (deserializers...) ->
|
||||
@deserializers[deserializer.name] = deserializer for deserializer in deserializers
|
||||
new Disposable =>
|
||||
@@ -39,15 +42,13 @@ class DeserializerManager
|
||||
# Public: Deserialize the state and params.
|
||||
#
|
||||
# * `state` The state {Object} to deserialize.
|
||||
# * `params` The params {Object} to pass as the second arguments to the
|
||||
# deserialize method of the deserializer.
|
||||
deserialize: (state, params) ->
|
||||
deserialize: (state) ->
|
||||
return unless state?
|
||||
|
||||
if deserializer = @get(state)
|
||||
stateVersion = state.get?('version') ? state.version
|
||||
return if deserializer.version? and deserializer.version isnt stateVersion
|
||||
deserializer.deserialize(state, params)
|
||||
deserializer.deserialize(state, @atomEnvironment)
|
||||
else
|
||||
console.warn "No deserializer found for", state
|
||||
|
||||
@@ -59,3 +60,6 @@ class DeserializerManager
|
||||
|
||||
name = state.get?('deserializer') ? state.deserializer
|
||||
@deserializers[name]
|
||||
|
||||
clear: ->
|
||||
@deserializers = {}
|
||||
|
||||
@@ -26,17 +26,29 @@ class DisplayBuffer extends Model
|
||||
height: null
|
||||
width: null
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer)
|
||||
@deserialize: (state, atomEnvironment) ->
|
||||
state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer, atomEnvironment)
|
||||
state.config = atomEnvironment.config
|
||||
state.assert = atomEnvironment.assert
|
||||
state.grammarRegistry = atomEnvironment.grammars
|
||||
state.packageManager = atomEnvironment.packages
|
||||
new this(state)
|
||||
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles, @largeFileMode}={}) ->
|
||||
constructor: (params={}) ->
|
||||
super
|
||||
|
||||
{
|
||||
tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles,
|
||||
@largeFileMode, @config, @assert, @grammarRegistry, @packageManager
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles, @largeFileMode})
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({
|
||||
tabLength, buffer, ignoreInvisibles, @largeFileMode, @config,
|
||||
@grammarRegistry, @packageManager, @assert
|
||||
})
|
||||
@buffer = @tokenizedBuffer.buffer
|
||||
@charWidthsByScope = {}
|
||||
@markers = {}
|
||||
@@ -61,29 +73,29 @@ class DisplayBuffer extends Model
|
||||
|
||||
oldConfigSettings = @configSettings
|
||||
@configSettings =
|
||||
scrollPastEnd: atom.config.get('editor.scrollPastEnd', scope: scopeDescriptor)
|
||||
softWrap: atom.config.get('editor.softWrap', scope: scopeDescriptor)
|
||||
softWrapAtPreferredLineLength: atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
|
||||
softWrapHangingIndent: atom.config.get('editor.softWrapHangingIndent', scope: scopeDescriptor)
|
||||
preferredLineLength: atom.config.get('editor.preferredLineLength', scope: scopeDescriptor)
|
||||
scrollPastEnd: @config.get('editor.scrollPastEnd', scope: scopeDescriptor)
|
||||
softWrap: @config.get('editor.softWrap', scope: scopeDescriptor)
|
||||
softWrapAtPreferredLineLength: @config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
|
||||
softWrapHangingIndent: @config.get('editor.softWrapHangingIndent', scope: scopeDescriptor)
|
||||
preferredLineLength: @config.get('editor.preferredLineLength', scope: scopeDescriptor)
|
||||
|
||||
subscriptions.add atom.config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) =>
|
||||
subscriptions.add @config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.softWrap = newValue
|
||||
@updateWrappedScreenLines()
|
||||
|
||||
subscriptions.add atom.config.onDidChange 'editor.softWrapHangingIndent', scope: scopeDescriptor, ({newValue}) =>
|
||||
subscriptions.add @config.onDidChange 'editor.softWrapHangingIndent', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.softWrapHangingIndent = newValue
|
||||
@updateWrappedScreenLines()
|
||||
|
||||
subscriptions.add atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) =>
|
||||
subscriptions.add @config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.softWrapAtPreferredLineLength = newValue
|
||||
@updateWrappedScreenLines() if @isSoftWrapped()
|
||||
|
||||
subscriptions.add atom.config.onDidChange 'editor.preferredLineLength', scope: scopeDescriptor, ({newValue}) =>
|
||||
subscriptions.add @config.onDidChange 'editor.preferredLineLength', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.preferredLineLength = newValue
|
||||
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
|
||||
@updateWrappedScreenLines() if @isSoftWrapped() and @config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
|
||||
|
||||
subscriptions.add atom.config.observe 'editor.scrollPastEnd', scope: scopeDescriptor, (value) =>
|
||||
subscriptions.add @config.observe 'editor.scrollPastEnd', scope: scopeDescriptor, (value) =>
|
||||
@configSettings.scrollPastEnd = value
|
||||
|
||||
@updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings)
|
||||
@@ -97,7 +109,10 @@ class DisplayBuffer extends Model
|
||||
largeFileMode: @largeFileMode
|
||||
|
||||
copy: ->
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @largeFileMode})
|
||||
newDisplayBuffer = new DisplayBuffer({
|
||||
@buffer, tabLength: @getTabLength(), @largeFileMode, @config, @assert,
|
||||
@grammarRegistry, @packageManager
|
||||
})
|
||||
|
||||
for marker in @findMarkers(displayBufferId: @id)
|
||||
marker.copy(displayBufferId: newDisplayBuffer.id)
|
||||
@@ -1080,8 +1095,8 @@ class DisplayBuffer extends Model
|
||||
tokenizedLinesCount = @tokenizedBuffer.getLineCount()
|
||||
bufferLinesCount = @buffer.getLineCount()
|
||||
|
||||
atom.assert screenLinesCount is tokenizedLinesCount, "Display buffer line count out of sync with tokenized buffer", (error) ->
|
||||
@assert screenLinesCount is tokenizedLinesCount, "Display buffer line count out of sync with tokenized buffer", (error) ->
|
||||
error.metadata = {screenLinesCount, tokenizedLinesCount, bufferLinesCount}
|
||||
|
||||
atom.assert screenLinesCount is bufferLinesCount, "Display buffer line count out of sync with buffer", (error) ->
|
||||
@assert screenLinesCount is bufferLinesCount, "Display buffer line count out of sync with buffer", (error) ->
|
||||
error.metadata = {screenLinesCount, tokenizedLinesCount, bufferLinesCount}
|
||||
|
||||
@@ -48,7 +48,7 @@ isValidGitDirectorySync = (directory) ->
|
||||
module.exports =
|
||||
class GitRepositoryProvider
|
||||
|
||||
constructor: (@project) ->
|
||||
constructor: (@project, @config) ->
|
||||
# Keys are real paths that end in `.git`.
|
||||
# Values are the corresponding GitRepository objects.
|
||||
@pathToRepository = {}
|
||||
@@ -75,7 +75,7 @@ class GitRepositoryProvider
|
||||
gitDirPath = gitDir.getPath()
|
||||
repo = @pathToRepository[gitDirPath]
|
||||
unless repo
|
||||
repo = GitRepository.open(gitDirPath, project: @project)
|
||||
repo = GitRepository.open(gitDirPath, {@project, @config})
|
||||
return null unless repo
|
||||
repo.onDidDestroy(=> delete @pathToRepository[gitDirPath])
|
||||
@pathToRepository[gitDirPath] = repo
|
||||
|
||||
@@ -80,7 +80,7 @@ class GitRepository
|
||||
for submodulePath, submoduleRepo of @repo.submodules
|
||||
submoduleRepo.upstream = {ahead: 0, behind: 0}
|
||||
|
||||
{@project, refreshOnWindowFocus} = options
|
||||
{@project, @config, refreshOnWindowFocus} = options
|
||||
|
||||
refreshOnWindowFocus ?= true
|
||||
if refreshOnWindowFocus
|
||||
@@ -443,25 +443,10 @@ class GitRepository
|
||||
|
||||
# Subscribes to editor view event.
|
||||
checkoutHeadForEditor: (editor) ->
|
||||
filePath = editor.getPath()
|
||||
return unless filePath
|
||||
|
||||
fileName = basename(filePath)
|
||||
|
||||
checkoutHead = =>
|
||||
if filePath = editor.getPath()
|
||||
editor.buffer.reload() if editor.buffer.isModified()
|
||||
@checkoutHead(filePath)
|
||||
|
||||
if atom.config.get('editor.confirmCheckoutHeadRevision')
|
||||
atom.confirm
|
||||
message: 'Confirm Checkout HEAD Revision'
|
||||
detailedMessage: "Are you sure you want to discard all changes to \"#{fileName}\" since the last Git commit?"
|
||||
buttons:
|
||||
OK: checkoutHead
|
||||
Cancel: null
|
||||
else
|
||||
checkoutHead()
|
||||
|
||||
# Returns the corresponding {Repository}
|
||||
getRepo: (path) ->
|
||||
if @repo?
|
||||
|
||||
@@ -14,19 +14,9 @@ PathSplitRegex = new RegExp("[/.]")
|
||||
# language-specific comment regexes. See {::getProperty} for more details.
|
||||
module.exports =
|
||||
class GrammarRegistry extends FirstMate.GrammarRegistry
|
||||
@deserialize: ({grammarOverridesByPath}) ->
|
||||
grammarRegistry = new GrammarRegistry()
|
||||
grammarRegistry.grammarOverridesByPath = grammarOverridesByPath
|
||||
grammarRegistry
|
||||
|
||||
atom.deserializers.add(this)
|
||||
|
||||
constructor: ->
|
||||
constructor: ({@config}={}) ->
|
||||
super(maxTokensPerLine: 100)
|
||||
|
||||
serialize: ->
|
||||
{deserializer: @constructor.name, @grammarOverridesByPath}
|
||||
|
||||
createToken: (value, scopes) -> new Token({value, scopes})
|
||||
|
||||
# Extended: Select a grammar for the given file path and file contents.
|
||||
@@ -70,7 +60,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry
|
||||
pathScore = -1
|
||||
|
||||
fileTypes = grammar.fileTypes
|
||||
if customFileTypes = atom.config.get('core.customFileTypes')?[grammar.scopeName]
|
||||
if customFileTypes = @config.get('core.customFileTypes')?[grammar.scopeName]
|
||||
fileTypes = fileTypes.concat(customFileTypes)
|
||||
|
||||
for fileType, i in fileTypes
|
||||
@@ -133,6 +123,3 @@ class GrammarRegistry extends FirstMate.GrammarRegistry
|
||||
clearGrammarOverrides: ->
|
||||
@grammarOverridesByPath = {}
|
||||
undefined
|
||||
|
||||
clearObservers: ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@@ -7,7 +7,7 @@ LineNumberGutterComponent = require './line-number-gutter-component'
|
||||
|
||||
module.exports =
|
||||
class GutterContainerComponent
|
||||
constructor: ({@onLineNumberGutterMouseDown, @editor, @domElementPool}) ->
|
||||
constructor: ({@onLineNumberGutterMouseDown, @editor, @domElementPool, @views}) ->
|
||||
# An array of objects of the form: {name: {String}, component: {Object}}
|
||||
@gutterComponents = []
|
||||
@gutterComponentsByGutterName = {}
|
||||
@@ -39,10 +39,10 @@ class GutterContainerComponent
|
||||
gutterComponent = @gutterComponentsByGutterName[gutter.name]
|
||||
if not gutterComponent
|
||||
if gutter.name is 'line-number'
|
||||
gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, gutter, @domElementPool})
|
||||
gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, gutter, @domElementPool, @views})
|
||||
@lineNumberGutterComponent = gutterComponent
|
||||
else
|
||||
gutterComponent = new CustomGutterComponent({gutter})
|
||||
gutterComponent = new CustomGutterComponent({gutter, @views})
|
||||
|
||||
if visible then gutterComponent.showNode() else gutterComponent.hideNode()
|
||||
# Pass the gutter only the state that it needs.
|
||||
|
||||
34
src/initialize-application-window.coffee
Normal file
34
src/initialize-application-window.coffee
Normal file
@@ -0,0 +1,34 @@
|
||||
# Like sands through the hourglass, so are the days of our lives.
|
||||
|
||||
path = require 'path'
|
||||
require './window'
|
||||
{getWindowLoadSettings} = require './window-load-settings-helpers'
|
||||
|
||||
{resourcePath, isSpec, devMode} = getWindowLoadSettings()
|
||||
|
||||
# Add application-specific exports to module search path.
|
||||
exportsPath = path.join(resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
# Make React faster
|
||||
process.env.NODE_ENV ?= 'production' unless devMode
|
||||
|
||||
AtomEnvironment = require './atom-environment'
|
||||
ApplicationDelegate = require './application-delegate'
|
||||
window.atom = new AtomEnvironment({
|
||||
window, document,
|
||||
applicationDelegate: new ApplicationDelegate,
|
||||
configDirPath: process.env.ATOM_HOME
|
||||
enablePersistence: true
|
||||
})
|
||||
|
||||
atom.displayWindow()
|
||||
atom.loadStateSync()
|
||||
atom.startEditorWindow()
|
||||
|
||||
# Workaround for focus getting cleared upon window creation
|
||||
windowFocused = ->
|
||||
window.removeEventListener('focus', windowFocused)
|
||||
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
|
||||
window.addEventListener('focus', windowFocused)
|
||||
59
src/initialize-test-window.coffee
Normal file
59
src/initialize-test-window.coffee
Normal file
@@ -0,0 +1,59 @@
|
||||
# Start the crash reporter before anything else.
|
||||
require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub')
|
||||
remote = require 'remote'
|
||||
|
||||
exitWithStatusCode = (status) ->
|
||||
remote.require('app').emit('will-quit')
|
||||
remote.process.exit(status)
|
||||
|
||||
try
|
||||
path = require 'path'
|
||||
ipc = require 'ipc'
|
||||
{getWindowLoadSettings} = require './window-load-settings-helpers'
|
||||
AtomEnvironment = require '../src/atom-environment'
|
||||
ApplicationDelegate = require '../src/application-delegate'
|
||||
|
||||
# Show window synchronously so a focusout doesn't fire on input elements
|
||||
# that are focused in the very first spec run.
|
||||
remote.getCurrentWindow().show() unless getWindowLoadSettings().headless
|
||||
|
||||
handleKeydown = (event) ->
|
||||
# Reload: cmd-r / ctrl-r
|
||||
if (event.metaKey or event.ctrlKey) and event.keyCode is 82
|
||||
ipc.send('call-window-method', 'restart')
|
||||
|
||||
# Toggle Dev Tools: cmd-alt-i / ctrl-alt-i
|
||||
if (event.metaKey or event.ctrlKey) and event.altKey and event.keyCode is 73
|
||||
ipc.send('call-window-method', 'toggleDevTools')
|
||||
|
||||
# Reload: cmd-w / ctrl-w
|
||||
if (event.metaKey or event.ctrlKey) and event.keyCode is 87
|
||||
ipc.send('call-window-method', 'close')
|
||||
|
||||
window.addEventListener('keydown', handleKeydown, true)
|
||||
|
||||
# Add 'exports' to module search path.
|
||||
exportsPath = path.join(getWindowLoadSettings().resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
process.env.NODE_PATH = exportsPath # Set NODE_PATH env variable since tasks may need it.
|
||||
|
||||
document.title = "Spec Suite"
|
||||
|
||||
legacyTestRunner = require(getWindowLoadSettings().legacyTestRunnerPath)
|
||||
testRunner = require(getWindowLoadSettings().testRunnerPath)
|
||||
promise = testRunner({
|
||||
logFile: getWindowLoadSettings().logFile
|
||||
headless: getWindowLoadSettings().headless
|
||||
testPaths: getWindowLoadSettings().testPaths
|
||||
buildAtomEnvironment: (params) -> new AtomEnvironment(params)
|
||||
buildDefaultApplicationDelegate: (params) -> new ApplicationDelegate()
|
||||
legacyTestRunner: legacyTestRunner
|
||||
})
|
||||
|
||||
promise.then(exitWithStatusCode) if getWindowLoadSettings().headless
|
||||
catch error
|
||||
if getWindowLoadSettings().headless
|
||||
console.error(error.stack ? error)
|
||||
exitWithStatusCode(1)
|
||||
else
|
||||
throw error
|
||||
@@ -20,6 +20,8 @@ KeymapManager::loadBundledKeymaps = ->
|
||||
@emitter.emit 'did-load-bundled-keymaps'
|
||||
|
||||
KeymapManager::getUserKeymapPath = ->
|
||||
return "" unless @configDirPath?
|
||||
|
||||
if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap'))
|
||||
userKeymapPath
|
||||
else
|
||||
@@ -41,11 +43,11 @@ KeymapManager::loadUserKeymap = ->
|
||||
[this document][watches] for more info.
|
||||
[watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path
|
||||
"""
|
||||
atom.notifications.addError(message, {dismissable: true})
|
||||
@notificationManager.addError(message, {dismissable: true})
|
||||
else
|
||||
detail = error.path
|
||||
stack = error.stack
|
||||
atom.notifications.addFatalError(error.message, {detail, stack, dismissable: true})
|
||||
@notificationManager.addFatalError(error.message, {detail, stack, dismissable: true})
|
||||
|
||||
KeymapManager::subscribeToFileReadFailure = ->
|
||||
@onDidFailToReadFile (error) =>
|
||||
@@ -57,6 +59,6 @@ KeymapManager::subscribeToFileReadFailure = ->
|
||||
else
|
||||
error.message
|
||||
|
||||
atom.notifications.addError(message, {detail, dismissable: true})
|
||||
@notificationManager.addError(message, {detail, dismissable: true})
|
||||
|
||||
module.exports = KeymapManager
|
||||
|
||||
@@ -8,7 +8,7 @@ class LanguageMode
|
||||
# Sets up a `LanguageMode` for the given {TextEditor}.
|
||||
#
|
||||
# editor - The {TextEditor} to associate with
|
||||
constructor: (@editor) ->
|
||||
constructor: (@editor, @config) ->
|
||||
{@buffer} = @editor
|
||||
|
||||
destroy: ->
|
||||
@@ -327,7 +327,7 @@ class LanguageMode
|
||||
@editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
|
||||
|
||||
getRegexForProperty: (scopeDescriptor, property) ->
|
||||
if pattern = atom.config.get(property, scope: scopeDescriptor)
|
||||
if pattern = @config.get(property, scope: scopeDescriptor)
|
||||
new OnigRegExp(pattern)
|
||||
|
||||
increaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
|
||||
@@ -343,8 +343,8 @@ class LanguageMode
|
||||
@getRegexForProperty(scopeDescriptor, 'editor.foldEndPattern')
|
||||
|
||||
commentStartAndEndStringsForScope: (scope) ->
|
||||
commentStartEntry = atom.config.getAll('editor.commentStart', {scope})[0]
|
||||
commentEndEntry = _.find atom.config.getAll('editor.commentEnd', {scope}), (entry) ->
|
||||
commentStartEntry = @config.getAll('editor.commentStart', {scope})[0]
|
||||
commentEndEntry = _.find @config.getAll('editor.commentEnd', {scope}), (entry) ->
|
||||
entry.scopeSelector is commentStartEntry.scopeSelector
|
||||
commentStartString = commentStartEntry?.value
|
||||
commentEndString = commentEndEntry?.value
|
||||
|
||||
@@ -7,12 +7,12 @@ module.exports =
|
||||
class LineNumberGutterComponent extends TiledComponent
|
||||
dummyLineNumberNode: null
|
||||
|
||||
constructor: ({@onMouseDown, @editor, @gutter, @domElementPool}) ->
|
||||
constructor: ({@onMouseDown, @editor, @gutter, @domElementPool, @views}) ->
|
||||
@visible = true
|
||||
|
||||
@dummyLineNumberComponent = LineNumbersTileComponent.createDummy(@domElementPool)
|
||||
|
||||
@domNode = atom.views.getView(@gutter)
|
||||
@domNode = @views.getView(@gutter)
|
||||
@lineNumbersNode = @domNode.firstChild
|
||||
@lineNumbersNode.innerHTML = ''
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ module.exports =
|
||||
class LinesComponent extends TiledComponent
|
||||
placeholderTextDiv: null
|
||||
|
||||
constructor: ({@presenter, @useShadowDOM, @domElementPool}) ->
|
||||
constructor: ({@presenter, @useShadowDOM, @domElementPool, @assert, @grammars}) ->
|
||||
@domNode = document.createElement('div')
|
||||
@domNode.classList.add('lines')
|
||||
@tilesNode = document.createElement("div")
|
||||
@@ -72,7 +72,7 @@ class LinesComponent extends TiledComponent
|
||||
|
||||
@oldState.indentGuidesVisible = @newState.indentGuidesVisible
|
||||
|
||||
buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter, @domElementPool})
|
||||
buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter, @domElementPool, @assert, @grammars})
|
||||
|
||||
buildEmptyState: ->
|
||||
{tiles: {}}
|
||||
|
||||
@@ -13,8 +13,8 @@ cloneObject = (object) ->
|
||||
|
||||
module.exports =
|
||||
class LinesTileComponent
|
||||
constructor: ({@presenter, @id, @domElementPool}) ->
|
||||
@tokenIterator = new TokenIterator
|
||||
constructor: ({@presenter, @id, @domElementPool, @assert, grammars}) ->
|
||||
@tokenIterator = new TokenIterator(grammarRegistry: grammars)
|
||||
@measuredLines = new Set
|
||||
@lineNodesByLineId = {}
|
||||
@screenRowsByLineId = {}
|
||||
|
||||
@@ -3,8 +3,8 @@ TokenIterator = require './token-iterator'
|
||||
|
||||
module.exports =
|
||||
class LinesYardstick
|
||||
constructor: (@model, @presenter, @lineNodesProvider) ->
|
||||
@tokenIterator = new TokenIterator
|
||||
constructor: (@model, @presenter, @lineNodesProvider, grammarRegistry) ->
|
||||
@tokenIterator = new TokenIterator({grammarRegistry})
|
||||
@rangeForMeasurement = document.createRange()
|
||||
@invalidateCache()
|
||||
|
||||
|
||||
@@ -59,12 +59,12 @@ platformMenu = require('../package.json')?._atomMenu?.menu
|
||||
# See {::add} for more info about adding menu's directly.
|
||||
module.exports =
|
||||
class MenuManager
|
||||
constructor: ({@resourcePath}) ->
|
||||
constructor: ({@resourcePath, @keymapManager, @packageManager}) ->
|
||||
@pendingUpdateOperation = null
|
||||
@template = []
|
||||
atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()
|
||||
atom.keymaps.onDidReloadKeymap => @update()
|
||||
atom.packages.onDidActivateInitialPackages => @sortPackagesMenu()
|
||||
@keymapManager.onDidLoadBundledKeymaps => @loadPlatformItems()
|
||||
@keymapManager.onDidReloadKeymap => @update()
|
||||
@packageManager.onDidActivateInitialPackages => @sortPackagesMenu()
|
||||
|
||||
# Public: Adds the given items to the application menu.
|
||||
#
|
||||
@@ -96,6 +96,10 @@ class MenuManager
|
||||
@unmerge(@template, item) for item in items
|
||||
@update()
|
||||
|
||||
clear: ->
|
||||
@template = []
|
||||
@update()
|
||||
|
||||
# Should the binding for the given selector be included in the menu
|
||||
# commands.
|
||||
#
|
||||
@@ -143,7 +147,7 @@ class MenuManager
|
||||
includedBindings = []
|
||||
unsetKeystrokes = new Set
|
||||
|
||||
for binding in atom.keymaps.getKeyBindings() when @includeSelector(binding.selector)
|
||||
for binding in @keymapManager.getKeyBindings() when @includeSelector(binding.selector)
|
||||
includedBindings.push(binding)
|
||||
if binding.command is 'unset!'
|
||||
unsetKeystrokes.add(binding.keystrokes)
|
||||
@@ -191,7 +195,10 @@ class MenuManager
|
||||
|
||||
# Get an {Array} of {String} classes for the given element.
|
||||
classesForElement: (element) ->
|
||||
element?.classList.toString().split(' ') ? []
|
||||
if classList = element?.classList
|
||||
Array::slice.apply(classList)
|
||||
else
|
||||
[]
|
||||
|
||||
sortPackagesMenu: ->
|
||||
packagesMenu = _.find @template, ({label}) -> MenuHelpers.normalizeLabel(label) is 'Packages'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports =
|
||||
class OverlayManager
|
||||
constructor: (@presenter, @container) ->
|
||||
constructor: (@presenter, @container, @views) ->
|
||||
@overlaysById = {}
|
||||
|
||||
render: (state) ->
|
||||
@@ -28,7 +28,7 @@ class OverlayManager
|
||||
@presenter.setOverlayDimensions(decorationId, itemView.offsetWidth, itemView.offsetHeight, contentMargin)
|
||||
|
||||
renderOverlay: (state, decorationId, {item, pixelPosition, class: klass}) ->
|
||||
itemView = atom.views.getView(item)
|
||||
itemView = @views.getView(item)
|
||||
cachedOverlay = @overlaysById[decorationId]
|
||||
unless overlayNode = cachedOverlay?.overlayNode
|
||||
overlayNode = document.createElement('atom-overlay')
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
path = require 'path'
|
||||
normalizePackageData = null
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
fs = require 'fs-plus'
|
||||
CSON = require 'season'
|
||||
|
||||
ServiceHub = require 'service-hub'
|
||||
Package = require './package'
|
||||
@@ -26,15 +28,21 @@ ThemePackage = require './theme-package'
|
||||
# settings and also by calling `enablePackage()/disablePackage()`.
|
||||
module.exports =
|
||||
class PackageManager
|
||||
constructor: ({configDirPath, @devMode, safeMode, @resourcePath}) ->
|
||||
constructor: (params) ->
|
||||
{
|
||||
configDirPath, @devMode, safeMode, @resourcePath, @config, @styleManager,
|
||||
@notificationManager, @keymapManager, @commandRegistry, @grammarRegistry
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@activationHookEmitter = new Emitter
|
||||
@packageDirPaths = []
|
||||
unless safeMode
|
||||
if configDirPath? and not safeMode
|
||||
if @devMode
|
||||
@packageDirPaths.push(path.join(configDirPath, "dev", "packages"))
|
||||
@packageDirPaths.push(path.join(configDirPath, "packages"))
|
||||
|
||||
@packagesCache = require('../package.json')?._atomPackages ? {}
|
||||
@loadedPackages = {}
|
||||
@activePackages = {}
|
||||
@packageStates = {}
|
||||
@@ -43,6 +51,17 @@ class PackageManager
|
||||
@packageActivators = []
|
||||
@registerPackageActivator(this, ['atom', 'textmate'])
|
||||
|
||||
setContextMenuManager: (@contextMenuManager) ->
|
||||
|
||||
setMenuManager: (@menuManager) ->
|
||||
|
||||
setThemeManager: (@themeManager) ->
|
||||
|
||||
reset: ->
|
||||
@serviceHub.clear()
|
||||
@deactivatePackages()
|
||||
@packageStates = {}
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
@@ -185,7 +204,7 @@ class PackageManager
|
||||
#
|
||||
# Returns a {Boolean}.
|
||||
isPackageDisabled: (name) ->
|
||||
_.include(atom.config.get('core.disabledPackages') ? [], name)
|
||||
_.include(@config.get('core.disabledPackages') ? [], name)
|
||||
|
||||
###
|
||||
Section: Accessing active packages
|
||||
@@ -269,7 +288,7 @@ class PackageManager
|
||||
packages = []
|
||||
for packagePath in @getAvailablePackagePaths()
|
||||
name = path.basename(packagePath)
|
||||
metadata = @getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true)
|
||||
metadata = @getLoadedPackage(name)?.metadata ? @loadPackageMetadata(packagePath, true)
|
||||
packages.push(metadata)
|
||||
packages
|
||||
|
||||
@@ -292,7 +311,7 @@ class PackageManager
|
||||
@packageDependencies
|
||||
|
||||
hasAtomEngine: (packagePath) ->
|
||||
metadata = Package.loadMetadata(packagePath, true)
|
||||
metadata = @loadPackageMetadata(packagePath, true)
|
||||
metadata?.engines?.atom?
|
||||
|
||||
unobserveDisabledPackages: ->
|
||||
@@ -300,7 +319,7 @@ class PackageManager
|
||||
@disabledPackagesSubscription = null
|
||||
|
||||
observeDisabledPackages: ->
|
||||
@disabledPackagesSubscription ?= atom.config.onDidChange 'core.disabledPackages', ({newValue, oldValue}) =>
|
||||
@disabledPackagesSubscription ?= @config.onDidChange 'core.disabledPackages', ({newValue, oldValue}) =>
|
||||
packagesToEnable = _.difference(oldValue, newValue)
|
||||
packagesToDisable = _.difference(newValue, oldValue)
|
||||
|
||||
@@ -313,7 +332,7 @@ class PackageManager
|
||||
@packagesWithKeymapsDisabledSubscription = null
|
||||
|
||||
observePackagesWithKeymapsDisabled: ->
|
||||
@packagesWithKeymapsDisabledSubscription ?= atom.config.onDidChange 'core.packagesWithKeymapsDisabled', ({newValue, oldValue}) =>
|
||||
@packagesWithKeymapsDisabledSubscription ?= @config.onDidChange 'core.packagesWithKeymapsDisabled', ({newValue, oldValue}) =>
|
||||
keymapsToEnable = _.difference(oldValue, newValue)
|
||||
keymapsToDisable = _.difference(newValue, oldValue)
|
||||
|
||||
@@ -340,7 +359,7 @@ class PackageManager
|
||||
return pack if pack = @getLoadedPackage(name)
|
||||
|
||||
try
|
||||
metadata = Package.loadMetadata(packagePath) ? {}
|
||||
metadata = @loadPackageMetadata(packagePath) ? {}
|
||||
catch error
|
||||
@handleMetadataError(error, packagePath)
|
||||
return null
|
||||
@@ -350,10 +369,15 @@ class PackageManager
|
||||
console.warn "Could not load #{metadata.name}@#{metadata.version} because it uses deprecated APIs that have been removed."
|
||||
return null
|
||||
|
||||
options = {
|
||||
path: packagePath, metadata, packageManager: this, @config, @styleManager,
|
||||
@commandRegistry, @keymapManager, @devMode, @notificationManager,
|
||||
@grammarRegistry, @themeManager, @menuManager, @contextMenuManager
|
||||
}
|
||||
if metadata.theme
|
||||
pack = new ThemePackage(packagePath, metadata)
|
||||
pack = new ThemePackage(options)
|
||||
else
|
||||
pack = new Package(packagePath, metadata)
|
||||
pack = new Package(options)
|
||||
pack.load()
|
||||
@loadedPackages[pack.name] = pack
|
||||
@emitter.emit 'did-load-package', pack
|
||||
@@ -392,7 +416,7 @@ class PackageManager
|
||||
|
||||
activatePackages: (packages) ->
|
||||
promises = []
|
||||
atom.config.transact =>
|
||||
@config.transact =>
|
||||
for pack in packages
|
||||
promise = @activatePackage(pack.name)
|
||||
promises.push(promise) unless pack.hasActivationCommands()
|
||||
@@ -423,7 +447,7 @@ class PackageManager
|
||||
|
||||
# Deactivate all packages
|
||||
deactivatePackages: ->
|
||||
atom.config.transact =>
|
||||
@config.transact =>
|
||||
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
|
||||
return
|
||||
@unobserveDisabledPackages()
|
||||
@@ -443,7 +467,7 @@ class PackageManager
|
||||
detail = "#{error.message} in #{metadataPath}"
|
||||
stack = "#{error.stack}\n at #{metadataPath}:1:1"
|
||||
message = "Failed to load the #{path.basename(packagePath)} package"
|
||||
atom.notifications.addError(message, {stack, detail, dismissable: true})
|
||||
@notificationManager.addError(message, {stack, detail, dismissable: true})
|
||||
|
||||
uninstallDirectory: (directory) ->
|
||||
symlinkPromise = new Promise (resolve) ->
|
||||
@@ -456,3 +480,40 @@ class PackageManager
|
||||
[isSymLink, isDir] = values
|
||||
if not isSymLink and isDir
|
||||
fs.remove directory, ->
|
||||
|
||||
reloadActivePackageStyleSheets: ->
|
||||
for pack in @getActivePackages() when pack.getType() isnt 'theme'
|
||||
pack.reloadStylesheets?()
|
||||
return
|
||||
|
||||
isBundledPackagePath: (packagePath) ->
|
||||
if @devMode
|
||||
return false unless @resourcePath.startsWith("#{process.resourcesPath}#{path.sep}")
|
||||
|
||||
@resourcePathWithTrailingSlash ?= "#{@resourcePath}#{path.sep}"
|
||||
packagePath?.startsWith(@resourcePathWithTrailingSlash)
|
||||
|
||||
loadPackageMetadata: (packagePath, ignoreErrors=false) ->
|
||||
packageName = path.basename(packagePath)
|
||||
if @isBundledPackagePath(packagePath)
|
||||
metadata = @packagesCache[packageName]?.metadata
|
||||
unless metadata?
|
||||
if metadataPath = CSON.resolve(path.join(packagePath, 'package'))
|
||||
try
|
||||
metadata = CSON.readFileSync(metadataPath)
|
||||
@normalizePackageMetadata(metadata)
|
||||
catch error
|
||||
throw error unless ignoreErrors
|
||||
|
||||
metadata ?= {}
|
||||
unless typeof metadata.name is 'string' and metadata.name.length > 0
|
||||
metadata.name = packageName
|
||||
|
||||
metadata
|
||||
|
||||
normalizePackageMetadata: (metadata) ->
|
||||
unless metadata?._id
|
||||
normalizePackageData ?= require 'normalize-package-data'
|
||||
normalizePackageData(metadata)
|
||||
if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string'
|
||||
metadata.repository.url = metadata.repository.url.replace(/^git\+/, '')
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
path = require 'path'
|
||||
normalizePackageData = null
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
async = require 'async'
|
||||
@@ -11,44 +10,10 @@ ModuleCache = require './module-cache'
|
||||
ScopedProperties = require './scoped-properties'
|
||||
BufferedProcess = require './buffered-process'
|
||||
|
||||
packagesCache = require('../package.json')?._atomPackages ? {}
|
||||
|
||||
# Extended: Loads and activates a package's main module and resources such as
|
||||
# stylesheets, keymaps, grammar, editor properties, and menus.
|
||||
module.exports =
|
||||
class Package
|
||||
@isBundledPackagePath: (packagePath) ->
|
||||
if atom.packages.devMode
|
||||
return false unless atom.packages.resourcePath.startsWith("#{process.resourcesPath}#{path.sep}")
|
||||
|
||||
@resourcePathWithTrailingSlash ?= "#{atom.packages.resourcePath}#{path.sep}"
|
||||
packagePath?.startsWith(@resourcePathWithTrailingSlash)
|
||||
|
||||
@normalizeMetadata: (metadata) ->
|
||||
unless metadata?._id
|
||||
normalizePackageData ?= require 'normalize-package-data'
|
||||
normalizePackageData(metadata)
|
||||
if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string'
|
||||
metadata.repository.url = metadata.repository.url.replace(/^git\+/, '')
|
||||
|
||||
@loadMetadata: (packagePath, ignoreErrors=false) ->
|
||||
packageName = path.basename(packagePath)
|
||||
if @isBundledPackagePath(packagePath)
|
||||
metadata = packagesCache[packageName]?.metadata
|
||||
unless metadata?
|
||||
if metadataPath = CSON.resolve(path.join(packagePath, 'package'))
|
||||
try
|
||||
metadata = CSON.readFileSync(metadataPath)
|
||||
@normalizeMetadata(metadata)
|
||||
catch error
|
||||
throw error unless ignoreErrors
|
||||
|
||||
metadata ?= {}
|
||||
unless typeof metadata.name is 'string' and metadata.name.length > 0
|
||||
metadata.name = packageName
|
||||
|
||||
metadata
|
||||
|
||||
keymaps: null
|
||||
menus: null
|
||||
stylesheets: null
|
||||
@@ -64,10 +29,16 @@ class Package
|
||||
Section: Construction
|
||||
###
|
||||
|
||||
constructor: (@path, @metadata) ->
|
||||
constructor: (params) ->
|
||||
{
|
||||
@path, @metadata, @packageManager, @config, @styleManager, @commandRegistry,
|
||||
@keymapManager, @devMode, @notificationManager, @grammarRegistry, @themeManager,
|
||||
@menuManager, @contextMenuManager
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@metadata ?= Package.loadMetadata(@path)
|
||||
@bundledPackage = Package.isBundledPackagePath(@path)
|
||||
@metadata ?= @packageManager.loadPackageMetadata(@path)
|
||||
@bundledPackage = @packageManager.isBundledPackagePath(@path)
|
||||
@name = @metadata?.name ? path.basename(@path)
|
||||
ModuleCache.add(@path, @metadata)
|
||||
@reset()
|
||||
@@ -89,10 +60,10 @@ class Package
|
||||
###
|
||||
|
||||
enable: ->
|
||||
atom.config.removeAtKeyPath('core.disabledPackages', @name)
|
||||
@config.removeAtKeyPath('core.disabledPackages', @name)
|
||||
|
||||
disable: ->
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', @name)
|
||||
@config.pushAtKeyPath('core.disabledPackages', @name)
|
||||
|
||||
isTheme: ->
|
||||
@metadata?.theme?
|
||||
@@ -132,7 +103,6 @@ class Package
|
||||
@activationPromise ?=
|
||||
new Promise (resolve, reject) =>
|
||||
@resolveActivationPromise = resolve
|
||||
@rejectActivationPromise = reject
|
||||
@measure 'activateTime', =>
|
||||
try
|
||||
@activateResources()
|
||||
@@ -150,7 +120,7 @@ class Package
|
||||
@activateConfig()
|
||||
@activateStylesheets()
|
||||
if @mainModule? and not @mainActivated
|
||||
@mainModule.activate?(atom.packages.getPackageState(@name) ? {})
|
||||
@mainModule.activate?(@packageManager.getPackageState(@name) ? {})
|
||||
@mainActivated = true
|
||||
@activateServices()
|
||||
catch error
|
||||
@@ -164,7 +134,7 @@ class Package
|
||||
@requireMainModule() unless @mainModule?
|
||||
if @mainModule?
|
||||
if @mainModule.config? and typeof @mainModule.config is 'object'
|
||||
atom.config.setSchema @name, {type: 'object', properties: @mainModule.config}
|
||||
@config.setSchema @name, {type: 'object', properties: @mainModule.config}
|
||||
@mainModule.activateConfig?()
|
||||
@configActivated = true
|
||||
|
||||
@@ -182,13 +152,13 @@ class Package
|
||||
else
|
||||
context = undefined
|
||||
|
||||
@stylesheetDisposables.add(atom.styles.addStyleSheet(source, {sourcePath, priority, context}))
|
||||
@stylesheetDisposables.add(@styleManager.addStyleSheet(source, {sourcePath, priority, context}))
|
||||
@stylesheetsActivated = true
|
||||
|
||||
activateResources: ->
|
||||
@activationDisposables = new CompositeDisposable
|
||||
|
||||
keymapIsDisabled = _.include(atom.config.get("core.packagesWithKeymapsDisabled") ? [], @name)
|
||||
keymapIsDisabled = _.include(@config.get("core.packagesWithKeymapsDisabled") ? [], @name)
|
||||
if keymapIsDisabled
|
||||
@deactivateKeymaps()
|
||||
else
|
||||
@@ -197,14 +167,14 @@ class Package
|
||||
for [menuPath, map] in @menus when map['context-menu']?
|
||||
try
|
||||
itemsBySelector = map['context-menu']
|
||||
@activationDisposables.add(atom.contextMenu.add(itemsBySelector))
|
||||
@activationDisposables.add(@contextMenuManager.add(itemsBySelector))
|
||||
catch error
|
||||
if error.code is 'EBADSELECTOR'
|
||||
error.message += " in #{menuPath}"
|
||||
error.stack += "\n at #{menuPath}:1:1"
|
||||
throw error
|
||||
|
||||
@activationDisposables.add(atom.menu.add(map['menu'])) for [menuPath, map] in @menus when map['menu']?
|
||||
@activationDisposables.add(@menuManager.add(map['menu'])) for [menuPath, map] in @menus when map['menu']?
|
||||
|
||||
unless @grammarsActivated
|
||||
grammar.activate() for grammar in @grammars
|
||||
@@ -218,8 +188,8 @@ class Package
|
||||
|
||||
@keymapDisposables = new CompositeDisposable()
|
||||
|
||||
@keymapDisposables.add(atom.keymaps.add(keymapPath, map)) for [keymapPath, map] in @keymaps
|
||||
atom.menu.update()
|
||||
@keymapDisposables.add(@keymapManager.add(keymapPath, map)) for [keymapPath, map] in @keymaps
|
||||
@menuManager.update()
|
||||
|
||||
@keymapActivated = true
|
||||
|
||||
@@ -227,7 +197,7 @@ class Package
|
||||
return if not @keymapActivated
|
||||
|
||||
@keymapDisposables?.dispose()
|
||||
atom.menu.update()
|
||||
@menuManager.update()
|
||||
|
||||
@keymapActivated = false
|
||||
|
||||
@@ -243,24 +213,24 @@ class Package
|
||||
for version, methodName of versions
|
||||
if typeof @mainModule[methodName] is 'function'
|
||||
servicesByVersion[version] = @mainModule[methodName]()
|
||||
@activationDisposables.add atom.packages.serviceHub.provide(name, servicesByVersion)
|
||||
@activationDisposables.add @packageManager.serviceHub.provide(name, servicesByVersion)
|
||||
|
||||
for name, {versions} of @metadata.consumedServices
|
||||
for version, methodName of versions
|
||||
if typeof @mainModule[methodName] is 'function'
|
||||
@activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule))
|
||||
@activationDisposables.add @packageManager.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule))
|
||||
return
|
||||
|
||||
loadKeymaps: ->
|
||||
if @bundledPackage and packagesCache[@name]?
|
||||
@keymaps = (["#{atom.packages.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of packagesCache[@name].keymaps)
|
||||
if @bundledPackage and @packageManager.packagesCache[@name]?
|
||||
@keymaps = (["#{@packageManager.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of @packageManager.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)
|
||||
if @bundledPackage and @packageManager.packagesCache[@name]?
|
||||
@menus = (["#{@packageManager.resourcePath}#{path.sep}#{menuPath}", menuObject] for menuPath, menuObject of @packageManager.packagesCache[@name].menus)
|
||||
else
|
||||
@menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath) ? {}]
|
||||
return
|
||||
@@ -280,8 +250,8 @@ class Package
|
||||
fs.listSync(menusDirPath, ['cson', 'json'])
|
||||
|
||||
loadStylesheets: ->
|
||||
@stylesheets = @getStylesheetPaths().map (stylesheetPath) ->
|
||||
[stylesheetPath, atom.themes.loadStylesheet(stylesheetPath, true)]
|
||||
@stylesheets = @getStylesheetPaths().map (stylesheetPath) =>
|
||||
[stylesheetPath, @themeManager.loadStylesheet(stylesheetPath, true)]
|
||||
|
||||
getStylesheetsPath: ->
|
||||
path.join(@path, 'styles')
|
||||
@@ -304,7 +274,7 @@ class Package
|
||||
grammarPaths = fs.listSync(grammarsDirPath, ['json', 'cson'])
|
||||
for grammarPath in grammarPaths
|
||||
try
|
||||
grammar = atom.grammars.readGrammarSync(grammarPath)
|
||||
grammar = @grammarRegistry.readGrammarSync(grammarPath)
|
||||
grammar.packageName = @name
|
||||
grammar.bundledPackage = @bundledPackage
|
||||
@grammars.push(grammar)
|
||||
@@ -319,11 +289,11 @@ class Package
|
||||
return Promise.resolve() if @grammarsLoaded
|
||||
|
||||
loadGrammar = (grammarPath, callback) =>
|
||||
atom.grammars.readGrammar grammarPath, (error, grammar) =>
|
||||
@grammarRegistry.readGrammar grammarPath, (error, grammar) =>
|
||||
if error?
|
||||
detail = "#{error.message} in #{grammarPath}"
|
||||
stack = "#{error.stack}\n at #{grammarPath}:1:1"
|
||||
atom.notifications.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, dismissable: true})
|
||||
@notificationManager.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, dismissable: true})
|
||||
else
|
||||
grammar.packageName = @name
|
||||
grammar.bundledPackage = @bundledPackage
|
||||
@@ -343,11 +313,11 @@ class Package
|
||||
@settings = []
|
||||
|
||||
loadSettingsFile = (settingsPath, callback) =>
|
||||
ScopedProperties.load settingsPath, (error, settings) =>
|
||||
ScopedProperties.load settingsPath, @config, (error, settings) =>
|
||||
if error?
|
||||
detail = "#{error.message} in #{settingsPath}"
|
||||
stack = "#{error.stack}\n at #{settingsPath}:1:1"
|
||||
atom.notifications.addFatalError("Failed to load the #{@name} package settings", {stack, detail, dismissable: true})
|
||||
@notificationManager.addFatalError("Failed to load the #{@name} package settings", {stack, detail, dismissable: true})
|
||||
else
|
||||
@settings.push(settings)
|
||||
settings.activate() if @settingsActivated
|
||||
@@ -370,10 +340,8 @@ class Package
|
||||
console.error "Error serializing package '#{@name}'", e.stack
|
||||
|
||||
deactivate: ->
|
||||
@rejectActivationPromise?()
|
||||
@activationPromise = null
|
||||
@resolveActivationPromise = null
|
||||
@rejectActivationPromise = null
|
||||
@activationCommandSubscriptions?.dispose()
|
||||
@deactivateResources()
|
||||
@deactivateConfig()
|
||||
@@ -430,9 +398,9 @@ class Package
|
||||
return @mainModulePath if @resolvedMainModulePath
|
||||
@resolvedMainModulePath = true
|
||||
|
||||
if @bundledPackage and packagesCache[@name]?
|
||||
if packagesCache[@name].main
|
||||
@mainModulePath = "#{atom.packages.resourcePath}#{path.sep}#{packagesCache[@name].main}"
|
||||
if @bundledPackage and @packageManager.packagesCache[@name]?
|
||||
if @packageManager.packagesCache[@name].main
|
||||
@mainModulePath = "#{@packageManager.resourcePath}#{path.sep}#{@packageManager.packagesCache[@name].main}"
|
||||
else
|
||||
@mainModulePath = null
|
||||
else
|
||||
@@ -466,7 +434,7 @@ class Package
|
||||
# Add dummy command so it appears in menu.
|
||||
# The real command will be registered on package activation
|
||||
try
|
||||
@activationCommandSubscriptions.add atom.commands.add selector, command, ->
|
||||
@activationCommandSubscriptions.add @commandRegistry.add selector, command, ->
|
||||
catch error
|
||||
if error.code is 'EBADSELECTOR'
|
||||
metadataPath = path.join(@path, 'package.json')
|
||||
@@ -474,7 +442,7 @@ class Package
|
||||
error.stack += "\n at #{metadataPath}:1:1"
|
||||
throw error
|
||||
|
||||
@activationCommandSubscriptions.add atom.commands.onWillDispatch (event) =>
|
||||
@activationCommandSubscriptions.add @commandRegistry.onWillDispatch (event) =>
|
||||
return unless event.type is command
|
||||
currentTarget = event.target
|
||||
while currentTarget
|
||||
@@ -505,7 +473,7 @@ class Package
|
||||
@activationHookSubscriptions = new CompositeDisposable
|
||||
for hook in @getActivationHooks()
|
||||
do (hook) =>
|
||||
@activationHookSubscriptions.add(atom.packages.onDidTriggerActivationHook(hook, => @activateNow())) if hook? and _.isString(hook) and hook.trim().length > 0
|
||||
@activationHookSubscriptions.add(@packageManager.onDidTriggerActivationHook(hook, => @activateNow())) if hook? and _.isString(hook) and hook.trim().length > 0
|
||||
|
||||
return
|
||||
|
||||
@@ -567,7 +535,7 @@ class Package
|
||||
isCompatible: ->
|
||||
return @compatible if @compatible?
|
||||
|
||||
if @path.indexOf(path.join(atom.packages.resourcePath, 'node_modules') + path.sep) is 0
|
||||
if @path.indexOf(path.join(@packageManager.resourcePath, 'node_modules') + path.sep) is 0
|
||||
# Bundled packages are always considered compatible
|
||||
@compatible = true
|
||||
else if @getMainModulePath()
|
||||
@@ -603,7 +571,7 @@ class Package
|
||||
stderr = ''
|
||||
stdout = ''
|
||||
new BufferedProcess({
|
||||
command: atom.packages.getApmPath()
|
||||
command: @packageManager.getApmPath()
|
||||
args: ['rebuild', '--no-color']
|
||||
options: {cwd: @path}
|
||||
stderr: (output) -> stderr += output
|
||||
@@ -625,7 +593,7 @@ class Package
|
||||
# This information is cached in local storage on a per package/version basis
|
||||
# to minimize the impact on startup time.
|
||||
getIncompatibleNativeModules: ->
|
||||
unless atom.inDevMode()
|
||||
unless @devMode
|
||||
try
|
||||
if arrayAsString = global.localStorage.getItem(@getIncompatibleNativeModulesStorageKey())
|
||||
return JSON.parse(arrayAsString)
|
||||
@@ -666,4 +634,4 @@ class Package
|
||||
detail = error.message
|
||||
stack = error.stack ? error
|
||||
|
||||
atom.notifications.addFatalError(message, {stack, detail, dismissable: true})
|
||||
@notificationManager.addFatalError(message, {stack, detail, dismissable: true})
|
||||
|
||||
@@ -8,7 +8,9 @@ class PaneAxisElement extends HTMLElement
|
||||
detachedCallback: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
initialize: (@model) ->
|
||||
initialize: (@model, {@views}) ->
|
||||
throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views?
|
||||
|
||||
@subscriptions.add @model.onDidAddChild(@childAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this))
|
||||
@@ -27,7 +29,7 @@ class PaneAxisElement extends HTMLElement
|
||||
element?.nodeName.toLowerCase() is 'atom-pane-resize-handle'
|
||||
|
||||
childAdded: ({child, index}) ->
|
||||
view = atom.views.getView(child)
|
||||
view = @views.getView(child)
|
||||
@insertBefore(view, @children[index * 2])
|
||||
|
||||
prevElement = view.previousSibling
|
||||
@@ -43,7 +45,7 @@ class PaneAxisElement extends HTMLElement
|
||||
@insertBefore(resizeHandle, nextElement)
|
||||
|
||||
childRemoved: ({child}) ->
|
||||
view = atom.views.getView(child)
|
||||
view = @views.getView(child)
|
||||
siblingView = view.previousSibling
|
||||
# make sure next sibling view is pane resize view
|
||||
if siblingView? and @isPaneResizeHandleElement(siblingView)
|
||||
|
||||
@@ -4,19 +4,16 @@ Model = require './model'
|
||||
|
||||
module.exports =
|
||||
class PaneAxis extends Model
|
||||
atom.deserializers.add(this)
|
||||
|
||||
parent: null
|
||||
container: null
|
||||
orientation: null
|
||||
|
||||
@deserialize: (state, params) ->
|
||||
container = params?.container
|
||||
state.container = container
|
||||
state.children = state.children.map (childState) -> atom.deserializers.deserialize(childState, {container})
|
||||
@deserialize: (state, {deserializers}) ->
|
||||
state.children = state.children.map (childState) ->
|
||||
deserializers.deserialize(childState)
|
||||
new this(state)
|
||||
|
||||
constructor: ({@container, @orientation, children, flexScale}={}) ->
|
||||
constructor: ({@orientation, children, flexScale}={}) ->
|
||||
@emitter = new Emitter
|
||||
@subscriptionsByChild = new WeakMap
|
||||
@subscriptions = new CompositeDisposable
|
||||
@@ -43,7 +40,10 @@ class PaneAxis extends Model
|
||||
|
||||
getContainer: -> @container
|
||||
|
||||
setContainer: (@container) -> @container
|
||||
setContainer: (container) ->
|
||||
if container and container isnt @container
|
||||
@container = container
|
||||
child.setContainer(container) for child in @children
|
||||
|
||||
getOrientation: -> @orientation
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ class PaneContainerElement extends HTMLElement
|
||||
@subscriptions = new CompositeDisposable
|
||||
@classList.add 'panes'
|
||||
|
||||
initialize: (@model) ->
|
||||
initialize: (@model, {@views}) ->
|
||||
throw new Error("Must pass a views parameter when initializing PaneContainerElements") unless @views?
|
||||
|
||||
@subscriptions.add @model.observeRoot(@rootChanged.bind(this))
|
||||
this
|
||||
|
||||
@@ -15,7 +17,7 @@ class PaneContainerElement extends HTMLElement
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@firstChild?.remove()
|
||||
if root?
|
||||
view = atom.views.getView(root)
|
||||
view = @views.getView(root)
|
||||
@appendChild(view)
|
||||
focusedElement?.focus()
|
||||
|
||||
@@ -40,7 +42,7 @@ class PaneContainerElement extends HTMLElement
|
||||
y = pointB.y - pointA.y
|
||||
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
|
||||
paneView = atom.views.getView(@model.getActivePane())
|
||||
paneView = @views.getView(@model.getActivePane())
|
||||
box = @boundingBoxForPaneView(paneView)
|
||||
|
||||
paneViews = _.toArray(@querySelectorAll('atom-pane'))
|
||||
|
||||
@@ -7,46 +7,37 @@ ItemRegistry = require './item-registry'
|
||||
|
||||
module.exports =
|
||||
class PaneContainer extends Model
|
||||
atom.deserializers.add(this)
|
||||
|
||||
@version: 1
|
||||
|
||||
serializationVersion: 1
|
||||
root: null
|
||||
stoppedChangingActivePaneItemDelay: 100
|
||||
stoppedChangingActivePaneItemTimeout: null
|
||||
|
||||
@deserialize: (state) ->
|
||||
container = Object.create(@prototype) # allows us to pass a self reference to our child before invoking constructor
|
||||
state.root = atom.deserializers.deserialize(state.root, {container})
|
||||
state.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
||||
state.activePane = find state.root.getPanes(), (pane) -> pane.id is state.activePaneId
|
||||
@call(container, state) # run constructor
|
||||
container
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@activePane = params?.activePane
|
||||
|
||||
{@config, applicationDelegate, notificationManager, deserializerManager} = params
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@itemRegistry = new ItemRegistry
|
||||
|
||||
@setRoot(params?.root ? new Pane)
|
||||
@setActivePane(@getPanes()[0]) unless @getActivePane()
|
||||
|
||||
@destroyEmptyPanes() if params?.destroyEmptyPanes
|
||||
|
||||
@setRoot(new Pane({container: this, @config, applicationDelegate, notificationManager, deserializerManager}))
|
||||
@setActivePane(@getRoot())
|
||||
@monitorActivePaneItem()
|
||||
@monitorPaneItems()
|
||||
|
||||
serialize: (params) ->
|
||||
deserializer: 'PaneContainer'
|
||||
version: @constructor.version
|
||||
version: @serializationVersion
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
deserialize: (state, deserializerManager) ->
|
||||
return unless state.version is @serializationVersion
|
||||
@setRoot(deserializerManager.deserialize(state.root))
|
||||
activePane = find @getRoot().getPanes(), (pane) -> pane.id is state.activePaneId
|
||||
@setActivePane(activePane ? @getPanes()[0])
|
||||
@destroyEmptyPanes() if @config.get('core.destroyEmptyPanes')
|
||||
|
||||
onDidChangeRoot: (fn) ->
|
||||
@emitter.on 'did-change-root', fn
|
||||
|
||||
|
||||
@@ -44,14 +44,17 @@ class PaneElement extends HTMLElement
|
||||
event.stopPropagation()
|
||||
@getModel().activate()
|
||||
pathsToOpen = Array::map.call event.dataTransfer.files, (file) -> file.path
|
||||
atom.open({pathsToOpen}) if pathsToOpen.length > 0
|
||||
@open({pathsToOpen}) if pathsToOpen.length > 0
|
||||
|
||||
@addEventListener 'focus', handleFocus, true
|
||||
@addEventListener 'blur', handleBlur, true
|
||||
@addEventListener 'dragover', handleDragOver
|
||||
@addEventListener 'drop', handleDrop
|
||||
|
||||
initialize: (@model) ->
|
||||
initialize: (@model, {@views, @open}) ->
|
||||
throw new Error("Must pass a views parameter when initializing PaneElements") unless @views?
|
||||
throw new Error("Must pass a open parameter when initializing PaneElements") unless @open?
|
||||
|
||||
@subscriptions.add @model.onDidActivate(@activated.bind(this))
|
||||
@subscriptions.add @model.observeActive(@activeStatusChanged.bind(this))
|
||||
@subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this))
|
||||
@@ -78,7 +81,7 @@ class PaneElement extends HTMLElement
|
||||
return unless item?
|
||||
|
||||
hasFocus = @hasFocus()
|
||||
itemView = atom.views.getView(item)
|
||||
itemView = @views.getView(item)
|
||||
|
||||
if itemPath = item.getPath?()
|
||||
@dataset.activeItemName = path.basename(itemPath)
|
||||
@@ -109,7 +112,7 @@ class PaneElement extends HTMLElement
|
||||
itemView.style.display = 'none'
|
||||
|
||||
itemRemoved: ({item, index, destroyed}) ->
|
||||
if viewToRemove = atom.views.getView(item)
|
||||
if viewToRemove = @views.getView(item)
|
||||
viewToRemove.remove()
|
||||
|
||||
paneDestroyed: ->
|
||||
@@ -118,35 +121,9 @@ class PaneElement extends HTMLElement
|
||||
flexScaleChanged: (flexScale) ->
|
||||
@style.flexGrow = flexScale
|
||||
|
||||
getActiveView: -> atom.views.getView(@model.getActiveItem())
|
||||
getActiveView: -> @views.getView(@model.getActiveItem())
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
atom.commands.add 'atom-workspace',
|
||||
'pane:show-next-item': -> @getModel().getActivePane().activateNextItem()
|
||||
'pane:show-previous-item': -> @getModel().getActivePane().activatePreviousItem()
|
||||
'pane:show-item-1': -> @getModel().getActivePane().activateItemAtIndex(0)
|
||||
'pane:show-item-2': -> @getModel().getActivePane().activateItemAtIndex(1)
|
||||
'pane:show-item-3': -> @getModel().getActivePane().activateItemAtIndex(2)
|
||||
'pane:show-item-4': -> @getModel().getActivePane().activateItemAtIndex(3)
|
||||
'pane:show-item-5': -> @getModel().getActivePane().activateItemAtIndex(4)
|
||||
'pane:show-item-6': -> @getModel().getActivePane().activateItemAtIndex(5)
|
||||
'pane:show-item-7': -> @getModel().getActivePane().activateItemAtIndex(6)
|
||||
'pane:show-item-8': -> @getModel().getActivePane().activateItemAtIndex(7)
|
||||
'pane:show-item-9': -> @getModel().getActivePane().activateItemAtIndex(8)
|
||||
'pane:move-item-right': -> @getModel().getActivePane().moveItemRight()
|
||||
'pane:move-item-left': -> @getModel().getActivePane().moveItemLeft()
|
||||
|
||||
atom.commands.add 'atom-pane',
|
||||
'pane:save-items': -> @getModel().saveItems()
|
||||
'pane:split-left': -> @getModel().splitLeft(copyActiveItem: true)
|
||||
'pane:split-right': -> @getModel().splitRight(copyActiveItem: true)
|
||||
'pane:split-up': -> @getModel().splitUp(copyActiveItem: true)
|
||||
'pane:split-down': -> @getModel().splitDown(copyActiveItem: true)
|
||||
'pane:close': -> @getModel().close()
|
||||
'pane:close-other-items': -> @getModel().destroyInactiveItems()
|
||||
'pane:increase-size': -> @getModel().increaseSize()
|
||||
'pane:decrease-size': -> @getModel().decreaseSize()
|
||||
|
||||
module.exports = PaneElement = document.registerElement 'atom-pane', prototype: PaneElement.prototype
|
||||
|
||||
@@ -10,30 +10,31 @@ TextEditor = require './text-editor'
|
||||
# the default configuration, tabs are also displayed for each item.
|
||||
module.exports =
|
||||
class Pane extends Model
|
||||
atom.deserializers.add(this)
|
||||
|
||||
container: undefined
|
||||
activeItem: undefined
|
||||
focused: false
|
||||
|
||||
@deserialize: (state, params) ->
|
||||
@deserialize: (state, {deserializers, applicationDelegate, config, notifications}) ->
|
||||
{items, activeItemURI, activeItemUri} = state
|
||||
state.container = params?.container
|
||||
activeItemURI ?= activeItemUri
|
||||
state.items = compact(items.map (itemState) -> atom.deserializers.deserialize(itemState))
|
||||
state.items = compact(items.map (itemState) -> deserializers.deserialize(itemState))
|
||||
state.activeItem = find state.items, (item) ->
|
||||
if typeof item.getURI is 'function'
|
||||
itemURI = item.getURI()
|
||||
itemURI is activeItemURI
|
||||
|
||||
new this(state)
|
||||
new Pane(extend(state, {
|
||||
deserializerManager: deserializers,
|
||||
notificationManager: notifications,
|
||||
config, applicationDelegate
|
||||
}))
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@container = params?.container
|
||||
@activeItem = params?.activeItem
|
||||
@focused = params?.focused
|
||||
{
|
||||
@activeItem, @focused, @applicationDelegate, @notificationManager, @config,
|
||||
@deserializerManager
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@itemSubscriptions = new WeakMap
|
||||
@@ -61,7 +62,7 @@ class Pane extends Model
|
||||
getContainer: -> @container
|
||||
|
||||
setContainer: (container) ->
|
||||
unless container is @container
|
||||
if container and container isnt @container
|
||||
@container = container
|
||||
container.didAddPane({pane: this})
|
||||
|
||||
@@ -395,7 +396,7 @@ class Pane extends Model
|
||||
@items.splice(index, 1)
|
||||
@emitter.emit 'did-remove-item', {item, index, destroyed: not moved, moved}
|
||||
@container?.didDestroyPaneItem({item, index, pane: this}) unless moved
|
||||
@destroy() if @items.length is 0 and atom.config.get('core.destroyEmptyPanes')
|
||||
@destroy() if @items.length is 0 and @config.get('core.destroyEmptyPanes')
|
||||
|
||||
# Public: Move the given item to the given index.
|
||||
#
|
||||
@@ -461,7 +462,7 @@ class Pane extends Model
|
||||
else
|
||||
return true
|
||||
|
||||
chosen = atom.confirm
|
||||
chosen = @applicationDelegate.confirm
|
||||
message: "'#{item.getTitle?() ? uri}' has changes, do you want to save them?"
|
||||
detailedMessage: "Your changes will be lost if you close this item without saving."
|
||||
buttons: ["Save", "Cancel", "Don't Save"]
|
||||
@@ -514,7 +515,7 @@ class Pane extends Model
|
||||
|
||||
saveOptions = item.getSaveDialogOptions?() ? {}
|
||||
saveOptions.defaultPath ?= item.getPath()
|
||||
newItemPath = atom.showSaveDialogSync(saveOptions)
|
||||
newItemPath = @applicationDelegate.showSaveDialog(saveOptions)
|
||||
if newItemPath
|
||||
try
|
||||
item.saveAs(newItemPath)
|
||||
@@ -554,7 +555,7 @@ class Pane extends Model
|
||||
|
||||
copyActiveItem: ->
|
||||
if @activeItem?
|
||||
@activeItem.copy?() ? atom.deserializers.deserialize(@activeItem.serialize())
|
||||
@activeItem.copy?() ? @deserializerManager.deserialize(@activeItem.serialize())
|
||||
|
||||
###
|
||||
Section: Lifecycle
|
||||
@@ -646,7 +647,7 @@ class Pane extends Model
|
||||
@parent.replaceChild(this, new PaneAxis({@container, orientation, children: [this], @flexScale}))
|
||||
@setFlexScale(1)
|
||||
|
||||
newPane = new @constructor(params)
|
||||
newPane = new Pane(extend({@applicationDelegate, @deserializerManager, @config}, params))
|
||||
switch side
|
||||
when 'before' then @parent.insertChildBefore(this, newPane)
|
||||
when 'after' then @parent.insertChildAfter(this, newPane)
|
||||
@@ -688,12 +689,12 @@ class Pane extends Model
|
||||
|
||||
handleSaveError: (error, item) ->
|
||||
itemPath = error.path ? item?.getPath?()
|
||||
addWarningWithPath = (message, options) ->
|
||||
addWarningWithPath = (message, options) =>
|
||||
message = "#{message} '#{itemPath}'" if itemPath
|
||||
atom.notifications.addWarning(message, options)
|
||||
@notificationManager.addWarning(message, options)
|
||||
|
||||
if error.code is 'EISDIR' or error.message?.endsWith?('is a directory')
|
||||
atom.notifications.addWarning("Unable to save file: #{error.message}")
|
||||
@notificationManager.addWarning("Unable to save file: #{error.message}")
|
||||
else if error.code is 'EACCES'
|
||||
addWarningWithPath('Unable to save file: Permission denied')
|
||||
else if error.code in ['EPERM', 'EBUSY', 'UNKNOWN', 'EEXIST']
|
||||
@@ -716,6 +717,6 @@ class Pane extends Model
|
||||
addWarningWithPath('Unable to save file: Invalid seek')
|
||||
else if errorMatch = /ENOTDIR, not a directory '([^']+)'/.exec(error.message)
|
||||
fileName = errorMatch[1]
|
||||
atom.notifications.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to")
|
||||
@notificationManager.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to")
|
||||
else
|
||||
throw error
|
||||
|
||||
@@ -4,7 +4,9 @@ class PanelContainerElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
initialize: (@model) ->
|
||||
initialize: (@model, {@views}) ->
|
||||
throw new Error("Must pass a views parameter when initializing PanelContainerElements") unless @views?
|
||||
|
||||
@subscriptions.add @model.onDidAddPanel(@panelAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemovePanel(@panelRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@destroyed.bind(this))
|
||||
@@ -14,7 +16,7 @@ class PanelContainerElement extends HTMLElement
|
||||
getModel: -> @model
|
||||
|
||||
panelAdded: ({panel, index}) ->
|
||||
panelElement = atom.views.getView(panel)
|
||||
panelElement = @views.getView(panel)
|
||||
panelElement.classList.add(@model.getLocation())
|
||||
if @model.isModal()
|
||||
panelElement.classList.add("overlay", "from-top")
|
||||
@@ -33,7 +35,7 @@ class PanelContainerElement extends HTMLElement
|
||||
@hideAllPanelsExcept(panel) if visible
|
||||
|
||||
panelRemoved: ({panel, index}) ->
|
||||
@removeChild(atom.views.getView(panel))
|
||||
@removeChild(@views.getView(panel))
|
||||
|
||||
destroyed: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
@@ -5,7 +5,9 @@ class PanelElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
initialize: (@model) ->
|
||||
initialize: (@model, {@views}) ->
|
||||
throw new Error("Must pass a views parameter when initializing PanelElements") unless @views?
|
||||
|
||||
@appendChild(@getItemView())
|
||||
|
||||
@classList.add(@model.getClassName().split(' ')...) if @model.getClassName()?
|
||||
@@ -17,7 +19,7 @@ class PanelElement extends HTMLElement
|
||||
@model ?= new Panel
|
||||
|
||||
getItemView: ->
|
||||
atom.views.getView(@getModel().getItem())
|
||||
@views.getView(@getModel().getItem())
|
||||
|
||||
attachedCallback: ->
|
||||
@visibleChanged(@getModel().isVisible())
|
||||
|
||||
@@ -3,7 +3,7 @@ url = require 'url'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
TextBuffer = require 'text-buffer'
|
||||
|
||||
DefaultDirectoryProvider = require './default-directory-provider'
|
||||
@@ -17,68 +17,35 @@ GitRepositoryProvider = require './git-repository-provider'
|
||||
# An instance of this class is always available as the `atom.project` global.
|
||||
module.exports =
|
||||
class Project extends Model
|
||||
atom.deserializers.add(this)
|
||||
|
||||
###
|
||||
Section: Construction and Destruction
|
||||
###
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.buffers = _.compact state.buffers.map (bufferState) ->
|
||||
# Check that buffer's file path is accessible
|
||||
return if fs.isDirectorySync(bufferState.filePath)
|
||||
if bufferState.filePath
|
||||
try
|
||||
fs.closeSync(fs.openSync(bufferState.filePath, 'r'))
|
||||
catch error
|
||||
return unless error.code is 'ENOENT'
|
||||
|
||||
atom.deserializers.deserialize(bufferState)
|
||||
|
||||
new this(state)
|
||||
|
||||
constructor: ({path, paths, @buffers}={}) ->
|
||||
constructor: ({@notificationManager, packageManager, config}) ->
|
||||
@emitter = new Emitter
|
||||
@buffers ?= []
|
||||
@buffers = []
|
||||
@paths = []
|
||||
@rootDirectories = []
|
||||
@repositories = []
|
||||
|
||||
@directoryProviders = []
|
||||
@defaultDirectoryProvider = new DefaultDirectoryProvider()
|
||||
atom.packages.serviceHub.consume(
|
||||
'atom.directory-provider',
|
||||
'^0.1.0',
|
||||
(provider) => @directoryProviders.unshift(provider))
|
||||
|
||||
# Mapping from the real path of a {Directory} to a {Promise} that resolves
|
||||
# to either a {Repository} or null. Ideally, the {Directory} would be used
|
||||
# as the key; however, there can be multiple {Directory} objects created for
|
||||
# the same real path, so it is not a good key.
|
||||
@repositoryPromisesByPath = new Map()
|
||||
|
||||
@repositoryProviders = [new GitRepositoryProvider(this)]
|
||||
atom.packages.serviceHub.consume(
|
||||
'atom.repository-provider',
|
||||
'^0.1.0',
|
||||
(provider) =>
|
||||
@repositoryProviders.push(provider)
|
||||
|
||||
# If a path in getPaths() does not have a corresponding Repository, try
|
||||
# to assign one by running through setPaths() again now that
|
||||
# @repositoryProviders has been updated.
|
||||
if null in @repositories
|
||||
@setPaths(@getPaths())
|
||||
)
|
||||
|
||||
@subscribeToBuffer(buffer) for buffer in @buffers
|
||||
|
||||
paths ?= _.compact([path])
|
||||
@setPaths(paths)
|
||||
@repositoryProviders = [new GitRepositoryProvider(this, config)]
|
||||
@consumeServices(packageManager)
|
||||
|
||||
destroyed: ->
|
||||
buffer.destroy() for buffer in @getBuffers()
|
||||
buffer.destroy() for buffer in @buffers
|
||||
@setPaths([])
|
||||
|
||||
reset: (packageManager) ->
|
||||
@emitter.dispose()
|
||||
@emitter = new Emitter
|
||||
|
||||
buffer?.destroy() for buffer in @buffers
|
||||
@buffers = []
|
||||
@setPaths([])
|
||||
@consumeServices(packageManager)
|
||||
|
||||
destroyUnretainedBuffers: ->
|
||||
buffer.destroy() for buffer in @getBuffers() when not buffer.isRetained()
|
||||
return
|
||||
@@ -87,6 +54,22 @@ class Project extends Model
|
||||
Section: Serialization
|
||||
###
|
||||
|
||||
deserialize: (state, deserializerManager) ->
|
||||
states.paths = [state.path] if state.path? # backward compatibility
|
||||
|
||||
@buffers = _.compact state.buffers.map (bufferState) ->
|
||||
# Check that buffer's file path is accessible
|
||||
return if fs.isDirectorySync(bufferState.filePath)
|
||||
if bufferState.filePath
|
||||
try
|
||||
fs.closeSync(fs.openSync(bufferState.filePath, 'r'))
|
||||
catch error
|
||||
return unless error.code is 'ENOENT'
|
||||
deserializerManager.deserialize(bufferState)
|
||||
|
||||
@subscribeToBuffer(buffer) for buffer in @buffers
|
||||
@setPaths(state.paths)
|
||||
|
||||
serialize: ->
|
||||
deserializer: 'Project'
|
||||
paths: @getPaths()
|
||||
@@ -291,39 +274,25 @@ class Project extends Model
|
||||
Section: Private
|
||||
###
|
||||
|
||||
# Given a path to a file, this constructs and associates a new
|
||||
# {TextEditor}, showing the file.
|
||||
#
|
||||
# * `filePath` The {String} path of the file to associate with.
|
||||
# * `options` Options that you can pass to the {TextEditor} constructor.
|
||||
#
|
||||
# Returns a promise that resolves to an {TextEditor}.
|
||||
open: (filePath, options={}) ->
|
||||
filePath = @resolvePath(filePath)
|
||||
consumeServices: ({serviceHub}) ->
|
||||
serviceHub.consume(
|
||||
'atom.directory-provider',
|
||||
'^0.1.0',
|
||||
(provider) =>
|
||||
@directoryProviders.unshift(provider)
|
||||
new Disposable =>
|
||||
@directoryProviders.splice(@directoryProviders.indexOf(provider), 1)
|
||||
)
|
||||
|
||||
if filePath?
|
||||
try
|
||||
fs.closeSync(fs.openSync(filePath, 'r'))
|
||||
catch error
|
||||
# allow ENOENT errors to create an editor for paths that dont exist
|
||||
throw error unless error.code is 'ENOENT'
|
||||
|
||||
absoluteFilePath = @resolvePath(filePath)
|
||||
|
||||
fileSize = fs.getSizeSync(absoluteFilePath)
|
||||
|
||||
if fileSize >= 20 * 1048576 # 20MB
|
||||
choice = atom.confirm
|
||||
message: 'Atom will be unresponsive during the loading of very large files.'
|
||||
detailedMessage: "Do you still want to load this file?"
|
||||
buttons: ["Proceed", "Cancel"]
|
||||
if choice is 1
|
||||
error = new Error
|
||||
error.code = 'CANCELLED'
|
||||
throw error
|
||||
|
||||
@bufferForPath(absoluteFilePath).then (buffer) =>
|
||||
@buildEditorForBuffer(buffer, _.extend({fileSize}, options))
|
||||
serviceHub.consume(
|
||||
'atom.repository-provider',
|
||||
'^0.1.0',
|
||||
(provider) =>
|
||||
@repositoryProviders.push(provider)
|
||||
@setPaths(@getPaths()) if null in @repositories
|
||||
new Disposable =>
|
||||
@repositoryProviders.splice(@repositoryProviders.indexOf(provider), 1)
|
||||
)
|
||||
|
||||
# Retrieves all the {TextBuffer}s in the project; that is, the
|
||||
# buffers for all open files.
|
||||
@@ -404,11 +373,6 @@ class Project extends Model
|
||||
[buffer] = @buffers.splice(index, 1)
|
||||
buffer?.destroy()
|
||||
|
||||
buildEditorForBuffer: (buffer, editorOptions) ->
|
||||
largeFileMode = editorOptions.fileSize >= 2 * 1048576 # 2MB
|
||||
editor = new TextEditor(_.extend({buffer, largeFileMode, registerEditor: true}, editorOptions))
|
||||
editor
|
||||
|
||||
eachBuffer: (args...) ->
|
||||
subscriber = args.shift() if args.length > 1
|
||||
callback = args.shift()
|
||||
@@ -421,9 +385,9 @@ class Project extends Model
|
||||
|
||||
subscribeToBuffer: (buffer) ->
|
||||
buffer.onDidDestroy => @removeBuffer(buffer)
|
||||
buffer.onWillThrowWatchError ({error, handle}) ->
|
||||
buffer.onWillThrowWatchError ({error, handle}) =>
|
||||
handle()
|
||||
atom.notifications.addWarning """
|
||||
@notificationManager.addWarning """
|
||||
Unable to read file after file `#{error.eventType}` event.
|
||||
Make sure you have permission to access `#{buffer.getPath()}`.
|
||||
""",
|
||||
|
||||
212
src/register-default-commands.coffee
Normal file
212
src/register-default-commands.coffee
Normal file
@@ -0,0 +1,212 @@
|
||||
ipc = require 'ipc'
|
||||
|
||||
module.exports = ({commandRegistry, commandInstaller, config}) ->
|
||||
commandRegistry.add 'atom-workspace',
|
||||
'pane:show-next-item': -> @getModel().getActivePane().activateNextItem()
|
||||
'pane:show-previous-item': -> @getModel().getActivePane().activatePreviousItem()
|
||||
'pane:show-item-1': -> @getModel().getActivePane().activateItemAtIndex(0)
|
||||
'pane:show-item-2': -> @getModel().getActivePane().activateItemAtIndex(1)
|
||||
'pane:show-item-3': -> @getModel().getActivePane().activateItemAtIndex(2)
|
||||
'pane:show-item-4': -> @getModel().getActivePane().activateItemAtIndex(3)
|
||||
'pane:show-item-5': -> @getModel().getActivePane().activateItemAtIndex(4)
|
||||
'pane:show-item-6': -> @getModel().getActivePane().activateItemAtIndex(5)
|
||||
'pane:show-item-7': -> @getModel().getActivePane().activateItemAtIndex(6)
|
||||
'pane:show-item-8': -> @getModel().getActivePane().activateItemAtIndex(7)
|
||||
'pane:show-item-9': -> @getModel().getActivePane().activateItemAtIndex(8)
|
||||
'pane:move-item-right': -> @getModel().getActivePane().moveItemRight()
|
||||
'pane:move-item-left': -> @getModel().getActivePane().moveItemLeft()
|
||||
'window:increase-font-size': -> @getModel().increaseFontSize()
|
||||
'window:decrease-font-size': -> @getModel().decreaseFontSize()
|
||||
'window:reset-font-size': -> @getModel().resetFontSize()
|
||||
'application:about': -> ipc.send('command', 'application:about')
|
||||
'application:show-preferences': -> ipc.send('command', 'application:show-settings')
|
||||
'application:show-settings': -> ipc.send('command', 'application:show-settings')
|
||||
'application:quit': -> ipc.send('command', 'application:quit')
|
||||
'application:hide': -> ipc.send('command', 'application:hide')
|
||||
'application:hide-other-applications': -> ipc.send('command', 'application:hide-other-applications')
|
||||
'application:install-update': -> ipc.send('command', 'application:install-update')
|
||||
'application:unhide-all-applications': -> ipc.send('command', 'application:unhide-all-applications')
|
||||
'application:new-window': -> ipc.send('command', 'application:new-window')
|
||||
'application:new-file': -> ipc.send('command', 'application:new-file')
|
||||
'application:open': -> ipc.send('command', 'application:open')
|
||||
'application:open-file': -> ipc.send('command', 'application:open-file')
|
||||
'application:open-folder': -> ipc.send('command', 'application:open-folder')
|
||||
'application:open-dev': -> ipc.send('command', 'application:open-dev')
|
||||
'application:open-safe': -> ipc.send('command', 'application:open-safe')
|
||||
'application:add-project-folder': -> atom.addProjectFolder()
|
||||
'application:minimize': -> ipc.send('command', 'application:minimize')
|
||||
'application:zoom': -> ipc.send('command', 'application:zoom')
|
||||
'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front')
|
||||
'application:open-your-config': -> ipc.send('command', 'application:open-your-config')
|
||||
'application:open-your-init-script': -> ipc.send('command', 'application:open-your-init-script')
|
||||
'application:open-your-keymap': -> ipc.send('command', 'application:open-your-keymap')
|
||||
'application:open-your-snippets': -> ipc.send('command', 'application:open-your-snippets')
|
||||
'application:open-your-stylesheet': -> ipc.send('command', 'application:open-your-stylesheet')
|
||||
'application:open-license': -> @getModel().openLicense()
|
||||
'window:run-package-specs': -> @runPackageSpecs()
|
||||
'window:focus-next-pane': -> @getModel().activateNextPane()
|
||||
'window:focus-previous-pane': -> @getModel().activatePreviousPane()
|
||||
'window:focus-pane-above': -> @focusPaneViewAbove()
|
||||
'window:focus-pane-below': -> @focusPaneViewBelow()
|
||||
'window:focus-pane-on-left': -> @focusPaneViewOnLeft()
|
||||
'window:focus-pane-on-right': -> @focusPaneViewOnRight()
|
||||
'window:save-all': -> @getModel().saveAll()
|
||||
'window:toggle-invisibles': -> config.set("editor.showInvisibles", not config.get("editor.showInvisibles"))
|
||||
'window:log-deprecation-warnings': -> Grim.logDeprecations()
|
||||
'window:toggle-auto-indent': -> config.set("editor.autoIndent", not config.get("editor.autoIndent"))
|
||||
'pane:reopen-closed-item': -> @getModel().reopenItem()
|
||||
'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane()
|
||||
'core:save': -> @getModel().saveActivePaneItem()
|
||||
'core:save-as': -> @getModel().saveActivePaneItemAs()
|
||||
|
||||
if process.platform is 'darwin'
|
||||
commandRegistry.add 'atom-workspace', 'window:install-shell-commands', ->
|
||||
commandInstaller.installShellCommandsInteractively()
|
||||
|
||||
commandRegistry.add 'atom-pane',
|
||||
'pane:save-items': -> @getModel().saveItems()
|
||||
'pane:split-left': -> @getModel().splitLeft(copyActiveItem: true)
|
||||
'pane:split-right': -> @getModel().splitRight(copyActiveItem: true)
|
||||
'pane:split-up': -> @getModel().splitUp(copyActiveItem: true)
|
||||
'pane:split-down': -> @getModel().splitDown(copyActiveItem: true)
|
||||
'pane:close': -> @getModel().close()
|
||||
'pane:close-other-items': -> @getModel().destroyInactiveItems()
|
||||
'pane:increase-size': -> @getModel().increaseSize()
|
||||
'pane:decrease-size': -> @getModel().decreaseSize()
|
||||
|
||||
commandRegistry.add 'atom-text-editor', stopEventPropagation(
|
||||
'core:undo': -> @undo()
|
||||
'core:redo': -> @redo()
|
||||
'core:move-left': -> @moveLeft()
|
||||
'core:move-right': -> @moveRight()
|
||||
'core:select-left': -> @selectLeft()
|
||||
'core:select-right': -> @selectRight()
|
||||
'core:select-up': -> @selectUp()
|
||||
'core:select-down': -> @selectDown()
|
||||
'core:select-all': -> @selectAll()
|
||||
'editor:select-word': -> @selectWordsContainingCursors()
|
||||
'editor:consolidate-selections': (event) -> event.abortKeyBinding() unless @consolidateSelections()
|
||||
'editor:move-to-beginning-of-next-paragraph': -> @moveToBeginningOfNextParagraph()
|
||||
'editor:move-to-beginning-of-previous-paragraph': -> @moveToBeginningOfPreviousParagraph()
|
||||
'editor:move-to-beginning-of-screen-line': -> @moveToBeginningOfScreenLine()
|
||||
'editor:move-to-beginning-of-line': -> @moveToBeginningOfLine()
|
||||
'editor:move-to-end-of-screen-line': -> @moveToEndOfScreenLine()
|
||||
'editor:move-to-end-of-line': -> @moveToEndOfLine()
|
||||
'editor:move-to-first-character-of-line': -> @moveToFirstCharacterOfLine()
|
||||
'editor:move-to-beginning-of-word': -> @moveToBeginningOfWord()
|
||||
'editor:move-to-end-of-word': -> @moveToEndOfWord()
|
||||
'editor:move-to-beginning-of-next-word': -> @moveToBeginningOfNextWord()
|
||||
'editor:move-to-previous-word-boundary': -> @moveToPreviousWordBoundary()
|
||||
'editor:move-to-next-word-boundary': -> @moveToNextWordBoundary()
|
||||
'editor:move-to-previous-subword-boundary': -> @moveToPreviousSubwordBoundary()
|
||||
'editor:move-to-next-subword-boundary': -> @moveToNextSubwordBoundary()
|
||||
'editor:select-to-beginning-of-next-paragraph': -> @selectToBeginningOfNextParagraph()
|
||||
'editor:select-to-beginning-of-previous-paragraph': -> @selectToBeginningOfPreviousParagraph()
|
||||
'editor:select-to-end-of-line': -> @selectToEndOfLine()
|
||||
'editor:select-to-beginning-of-line': -> @selectToBeginningOfLine()
|
||||
'editor:select-to-end-of-word': -> @selectToEndOfWord()
|
||||
'editor:select-to-beginning-of-word': -> @selectToBeginningOfWord()
|
||||
'editor:select-to-beginning-of-next-word': -> @selectToBeginningOfNextWord()
|
||||
'editor:select-to-next-word-boundary': -> @selectToNextWordBoundary()
|
||||
'editor:select-to-previous-word-boundary': -> @selectToPreviousWordBoundary()
|
||||
'editor:select-to-next-subword-boundary': -> @selectToNextSubwordBoundary()
|
||||
'editor:select-to-previous-subword-boundary': -> @selectToPreviousSubwordBoundary()
|
||||
'editor:select-to-first-character-of-line': -> @selectToFirstCharacterOfLine()
|
||||
'editor:select-line': -> @selectLinesContainingCursors()
|
||||
)
|
||||
|
||||
commandRegistry.add 'atom-text-editor', stopEventPropagationAndGroupUndo(config,
|
||||
'core:backspace': -> @backspace()
|
||||
'core:delete': -> @delete()
|
||||
'core:cut': -> @cutSelectedText()
|
||||
'core:copy': -> @copySelectedText()
|
||||
'core:paste': -> @pasteText()
|
||||
'editor:delete-to-previous-word-boundary': -> @deleteToPreviousWordBoundary()
|
||||
'editor:delete-to-next-word-boundary': -> @deleteToNextWordBoundary()
|
||||
'editor:delete-to-beginning-of-word': -> @deleteToBeginningOfWord()
|
||||
'editor:delete-to-beginning-of-line': -> @deleteToBeginningOfLine()
|
||||
'editor:delete-to-end-of-line': -> @deleteToEndOfLine()
|
||||
'editor:delete-to-end-of-word': -> @deleteToEndOfWord()
|
||||
'editor:delete-to-beginning-of-subword': -> @deleteToBeginningOfSubword()
|
||||
'editor:delete-to-end-of-subword': -> @deleteToEndOfSubword()
|
||||
'editor:delete-line': -> @deleteLine()
|
||||
'editor:cut-to-end-of-line': -> @cutToEndOfLine()
|
||||
'editor:cut-to-end-of-buffer-line': -> @cutToEndOfBufferLine()
|
||||
'editor:transpose': -> @transpose()
|
||||
'editor:upper-case': -> @upperCase()
|
||||
'editor:lower-case': -> @lowerCase()
|
||||
'editor:copy-selection': -> @copyOnlySelectedText()
|
||||
)
|
||||
|
||||
commandRegistry.add 'atom-text-editor:not([mini])', stopEventPropagation(
|
||||
'core:move-up': -> @moveUp()
|
||||
'core:move-down': -> @moveDown()
|
||||
'core:move-to-top': -> @moveToTop()
|
||||
'core:move-to-bottom': -> @moveToBottom()
|
||||
'core:page-up': -> @pageUp()
|
||||
'core:page-down': -> @pageDown()
|
||||
'core:select-to-top': -> @selectToTop()
|
||||
'core:select-to-bottom': -> @selectToBottom()
|
||||
'core:select-page-up': -> @selectPageUp()
|
||||
'core:select-page-down': -> @selectPageDown()
|
||||
'editor:add-selection-below': -> @addSelectionBelow()
|
||||
'editor:add-selection-above': -> @addSelectionAbove()
|
||||
'editor:split-selections-into-lines': -> @splitSelectionsIntoLines()
|
||||
'editor:toggle-soft-tabs': -> @toggleSoftTabs()
|
||||
'editor:toggle-soft-wrap': -> @toggleSoftWrapped()
|
||||
'editor:fold-all': -> @foldAll()
|
||||
'editor:unfold-all': -> @unfoldAll()
|
||||
'editor:fold-current-row': -> @foldCurrentRow()
|
||||
'editor:unfold-current-row': -> @unfoldCurrentRow()
|
||||
'editor:fold-selection': -> @foldSelectedLines()
|
||||
'editor:fold-at-indent-level-1': -> @foldAllAtIndentLevel(0)
|
||||
'editor:fold-at-indent-level-2': -> @foldAllAtIndentLevel(1)
|
||||
'editor:fold-at-indent-level-3': -> @foldAllAtIndentLevel(2)
|
||||
'editor:fold-at-indent-level-4': -> @foldAllAtIndentLevel(3)
|
||||
'editor:fold-at-indent-level-5': -> @foldAllAtIndentLevel(4)
|
||||
'editor:fold-at-indent-level-6': -> @foldAllAtIndentLevel(5)
|
||||
'editor:fold-at-indent-level-7': -> @foldAllAtIndentLevel(6)
|
||||
'editor:fold-at-indent-level-8': -> @foldAllAtIndentLevel(7)
|
||||
'editor:fold-at-indent-level-9': -> @foldAllAtIndentLevel(8)
|
||||
'editor:log-cursor-scope': -> @logCursorScope()
|
||||
'editor:copy-path': -> @copyPathToClipboard()
|
||||
'editor:toggle-indent-guide': -> config.set('editor.showIndentGuide', not config.get('editor.showIndentGuide'))
|
||||
'editor:toggle-line-numbers': -> config.set('editor.showLineNumbers', not config.get('editor.showLineNumbers'))
|
||||
'editor:scroll-to-cursor': -> @scrollToCursorPosition()
|
||||
)
|
||||
|
||||
commandRegistry.add 'atom-text-editor:not([mini])', stopEventPropagationAndGroupUndo(config,
|
||||
'editor:indent': -> @indent()
|
||||
'editor:auto-indent': -> @autoIndentSelectedRows()
|
||||
'editor:indent-selected-rows': -> @indentSelectedRows()
|
||||
'editor:outdent-selected-rows': -> @outdentSelectedRows()
|
||||
'editor:newline': -> @insertNewline()
|
||||
'editor:newline-below': -> @insertNewlineBelow()
|
||||
'editor:newline-above': -> @insertNewlineAbove()
|
||||
'editor:toggle-line-comments': -> @toggleLineCommentsInSelection()
|
||||
'editor:checkout-head-revision': -> @checkoutHeadRevision()
|
||||
'editor:move-line-up': -> @moveLineUp()
|
||||
'editor:move-line-down': -> @moveLineDown()
|
||||
'editor:duplicate-lines': -> @duplicateLines()
|
||||
'editor:join-lines': -> @joinLines()
|
||||
)
|
||||
|
||||
stopEventPropagation = (commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
do (commandListener) ->
|
||||
newCommandListeners[commandName] = (event) ->
|
||||
event.stopPropagation()
|
||||
commandListener.call(@getModel(), event)
|
||||
newCommandListeners
|
||||
|
||||
stopEventPropagationAndGroupUndo = (config, commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
do (commandListener) ->
|
||||
newCommandListeners[commandName] = (event) ->
|
||||
event.stopPropagation()
|
||||
model = @getModel()
|
||||
model.transact config.get('editor.undoGroupingInterval'), ->
|
||||
commandListener.call(model, event)
|
||||
newCommandListeners
|
||||
@@ -3,21 +3,21 @@ CSON = require 'season'
|
||||
|
||||
module.exports =
|
||||
class ScopedProperties
|
||||
@load: (scopedPropertiesPath, callback) ->
|
||||
@load: (scopedPropertiesPath, config, callback) ->
|
||||
CSON.readFile scopedPropertiesPath, (error, scopedProperties={}) ->
|
||||
if error?
|
||||
callback(error)
|
||||
else
|
||||
callback(null, new ScopedProperties(scopedPropertiesPath, scopedProperties))
|
||||
callback(null, new ScopedProperties(scopedPropertiesPath, scopedProperties, config))
|
||||
|
||||
constructor: (@path, @scopedProperties) ->
|
||||
constructor: (@path, @scopedProperties, @config) ->
|
||||
|
||||
activate: ->
|
||||
for selector, properties of @scopedProperties
|
||||
atom.config.set(null, properties, scopeSelector: selector, source: @path)
|
||||
@config.set(null, properties, scopeSelector: selector, source: @path)
|
||||
return
|
||||
|
||||
deactivate: ->
|
||||
for selector of @scopedProperties
|
||||
atom.config.unset(null, scopeSelector: selector, source: @path)
|
||||
@config.unset(null, scopeSelector: selector, source: @path)
|
||||
return
|
||||
|
||||
@@ -14,7 +14,7 @@ class Selection extends Model
|
||||
initialScreenRange: null
|
||||
wordwise: false
|
||||
|
||||
constructor: ({@cursor, @marker, @editor, id}) ->
|
||||
constructor: ({@cursor, @marker, @editor, id, @clipboard}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@assignId(id)
|
||||
@@ -611,7 +611,7 @@ class Selection extends Model
|
||||
startLevel = @editor.indentLevelForLine(precedingText)
|
||||
|
||||
if maintainClipboard
|
||||
{text: clipboardText, metadata} = atom.clipboard.readWithMetadata()
|
||||
{text: clipboardText, metadata} = @clipboard.readWithMetadata()
|
||||
metadata ?= {}
|
||||
unless metadata.selections?
|
||||
metadata.selections = [{
|
||||
@@ -624,9 +624,9 @@ class Selection extends Model
|
||||
indentBasis: startLevel,
|
||||
fullLine: fullLine
|
||||
})
|
||||
atom.clipboard.write([clipboardText, selectionText].join("\n"), metadata)
|
||||
@clipboard.write([clipboardText, selectionText].join("\n"), metadata)
|
||||
else
|
||||
atom.clipboard.write(selectionText, {
|
||||
@clipboard.write(selectionText, {
|
||||
indentBasis: startLevel,
|
||||
fullLine: fullLine
|
||||
})
|
||||
|
||||
@@ -4,12 +4,16 @@ fs = require "fs-plus"
|
||||
module.exports =
|
||||
class StorageFolder
|
||||
constructor: (containingPath) ->
|
||||
@path = path.join(containingPath, "storage")
|
||||
@path = path.join(containingPath, "storage") if containingPath?
|
||||
|
||||
store: (name, object) ->
|
||||
return unless @path?
|
||||
|
||||
fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8')
|
||||
|
||||
load: (name) ->
|
||||
return unless @path?
|
||||
|
||||
statePath = @pathForKey(name)
|
||||
try
|
||||
stateString = fs.readFileSync(statePath, 'utf8')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
StylesElement = require './styles-element'
|
||||
|
||||
# Extended: A singleton instance of this class available via `atom.styles`,
|
||||
# which you can use to globally query and observe the set of active style
|
||||
@@ -9,7 +10,7 @@ path = require 'path'
|
||||
# which clone and attach style elements in different contexts.
|
||||
module.exports =
|
||||
class StyleManager
|
||||
constructor: ->
|
||||
constructor: ({@configDirPath}) ->
|
||||
@emitter = new Emitter
|
||||
@styleElements = []
|
||||
@styleElementsBySourcePath = {}
|
||||
@@ -154,6 +155,11 @@ class StyleManager
|
||||
|
||||
return
|
||||
|
||||
buildStylesElement: ->
|
||||
stylesElement = new StylesElement
|
||||
stylesElement.initialize(this)
|
||||
stylesElement
|
||||
|
||||
###
|
||||
Section: Paths
|
||||
###
|
||||
@@ -162,8 +168,10 @@ class StyleManager
|
||||
#
|
||||
# Returns a {String}.
|
||||
getUserStyleSheetPath: ->
|
||||
stylesheetPath = fs.resolve(path.join(atom.getConfigDirPath(), 'styles'), ['css', 'less'])
|
||||
return "" unless @configDirPath?
|
||||
|
||||
stylesheetPath = fs.resolve(path.join(@configDirPath, 'styles'), ['css', 'less'])
|
||||
if fs.isFileSync(stylesheetPath)
|
||||
stylesheetPath
|
||||
else
|
||||
path.join(atom.getConfigDirPath(), 'styles.less')
|
||||
path.join(@configDirPath, 'styles.less')
|
||||
|
||||
@@ -14,6 +14,7 @@ class StylesElement extends HTMLElement
|
||||
@emitter.on 'did-update-style-element', callback
|
||||
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@emitter = new Emitter
|
||||
@styleElementClonesByOriginalElement = new WeakMap
|
||||
|
||||
@@ -21,31 +22,29 @@ class StylesElement extends HTMLElement
|
||||
if @context is 'atom-text-editor'
|
||||
for styleElement in @children
|
||||
@upgradeDeprecatedSelectors(styleElement)
|
||||
@initialize()
|
||||
|
||||
@context = @getAttribute('context') ? undefined
|
||||
|
||||
detachedCallback: ->
|
||||
@subscriptions.dispose()
|
||||
@subscriptions = null
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
attributeChangedCallback: (attrName, oldVal, newVal) ->
|
||||
@contextChanged() if attrName is 'context'
|
||||
|
||||
initialize: ->
|
||||
return if @subscriptions?
|
||||
initialize: (@styleManager) ->
|
||||
throw new Error("Must pass a styleManager parameter when initializing a StylesElement") unless @styleManager?
|
||||
|
||||
@subscriptions = new CompositeDisposable
|
||||
@context = @getAttribute('context') ? undefined
|
||||
|
||||
@subscriptions.add atom.styles.observeStyleElements(@styleElementAdded.bind(this))
|
||||
@subscriptions.add atom.styles.onDidRemoveStyleElement(@styleElementRemoved.bind(this))
|
||||
@subscriptions.add atom.styles.onDidUpdateStyleElement(@styleElementUpdated.bind(this))
|
||||
@subscriptions.add @styleManager.observeStyleElements(@styleElementAdded.bind(this))
|
||||
@subscriptions.add @styleManager.onDidRemoveStyleElement(@styleElementRemoved.bind(this))
|
||||
@subscriptions.add @styleManager.onDidUpdateStyleElement(@styleElementUpdated.bind(this))
|
||||
|
||||
contextChanged: ->
|
||||
return unless @subscriptions?
|
||||
|
||||
@styleElementRemoved(child) for child in Array::slice.call(@children)
|
||||
@context = @getAttribute('context')
|
||||
@styleElementAdded(styleElement) for styleElement in atom.styles.getStyleElements()
|
||||
@styleElementAdded(styleElement) for styleElement in @styleManager.getStyleElements()
|
||||
return
|
||||
|
||||
styleElementAdded: (styleElement) ->
|
||||
|
||||
@@ -38,15 +38,15 @@ class TextEditorComponent
|
||||
Object.defineProperty @prototype, "domNode",
|
||||
get: -> @domNodeValue
|
||||
set: (domNode) ->
|
||||
atom.assert domNode?, "TextEditorComponent::domNode was set to null."
|
||||
@assert domNode?, "TextEditorComponent::domNode was set to null."
|
||||
@domNodeValue = domNode
|
||||
|
||||
constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize}) ->
|
||||
constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars}) ->
|
||||
@tileSize = tileSize if tileSize?
|
||||
@disposables = new CompositeDisposable
|
||||
|
||||
@observeConfig()
|
||||
@setScrollSensitivity(atom.config.get('editor.scrollSensitivity'))
|
||||
@setScrollSensitivity(@config.get('editor.scrollSensitivity'))
|
||||
|
||||
@presenter = new TextEditorPresenter
|
||||
model: @editor
|
||||
@@ -58,6 +58,7 @@ class TextEditorComponent
|
||||
cursorBlinkPeriod: @cursorBlinkPeriod
|
||||
cursorBlinkResumeDelay: @cursorBlinkResumeDelay
|
||||
stoppedScrollingDelay: 200
|
||||
config: @config
|
||||
|
||||
@presenter.onDidUpdateState(@requestUpdate)
|
||||
|
||||
@@ -70,10 +71,10 @@ class TextEditorComponent
|
||||
insertionPoint = document.createElement('content')
|
||||
insertionPoint.setAttribute('select', 'atom-overlay')
|
||||
@domNode.appendChild(insertionPoint)
|
||||
@overlayManager = new OverlayManager(@presenter, @hostElement)
|
||||
@overlayManager = new OverlayManager(@presenter, @hostElement, @views)
|
||||
else
|
||||
@domNode.classList.add('editor-contents')
|
||||
@overlayManager = new OverlayManager(@presenter, @domNode)
|
||||
@overlayManager = new OverlayManager(@presenter, @domNode, @views)
|
||||
|
||||
@scrollViewNode = document.createElement('div')
|
||||
@scrollViewNode.classList.add('scroll-view')
|
||||
@@ -82,10 +83,10 @@ class TextEditorComponent
|
||||
@hiddenInputComponent = new InputComponent
|
||||
@scrollViewNode.appendChild(@hiddenInputComponent.getDomNode())
|
||||
|
||||
@linesComponent = new LinesComponent({@presenter, @hostElement, @useShadowDOM, @domElementPool})
|
||||
@linesComponent = new LinesComponent({@presenter, @hostElement, @useShadowDOM, @domElementPool, @assert, @grammars})
|
||||
@scrollViewNode.appendChild(@linesComponent.getDomNode())
|
||||
|
||||
@linesYardstick = new LinesYardstick(@editor, @presenter, @linesComponent)
|
||||
@linesYardstick = new LinesYardstick(@editor, @presenter, @linesComponent, @grammars)
|
||||
@presenter.setLinesYardstick(@linesYardstick)
|
||||
|
||||
@horizontalScrollbarComponent = new ScrollbarComponent({orientation: 'horizontal', onScroll: @onHorizontalScroll})
|
||||
@@ -103,11 +104,11 @@ class TextEditorComponent
|
||||
@disposables.add @stylesElement.onDidAddStyleElement @onStylesheetsChanged
|
||||
@disposables.add @stylesElement.onDidUpdateStyleElement @onStylesheetsChanged
|
||||
@disposables.add @stylesElement.onDidRemoveStyleElement @onStylesheetsChanged
|
||||
unless atom.themes.isInitialLoadComplete()
|
||||
@disposables.add atom.themes.onDidChangeActiveThemes @onAllThemesLoaded
|
||||
unless @themes.isInitialLoadComplete()
|
||||
@disposables.add @themes.onDidChangeActiveThemes @onAllThemesLoaded
|
||||
@disposables.add scrollbarStyle.onDidChangePreferredScrollbarStyle @refreshScrollbars
|
||||
|
||||
@disposables.add atom.views.pollDocument(@pollDOM)
|
||||
@disposables.add @views.pollDocument(@pollDOM)
|
||||
|
||||
@updateSync()
|
||||
@checkForVisibilityChange()
|
||||
@@ -177,7 +178,7 @@ class TextEditorComponent
|
||||
@overlayManager?.measureOverlays()
|
||||
|
||||
mountGutterContainerComponent: ->
|
||||
@gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown, @domElementPool})
|
||||
@gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown, @domElementPool, @views})
|
||||
@domNode.insertBefore(@gutterContainerComponent.getDomNode(), @domNode.firstChild)
|
||||
|
||||
becameVisible: ->
|
||||
@@ -204,10 +205,10 @@ class TextEditorComponent
|
||||
@updateSync()
|
||||
else unless @updateRequested
|
||||
@updateRequested = true
|
||||
atom.views.updateDocument =>
|
||||
@views.updateDocument =>
|
||||
@updateRequested = false
|
||||
@updateSync() if @canUpdate()
|
||||
atom.views.readDocument(@readAfterUpdateSync)
|
||||
@views.readDocument(@readAfterUpdateSync)
|
||||
|
||||
canUpdate: ->
|
||||
@mounted and @editor.isAlive()
|
||||
@@ -275,13 +276,13 @@ class TextEditorComponent
|
||||
timeoutId = setTimeout(writeSelectedTextToSelectionClipboard)
|
||||
|
||||
observeConfig: ->
|
||||
@disposables.add atom.config.onDidChange 'editor.fontSize', =>
|
||||
@disposables.add @config.onDidChange 'editor.fontSize', =>
|
||||
@sampleFontStyling()
|
||||
@invalidateCharacterWidths()
|
||||
@disposables.add atom.config.onDidChange 'editor.fontFamily', =>
|
||||
@disposables.add @config.onDidChange 'editor.fontFamily', =>
|
||||
@sampleFontStyling()
|
||||
@invalidateCharacterWidths()
|
||||
@disposables.add atom.config.onDidChange 'editor.lineHeight', =>
|
||||
@disposables.add @config.onDidChange 'editor.lineHeight', =>
|
||||
@sampleFontStyling()
|
||||
@invalidateCharacterWidths()
|
||||
|
||||
@@ -294,7 +295,7 @@ class TextEditorComponent
|
||||
@disposables.add(@scopedConfigDisposables)
|
||||
|
||||
scope = @editor.getRootScopeDescriptor()
|
||||
@scopedConfigDisposables.add atom.config.observe 'editor.scrollSensitivity', {scope}, @setScrollSensitivity
|
||||
@scopedConfigDisposables.add @config.observe 'editor.scrollSensitivity', {scope}, @setScrollSensitivity
|
||||
|
||||
focused: ->
|
||||
if @mounted
|
||||
@@ -354,11 +355,11 @@ class TextEditorComponent
|
||||
{wheelDeltaX, wheelDeltaY} = event
|
||||
|
||||
# Ctrl+MouseWheel adjusts font size.
|
||||
if event.ctrlKey and atom.config.get('editor.zoomFontWhenCtrlScrolling')
|
||||
if event.ctrlKey and @config.get('editor.zoomFontWhenCtrlScrolling')
|
||||
if wheelDeltaY > 0
|
||||
atom.workspace.increaseFontSize()
|
||||
@workspace.increaseFontSize()
|
||||
else if wheelDeltaY < 0
|
||||
atom.workspace.decreaseFontSize()
|
||||
@workspace.decreaseFontSize()
|
||||
event.preventDefault()
|
||||
return
|
||||
|
||||
@@ -543,7 +544,7 @@ class TextEditorComponent
|
||||
|
||||
onStylesheetsChanged: (styleElement) =>
|
||||
return unless @performedInitialMeasurement
|
||||
return unless atom.themes.isInitialLoadComplete()
|
||||
return unless @themes.isInitialLoadComplete()
|
||||
|
||||
# This delay prevents the styling from going haywire when stylesheets are
|
||||
# reloaded in dev mode. It seems like a workaround for a browser bug, but
|
||||
@@ -650,7 +651,7 @@ class TextEditorComponent
|
||||
|
||||
isVisible: ->
|
||||
# Investigating an exception that occurs here due to ::domNode being null.
|
||||
atom.assert @domNode?, "TextEditorComponent::domNode was null.", (error) =>
|
||||
@assert @domNode?, "TextEditorComponent::domNode was null.", (error) =>
|
||||
error.metadata = {@initialized}
|
||||
|
||||
@domNode? and (@domNode.offsetHeight > 0 or @domNode.offsetWidth > 0)
|
||||
@@ -848,7 +849,7 @@ class TextEditorComponent
|
||||
@presenter.characterWidthsChanged()
|
||||
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
atom.config.set("editor.showIndentGuide", showIndentGuide)
|
||||
@config.set("editor.showIndentGuide", showIndentGuide)
|
||||
|
||||
setScrollSensitivity: (scrollSensitivity) =>
|
||||
if scrollSensitivity = parseInt(scrollSensitivity)
|
||||
|
||||
@@ -4,6 +4,7 @@ Path = require 'path'
|
||||
TextBuffer = require 'text-buffer'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorComponent = require './text-editor-component'
|
||||
StylesElement = require './styles-element'
|
||||
|
||||
ShadowStyleSheet = null
|
||||
|
||||
@@ -18,29 +19,38 @@ class TextEditorElement extends HTMLElement
|
||||
logicalDisplayBuffer: true
|
||||
|
||||
createdCallback: ->
|
||||
# Use globals when the following instance variables aren't set.
|
||||
@config = atom.config
|
||||
@themes = atom.themes
|
||||
@workspace = atom.workspace
|
||||
@assert = atom.assert
|
||||
@views = atom.views
|
||||
@styles = atom.styles
|
||||
@grammars = atom.grammars
|
||||
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
@initializeContent()
|
||||
|
||||
@addEventListener 'focus', @focused.bind(this)
|
||||
@addEventListener 'blur', @blurred.bind(this)
|
||||
|
||||
initializeContent: (attributes) ->
|
||||
@classList.add('editor')
|
||||
@setAttribute('tabindex', -1)
|
||||
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
initializeContent: (attributes) ->
|
||||
if @config.get('editor.useShadowDOM')
|
||||
@useShadowDOM = true
|
||||
|
||||
unless ShadowStyleSheet?
|
||||
ShadowStyleSheet = document.createElement('style')
|
||||
ShadowStyleSheet.textContent = atom.themes.loadLessStylesheet(require.resolve('../static/text-editor-shadow.less'))
|
||||
ShadowStyleSheet.textContent = @themes.loadLessStylesheet(require.resolve('../static/text-editor-shadow.less'))
|
||||
|
||||
@createShadowRoot()
|
||||
|
||||
@shadowRoot.appendChild(ShadowStyleSheet.cloneNode(true))
|
||||
@stylesElement = document.createElement('atom-styles')
|
||||
@stylesElement = new StylesElement
|
||||
@stylesElement.initialize(@styles)
|
||||
@stylesElement.setAttribute('context', 'atom-text-editor')
|
||||
@stylesElement.initialize()
|
||||
|
||||
@rootElement = document.createElement('div')
|
||||
@rootElement.classList.add('editor--private')
|
||||
@@ -56,7 +66,7 @@ class TextEditorElement extends HTMLElement
|
||||
|
||||
attachedCallback: ->
|
||||
@buildModel() unless @getModel()?
|
||||
atom.assert(@model.isAlive(), "Attaching a view for a destroyed editor")
|
||||
@assert(@model.isAlive(), "Attaching a view for a destroyed editor")
|
||||
@mountComponent() unless @component?
|
||||
@listenForComponentEvents()
|
||||
@component.checkForVisibilityChange()
|
||||
@@ -76,7 +86,15 @@ class TextEditorElement extends HTMLElement
|
||||
@subscriptions.add @component.onDidChangeScrollLeft =>
|
||||
@emitter.emit("did-change-scroll-left", arguments...)
|
||||
|
||||
initialize: (model) ->
|
||||
initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}) ->
|
||||
throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @views?
|
||||
throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config?
|
||||
throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes?
|
||||
throw new Error("Must pass a workspace parameter when initializing TextEditorElements") unless @workspace?
|
||||
throw new Error("Must pass a assert parameter when initializing TextEditorElements") unless @assert?
|
||||
throw new Error("Must pass a styles parameter when initializing TextEditorElements") unless @styles?
|
||||
throw new Error("Must pass a grammars parameter when initializing TextEditorElements") unless @grammars?
|
||||
|
||||
@setModel(model)
|
||||
this
|
||||
|
||||
@@ -85,6 +103,7 @@ class TextEditorElement extends HTMLElement
|
||||
return if model.isDestroyed()
|
||||
|
||||
@model = model
|
||||
@initializeContent()
|
||||
@mountComponent()
|
||||
@addGrammarScopeAttribute()
|
||||
@addMiniAttribute() if @model.isMini()
|
||||
@@ -99,7 +118,7 @@ class TextEditorElement extends HTMLElement
|
||||
@model ? @buildModel()
|
||||
|
||||
buildModel: ->
|
||||
@setModel(new TextEditor(
|
||||
@setModel(@workspace.buildTextEditor(
|
||||
buffer: new TextBuffer(@textContent)
|
||||
softWrapped: false
|
||||
tabLength: 2
|
||||
@@ -117,6 +136,12 @@ class TextEditorElement extends HTMLElement
|
||||
editor: @model
|
||||
tileSize: @tileSize
|
||||
useShadowDOM: @useShadowDOM
|
||||
views: @views
|
||||
themes: @themes
|
||||
config: @config
|
||||
workspace: @workspace
|
||||
assert: @assert
|
||||
grammars: @grammars
|
||||
)
|
||||
@rootElement.appendChild(@component.getDomNode())
|
||||
|
||||
@@ -313,141 +338,4 @@ class TextEditorElement extends HTMLElement
|
||||
getHeight: ->
|
||||
@offsetHeight
|
||||
|
||||
stopEventPropagation = (commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
do (commandListener) ->
|
||||
newCommandListeners[commandName] = (event) ->
|
||||
event.stopPropagation()
|
||||
commandListener.call(@getModel(), event)
|
||||
newCommandListeners
|
||||
|
||||
stopEventPropagationAndGroupUndo = (commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
do (commandListener) ->
|
||||
newCommandListeners[commandName] = (event) ->
|
||||
event.stopPropagation()
|
||||
model = @getModel()
|
||||
model.transact atom.config.get('editor.undoGroupingInterval'), ->
|
||||
commandListener.call(model, event)
|
||||
newCommandListeners
|
||||
|
||||
atom.commands.add 'atom-text-editor', stopEventPropagation(
|
||||
'core:undo': -> @undo()
|
||||
'core:redo': -> @redo()
|
||||
'core:move-left': -> @moveLeft()
|
||||
'core:move-right': -> @moveRight()
|
||||
'core:select-left': -> @selectLeft()
|
||||
'core:select-right': -> @selectRight()
|
||||
'core:select-up': -> @selectUp()
|
||||
'core:select-down': -> @selectDown()
|
||||
'core:select-all': -> @selectAll()
|
||||
'editor:select-word': -> @selectWordsContainingCursors()
|
||||
'editor:consolidate-selections': (event) -> event.abortKeyBinding() unless @consolidateSelections()
|
||||
'editor:move-to-beginning-of-next-paragraph': -> @moveToBeginningOfNextParagraph()
|
||||
'editor:move-to-beginning-of-previous-paragraph': -> @moveToBeginningOfPreviousParagraph()
|
||||
'editor:move-to-beginning-of-screen-line': -> @moveToBeginningOfScreenLine()
|
||||
'editor:move-to-beginning-of-line': -> @moveToBeginningOfLine()
|
||||
'editor:move-to-end-of-screen-line': -> @moveToEndOfScreenLine()
|
||||
'editor:move-to-end-of-line': -> @moveToEndOfLine()
|
||||
'editor:move-to-first-character-of-line': -> @moveToFirstCharacterOfLine()
|
||||
'editor:move-to-beginning-of-word': -> @moveToBeginningOfWord()
|
||||
'editor:move-to-end-of-word': -> @moveToEndOfWord()
|
||||
'editor:move-to-beginning-of-next-word': -> @moveToBeginningOfNextWord()
|
||||
'editor:move-to-previous-word-boundary': -> @moveToPreviousWordBoundary()
|
||||
'editor:move-to-next-word-boundary': -> @moveToNextWordBoundary()
|
||||
'editor:move-to-previous-subword-boundary': -> @moveToPreviousSubwordBoundary()
|
||||
'editor:move-to-next-subword-boundary': -> @moveToNextSubwordBoundary()
|
||||
'editor:select-to-beginning-of-next-paragraph': -> @selectToBeginningOfNextParagraph()
|
||||
'editor:select-to-beginning-of-previous-paragraph': -> @selectToBeginningOfPreviousParagraph()
|
||||
'editor:select-to-end-of-line': -> @selectToEndOfLine()
|
||||
'editor:select-to-beginning-of-line': -> @selectToBeginningOfLine()
|
||||
'editor:select-to-end-of-word': -> @selectToEndOfWord()
|
||||
'editor:select-to-beginning-of-word': -> @selectToBeginningOfWord()
|
||||
'editor:select-to-beginning-of-next-word': -> @selectToBeginningOfNextWord()
|
||||
'editor:select-to-next-word-boundary': -> @selectToNextWordBoundary()
|
||||
'editor:select-to-previous-word-boundary': -> @selectToPreviousWordBoundary()
|
||||
'editor:select-to-next-subword-boundary': -> @selectToNextSubwordBoundary()
|
||||
'editor:select-to-previous-subword-boundary': -> @selectToPreviousSubwordBoundary()
|
||||
'editor:select-to-first-character-of-line': -> @selectToFirstCharacterOfLine()
|
||||
'editor:select-line': -> @selectLinesContainingCursors()
|
||||
)
|
||||
|
||||
atom.commands.add 'atom-text-editor', stopEventPropagationAndGroupUndo(
|
||||
'core:backspace': -> @backspace()
|
||||
'core:delete': -> @delete()
|
||||
'core:cut': -> @cutSelectedText()
|
||||
'core:copy': -> @copySelectedText()
|
||||
'core:paste': -> @pasteText()
|
||||
'editor:delete-to-previous-word-boundary': -> @deleteToPreviousWordBoundary()
|
||||
'editor:delete-to-next-word-boundary': -> @deleteToNextWordBoundary()
|
||||
'editor:delete-to-beginning-of-word': -> @deleteToBeginningOfWord()
|
||||
'editor:delete-to-beginning-of-line': -> @deleteToBeginningOfLine()
|
||||
'editor:delete-to-end-of-line': -> @deleteToEndOfLine()
|
||||
'editor:delete-to-end-of-word': -> @deleteToEndOfWord()
|
||||
'editor:delete-to-beginning-of-subword': -> @deleteToBeginningOfSubword()
|
||||
'editor:delete-to-end-of-subword': -> @deleteToEndOfSubword()
|
||||
'editor:delete-line': -> @deleteLine()
|
||||
'editor:cut-to-end-of-line': -> @cutToEndOfLine()
|
||||
'editor:cut-to-end-of-buffer-line': -> @cutToEndOfBufferLine()
|
||||
'editor:transpose': -> @transpose()
|
||||
'editor:upper-case': -> @upperCase()
|
||||
'editor:lower-case': -> @lowerCase()
|
||||
'editor:copy-selection': -> @copyOnlySelectedText()
|
||||
)
|
||||
|
||||
atom.commands.add 'atom-text-editor:not([mini])', stopEventPropagation(
|
||||
'core:move-up': -> @moveUp()
|
||||
'core:move-down': -> @moveDown()
|
||||
'core:move-to-top': -> @moveToTop()
|
||||
'core:move-to-bottom': -> @moveToBottom()
|
||||
'core:page-up': -> @pageUp()
|
||||
'core:page-down': -> @pageDown()
|
||||
'core:select-to-top': -> @selectToTop()
|
||||
'core:select-to-bottom': -> @selectToBottom()
|
||||
'core:select-page-up': -> @selectPageUp()
|
||||
'core:select-page-down': -> @selectPageDown()
|
||||
'editor:add-selection-below': -> @addSelectionBelow()
|
||||
'editor:add-selection-above': -> @addSelectionAbove()
|
||||
'editor:split-selections-into-lines': -> @splitSelectionsIntoLines()
|
||||
'editor:toggle-soft-tabs': -> @toggleSoftTabs()
|
||||
'editor:toggle-soft-wrap': -> @toggleSoftWrapped()
|
||||
'editor:fold-all': -> @foldAll()
|
||||
'editor:unfold-all': -> @unfoldAll()
|
||||
'editor:fold-current-row': -> @foldCurrentRow()
|
||||
'editor:unfold-current-row': -> @unfoldCurrentRow()
|
||||
'editor:fold-selection': -> @foldSelectedLines()
|
||||
'editor:fold-at-indent-level-1': -> @foldAllAtIndentLevel(0)
|
||||
'editor:fold-at-indent-level-2': -> @foldAllAtIndentLevel(1)
|
||||
'editor:fold-at-indent-level-3': -> @foldAllAtIndentLevel(2)
|
||||
'editor:fold-at-indent-level-4': -> @foldAllAtIndentLevel(3)
|
||||
'editor:fold-at-indent-level-5': -> @foldAllAtIndentLevel(4)
|
||||
'editor:fold-at-indent-level-6': -> @foldAllAtIndentLevel(5)
|
||||
'editor:fold-at-indent-level-7': -> @foldAllAtIndentLevel(6)
|
||||
'editor:fold-at-indent-level-8': -> @foldAllAtIndentLevel(7)
|
||||
'editor:fold-at-indent-level-9': -> @foldAllAtIndentLevel(8)
|
||||
'editor:log-cursor-scope': -> @logCursorScope()
|
||||
'editor:copy-path': -> @copyPathToClipboard()
|
||||
'editor:toggle-indent-guide': -> atom.config.set('editor.showIndentGuide', not atom.config.get('editor.showIndentGuide'))
|
||||
'editor:toggle-line-numbers': -> atom.config.set('editor.showLineNumbers', not atom.config.get('editor.showLineNumbers'))
|
||||
'editor:scroll-to-cursor': -> @scrollToCursorPosition()
|
||||
)
|
||||
|
||||
atom.commands.add 'atom-text-editor:not([mini])', stopEventPropagationAndGroupUndo(
|
||||
'editor:indent': -> @indent()
|
||||
'editor:auto-indent': -> @autoIndentSelectedRows()
|
||||
'editor:indent-selected-rows': -> @indentSelectedRows()
|
||||
'editor:outdent-selected-rows': -> @outdentSelectedRows()
|
||||
'editor:newline': -> @insertNewline()
|
||||
'editor:newline-below': -> @insertNewlineBelow()
|
||||
'editor:newline-above': -> @insertNewlineAbove()
|
||||
'editor:toggle-line-comments': -> @toggleLineCommentsInSelection()
|
||||
'editor:checkout-head-revision': -> @checkoutHeadRevision()
|
||||
'editor:move-line-up': -> @moveLineUp()
|
||||
'editor:move-line-down': -> @moveLineDown()
|
||||
'editor:duplicate-lines': -> @duplicateLines()
|
||||
'editor:join-lines': -> @joinLines()
|
||||
)
|
||||
|
||||
module.exports = TextEditorElement = document.registerElement 'atom-text-editor', prototype: TextEditorElement.prototype
|
||||
|
||||
@@ -13,7 +13,7 @@ class TextEditorPresenter
|
||||
minimumReflowInterval: 200
|
||||
|
||||
constructor: (params) ->
|
||||
{@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @scrollColumn, @scrollRow, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
|
||||
{@model, @config, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @scrollColumn, @scrollRow, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
|
||||
{horizontalScrollbarHeight, verticalScrollbarWidth} = params
|
||||
{@lineHeight, @baseCharacterWidth, @backgroundColor, @gutterBackgroundColor, @tileSize} = params
|
||||
{@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params
|
||||
@@ -225,9 +225,9 @@ class TextEditorPresenter
|
||||
observeConfig: ->
|
||||
configParams = {scope: @model.getRootScopeDescriptor()}
|
||||
|
||||
@scrollPastEnd = atom.config.get('editor.scrollPastEnd', configParams)
|
||||
@showLineNumbers = atom.config.get('editor.showLineNumbers', configParams)
|
||||
@showIndentGuide = atom.config.get('editor.showIndentGuide', configParams)
|
||||
@scrollPastEnd = @config.get('editor.scrollPastEnd', configParams)
|
||||
@showLineNumbers = @config.get('editor.showLineNumbers', configParams)
|
||||
@showIndentGuide = @config.get('editor.showIndentGuide', configParams)
|
||||
|
||||
if @configDisposables?
|
||||
@configDisposables?.dispose()
|
||||
@@ -236,19 +236,19 @@ class TextEditorPresenter
|
||||
@configDisposables = new CompositeDisposable
|
||||
@disposables.add(@configDisposables)
|
||||
|
||||
@configDisposables.add atom.config.onDidChange 'editor.showIndentGuide', configParams, ({newValue}) =>
|
||||
@configDisposables.add @config.onDidChange 'editor.showIndentGuide', configParams, ({newValue}) =>
|
||||
@showIndentGuide = newValue
|
||||
@shouldUpdateContentState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
@configDisposables.add atom.config.onDidChange 'editor.scrollPastEnd', configParams, ({newValue}) =>
|
||||
@configDisposables.add @config.onDidChange 'editor.scrollPastEnd', configParams, ({newValue}) =>
|
||||
@scrollPastEnd = newValue
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@updateScrollHeight()
|
||||
|
||||
@emitDidUpdateState()
|
||||
@configDisposables.add atom.config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) =>
|
||||
@configDisposables.add @config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) =>
|
||||
@showLineNumbers = newValue
|
||||
@shouldUpdateLineNumberGutterState = true
|
||||
@shouldUpdateGutterOrderState = true
|
||||
|
||||
@@ -54,10 +54,7 @@ GutterContainer = require './gutter-container'
|
||||
# soft wraps and folds to ensure your code interacts with them correctly.
|
||||
module.exports =
|
||||
class TextEditor extends Model
|
||||
atom.deserializers.add(this)
|
||||
|
||||
callDisplayBufferCreatedHook: false
|
||||
registerEditor: false
|
||||
buffer: null
|
||||
languageMode: null
|
||||
cursors: null
|
||||
@@ -67,9 +64,9 @@ class TextEditor extends Model
|
||||
selectionFlashDuration: 500
|
||||
gutterContainer: null
|
||||
|
||||
@deserialize: (state) ->
|
||||
@deserialize: (state, atomEnvironment) ->
|
||||
try
|
||||
displayBuffer = DisplayBuffer.deserialize(state.displayBuffer)
|
||||
displayBuffer = DisplayBuffer.deserialize(state.displayBuffer, atomEnvironment)
|
||||
catch error
|
||||
if error.syscall is 'read'
|
||||
return # Error reading the file, don't deserialize an editor for it
|
||||
@@ -77,19 +74,46 @@ class TextEditor extends Model
|
||||
throw error
|
||||
|
||||
state.displayBuffer = displayBuffer
|
||||
state.registerEditor = true
|
||||
state.config = atomEnvironment.config
|
||||
state.notificationManager = atomEnvironment.notifications
|
||||
state.packageManager = atomEnvironment.packages
|
||||
state.clipboard = atomEnvironment.clipboard
|
||||
state.viewRegistry = atomEnvironment.views
|
||||
state.grammarRegistry = atomEnvironment.grammars
|
||||
state.project = atomEnvironment.project
|
||||
state.assert = atomEnvironment.assert.bind(atomEnvironment)
|
||||
state.applicationDelegate = atomEnvironment.applicationDelegate
|
||||
new this(state)
|
||||
|
||||
constructor: ({@softTabs, @scrollRow, @scrollColumn, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) ->
|
||||
constructor: (params={}) ->
|
||||
super
|
||||
|
||||
{
|
||||
@softTabs, @scrollRow, @scrollColumn, initialLine, initialColumn, tabLength,
|
||||
softWrapped, @displayBuffer, buffer, suppressCursorCreation, @mini, @placeholderText,
|
||||
lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager,
|
||||
@clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate
|
||||
} = params
|
||||
|
||||
throw new Error("Must pass a config parameter when constructing TextEditors") unless @config?
|
||||
throw new Error("Must pass a notificationManager parameter when constructing TextEditors") unless @notificationManager?
|
||||
throw new Error("Must pass a packageManager parameter when constructing TextEditors") unless @packageManager?
|
||||
throw new Error("Must pass a clipboard parameter when constructing TextEditors") unless @clipboard?
|
||||
throw new Error("Must pass a viewRegistry parameter when constructing TextEditors") unless @viewRegistry?
|
||||
throw new Error("Must pass a grammarRegistry parameter when constructing TextEditors") unless @grammarRegistry?
|
||||
throw new Error("Must pass a project parameter when constructing TextEditors") unless @project?
|
||||
throw new Error("Must pass an assert parameter when constructing TextEditors") unless @assert?
|
||||
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
@cursors = []
|
||||
@selections = []
|
||||
|
||||
buffer ?= new TextBuffer
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode})
|
||||
@displayBuffer ?= new DisplayBuffer({
|
||||
buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode,
|
||||
@config, @assert, @grammarRegistry, @packageManager
|
||||
})
|
||||
@buffer = @displayBuffer.buffer
|
||||
|
||||
for marker in @findMarkers(@getSelectionMarkerAttributes())
|
||||
@@ -105,9 +129,9 @@ class TextEditor extends Model
|
||||
initialColumn = Math.max(parseInt(initialColumn) or 0, 0)
|
||||
@addCursorAtBufferPosition([initialLine, initialColumn])
|
||||
|
||||
@languageMode = new LanguageMode(this)
|
||||
@languageMode = new LanguageMode(this, @config)
|
||||
|
||||
@setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor()))
|
||||
@setEncoding(@config.get('core.fileEncoding', scope: @getRootScopeDescriptor()))
|
||||
|
||||
@gutterContainer = new GutterContainer(this)
|
||||
@lineNumberGutter = @gutterContainer.addGutter
|
||||
@@ -115,8 +139,6 @@ class TextEditor extends Model
|
||||
priority: 0
|
||||
visible: lineNumberGutterVisible
|
||||
|
||||
atom.workspace?.editorAdded(this) if registerEditor
|
||||
|
||||
serialize: ->
|
||||
deserializer: 'TextEditor'
|
||||
id: @id
|
||||
@@ -128,8 +150,8 @@ class TextEditor extends Model
|
||||
subscribeToBuffer: ->
|
||||
@buffer.retain()
|
||||
@disposables.add @buffer.onDidChangePath =>
|
||||
unless atom.project.getPaths().length > 0
|
||||
atom.project.setPaths([path.dirname(@getPath())])
|
||||
unless @project.getPaths().length > 0
|
||||
@project.setPaths([path.dirname(@getPath())])
|
||||
@emitter.emit 'did-change-title', @getTitle()
|
||||
@emitter.emit 'did-change-path', @getPath()
|
||||
@disposables.add @buffer.onDidChangeEncoding =>
|
||||
@@ -148,7 +170,7 @@ class TextEditor extends Model
|
||||
|
||||
subscribeToTabTypeConfig: ->
|
||||
@tabTypeSubscription?.dispose()
|
||||
@tabTypeSubscription = atom.config.observe 'editor.tabType', scope: @getRootScopeDescriptor(), =>
|
||||
@tabTypeSubscription = @config.observe 'editor.tabType', scope: @getRootScopeDescriptor(), =>
|
||||
@softTabs = @shouldUseSoftTabs(defaultValue: @softTabs)
|
||||
|
||||
destroyed: ->
|
||||
@@ -429,12 +451,12 @@ class TextEditor extends Model
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollTop instead.")
|
||||
|
||||
atom.views.getView(this).onDidChangeScrollTop(callback)
|
||||
@viewRegistry.getView(this).onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).onDidChangeScrollLeft(callback)
|
||||
@viewRegistry.getView(this).onDidChangeScrollLeft(callback)
|
||||
|
||||
onDidRequestAutoscroll: (callback) ->
|
||||
@displayBuffer.onDidRequestAutoscroll(callback)
|
||||
@@ -456,7 +478,11 @@ class TextEditor extends Model
|
||||
copy: ->
|
||||
displayBuffer = @displayBuffer.copy()
|
||||
softTabs = @getSoftTabs()
|
||||
newEditor = new TextEditor({@buffer, displayBuffer, @tabLength, softTabs, suppressCursorCreation: true, registerEditor: true})
|
||||
newEditor = new TextEditor({
|
||||
@buffer, displayBuffer, @tabLength, softTabs, suppressCursorCreation: true,
|
||||
@config, @notificationManager, @packageManager, @clipboard, @viewRegistry,
|
||||
@grammarRegistry, @project, @assert, @applicationDelegate
|
||||
})
|
||||
for marker in @findMarkers(editorId: @id)
|
||||
marker.copy(editorId: newEditor.id, preserveFolds: true)
|
||||
newEditor
|
||||
@@ -557,7 +583,7 @@ class TextEditor extends Model
|
||||
getLongTitle: ->
|
||||
if sessionPath = @getPath()
|
||||
fileName = path.basename(sessionPath)
|
||||
directory = atom.project.relativize(path.dirname(sessionPath))
|
||||
directory = @project.relativize(path.dirname(sessionPath))
|
||||
directory = if directory.length > 0 then directory else path.basename(path.dirname(sessionPath))
|
||||
"#{fileName} - #{directory}"
|
||||
else
|
||||
@@ -585,7 +611,7 @@ class TextEditor extends Model
|
||||
# Copies the current file path to the native clipboard.
|
||||
copyPathToClipboard: ->
|
||||
if filePath = @getPath()
|
||||
atom.clipboard.write(filePath)
|
||||
@clipboard.write(filePath)
|
||||
|
||||
###
|
||||
Section: File Operations
|
||||
@@ -594,14 +620,14 @@ class TextEditor extends Model
|
||||
# Essential: Saves the editor's text buffer.
|
||||
#
|
||||
# See {TextBuffer::save} for more details.
|
||||
save: -> @buffer.save(backup: atom.config.get('editor.backUpBeforeSaving'))
|
||||
save: -> @buffer.save(backup: @config.get('editor.backUpBeforeSaving'))
|
||||
|
||||
# Essential: Saves the editor's text buffer as the given path.
|
||||
#
|
||||
# See {TextBuffer::saveAs} for more details.
|
||||
#
|
||||
# * `filePath` A {String} path.
|
||||
saveAs: (filePath) -> @buffer.saveAs(filePath, backup: atom.config.get('editor.backUpBeforeSaving'))
|
||||
saveAs: (filePath) -> @buffer.saveAs(filePath, backup: @config.get('editor.backUpBeforeSaving'))
|
||||
|
||||
# Determine whether the user should be prompted to save before closing
|
||||
# this editor.
|
||||
@@ -617,9 +643,20 @@ class TextEditor extends Model
|
||||
|
||||
checkoutHeadRevision: ->
|
||||
if filePath = this.getPath()
|
||||
atom.project.repositoryForDirectory(new Directory(path.dirname(filePath)))
|
||||
.then (repository) =>
|
||||
repository?.checkoutHeadForEditor(this)
|
||||
checkoutHead = =>
|
||||
@project.repositoryForDirectory(new Directory(path.dirname(filePath)))
|
||||
.then (repository) =>
|
||||
repository?.checkoutHeadForEditor(this)
|
||||
|
||||
if @config.get('editor.confirmCheckoutHeadRevision')
|
||||
@applicationDelegate.confirm
|
||||
message: 'Confirm Checkout HEAD Revision'
|
||||
detailedMessage: "Are you sure you want to discard all changes to \"#{path.basename(filePath)}\" since the last Git commit?"
|
||||
buttons:
|
||||
OK: checkoutHead
|
||||
Cancel: null
|
||||
else
|
||||
checkoutHead()
|
||||
else
|
||||
Promise.resolve(false)
|
||||
|
||||
@@ -748,7 +785,7 @@ class TextEditor extends Model
|
||||
return false unless @emitWillInsertTextEvent(text)
|
||||
|
||||
groupingInterval = if options.groupUndo
|
||||
atom.config.get('editor.undoGroupingInterval')
|
||||
@config.get('editor.undoGroupingInterval')
|
||||
else
|
||||
0
|
||||
|
||||
@@ -1742,7 +1779,7 @@ class TextEditor extends Model
|
||||
|
||||
# Add a cursor based on the given {Marker}.
|
||||
addCursor: (marker) ->
|
||||
cursor = new Cursor(editor: this, marker: marker)
|
||||
cursor = new Cursor(editor: this, marker: marker, config: @config)
|
||||
@cursors.push(cursor)
|
||||
@decorateMarker(marker, type: 'line-number', class: 'cursor-line')
|
||||
@decorateMarker(marker, type: 'line-number', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
|
||||
@@ -2225,7 +2262,7 @@ class TextEditor extends Model
|
||||
unless marker.getProperties().preserveFolds
|
||||
@destroyFoldsContainingBufferRange(marker.getBufferRange())
|
||||
cursor = @addCursor(marker)
|
||||
selection = new Selection(_.extend({editor: this, marker, cursor}, options))
|
||||
selection = new Selection(_.extend({editor: this, marker, cursor, @clipboard}, options))
|
||||
@selections.push(selection)
|
||||
selectionBufferRange = selection.getBufferRange()
|
||||
@mergeIntersectingSelections(preserveFolds: marker.getProperties().preserveFolds)
|
||||
@@ -2382,10 +2419,10 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns a {Boolean}
|
||||
shouldUseSoftTabs: ({defaultValue}) ->
|
||||
tabType = atom.config.get('editor.tabType', scope: @getRootScopeDescriptor())
|
||||
tabType = @config.get('editor.tabType', scope: @getRootScopeDescriptor())
|
||||
switch tabType
|
||||
when 'auto'
|
||||
@usesSoftTabs() ? defaultValue ? atom.config.get('editor.softTabs') ? true
|
||||
@usesSoftTabs() ? defaultValue ? @config.get('editor.softTabs') ? true
|
||||
when 'hard'
|
||||
false
|
||||
when 'soft'
|
||||
@@ -2561,7 +2598,7 @@ class TextEditor extends Model
|
||||
list = list.map (item) -> "* #{item}"
|
||||
content = "Scopes at Cursor\n#{list.join('\n')}"
|
||||
|
||||
atom.notifications.addInfo(content, dismissable: true)
|
||||
@notificationManager.addInfo(content, dismissable: true)
|
||||
|
||||
# {Delegates to: DisplayBuffer.tokenForBufferPosition}
|
||||
tokenForBufferPosition: (bufferPosition) -> @displayBuffer.tokenForBufferPosition(bufferPosition)
|
||||
@@ -2613,7 +2650,7 @@ class TextEditor extends Model
|
||||
#
|
||||
# * `options` (optional) See {Selection::insertText}.
|
||||
pasteText: (options={}) ->
|
||||
{text: clipboardText, metadata} = atom.clipboard.readWithMetadata()
|
||||
{text: clipboardText, metadata} = @clipboard.readWithMetadata()
|
||||
return false unless @emitWillInsertTextEvent(clipboardText)
|
||||
|
||||
metadata ?= {}
|
||||
@@ -2866,24 +2903,24 @@ class TextEditor extends Model
|
||||
scrollToTop: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")
|
||||
|
||||
atom.views.getView(this).scrollToTop()
|
||||
@viewRegistry.getView(this).scrollToTop()
|
||||
|
||||
scrollToBottom: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")
|
||||
|
||||
atom.views.getView(this).scrollToBottom()
|
||||
@viewRegistry.getView(this).scrollToBottom()
|
||||
|
||||
scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options)
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.")
|
||||
|
||||
atom.views.getView(this).getHorizontalScrollbarHeight()
|
||||
@viewRegistry.getView(this).getHorizontalScrollbarHeight()
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getVerticalScrollbarWidth instead.")
|
||||
|
||||
atom.views.getView(this).getVerticalScrollbarWidth()
|
||||
@viewRegistry.getView(this).getVerticalScrollbarWidth()
|
||||
|
||||
pageUp: ->
|
||||
@moveUp(@getRowsPerPage())
|
||||
@@ -2908,10 +2945,10 @@ class TextEditor extends Model
|
||||
###
|
||||
|
||||
shouldAutoIndent: ->
|
||||
atom.config.get("editor.autoIndent", scope: @getRootScopeDescriptor())
|
||||
@config.get("editor.autoIndent", scope: @getRootScopeDescriptor())
|
||||
|
||||
shouldAutoIndentOnPaste: ->
|
||||
atom.config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor())
|
||||
@config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor())
|
||||
|
||||
###
|
||||
Section: Event Handlers
|
||||
@@ -2950,19 +2987,19 @@ class TextEditor extends Model
|
||||
|
||||
getFirstVisibleScreenRow: ->
|
||||
deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.")
|
||||
atom.views.getView(this).getVisibleRowRange()[0]
|
||||
@viewRegistry.getView(this).getVisibleRowRange()[0]
|
||||
|
||||
getLastVisibleScreenRow: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.")
|
||||
atom.views.getView(this).getVisibleRowRange()[1]
|
||||
@viewRegistry.getView(this).getVisibleRowRange()[1]
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
|
||||
atom.views.getView(this).pixelPositionForBufferPosition(bufferPosition)
|
||||
@viewRegistry.getView(this).pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead")
|
||||
atom.views.getView(this).pixelPositionForScreenPosition(screenPosition)
|
||||
@viewRegistry.getView(this).pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
getSelectionMarkerAttributes: ->
|
||||
{type: 'selection', editorId: @id, invalidate: 'never', maintainHistory: true}
|
||||
@@ -2991,7 +3028,7 @@ class TextEditor extends Model
|
||||
@displayBuffer.setHeight(height)
|
||||
else
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setHeight instead.")
|
||||
atom.views.getView(this).setHeight(height)
|
||||
@viewRegistry.getView(this).setHeight(height)
|
||||
|
||||
getHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getHeight instead.")
|
||||
@@ -3004,7 +3041,7 @@ class TextEditor extends Model
|
||||
@displayBuffer.setWidth(width)
|
||||
else
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setWidth instead.")
|
||||
atom.views.getView(this).setWidth(width)
|
||||
@viewRegistry.getView(this).setWidth(width)
|
||||
|
||||
getWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.")
|
||||
@@ -3019,77 +3056,77 @@ class TextEditor extends Model
|
||||
getScrollTop: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.")
|
||||
|
||||
atom.views.getView(this).getScrollTop()
|
||||
@viewRegistry.getView(this).getScrollTop()
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollTop instead.")
|
||||
|
||||
atom.views.getView(this).setScrollTop(scrollTop)
|
||||
@viewRegistry.getView(this).setScrollTop(scrollTop)
|
||||
|
||||
getScrollBottom: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollBottom instead.")
|
||||
|
||||
atom.views.getView(this).getScrollBottom()
|
||||
@viewRegistry.getView(this).getScrollBottom()
|
||||
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollBottom instead.")
|
||||
|
||||
atom.views.getView(this).setScrollBottom(scrollBottom)
|
||||
@viewRegistry.getView(this).setScrollBottom(scrollBottom)
|
||||
|
||||
getScrollLeft: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).getScrollLeft()
|
||||
@viewRegistry.getView(this).getScrollLeft()
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).setScrollLeft(scrollLeft)
|
||||
@viewRegistry.getView(this).setScrollLeft(scrollLeft)
|
||||
|
||||
getScrollRight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollRight instead.")
|
||||
|
||||
atom.views.getView(this).getScrollRight()
|
||||
@viewRegistry.getView(this).getScrollRight()
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollRight instead.")
|
||||
|
||||
atom.views.getView(this).setScrollRight(scrollRight)
|
||||
@viewRegistry.getView(this).setScrollRight(scrollRight)
|
||||
|
||||
getScrollHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollHeight instead.")
|
||||
|
||||
atom.views.getView(this).getScrollHeight()
|
||||
@viewRegistry.getView(this).getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollWidth instead.")
|
||||
|
||||
atom.views.getView(this).getScrollWidth()
|
||||
@viewRegistry.getView(this).getScrollWidth()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).getVisibleRowRange()
|
||||
@viewRegistry.getView(this).getVisibleRowRange()
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).intersectsVisibleRowRange(startRow, endRow)
|
||||
@viewRegistry.getView(this).intersectsVisibleRowRange(startRow, endRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::selectionIntersectsVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).selectionIntersectsVisibleRowRange(selection)
|
||||
@viewRegistry.getView(this).selectionIntersectsVisibleRowRange(selection)
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::screenPositionForPixelPosition instead.")
|
||||
|
||||
atom.views.getView(this).screenPositionForPixelPosition(pixelPosition)
|
||||
@viewRegistry.getView(this).screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::pixelRectForScreenRange instead.")
|
||||
|
||||
atom.views.getView(this).pixelRectForScreenRange(screenRange)
|
||||
@viewRegistry.getView(this).pixelRectForScreenRange(screenRange)
|
||||
|
||||
###
|
||||
Section: Utility
|
||||
|
||||
@@ -9,12 +9,14 @@ fs = require 'fs-plus'
|
||||
# An instance of this class is always available as the `atom.themes` global.
|
||||
module.exports =
|
||||
class ThemeManager
|
||||
constructor: ({@packageManager, @resourcePath, @configDirPath, @safeMode}) ->
|
||||
constructor: ({@packageManager, @resourcePath, @configDirPath, @safeMode, @config, @styleManager, @notificationManager, @viewRegistry}) ->
|
||||
@emitter = new Emitter
|
||||
@styleSheetDisposablesBySourcePath = {}
|
||||
@lessCache = null
|
||||
@initialLoadComplete = false
|
||||
@packageManager.registerPackageActivator(this, ['theme'])
|
||||
@packageManager.onDidActivateInitialPackages =>
|
||||
@onDidChangeActiveThemes => @packageManager.reloadActivePackageStyleSheets()
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
@@ -66,21 +68,21 @@ class ThemeManager
|
||||
###
|
||||
|
||||
warnForNonExistentThemes: ->
|
||||
themeNames = atom.config.get('core.themes') ? []
|
||||
themeNames = @config.get('core.themes') ? []
|
||||
themeNames = [themeNames] unless _.isArray(themeNames)
|
||||
for themeName in themeNames
|
||||
unless themeName and typeof themeName is 'string' and atom.packages.resolvePackagePath(themeName)
|
||||
unless themeName and typeof themeName is 'string' and @packageManager.resolvePackagePath(themeName)
|
||||
console.warn("Enabled theme '#{themeName}' is not installed.")
|
||||
|
||||
# Public: Get the enabled theme names from the config.
|
||||
#
|
||||
# Returns an array of theme names in the order that they should be activated.
|
||||
getEnabledThemeNames: ->
|
||||
themeNames = atom.config.get('core.themes') ? []
|
||||
themeNames = @config.get('core.themes') ? []
|
||||
themeNames = [themeNames] unless _.isArray(themeNames)
|
||||
themeNames = themeNames.filter (themeName) ->
|
||||
themeNames = themeNames.filter (themeName) =>
|
||||
if themeName and typeof themeName is 'string'
|
||||
return true if atom.packages.resolvePackagePath(themeName)
|
||||
return true if @packageManager.resolvePackagePath(themeName)
|
||||
false
|
||||
|
||||
# Use a built-in syntax and UI theme any time the configured themes are not
|
||||
@@ -139,7 +141,7 @@ class ThemeManager
|
||||
loadUserStylesheet: ->
|
||||
@unwatchUserStylesheet()
|
||||
|
||||
userStylesheetPath = atom.styles.getUserStyleSheetPath()
|
||||
userStylesheetPath = @styleManager.getUserStyleSheetPath()
|
||||
return unless fs.isFileSync(userStylesheetPath)
|
||||
|
||||
try
|
||||
@@ -158,14 +160,14 @@ class ThemeManager
|
||||
[this document][watches] for more info.
|
||||
[watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path
|
||||
"""
|
||||
atom.notifications.addError(message, dismissable: true)
|
||||
@notificationManager.addError(message, dismissable: true)
|
||||
|
||||
try
|
||||
userStylesheetContents = @loadStylesheet(userStylesheetPath, true)
|
||||
catch
|
||||
return
|
||||
|
||||
@userStyleSheetDisposable = atom.styles.addStyleSheet(userStylesheetContents, sourcePath: userStylesheetPath, priority: 2)
|
||||
@userStyleSheetDisposable = @styleManager.addStyleSheet(userStylesheetContents, sourcePath: userStylesheetPath, priority: 2)
|
||||
|
||||
loadBaseStylesheets: ->
|
||||
@requireStylesheet('../static/bootstrap')
|
||||
@@ -221,22 +223,22 @@ class ThemeManager
|
||||
message = "Error loading Less stylesheet: `#{lessStylesheetPath}`"
|
||||
detail = error.message
|
||||
|
||||
atom.notifications.addError(message, {detail, dismissable: true})
|
||||
@notificationManager.addError(message, {detail, dismissable: true})
|
||||
throw error
|
||||
|
||||
removeStylesheet: (stylesheetPath) ->
|
||||
@styleSheetDisposablesBySourcePath[stylesheetPath]?.dispose()
|
||||
|
||||
applyStylesheet: (path, text) ->
|
||||
@styleSheetDisposablesBySourcePath[path] = atom.styles.addStyleSheet(text, sourcePath: path)
|
||||
@styleSheetDisposablesBySourcePath[path] = @styleManager.addStyleSheet(text, sourcePath: path)
|
||||
|
||||
stringToId: (string) ->
|
||||
string.replace(/\\/g, '/')
|
||||
|
||||
activateThemes: ->
|
||||
new Promise (resolve) =>
|
||||
# atom.config.observe runs the callback once, then on subsequent changes.
|
||||
atom.config.observe 'core.themes', =>
|
||||
# @config.observe runs the callback once, then on subsequent changes.
|
||||
@config.observe 'core.themes', =>
|
||||
@deactivateThemes()
|
||||
|
||||
@warnForNonExistentThemes()
|
||||
@@ -268,13 +270,13 @@ class ThemeManager
|
||||
isInitialLoadComplete: -> @initialLoadComplete
|
||||
|
||||
addActiveThemeClasses: ->
|
||||
if workspaceElement = atom.views.getView(atom.workspace)
|
||||
if workspaceElement = @viewRegistry.getView(@workspace)
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.add("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
removeActiveThemeClasses: ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
workspaceElement = @viewRegistry.getView(@workspace)
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.remove("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
@@ -7,10 +7,10 @@ class ThemePackage extends Package
|
||||
getStyleSheetPriority: -> 1
|
||||
|
||||
enable: ->
|
||||
atom.config.unshiftAtKeyPath('core.themes', @name)
|
||||
@config.unshiftAtKeyPath('core.themes', @name)
|
||||
|
||||
disable: ->
|
||||
atom.config.removeAtKeyPath('core.themes', @name)
|
||||
@config.removeAtKeyPath('core.themes', @name)
|
||||
|
||||
load: ->
|
||||
@loadTime = 0
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
module.exports =
|
||||
class TokenIterator
|
||||
constructor: (line) ->
|
||||
constructor: ({@grammarRegistry}, line) ->
|
||||
@reset(line) if line?
|
||||
|
||||
reset: (@line) ->
|
||||
@@ -12,7 +12,7 @@ class TokenIterator
|
||||
@bufferEnd = @bufferStart
|
||||
@screenStart = 0
|
||||
@screenEnd = 0
|
||||
@scopes = @line.openScopes.map (id) -> atom.grammars.scopeForId(id)
|
||||
@scopes = @line.openScopes.map (id) => @grammarRegistry.scopeForId(id)
|
||||
@scopeStarts = @scopes.slice()
|
||||
@scopeEnds = []
|
||||
this
|
||||
@@ -32,7 +32,7 @@ class TokenIterator
|
||||
while @index < tags.length
|
||||
tag = tags[@index]
|
||||
if tag < 0
|
||||
scope = atom.grammars.scopeForId(tag)
|
||||
scope = @grammarRegistry.scopeForId(tag)
|
||||
if tag % 2 is 0
|
||||
if @scopeStarts[@scopeStarts.length - 1] is scope
|
||||
@scopeStarts.pop()
|
||||
|
||||
@@ -21,17 +21,26 @@ class TokenizedBuffer extends Model
|
||||
configSettings: null
|
||||
changeCount: 0
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.buffer = atom.project.bufferForPathSync(state.bufferPath)
|
||||
@deserialize: (state, atomEnvironment) ->
|
||||
state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath)
|
||||
state.config = atomEnvironment.config
|
||||
state.grammarRegistry = atomEnvironment.grammars
|
||||
state.packageManager = atomEnvironment.packages
|
||||
state.assert = atomEnvironment.assert
|
||||
new this(state)
|
||||
|
||||
constructor: ({@buffer, @tabLength, @ignoreInvisibles, @largeFileMode}) ->
|
||||
constructor: (params) ->
|
||||
{
|
||||
@buffer, @tabLength, @ignoreInvisibles, @largeFileMode, @config,
|
||||
@grammarRegistry, @packageManager, @assert
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
@tokenIterator = new TokenIterator
|
||||
@tokenIterator = new TokenIterator({@grammarRegistry})
|
||||
|
||||
@disposables.add atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated)
|
||||
@disposables.add atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated)
|
||||
@disposables.add @grammarRegistry.onDidAddGrammar(@grammarAddedOrUpdated)
|
||||
@disposables.add @grammarRegistry.onDidUpdateGrammar(@grammarAddedOrUpdated)
|
||||
|
||||
@disposables.add @buffer.preemptDidChange (e) => @handleBufferChange(e)
|
||||
@disposables.add @buffer.onDidChangePath (@bufferPath) => @reloadGrammar()
|
||||
@@ -65,7 +74,7 @@ class TokenizedBuffer extends Model
|
||||
if grammar.injectionSelector?
|
||||
@retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector)
|
||||
else
|
||||
newScore = atom.grammars.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent())
|
||||
newScore = @grammarRegistry.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent())
|
||||
@setGrammar(grammar, newScore) if newScore > @currentGrammarScore
|
||||
|
||||
setGrammar: (grammar, score) ->
|
||||
@@ -73,7 +82,7 @@ class TokenizedBuffer extends Model
|
||||
|
||||
@grammar = grammar
|
||||
@rootScopeDescriptor = new ScopeDescriptor(scopes: [@grammar.scopeName])
|
||||
@currentGrammarScore = score ? atom.grammars.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent())
|
||||
@currentGrammarScore = score ? @grammarRegistry.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent())
|
||||
|
||||
@grammarUpdateDisposable?.dispose()
|
||||
@grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines()
|
||||
@@ -81,33 +90,33 @@ class TokenizedBuffer extends Model
|
||||
|
||||
scopeOptions = {scope: @rootScopeDescriptor}
|
||||
@configSettings =
|
||||
tabLength: atom.config.get('editor.tabLength', scopeOptions)
|
||||
invisibles: atom.config.get('editor.invisibles', scopeOptions)
|
||||
showInvisibles: atom.config.get('editor.showInvisibles', scopeOptions)
|
||||
tabLength: @config.get('editor.tabLength', scopeOptions)
|
||||
invisibles: @config.get('editor.invisibles', scopeOptions)
|
||||
showInvisibles: @config.get('editor.showInvisibles', scopeOptions)
|
||||
|
||||
if @configSubscriptions?
|
||||
@configSubscriptions.dispose()
|
||||
@disposables.remove(@configSubscriptions)
|
||||
@configSubscriptions = new CompositeDisposable
|
||||
@configSubscriptions.add atom.config.onDidChange 'editor.tabLength', scopeOptions, ({newValue}) =>
|
||||
@configSubscriptions.add @config.onDidChange 'editor.tabLength', scopeOptions, ({newValue}) =>
|
||||
@configSettings.tabLength = newValue
|
||||
@retokenizeLines()
|
||||
['invisibles', 'showInvisibles'].forEach (key) =>
|
||||
@configSubscriptions.add atom.config.onDidChange "editor.#{key}", scopeOptions, ({newValue}) =>
|
||||
@configSubscriptions.add @config.onDidChange "editor.#{key}", scopeOptions, ({newValue}) =>
|
||||
oldInvisibles = @getInvisiblesToShow()
|
||||
@configSettings[key] = newValue
|
||||
@retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles)
|
||||
@disposables.add(@configSubscriptions)
|
||||
|
||||
@retokenizeLines()
|
||||
atom.packages.triggerActivationHook("#{grammar.packageName}:grammar-used")
|
||||
@packageManager.triggerActivationHook("#{grammar.packageName}:grammar-used")
|
||||
@emitter.emit 'did-change-grammar', grammar
|
||||
|
||||
getGrammarSelectionContent: ->
|
||||
@buffer.getTextInRange([[0, 0], [10, 0]])
|
||||
|
||||
reloadGrammar: ->
|
||||
if grammar = atom.grammars.selectGrammar(@buffer.getPath(), @getGrammarSelectionContent())
|
||||
if grammar = @grammarRegistry.selectGrammar(@buffer.getPath(), @getGrammarSelectionContent())
|
||||
@setGrammar(grammar)
|
||||
else
|
||||
throw new Error("No grammar found for path: #{path}")
|
||||
@@ -155,7 +164,7 @@ class TokenizedBuffer extends Model
|
||||
|
||||
tokenizeNextChunk: ->
|
||||
# Short circuit null grammar which can just use the placeholder tokens
|
||||
if @grammar is atom.grammars.nullGrammar and @firstInvalidRow()?
|
||||
if @grammar is @grammarRegistry.nullGrammar and @firstInvalidRow()?
|
||||
@invalidRows = []
|
||||
@markTokenizationComplete()
|
||||
return
|
||||
@@ -291,7 +300,7 @@ class TokenizedBuffer extends Model
|
||||
# undefined. This should paper over the problem but we want to figure out
|
||||
# what is happening:
|
||||
tokenizedLine = @tokenizedLineForRow(row)
|
||||
atom.assert tokenizedLine?, "TokenizedLine is undefined", (error) =>
|
||||
@assert tokenizedLine?, "TokenizedLine is undefined", (error) =>
|
||||
error.metadata = {
|
||||
row: row
|
||||
rowCount: @tokenizedLines.length
|
||||
@@ -391,7 +400,7 @@ class TokenizedBuffer extends Model
|
||||
loop
|
||||
break if scopes.pop() is matchingStartTag
|
||||
if scopes.length is 0
|
||||
atom.assert false, "Encountered an unmatched scope end tag.", (error) =>
|
||||
@assert false, "Encountered an unmatched scope end tag.", (error) =>
|
||||
error.metadata = {
|
||||
grammarScopeName: @grammar.scopeName
|
||||
unmatchedEndTag: @grammar.scopeForId(tag)
|
||||
@@ -472,13 +481,13 @@ class TokenizedBuffer extends Model
|
||||
position = Point.fromObject(position)
|
||||
|
||||
{openScopes, tags} = @tokenizedLineForRow(position.row)
|
||||
scopes = openScopes.map (tag) -> atom.grammars.scopeForId(tag)
|
||||
scopes = openScopes.map (tag) => @grammarRegistry.scopeForId(tag)
|
||||
|
||||
startColumn = 0
|
||||
for tag, tokenIndex in tags
|
||||
if tag < 0
|
||||
if tag % 2 is -1
|
||||
scopes.push(atom.grammars.scopeForId(tag))
|
||||
scopes.push(@grammarRegistry.scopeForId(tag))
|
||||
else
|
||||
scopes.pop()
|
||||
else
|
||||
@@ -498,7 +507,7 @@ class TokenizedBuffer extends Model
|
||||
if tag % 2 is -1
|
||||
startScopes.pop()
|
||||
else
|
||||
startScopes.push(atom.grammars.scopeForId(tag))
|
||||
startScopes.push(@grammarRegistry.scopeForId(tag))
|
||||
else
|
||||
break unless selectorMatchesAnyScope(selector, startScopes)
|
||||
startColumn -= tag
|
||||
@@ -508,7 +517,7 @@ class TokenizedBuffer extends Model
|
||||
tag = tags[endTokenIndex]
|
||||
if tag < 0
|
||||
if tag % 2 is -1
|
||||
endScopes.push(atom.grammars.scopeForId(tag))
|
||||
endScopes.push(@grammarRegistry.scopeForId(tag))
|
||||
else
|
||||
endScopes.pop()
|
||||
else
|
||||
|
||||
@@ -54,6 +54,8 @@ class TooltipManager
|
||||
placement: 'auto top'
|
||||
viewportPadding: 2
|
||||
|
||||
constructor: ({@keymapManager}) ->
|
||||
|
||||
# Essential: Add a tooltip to the given element.
|
||||
#
|
||||
# * `target` An `HTMLElement`
|
||||
@@ -81,7 +83,7 @@ class TooltipManager
|
||||
{keyBindingCommand, keyBindingTarget} = options
|
||||
|
||||
if keyBindingCommand?
|
||||
bindings = atom.keymaps.findKeyBindings(command: keyBindingCommand, target: keyBindingTarget)
|
||||
bindings = @keymapManager.findKeyBindings(command: keyBindingCommand, target: keyBindingTarget)
|
||||
keystroke = getKeystroke(bindings)
|
||||
if options.title? and keystroke?
|
||||
options.title += " " + getKeystroke(bindings)
|
||||
|
||||
@@ -49,15 +49,15 @@ class ViewRegistry
|
||||
debouncedPerformDocumentPoll: null
|
||||
minimumPollInterval: 200
|
||||
|
||||
constructor: ->
|
||||
constructor: (@atomEnvironment) ->
|
||||
@observer = new MutationObserver(@requestDocumentPoll)
|
||||
@clear()
|
||||
|
||||
clear: ->
|
||||
@views = new WeakMap
|
||||
@providers = []
|
||||
@documentWriters = []
|
||||
@documentReaders = []
|
||||
@documentPollers = []
|
||||
|
||||
@observer = new MutationObserver(@requestDocumentPoll)
|
||||
@debouncedPerformDocumentPoll = _.throttle(@performDocumentPoll, @minimumPollInterval).bind(this)
|
||||
@clearDocumentRequests()
|
||||
|
||||
# Essential: Add a provider that will be used to construct views in the
|
||||
# workspace's view layer based on model objects in its model layer.
|
||||
@@ -159,7 +159,7 @@ class ViewRegistry
|
||||
else if object?.jquery
|
||||
object[0]
|
||||
else if provider = @findProvider(object)
|
||||
element = provider.createView?(object)
|
||||
element = provider.createView?(object, @atomEnvironment)
|
||||
unless element?
|
||||
element = new provider.viewConstructor
|
||||
element.initialize?(object) ? element.setModel?(object)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Like sands through the hourglass, so are the days of our lives.
|
||||
require './window'
|
||||
|
||||
Atom = require './atom'
|
||||
window.atom = Atom.loadOrCreate('editor')
|
||||
atom.initialize()
|
||||
atom.startEditorWindow()
|
||||
|
||||
# Workaround for focus getting cleared upon window creation
|
||||
windowFocused = ->
|
||||
window.removeEventListener('focus', windowFocused)
|
||||
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
|
||||
window.addEventListener('focus', windowFocused)
|
||||
@@ -1,45 +1,38 @@
|
||||
path = require 'path'
|
||||
{Disposable, CompositeDisposable} = require 'event-kit'
|
||||
ipc = require 'ipc'
|
||||
shell = require 'shell'
|
||||
fs = require 'fs-plus'
|
||||
listen = require './delegated-listener'
|
||||
|
||||
# Handles low-level events related to the window.
|
||||
# Handles low-level events related to the @window.
|
||||
module.exports =
|
||||
class WindowEventHandler
|
||||
constructor: ->
|
||||
constructor: ({@atomEnvironment, @applicationDelegate, @window, @document}) ->
|
||||
@reloadRequested = false
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@on(ipc, 'message', @handleIPCMessage)
|
||||
@on(ipc, 'command', @handleIPCCommand)
|
||||
@on(ipc, 'context-command', @handleIPCContextCommand)
|
||||
@previousOnbeforeunloadHandler = @window.onbeforeunload
|
||||
@window.onbeforeunload = @handleWindowBeforeunload
|
||||
@addEventListener(@window, 'focus', @handleWindowFocus)
|
||||
@addEventListener(@window, 'blur', @handleWindowBlur)
|
||||
|
||||
@previousOnbeforeunloadHandler = window.onbeforeunload
|
||||
window.onbeforeunload = @handleWindowBeforeunload
|
||||
@addEventListener(window, 'focus', @handleWindowFocus)
|
||||
@addEventListener(window, 'blur', @handleWindowBlur)
|
||||
@addEventListener(window, 'unload', @handleWindowUnload)
|
||||
@addEventListener(@document, 'keydown', @handleDocumentKeydown)
|
||||
@addEventListener(@document, 'drop', @handleDocumentDrop)
|
||||
@addEventListener(@document, 'dragover', @handleDocumentDragover)
|
||||
@addEventListener(@document, 'contextmenu', @handleDocumentContextmenu)
|
||||
@subscriptions.add listen(@document, 'click', 'a', @handleLinkClick)
|
||||
@subscriptions.add listen(@document, 'submit', 'form', @handleFormSubmit)
|
||||
|
||||
@addEventListener(document, 'keydown', @handleDocumentKeydown)
|
||||
@addEventListener(document, 'drop', @handleDocumentDrop)
|
||||
@addEventListener(document, 'dragover', @handleDocumentDragover)
|
||||
@addEventListener(document, 'contextmenu', @handleDocumentContextmenu)
|
||||
@subscriptions.add listen(document, 'click', 'a', @handleLinkClick)
|
||||
@subscriptions.add listen(document, 'submit', 'form', @handleFormSubmit)
|
||||
|
||||
@subscriptions.add atom.commands.add window,
|
||||
@subscriptions.add @atomEnvironment.commands.add @window,
|
||||
'window:toggle-full-screen': @handleWindowToggleFullScreen
|
||||
'window:close': @handleWindowClose
|
||||
'window:reload': @handleWindowReload
|
||||
'window:toggle-dev-tools': @handleWindowToggleDevTools
|
||||
|
||||
if process.platform in ['win32', 'linux']
|
||||
@subscriptions.add atom.commands.add window,
|
||||
'window:toggle-menu-bar': @handleWindowToggleMenuBar
|
||||
@subscriptions.add @atomEnvironment.commands.add @window,
|
||||
'@window:toggle-menu-bar': @handleWindowToggleMenuBar
|
||||
|
||||
@subscriptions.add atom.commands.add document,
|
||||
@subscriptions.add @atomEnvironment.commands.add @document,
|
||||
'core:focus-next': @handleFocusNext
|
||||
'core:focus-previous': @handleFocusPrevious
|
||||
|
||||
@@ -49,9 +42,9 @@ class WindowEventHandler
|
||||
# `.native-key-bindings` class.
|
||||
handleNativeKeybindings: ->
|
||||
bindCommandToAction = (command, action) =>
|
||||
@addEventListener document, command, (event) ->
|
||||
@addEventListener @document, command, (event) =>
|
||||
if event.target.webkitMatchesSelector('.native-key-bindings')
|
||||
atom.getCurrentWindow().webContents[action]()
|
||||
@applicationDelegate.getCurrentWindow().webContents[action]()
|
||||
|
||||
bindCommandToAction('core:copy', 'copy')
|
||||
bindCommandToAction('core:paste', 'paste')
|
||||
@@ -61,7 +54,7 @@ class WindowEventHandler
|
||||
bindCommandToAction('core:cut', 'cut')
|
||||
|
||||
unsubscribe: ->
|
||||
window.onbeforeunload = @previousOnbeforeunloadHandler
|
||||
@window.onbeforeunload = @previousOnbeforeunloadHandler
|
||||
@subscriptions.dispose()
|
||||
|
||||
on: (target, eventName, handler) ->
|
||||
@@ -74,8 +67,8 @@ class WindowEventHandler
|
||||
target.addEventListener(eventName, handler)
|
||||
@subscriptions.add(new Disposable(-> target.removeEventListener(eventName, handler)))
|
||||
|
||||
handleDocumentKeydown: (event) ->
|
||||
atom.keymaps.handleKeyboardEvent(event)
|
||||
handleDocumentKeydown: (event) =>
|
||||
@atomEnvironment.keymaps.handleKeyboardEvent(event)
|
||||
event.stopImmediatePropagation()
|
||||
|
||||
handleDrop: (event) ->
|
||||
@@ -88,14 +81,14 @@ class WindowEventHandler
|
||||
event.dataTransfer.dropEffect = 'none'
|
||||
|
||||
eachTabIndexedElement: (callback) ->
|
||||
for element in document.querySelectorAll('[tabindex]')
|
||||
for element in @document.querySelectorAll('[tabindex]')
|
||||
continue if element.disabled
|
||||
continue unless element.tabIndex >= 0
|
||||
callback(element, element.tabIndex)
|
||||
return
|
||||
|
||||
handleFocusNext: =>
|
||||
focusedTabIndex = document.activeElement.tabIndex ? -Infinity
|
||||
focusedTabIndex = @document.activeElement.tabIndex ? -Infinity
|
||||
|
||||
nextElement = null
|
||||
nextTabIndex = Infinity
|
||||
@@ -116,7 +109,7 @@ class WindowEventHandler
|
||||
lowestElement.focus()
|
||||
|
||||
handleFocusPrevious: =>
|
||||
focusedTabIndex = document.activeElement.tabIndex ? Infinity
|
||||
focusedTabIndex = @document.activeElement.tabIndex ? Infinity
|
||||
|
||||
previousElement = null
|
||||
previousTabIndex = -Infinity
|
||||
@@ -136,91 +129,61 @@ class WindowEventHandler
|
||||
else if highestElement?
|
||||
highestElement.focus()
|
||||
|
||||
handleIPCMessage: (message, detail) ->
|
||||
switch message
|
||||
when 'open-locations'
|
||||
needsProjectPaths = atom.project?.getPaths().length is 0
|
||||
|
||||
for {pathToOpen, initialLine, initialColumn} in detail
|
||||
if pathToOpen? and needsProjectPaths
|
||||
if fs.existsSync(pathToOpen)
|
||||
atom.project.addPath(pathToOpen)
|
||||
else if fs.existsSync(path.dirname(pathToOpen))
|
||||
atom.project.addPath(path.dirname(pathToOpen))
|
||||
else
|
||||
atom.project.addPath(pathToOpen)
|
||||
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
return
|
||||
when 'update-available'
|
||||
atom.updateAvailable(detail)
|
||||
|
||||
handleIPCCommand: (command, args...) ->
|
||||
activeElement = document.activeElement
|
||||
# Use the workspace element view if body has focus
|
||||
if activeElement is document.body and workspaceElement = atom.views.getView(atom.workspace)
|
||||
activeElement = workspaceElement
|
||||
|
||||
atom.commands.dispatch(activeElement, command, args[0])
|
||||
|
||||
handleIPCContextCommand: (command, args...) ->
|
||||
atom.commands.dispatch(atom.contextMenu.activeElement, command, args)
|
||||
|
||||
handleWindowFocus: ->
|
||||
document.body.classList.remove('is-blurred')
|
||||
@document.body.classList.remove('is-blurred')
|
||||
|
||||
handleWindowBlur: ->
|
||||
document.body.classList.add('is-blurred')
|
||||
atom.storeDefaultWindowDimensions()
|
||||
handleWindowBlur: =>
|
||||
@document.body.classList.add('is-blurred')
|
||||
@atomEnvironment.storeDefaultWindowDimensions()
|
||||
|
||||
handleWindowBeforeunload: =>
|
||||
confirmed = atom.workspace?.confirmClose(windowCloseRequested: true)
|
||||
atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
|
||||
confirmed = @atomEnvironment.workspace?.confirmClose(windowCloseRequested: true)
|
||||
if confirmed and not @reloadRequested and not @atomEnvironment.inSpecMode() and @atomEnvironment.getCurrentWindow().isWebViewFocused()
|
||||
@atomEnvironment.hide()
|
||||
@reloadRequested = false
|
||||
|
||||
atom.storeDefaultWindowDimensions()
|
||||
atom.storeWindowDimensions()
|
||||
@atomEnvironment.storeDefaultWindowDimensions()
|
||||
@atomEnvironment.storeWindowDimensions()
|
||||
if confirmed
|
||||
atom.unloadEditorWindow()
|
||||
@atomEnvironment.unloadEditorWindow()
|
||||
else
|
||||
ipc.send('cancel-window-close')
|
||||
@applicationDelegate.didCancelWindowUnload()
|
||||
|
||||
confirmed
|
||||
|
||||
handleWindowUnload: ->
|
||||
atom.removeEditorWindow()
|
||||
handleWindowUnload: =>
|
||||
@atomEnvironment.destroy()
|
||||
|
||||
handleWindowToggleFullScreen: ->
|
||||
atom.toggleFullScreen()
|
||||
handleWindowToggleFullScreen: =>
|
||||
@atomEnvironment.toggleFullScreen()
|
||||
|
||||
handleWindowClose: ->
|
||||
atom.close()
|
||||
handleWindowClose: =>
|
||||
@atomEnvironment.close()
|
||||
|
||||
handleWindowReload: ->
|
||||
handleWindowReload: =>
|
||||
@reloadRequested = true
|
||||
atom.reload()
|
||||
@atomEnvironment.reload()
|
||||
|
||||
handleWindowToggleDevTools: ->
|
||||
atom.toggleDevTools()
|
||||
handleWindowToggleDevTools: =>
|
||||
@atomEnvironment.toggleDevTools()
|
||||
|
||||
handleWindowToggleMenuBar: ->
|
||||
atom.config.set('core.autoHideMenuBar', not atom.config.get('core.autoHideMenuBar'))
|
||||
handleWindowToggleMenuBar: =>
|
||||
@atomEnvironment.config.set('core.autoHideMenuBar', not @atomEnvironment.config.get('core.autoHideMenuBar'))
|
||||
|
||||
if atom.config.get('core.autoHideMenuBar')
|
||||
if @atomEnvironment.config.get('core.autoHideMenuBar')
|
||||
detail = "To toggle, press the Alt key or execute the window:toggle-menu-bar command"
|
||||
atom.notifications.addInfo('Menu bar hidden', {detail})
|
||||
@atomEnvironment.notifications.addInfo('Menu bar hidden', {detail})
|
||||
|
||||
handleLinkClick: (event) ->
|
||||
event.preventDefault()
|
||||
location = event.currentTarget?.getAttribute('href')
|
||||
if location and location[0] isnt '#' and /^https?:\/\//.test(location)
|
||||
shell.openExternal(location)
|
||||
uri = event.currentTarget?.getAttribute('href')
|
||||
if uri and uri[0] isnt '#' and /^https?:\/\//.test(uri)
|
||||
@applicationDelegate.openExternal(uri)
|
||||
|
||||
handleFormSubmit: (event) ->
|
||||
# Prevent form submits from changing the current window's URL
|
||||
event.preventDefault()
|
||||
|
||||
handleDocumentContextmenu: (event) ->
|
||||
handleDocumentContextmenu: (event) =>
|
||||
event.preventDefault()
|
||||
atom.contextMenu.showForEvent(event)
|
||||
@atomEnvironment.contextMenu.showForEvent(event)
|
||||
|
||||
20
src/window-load-settings-helpers.coffee
Normal file
20
src/window-load-settings-helpers.coffee
Normal file
@@ -0,0 +1,20 @@
|
||||
remote = require 'remote'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
windowLoadSettings = null
|
||||
|
||||
exports.getWindowLoadSettings = ->
|
||||
windowLoadSettings ?= JSON.parse(window.decodeURIComponent(window.location.hash.substr(1)))
|
||||
clone = _.deepClone(windowLoadSettings)
|
||||
|
||||
# The windowLoadSettings.windowState could be large, request it only when needed.
|
||||
clone.__defineGetter__ 'windowState', ->
|
||||
remote.getCurrentWindow().loadSettings.windowState
|
||||
clone.__defineSetter__ 'windowState', (value) ->
|
||||
remote.getCurrentWindow().loadSettings.windowState = value
|
||||
|
||||
clone
|
||||
|
||||
exports.setWindowLoadSettings = (settings) ->
|
||||
windowLoadSettings = settings
|
||||
location.hash = encodeURIComponent(JSON.stringify(settings))
|
||||
@@ -8,18 +8,11 @@ module.exports =
|
||||
class WorkspaceElement extends HTMLElement
|
||||
globalTextEditorStyleSheet: null
|
||||
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@initializeContent()
|
||||
@observeScrollbarStyle()
|
||||
@observeTextEditorFontConfig()
|
||||
|
||||
attachedCallback: ->
|
||||
@focus()
|
||||
|
||||
detachedCallback: ->
|
||||
@subscriptions.dispose()
|
||||
@model.destroy()
|
||||
|
||||
initializeContent: ->
|
||||
@classList.add 'workspace'
|
||||
@@ -46,31 +39,42 @@ class WorkspaceElement extends HTMLElement
|
||||
|
||||
observeTextEditorFontConfig: ->
|
||||
@updateGlobalTextEditorStyleSheet()
|
||||
@subscriptions.add atom.config.onDidChange 'editor.fontSize', @updateGlobalTextEditorStyleSheet.bind(this)
|
||||
@subscriptions.add atom.config.onDidChange 'editor.fontFamily', @updateGlobalTextEditorStyleSheet.bind(this)
|
||||
@subscriptions.add atom.config.onDidChange 'editor.lineHeight', @updateGlobalTextEditorStyleSheet.bind(this)
|
||||
@subscriptions.add @config.onDidChange 'editor.fontSize', @updateGlobalTextEditorStyleSheet.bind(this)
|
||||
@subscriptions.add @config.onDidChange 'editor.fontFamily', @updateGlobalTextEditorStyleSheet.bind(this)
|
||||
@subscriptions.add @config.onDidChange 'editor.lineHeight', @updateGlobalTextEditorStyleSheet.bind(this)
|
||||
|
||||
updateGlobalTextEditorStyleSheet: ->
|
||||
styleSheetSource = """
|
||||
atom-text-editor {
|
||||
font-size: #{atom.config.get('editor.fontSize')}px;
|
||||
font-family: #{atom.config.get('editor.fontFamily')};
|
||||
line-height: #{atom.config.get('editor.lineHeight')};
|
||||
font-size: #{@config.get('editor.fontSize')}px;
|
||||
font-family: #{@config.get('editor.fontFamily')};
|
||||
line-height: #{@config.get('editor.lineHeight')};
|
||||
}
|
||||
"""
|
||||
atom.styles.addStyleSheet(styleSheetSource, sourcePath: 'global-text-editor-styles')
|
||||
@styles.addStyleSheet(styleSheetSource, sourcePath: 'global-text-editor-styles')
|
||||
|
||||
initialize: (@model) ->
|
||||
@paneContainer = atom.views.getView(@model.paneContainer)
|
||||
initialize: (@model, {@views, @workspace, @project, @config, @styles}) ->
|
||||
throw new Error("Must pass a views parameter when initializing WorskpaceElements") unless @views?
|
||||
throw new Error("Must pass a workspace parameter when initializing WorskpaceElements") unless @workspace?
|
||||
throw new Error("Must pass a project parameter when initializing WorskpaceElements") unless @project?
|
||||
throw new Error("Must pass a config parameter when initializing WorskpaceElements") unless @config?
|
||||
throw new Error("Must pass a styles parameter when initializing WorskpaceElements") unless @styles?
|
||||
|
||||
@subscriptions = new CompositeDisposable
|
||||
@initializeContent()
|
||||
@observeScrollbarStyle()
|
||||
@observeTextEditorFontConfig()
|
||||
|
||||
@paneContainer = @views.getView(@model.paneContainer)
|
||||
@verticalAxis.appendChild(@paneContainer)
|
||||
@addEventListener 'focus', @handleFocus.bind(this)
|
||||
|
||||
@panelContainers =
|
||||
top: atom.views.getView(@model.panelContainers.top)
|
||||
left: atom.views.getView(@model.panelContainers.left)
|
||||
right: atom.views.getView(@model.panelContainers.right)
|
||||
bottom: atom.views.getView(@model.panelContainers.bottom)
|
||||
modal: atom.views.getView(@model.panelContainers.modal)
|
||||
top: @views.getView(@model.panelContainers.top)
|
||||
left: @views.getView(@model.panelContainers.left)
|
||||
right: @views.getView(@model.panelContainers.right)
|
||||
bottom: @views.getView(@model.panelContainers.bottom)
|
||||
modal: @views.getView(@model.panelContainers.modal)
|
||||
|
||||
@horizontalAxis.insertBefore(@panelContainers.left, @verticalAxis)
|
||||
@horizontalAxis.appendChild(@panelContainers.right)
|
||||
@@ -96,59 +100,10 @@ class WorkspaceElement extends HTMLElement
|
||||
focusPaneViewOnRight: -> @paneContainer.focusPaneViewOnRight()
|
||||
|
||||
runPackageSpecs: ->
|
||||
if activePath = atom.workspace.getActivePaneItem()?.getPath?()
|
||||
[projectPath] = atom.project.relativizePath(activePath)
|
||||
if activePath = @workspace.getActivePaneItem()?.getPath?()
|
||||
[projectPath] = @project.relativizePath(activePath)
|
||||
else
|
||||
[projectPath] = atom.project.getPaths()
|
||||
[projectPath] = @project.getPaths()
|
||||
ipc.send('run-package-specs', path.join(projectPath, 'spec')) if projectPath
|
||||
|
||||
atom.commands.add 'atom-workspace',
|
||||
'window:increase-font-size': -> @getModel().increaseFontSize()
|
||||
'window:decrease-font-size': -> @getModel().decreaseFontSize()
|
||||
'window:reset-font-size': -> @getModel().resetFontSize()
|
||||
'application:about': -> ipc.send('command', 'application:about')
|
||||
'application:run-all-specs': -> ipc.send('command', 'application:run-all-specs')
|
||||
'application:show-preferences': -> ipc.send('command', 'application:show-settings')
|
||||
'application:show-settings': -> ipc.send('command', 'application:show-settings')
|
||||
'application:quit': -> ipc.send('command', 'application:quit')
|
||||
'application:hide': -> ipc.send('command', 'application:hide')
|
||||
'application:hide-other-applications': -> ipc.send('command', 'application:hide-other-applications')
|
||||
'application:install-update': -> ipc.send('command', 'application:install-update')
|
||||
'application:unhide-all-applications': -> ipc.send('command', 'application:unhide-all-applications')
|
||||
'application:new-window': -> ipc.send('command', 'application:new-window')
|
||||
'application:new-file': -> ipc.send('command', 'application:new-file')
|
||||
'application:open': -> ipc.send('command', 'application:open')
|
||||
'application:open-file': -> ipc.send('command', 'application:open-file')
|
||||
'application:open-folder': -> ipc.send('command', 'application:open-folder')
|
||||
'application:open-dev': -> ipc.send('command', 'application:open-dev')
|
||||
'application:open-safe': -> ipc.send('command', 'application:open-safe')
|
||||
'application:add-project-folder': -> atom.addProjectFolder()
|
||||
'application:minimize': -> ipc.send('command', 'application:minimize')
|
||||
'application:zoom': -> ipc.send('command', 'application:zoom')
|
||||
'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front')
|
||||
'application:open-your-config': -> ipc.send('command', 'application:open-your-config')
|
||||
'application:open-your-init-script': -> ipc.send('command', 'application:open-your-init-script')
|
||||
'application:open-your-keymap': -> ipc.send('command', 'application:open-your-keymap')
|
||||
'application:open-your-snippets': -> ipc.send('command', 'application:open-your-snippets')
|
||||
'application:open-your-stylesheet': -> ipc.send('command', 'application:open-your-stylesheet')
|
||||
'application:open-license': -> @getModel().openLicense()
|
||||
'window:run-package-specs': -> @runPackageSpecs()
|
||||
'window:focus-next-pane': -> @getModel().activateNextPane()
|
||||
'window:focus-previous-pane': -> @getModel().activatePreviousPane()
|
||||
'window:focus-pane-above': -> @focusPaneViewAbove()
|
||||
'window:focus-pane-below': -> @focusPaneViewBelow()
|
||||
'window:focus-pane-on-left': -> @focusPaneViewOnLeft()
|
||||
'window:focus-pane-on-right': -> @focusPaneViewOnRight()
|
||||
'window:save-all': -> @getModel().saveAll()
|
||||
'window:toggle-invisibles': -> atom.config.set("editor.showInvisibles", not atom.config.get("editor.showInvisibles"))
|
||||
'window:log-deprecation-warnings': -> Grim.logDeprecations()
|
||||
'window:toggle-auto-indent': -> atom.config.set("editor.autoIndent", not atom.config.get("editor.autoIndent"))
|
||||
'pane:reopen-closed-item': -> @getModel().reopenItem()
|
||||
'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane()
|
||||
'core:save': -> @getModel().saveActivePaneItem()
|
||||
'core:save-as': -> @getModel().saveActivePaneItemAs()
|
||||
|
||||
if process.platform is 'darwin'
|
||||
atom.commands.add 'atom-workspace', 'window:install-shell-commands', -> @getModel().installShellCommands()
|
||||
|
||||
module.exports = WorkspaceElement = document.registerElement 'atom-workspace', prototype: WorkspaceElement.prototype
|
||||
|
||||
@@ -9,10 +9,7 @@ TextEditor = require './text-editor'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
Panel = require './panel'
|
||||
PanelElement = require './panel-element'
|
||||
PanelContainer = require './panel-container'
|
||||
PanelContainerElement = require './panel-container-element'
|
||||
WorkspaceElement = require './workspace-element'
|
||||
Task = require './task'
|
||||
|
||||
# Essential: Represents the state of the user interface for the entire window.
|
||||
@@ -26,36 +23,24 @@ Task = require './task'
|
||||
#
|
||||
module.exports =
|
||||
class Workspace extends Model
|
||||
atom.deserializers.add(this)
|
||||
|
||||
@deserialize: (state) ->
|
||||
return unless state?
|
||||
|
||||
for packageName in state.packagesWithActiveGrammars ? []
|
||||
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
|
||||
|
||||
state.paneContainer = PaneContainer.deserialize(state.paneContainer)
|
||||
new this(state)
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@paneContainer = params?.paneContainer
|
||||
@fullScreen = params?.fullScreen ? false
|
||||
@destroyedItemURIs = params?.destroyedItemURIs ? []
|
||||
{
|
||||
@packageManager, @config, @project, @grammarRegistry, @notificationManager,
|
||||
@clipboard, @viewRegistry, @grammarRegistry, @applicationDelegate, @assert,
|
||||
@deserializerManager
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@openers = []
|
||||
@destroyedItemURIs = []
|
||||
|
||||
@paneContainer ?= new PaneContainer()
|
||||
@paneContainer = new PaneContainer({@config, @applicationDelegate, @notificationManager, @deserializerManager})
|
||||
@paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem)
|
||||
|
||||
@directorySearchers = []
|
||||
@defaultDirectorySearcher = new DefaultDirectorySearcher()
|
||||
atom.packages.serviceHub.consume(
|
||||
'atom.directory-searcher',
|
||||
'^0.1.0',
|
||||
(provider) => @directorySearchers.unshift(provider))
|
||||
@consumeServices(@packageManager)
|
||||
|
||||
@panelContainers =
|
||||
top: new PanelContainer({location: 'top'})
|
||||
@@ -64,69 +49,80 @@ class Workspace extends Model
|
||||
bottom: new PanelContainer({location: 'bottom'})
|
||||
modal: new PanelContainer({location: 'modal'})
|
||||
|
||||
@subscribeToEvents()
|
||||
|
||||
reset: (@packageManager) ->
|
||||
@emitter.dispose()
|
||||
@emitter = new Emitter
|
||||
|
||||
@paneContainer.destroy()
|
||||
panelContainer.destroy() for panelContainer in @panelContainers
|
||||
|
||||
@paneContainer = new PaneContainer({@config, @applicationDelegate, @notificationManager, @deserializerManager})
|
||||
@paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem)
|
||||
|
||||
@panelContainers =
|
||||
top: new PanelContainer({location: 'top'})
|
||||
left: new PanelContainer({location: 'left'})
|
||||
right: new PanelContainer({location: 'right'})
|
||||
bottom: new PanelContainer({location: 'bottom'})
|
||||
modal: new PanelContainer({location: 'modal'})
|
||||
|
||||
@originalFontSize = null
|
||||
@openers = []
|
||||
@destroyedItemURIs = []
|
||||
@consumeServices(@packageManager)
|
||||
|
||||
subscribeToEvents: ->
|
||||
@subscribeToActiveItem()
|
||||
|
||||
@addOpener (filePath) ->
|
||||
switch filePath
|
||||
when 'atom://.atom/stylesheet'
|
||||
atom.project.open(atom.styles.getUserStyleSheetPath())
|
||||
when 'atom://.atom/keymap'
|
||||
atom.project.open(atom.keymaps.getUserKeymapPath())
|
||||
when 'atom://.atom/config'
|
||||
atom.project.open(atom.config.getUserConfigPath())
|
||||
when 'atom://.atom/init-script'
|
||||
atom.project.open(atom.getUserInitScriptPath())
|
||||
|
||||
atom.views.addViewProvider Workspace, (model) ->
|
||||
new WorkspaceElement().initialize(model)
|
||||
|
||||
atom.views.addViewProvider PanelContainer, (model) ->
|
||||
new PanelContainerElement().initialize(model)
|
||||
|
||||
atom.views.addViewProvider Panel, (model) ->
|
||||
new PanelElement().initialize(model)
|
||||
|
||||
@subscribeToFontSize()
|
||||
|
||||
consumeServices: ({serviceHub}) ->
|
||||
@directorySearchers = []
|
||||
serviceHub.consume(
|
||||
'atom.directory-searcher',
|
||||
'^0.1.0',
|
||||
(provider) => @directorySearchers.unshift(provider))
|
||||
|
||||
# Called by the Serializable mixin during serialization.
|
||||
serialize: ->
|
||||
deserializer: 'Workspace'
|
||||
paneContainer: @paneContainer.serialize()
|
||||
fullScreen: atom.isFullScreen()
|
||||
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
|
||||
destroyedItemURIs: @destroyedItemURIs.slice()
|
||||
|
||||
deserialize: (state, deserializerManager) ->
|
||||
for packageName in state.packagesWithActiveGrammars ? []
|
||||
@packageManager.getLoadedPackage(packageName)?.loadGrammarsSync()
|
||||
if state.destroyedItemURIs?
|
||||
@destroyedItemURIs = state.destroyedItemURIs
|
||||
@paneContainer.deserialize(state.paneContainer, deserializerManager)
|
||||
|
||||
getPackageNamesWithActiveGrammars: ->
|
||||
packageNames = []
|
||||
addGrammar = ({includedGrammarScopes, packageName}={}) ->
|
||||
addGrammar = ({includedGrammarScopes, packageName}={}) =>
|
||||
return unless packageName
|
||||
# Prevent cycles
|
||||
return if packageNames.indexOf(packageName) isnt -1
|
||||
|
||||
packageNames.push(packageName)
|
||||
for scopeName in includedGrammarScopes ? []
|
||||
addGrammar(atom.grammars.grammarForScopeName(scopeName))
|
||||
addGrammar(@grammarRegistry.grammarForScopeName(scopeName))
|
||||
return
|
||||
|
||||
editors = @getTextEditors()
|
||||
addGrammar(editor.getGrammar()) for editor in editors
|
||||
|
||||
if editors.length > 0
|
||||
for grammar in atom.grammars.getGrammars() when grammar.injectionSelector
|
||||
for grammar in @grammarRegistry.getGrammars() when grammar.injectionSelector
|
||||
addGrammar(grammar)
|
||||
|
||||
_.uniq(packageNames)
|
||||
|
||||
editorAdded: (editor) ->
|
||||
|
||||
installShellCommands: ->
|
||||
CommandInstaller = require('./command-installer')
|
||||
commandInstaller = new CommandInstaller(atom.getVersion())
|
||||
commandInstaller.installShellCommandsInteractively()
|
||||
|
||||
subscribeToActiveItem: ->
|
||||
@updateWindowTitle()
|
||||
@updateDocumentEdited()
|
||||
atom.project.onDidChangePaths @updateWindowTitle
|
||||
@project.onDidChangePaths @updateWindowTitle
|
||||
|
||||
@observeActivePaneItem (item) =>
|
||||
@updateWindowTitle()
|
||||
@@ -156,7 +152,7 @@ class Workspace extends Model
|
||||
# open.
|
||||
updateWindowTitle: =>
|
||||
appName = 'Atom'
|
||||
projectPaths = atom.project?.getPaths() ? []
|
||||
projectPaths = @project.getPaths() ? []
|
||||
if item = @getActivePaneItem()
|
||||
itemPath = item.getPath?()
|
||||
itemTitle = item.getTitle?()
|
||||
@@ -167,19 +163,19 @@ class Workspace extends Model
|
||||
|
||||
if item? and projectPath?
|
||||
document.title = "#{itemTitle} - #{projectPath} - #{appName}"
|
||||
atom.setRepresentedFilename(itemPath ? projectPath)
|
||||
@applicationDelegate.setRepresentedFilename(itemPath ? projectPath)
|
||||
else if projectPath?
|
||||
document.title = "#{projectPath} - #{appName}"
|
||||
atom.setRepresentedFilename(projectPath)
|
||||
@applicationDelegate.setRepresentedFilename(projectPath)
|
||||
else
|
||||
document.title = "#{itemTitle} - #{appName}"
|
||||
atom.setRepresentedFilename("")
|
||||
@applicationDelegate.setRepresentedFilename("")
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: =>
|
||||
modified = @getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
@applicationDelegate.setWindowDocumentEdited(modified)
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
@@ -391,6 +387,8 @@ class Workspace extends Model
|
||||
# item will be opened in the rightmost pane of the current active pane's row.
|
||||
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# containing pane. Defaults to `true`.
|
||||
# * `activateItem` A {Boolean} indicating whether to call {Pane::activateItem}
|
||||
# on containing pane. Defaults to `true`.
|
||||
# * `searchAllPanes` A {Boolean}. If `true`, the workspace will attempt to
|
||||
# activate an existing item for the given URI on any pane.
|
||||
# If `false`, only the active pane will be searched for
|
||||
@@ -400,7 +398,7 @@ class Workspace extends Model
|
||||
open: (uri, options={}) ->
|
||||
searchAllPanes = options.searchAllPanes
|
||||
split = options.split
|
||||
uri = atom.project.resolvePath(uri)
|
||||
uri = @project.resolvePath(uri)
|
||||
|
||||
pane = @paneContainer.paneForURI(uri) if searchAllPanes
|
||||
pane ?= switch split
|
||||
@@ -429,50 +427,51 @@ class Workspace extends Model
|
||||
# initially. Defaults to `0`.
|
||||
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# the containing pane. Defaults to `true`.
|
||||
# * `activateItem` A {Boolean} indicating whether to call {Pane::activateItem}
|
||||
# on containing pane. Defaults to `true`.
|
||||
openSync: (uri='', options={}) ->
|
||||
{initialLine, initialColumn} = options
|
||||
activatePane = options.activatePane ? true
|
||||
activateItem = options.activateItem ? true
|
||||
|
||||
uri = atom.project.resolvePath(uri)
|
||||
uri = @project.resolvePath(uri)
|
||||
item = @getActivePane().itemForURI(uri)
|
||||
if uri
|
||||
item ?= opener(uri, options) for opener in @getOpeners() when not item
|
||||
item ?= atom.project.openSync(uri, {initialLine, initialColumn})
|
||||
item ?= @project.openSync(uri, {initialLine, initialColumn})
|
||||
|
||||
@getActivePane().activateItem(item)
|
||||
@getActivePane().activateItem(item) if activateItem
|
||||
@itemOpened(item)
|
||||
@getActivePane().activate() if activatePane
|
||||
item
|
||||
|
||||
openURIInPane: (uri, pane, options={}) ->
|
||||
activatePane = options.activatePane ? true
|
||||
activateItem = options.activateItem ? true
|
||||
|
||||
if uri?
|
||||
item = pane.itemForURI(uri)
|
||||
item ?= opener(uri, options) for opener in @getOpeners() when not item
|
||||
|
||||
try
|
||||
item ?= atom.project.open(uri, options)
|
||||
item ?= @openTextFile(uri, options)
|
||||
catch error
|
||||
switch error.code
|
||||
when 'CANCELLED'
|
||||
return Promise.resolve()
|
||||
when 'EACCES'
|
||||
atom.notifications.addWarning("Permission denied '#{error.path}'")
|
||||
@notificationManager.addWarning("Permission denied '#{error.path}'")
|
||||
return Promise.resolve()
|
||||
when 'EPERM', 'EBUSY', 'ENXIO', 'EIO', 'ENOTCONN', 'UNKNOWN', 'ECONNRESET', 'EINVAL'
|
||||
atom.notifications.addWarning("Unable to open '#{error.path ? uri}'", detail: error.message)
|
||||
@notificationManager.addWarning("Unable to open '#{error.path ? uri}'", detail: error.message)
|
||||
return Promise.resolve()
|
||||
else
|
||||
throw error
|
||||
|
||||
Promise.resolve(item)
|
||||
.then (item) =>
|
||||
if not pane
|
||||
pane = new Pane(items: [item])
|
||||
@paneContainer.root = pane
|
||||
@itemOpened(item)
|
||||
pane.activateItem(item)
|
||||
pane.activateItem(item) if activateItem
|
||||
pane.activate() if activatePane
|
||||
|
||||
initialLine = initialColumn = 0
|
||||
@@ -487,6 +486,42 @@ class Workspace extends Model
|
||||
@emitter.emit 'did-open', {uri, pane, item, index}
|
||||
item
|
||||
|
||||
openTextFile: (uri, options) ->
|
||||
filePath = @project.resolvePath(uri)
|
||||
|
||||
if filePath?
|
||||
try
|
||||
fs.closeSync(fs.openSync(filePath, 'r'))
|
||||
catch error
|
||||
# allow ENOENT errors to create an editor for paths that dont exist
|
||||
throw error unless error.code is 'ENOENT'
|
||||
|
||||
fileSize = fs.getSizeSync(filePath)
|
||||
|
||||
largeFileMode = fileSize >= 2 * 1048576 # 2MB
|
||||
if fileSize >= 20 * 1048576 # 20MB
|
||||
choice = @applicationDelegate.confirm
|
||||
message: 'Atom will be unresponsive during the loading of very large files.'
|
||||
detailedMessage: "Do you still want to load this file?"
|
||||
buttons: ["Proceed", "Cancel"]
|
||||
if choice is 1
|
||||
error = new Error
|
||||
error.code = 'CANCELLED'
|
||||
throw error
|
||||
|
||||
@project.bufferForPath(filePath, options).then (buffer) =>
|
||||
@buildTextEditor(_.extend({buffer, largeFileMode}, options))
|
||||
|
||||
# Extended: Create a new text editor.
|
||||
#
|
||||
# Returns a {TextEditor}.
|
||||
buildTextEditor: (params) ->
|
||||
params = _.extend({
|
||||
@config, @notificationManager, @packageManager, @clipboard, @viewRegistry,
|
||||
@grammarRegistry, @project, @assert, @applicationDelegate
|
||||
}, params)
|
||||
new TextEditor(params)
|
||||
|
||||
# Public: Asynchronously reopens the last-closed item's URI if it hasn't already been
|
||||
# reopened.
|
||||
#
|
||||
@@ -640,20 +675,20 @@ class Workspace extends Model
|
||||
|
||||
# Increase the editor font size by 1px.
|
||||
increaseFontSize: ->
|
||||
atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
|
||||
@config.set("editor.fontSize", @config.get("editor.fontSize") + 1)
|
||||
|
||||
# Decrease the editor font size by 1px.
|
||||
decreaseFontSize: ->
|
||||
fontSize = atom.config.get("editor.fontSize")
|
||||
atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1
|
||||
fontSize = @config.get("editor.fontSize")
|
||||
@config.set("editor.fontSize", fontSize - 1) if fontSize > 1
|
||||
|
||||
# Restore to the window's original editor font size.
|
||||
resetFontSize: ->
|
||||
if @originalFontSize
|
||||
atom.config.set("editor.fontSize", @originalFontSize)
|
||||
@config.set("editor.fontSize", @originalFontSize)
|
||||
|
||||
subscribeToFontSize: ->
|
||||
atom.config.onDidChange 'editor.fontSize', ({oldValue}) =>
|
||||
@config.onDidChange 'editor.fontSize', ({oldValue}) =>
|
||||
@originalFontSize ?= oldValue
|
||||
|
||||
# Removes the item's uri from the list of potential items to reopen.
|
||||
@@ -831,7 +866,7 @@ class Workspace extends Model
|
||||
# Find a searcher for every Directory in the project. Each searcher that is matched
|
||||
# will be associated with an Array of Directory objects in the Map.
|
||||
directoriesForSearcher = new Map()
|
||||
for directory in atom.project.getDirectories()
|
||||
for directory in @project.getDirectories()
|
||||
searcher = @defaultDirectorySearcher
|
||||
for directorySearcher in @directorySearchers
|
||||
if directorySearcher.canSearchDirectory(directory)
|
||||
@@ -862,15 +897,15 @@ class Workspace extends Model
|
||||
|
||||
# Kick off all of the searches and unify them into one Promise.
|
||||
allSearches = []
|
||||
directoriesForSearcher.forEach (directories, searcher) ->
|
||||
directoriesForSearcher.forEach (directories, searcher) =>
|
||||
searchOptions =
|
||||
inclusions: options.paths or []
|
||||
includeHidden: true
|
||||
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
|
||||
exclusions: atom.config.get('core.ignoredNames')
|
||||
follow: atom.config.get('core.followSymlinks')
|
||||
didMatch: (result) ->
|
||||
iterator(result) unless atom.project.isPathModified(result.filePath)
|
||||
excludeVcsIgnores: @config.get('core.excludeVcsIgnoredPaths')
|
||||
exclusions: @config.get('core.ignoredNames')
|
||||
follow: @config.get('core.followSymlinks')
|
||||
didMatch: (result) =>
|
||||
iterator(result) unless @project.isPathModified(result.filePath)
|
||||
didError: (error) ->
|
||||
iterator(null, error)
|
||||
didSearchPaths: (count) -> onPathsSearched(searcher, count)
|
||||
@@ -878,9 +913,9 @@ class Workspace extends Model
|
||||
allSearches.push(directorySearcher)
|
||||
searchPromise = Promise.all(allSearches)
|
||||
|
||||
for buffer in atom.project.getBuffers() when buffer.isModified()
|
||||
for buffer in @project.getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless atom.project.contains(filePath)
|
||||
continue unless @project.contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
@@ -926,8 +961,8 @@ class Workspace extends Model
|
||||
#
|
||||
# Returns a `Promise`.
|
||||
replace: (regex, replacementText, filePaths, iterator) ->
|
||||
new Promise (resolve, reject) ->
|
||||
openPaths = (buffer.getPath() for buffer in atom.project.getBuffers())
|
||||
new Promise (resolve, reject) =>
|
||||
openPaths = (buffer.getPath() for buffer in @project.getBuffers())
|
||||
outOfProcessPaths = _.difference(filePaths, openPaths)
|
||||
|
||||
inProcessFinished = not openPaths.length
|
||||
@@ -946,7 +981,7 @@ class Workspace extends Model
|
||||
task.on 'replace:path-replaced', iterator
|
||||
task.on 'replace:file-error', (error) -> iterator(null, error)
|
||||
|
||||
for buffer in atom.project.getBuffers()
|
||||
for buffer in @project.getBuffers()
|
||||
continue unless buffer.getPath() in filePaths
|
||||
replacements = buffer.replace(regex, replacementText, iterator)
|
||||
iterator({filePath: buffer.getPath(), replacements}) if replacements
|
||||
|
||||
Reference in New Issue
Block a user