Convert workspace to JavaScript: cleanup

This commit is contained in:
Matthew Dapena-Tretter
2017-03-02 15:40:57 -08:00
parent 7a0d7f8b4c
commit 53ec839ae5
2 changed files with 841 additions and 704 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
'use strict'
const _ = require('underscore-plus') const _ = require('underscore-plus')
const url = require('url') const url = require('url')
const path = require('path') const path = require('path')
@@ -29,17 +31,27 @@ module.exports = class Workspace extends Model {
this.updateDocumentEdited = this.updateDocumentEdited.bind(this) this.updateDocumentEdited = this.updateDocumentEdited.bind(this)
this.didDestroyPaneItem = this.didDestroyPaneItem.bind(this) this.didDestroyPaneItem = this.didDestroyPaneItem.bind(this)
;({ this.packageManager = params.packageManager
packageManager: this.packageManager, config: this.config, project: this.project, grammarRegistry: this.grammarRegistry, notificationManager: this.notificationManager, this.config = params.config
viewRegistry: this.viewRegistry, grammarRegistry: this.grammarRegistry, applicationDelegate: this.applicationDelegate, assert: this.assert, this.project = params.project
deserializerManager: this.deserializerManager, textEditorRegistry: this.textEditorRegistry this.notificationManager = params.notificationManager
} = params) this.viewRegistry = params.viewRegistry
this.grammarRegistry = params.grammarRegistry
this.applicationDelegate = params.applicationDelegate
this.assert = params.assert
this.deserializerManager = params.deserializerManager
this.textEditorRegistry = params.textEditorRegistry
this.emitter = new Emitter() this.emitter = new Emitter()
this.openers = [] this.openers = []
this.destroyedItemURIs = [] this.destroyedItemURIs = []
this.paneContainer = new PaneContainer({config: this.config, applicationDelegate: this.applicationDelegate, notificationManager: this.notificationManager, deserializerManager: this.deserializerManager}) this.paneContainer = new PaneContainer({
config: this.config,
applicationDelegate: this.applicationDelegate,
notificationManager: this.notificationManager,
deserializerManager: this.deserializerManager
})
this.paneContainer.onDidDestroyPaneItem(this.didDestroyPaneItem) this.paneContainer.onDidDestroyPaneItem(this.didDestroyPaneItem)
this.defaultDirectorySearcher = new DefaultDirectorySearcher() this.defaultDirectorySearcher = new DefaultDirectorySearcher()
@@ -49,7 +61,7 @@ module.exports = class Workspace extends Model {
// Etch, in which case it'd be `new`d. And when it's `new`d, `this` is always // Etch, in which case it'd be `new`d. And when it's `new`d, `this` is always
// the newly created object. // the newly created object.
const realThis = this const realThis = this
this.buildTextEditor = function () { return Workspace.prototype.buildTextEditor.apply(realThis, arguments) } this.buildTextEditor = () => Workspace.prototype.buildTextEditor.apply(realThis, arguments)
this.panelContainers = { this.panelContainers = {
top: new PanelContainer({location: 'top'}), top: new PanelContainer({location: 'top'}),
@@ -70,9 +82,14 @@ module.exports = class Workspace extends Model {
this.emitter = new Emitter() this.emitter = new Emitter()
this.paneContainer.destroy() this.paneContainer.destroy()
for (let panelContainer of this.panelContainers) { panelContainer.destroy() } _.values(this.panelContainers).forEach(panelContainer => { panelContainer.destroy() })
this.paneContainer = new PaneContainer({config: this.config, applicationDelegate: this.applicationDelegate, notificationManager: this.notificationManager, deserializerManager: this.deserializerManager}) this.paneContainer = new PaneContainer({
config: this.config,
applicationDelegate: this.applicationDelegate,
notificationManager: this.notificationManager,
deserializerManager: this.deserializerManager
})
this.paneContainer.onDidDestroyPaneItem(this.didDestroyPaneItem) this.paneContainer.onDidDestroyPaneItem(this.didDestroyPaneItem)
this.panelContainers = { this.panelContainers = {
@@ -88,21 +105,22 @@ module.exports = class Workspace extends Model {
this.originalFontSize = null this.originalFontSize = null
this.openers = [] this.openers = []
this.destroyedItemURIs = [] this.destroyedItemURIs = []
return this.consumeServices(this.packageManager) this.consumeServices(this.packageManager)
} }
subscribeToEvents () { subscribeToEvents () {
this.subscribeToActiveItem() this.subscribeToActiveItem()
this.subscribeToFontSize() this.subscribeToFontSize()
return this.subscribeToAddedItems() this.subscribeToAddedItems()
} }
consumeServices ({serviceHub}) { consumeServices ({serviceHub}) {
this.directorySearchers = [] this.directorySearchers = []
return serviceHub.consume( serviceHub.consume(
'atom.directory-searcher', 'atom.directory-searcher',
'^0.1.0', '^0.1.0',
provider => this.directorySearchers.unshift(provider)) provider => this.directorySearchers.unshift(provider)
)
} }
// Called by the Serializable mixin during serialization. // Called by the Serializable mixin during serialization.
@@ -116,8 +134,13 @@ module.exports = class Workspace extends Model {
} }
deserialize (state, deserializerManager) { deserialize (state, deserializerManager) {
for (let packageName of state.packagesWithActiveGrammars != null ? state.packagesWithActiveGrammars : []) { const packagesWithActiveGrammars =
__guard__(this.packageManager.getLoadedPackage(packageName), x => x.loadGrammarsSync()) state.packagesWithActiveGrammars != null ? state.packagesWithActiveGrammars : []
for (let packageName of packagesWithActiveGrammars) {
const pkg = this.packageManager.getLoadedPackage(packageName)
if (pkg != null) {
pkg.loadGrammarsSync()
}
} }
if (state.destroyedItemURIs != null) { if (state.destroyedItemURIs != null) {
this.destroyedItemURIs = state.destroyedItemURIs this.destroyedItemURIs = state.destroyedItemURIs
@@ -127,7 +150,7 @@ module.exports = class Workspace extends Model {
getPackageNamesWithActiveGrammars () { getPackageNamesWithActiveGrammars () {
const packageNames = [] const packageNames = []
var addGrammar = ({includedGrammarScopes, packageName} = {}) => { const addGrammar = ({includedGrammarScopes, packageName} = {}) => {
if (!packageName) { return } if (!packageName) { return }
// Prevent cycles // Prevent cycles
if (packageNames.indexOf(packageName) !== -1) { return } if (packageNames.indexOf(packageName) !== -1) { return }
@@ -157,8 +180,7 @@ module.exports = class Workspace extends Model {
this.updateDocumentEdited() this.updateDocumentEdited()
this.project.onDidChangePaths(this.updateWindowTitle) this.project.onDidChangePaths(this.updateWindowTitle)
return this.observeActivePaneItem(item => { this.observeActivePaneItem(item => {
let modifiedSubscription, titleSubscription
this.updateWindowTitle() this.updateWindowTitle()
this.updateDocumentEdited() this.updateDocumentEdited()
@@ -167,32 +189,37 @@ module.exports = class Workspace extends Model {
} }
this.activeItemSubscriptions = new CompositeDisposable() this.activeItemSubscriptions = new CompositeDisposable()
if (typeof (item != null ? item.onDidChangeTitle : undefined) === 'function') { let modifiedSubscription, titleSubscription
if (item != null && typeof item.onDidChangeTitle === 'function') {
titleSubscription = item.onDidChangeTitle(this.updateWindowTitle) titleSubscription = item.onDidChangeTitle(this.updateWindowTitle)
} else if (typeof (item != null ? item.on : undefined) === 'function') { } else if (item != null && typeof item.on === 'function') {
titleSubscription = item.on('title-changed', this.updateWindowTitle) titleSubscription = item.on('title-changed', this.updateWindowTitle)
if (typeof (titleSubscription != null ? titleSubscription.dispose : undefined) !== 'function') { if (titleSubscription == null || typeof titleSubscription.dispose !== 'function') {
titleSubscription = new Disposable((function () { return item.off('title-changed', this.updateWindowTitle) }.bind(this))) titleSubscription = new Disposable(() => {
item.off('title-changed', this.updateWindowTitle)
})
} }
} }
if (typeof (item != null ? item.onDidChangeModified : undefined) === 'function') { if (item != null && typeof item.onDidChangeModified === 'function') {
modifiedSubscription = item.onDidChangeModified(this.updateDocumentEdited) modifiedSubscription = item.onDidChangeModified(this.updateDocumentEdited)
} else if (typeof ((item != null ? item.on : undefined) != null) === 'function') { } else if (item != null && typeof item.on === 'function') {
modifiedSubscription = item.on('modified-status-changed', this.updateDocumentEdited) modifiedSubscription = item.on('modified-status-changed', this.updateDocumentEdited)
if (typeof (modifiedSubscription != null ? modifiedSubscription.dispose : undefined) !== 'function') { if (modifiedSubscription == null || typeof modifiedSubscription.dispose !== 'function') {
modifiedSubscription = new Disposable((function () { return item.off('modified-status-changed', this.updateDocumentEdited) }.bind(this))) modifiedSubscription = new Disposable(() => {
item.off('modified-status-changed', this.updateDocumentEdited)
})
} }
} }
if (titleSubscription != null) { this.activeItemSubscriptions.add(titleSubscription) } if (titleSubscription != null) { this.activeItemSubscriptions.add(titleSubscription) }
if (modifiedSubscription != null) { return this.activeItemSubscriptions.add(modifiedSubscription) } if (modifiedSubscription != null) { this.activeItemSubscriptions.add(modifiedSubscription) }
} })
)
} }
subscribeToAddedItems () { subscribeToAddedItems () {
return this.onDidAddPaneItem(({item, pane, index}) => { this.onDidAddPaneItem(({item, pane, index}) => {
if (item instanceof TextEditor) { if (item instanceof TextEditor) {
const subscriptions = new CompositeDisposable( const subscriptions = new CompositeDisposable(
this.textEditorRegistry.add(item), this.textEditorRegistry.add(item),
@@ -200,8 +227,8 @@ module.exports = class Workspace extends Model {
this.textEditorRegistry.maintainConfig(item), this.textEditorRegistry.maintainConfig(item),
item.observeGrammar(this.handleGrammarUsed.bind(this)) item.observeGrammar(this.handleGrammarUsed.bind(this))
) )
item.onDidDestroy(() => subscriptions.dispose()) item.onDidDestroy(() => { subscriptions.dispose() })
return this.emitter.emit('did-add-text-editor', {textEditor: item, pane, index}) this.emitter.emit('did-add-text-editor', {textEditor: item, pane, index})
} }
}) })
} }
@@ -209,14 +236,22 @@ module.exports = class Workspace extends Model {
// Updates the application's title and proxy icon based on whichever file is // Updates the application's title and proxy icon based on whichever file is
// open. // open.
updateWindowTitle () { updateWindowTitle () {
let item, itemPath, itemTitle, left, projectPath, representedPath let itemPath, itemTitle, projectPath, representedPath
const appName = 'Atom' const appName = 'Atom'
const projectPaths = (left = this.project.getPaths()) != null ? left : [] const left = this.project.getPaths()
if ((item = this.getActivePaneItem())) { const projectPaths = left != null ? left : []
let left1 const item = this.getActivePaneItem()
if (item) {
itemPath = typeof item.getPath === 'function' ? item.getPath() : undefined itemPath = typeof item.getPath === 'function' ? item.getPath() : undefined
itemTitle = (left1 = (typeof item.getLongTitle === 'function' ? item.getLongTitle() : undefined)) != null ? left1 : (typeof item.getTitle === 'function' ? item.getTitle() : undefined) const longTitle = typeof item.getLongTitle === 'function' ? item.getLongTitle() : undefined
projectPath = _.find(projectPaths, projectPath => (itemPath === projectPath) || (itemPath != null ? itemPath.startsWith(projectPath + path.sep) : undefined)) itemTitle = longTitle == null
? (typeof item.getTitle === 'function' ? item.getTitle() : undefined)
: longTitle
projectPath = _.find(
projectPaths,
projectPath =>
(itemPath === projectPath) || (itemPath != null ? itemPath.startsWith(projectPath + path.sep) : undefined)
)
} }
if (itemTitle == null) { itemTitle = 'untitled' } if (itemTitle == null) { itemTitle = 'untitled' }
if (projectPath == null) { projectPath = itemPath ? path.dirname(itemPath) : projectPaths[0] } if (projectPath == null) { projectPath = itemPath ? path.dirname(itemPath) : projectPaths[0] }
@@ -241,15 +276,17 @@ module.exports = class Workspace extends Model {
} }
document.title = titleParts.join(' \u2014 ') document.title = titleParts.join(' \u2014 ')
return this.applicationDelegate.setRepresentedFilename(representedPath) this.applicationDelegate.setRepresentedFilename(representedPath)
} }
// On macOS, fades the application window's proxy icon when the current file // On macOS, fades the application window's proxy icon when the current file
// has been modified. // has been modified.
updateDocumentEdited () { updateDocumentEdited () {
let left const activePaneItem = this.getActivePaneItem()
const modified = (left = __guardMethod__(this.getActivePaneItem(), 'isModified', o => o.isModified())) != null ? left : false const modified = activePaneItem != null && typeof activePaneItem.isModified === 'function'
return this.applicationDelegate.setWindowDocumentEdited(modified) ? activePaneItem.isModified() || false
: false
this.applicationDelegate.setWindowDocumentEdited(modified)
} }
/* /*
@@ -479,11 +516,10 @@ module.exports = class Workspace extends Model {
// an existing item for the same URI. Defaults to `false`. // an existing item for the same URI. Defaults to `false`.
// //
// Returns a {Promise} that resolves to the {TextEditor} for the file URI. // Returns a {Promise} that resolves to the {TextEditor} for the file URI.
open (uri, options = {}) { open (uri_, options = {}) {
let pane
const { searchAllPanes } = options const { searchAllPanes } = options
const { split } = options const { split } = options
uri = this.project.resolvePath(uri) const uri = this.project.resolvePath(uri_)
if (!atom.config.get('core.allowPendingPaneItems')) { if (!atom.config.get('core.allowPendingPaneItems')) {
options.pending = false options.pending = false
@@ -495,22 +531,26 @@ module.exports = class Workspace extends Model {
this.applicationDelegate.addRecentDocument(uri) this.applicationDelegate.addRecentDocument(uri)
} }
let pane
if (searchAllPanes) { pane = this.paneContainer.paneForURI(uri) } if (searchAllPanes) { pane = this.paneContainer.paneForURI(uri) }
if (pane == null) { if (pane == null) {
pane = (() => {
switch (split) { switch (split) {
case 'left': case 'left':
return this.getActivePane().findLeftmostSibling() pane = this.getActivePane().findLeftmostSibling()
break
case 'right': case 'right':
return this.getActivePane().findOrCreateRightmostSibling() pane = this.getActivePane().findOrCreateRightmostSibling()
break
case 'up': case 'up':
return this.getActivePane().findTopmostSibling() pane = this.getActivePane().findTopmostSibling()
break
case 'down': case 'down':
return this.getActivePane().findOrCreateBottommostSibling() pane = this.getActivePane().findOrCreateBottommostSibling()
break
default: default:
return this.getActivePane() pane = this.getActivePane()
break
} }
})()
} }
return this.openURIInPane(uri, pane, options) return this.openURIInPane(uri, pane, options)
@@ -535,38 +575,54 @@ module.exports = class Workspace extends Model {
// the containing pane. Defaults to `true`. // the containing pane. Defaults to `true`.
// * `activateItem` A {Boolean} indicating whether to call {Pane::activateItem} // * `activateItem` A {Boolean} indicating whether to call {Pane::activateItem}
// on containing pane. Defaults to `true`. // on containing pane. Defaults to `true`.
openSync (uri = '', options = {}) { openSync (uri_ = '', options = {}) {
const {initialLine, initialColumn} = options const {initialLine, initialColumn} = options
const activatePane = options.activatePane != null ? options.activatePane : true const activatePane = options.activatePane != null ? options.activatePane : true
const activateItem = options.activateItem != null ? options.activateItem : true const activateItem = options.activateItem != null ? options.activateItem : true
uri = this.project.resolvePath(uri) const uri = this.project.resolvePath(uri)
let item = this.getActivePane().itemForURI(uri) let item = this.getActivePane().itemForURI(uri)
if (uri) { if (uri && (item == null)) {
for (let opener of this.getOpeners()) { if (!item) { if (item == null) { item = opener(uri, options) } } } for (const opener of this.getOpeners()) {
item = opener(uri, options)
if (item) break
}
}
if (item == null) {
item = this.project.openSync(uri, {initialLine, initialColumn})
} }
if (item == null) { item = this.project.openSync(uri, {initialLine, initialColumn}) }
if (activateItem) { this.getActivePane().activateItem(item) } if (activateItem) {
this.getActivePane().activateItem(item)
}
this.itemOpened(item) this.itemOpened(item)
if (activatePane) { this.getActivePane().activate() } if (activatePane) {
this.getActivePane().activate()
}
return item return item
} }
openURIInPane (uri, pane, options = {}) { openURIInPane (uri, pane, options = {}) {
let item
const activatePane = options.activatePane != null ? options.activatePane : true const activatePane = options.activatePane != null ? options.activatePane : true
const activateItem = options.activateItem != null ? options.activateItem : true const activateItem = options.activateItem != null ? options.activateItem : true
let item
if (uri != null) { if (uri != null) {
if ((item = pane.itemForURI(uri))) { item = pane.itemForURI(uri)
if (!options.pending && (pane.getPendingItem() === item)) { pane.clearPendingItem() } if (item == null) {
for (let opener of this.getOpeners()) {
item = opener(uri, options)
if (item != null) break
}
} else if (!options.pending && (pane.getPendingItem() === item)) {
pane.clearPendingItem()
} }
for (let opener of this.getOpeners()) { if (!item) { if (item == null) { item = opener(uri, options) } } }
} }
try { try {
if (item == null) { item = this.openTextFile(uri, options) } if (item == null) {
item = this.openTextFile(uri, options)
}
} catch (error) { } catch (error) {
switch (error.code) { switch (error.code) {
case 'CANCELLED': case 'CANCELLED':
@@ -574,8 +630,21 @@ module.exports = class Workspace extends Model {
case 'EACCES': case 'EACCES':
this.notificationManager.addWarning(`Permission denied '${error.path}'`) this.notificationManager.addWarning(`Permission denied '${error.path}'`)
return Promise.resolve() return Promise.resolve()
case 'EPERM': case 'EBUSY': case 'ENXIO': case 'EIO': case 'ENOTCONN': case 'UNKNOWN': case 'ECONNRESET': case 'EINVAL': case 'EMFILE': case 'ENOTDIR': case 'EAGAIN': case 'EPERM':
this.notificationManager.addWarning(`Unable to open '${error.path != null ? error.path : uri}'`, {detail: error.message}) case 'EBUSY':
case 'ENXIO':
case 'EIO':
case 'ENOTCONN':
case 'UNKNOWN':
case 'ECONNRESET':
case 'EINVAL':
case 'EMFILE':
case 'ENOTDIR':
case 'EAGAIN':
this.notificationManager.addWarning(
`Unable to open '${error.path != null ? error.path : uri}'`,
{detail: error.message}
)
return Promise.resolve() return Promise.resolve()
default: default:
throw error throw error
@@ -585,18 +654,24 @@ module.exports = class Workspace extends Model {
return Promise.resolve(item) return Promise.resolve(item)
.then(item => { .then(item => {
let initialColumn let initialColumn
if (pane.isDestroyed()) { return item } if (pane.isDestroyed()) {
return item
}
this.itemOpened(item) this.itemOpened(item)
if (activateItem) { pane.activateItem(item, {pending: options.pending}) } if (activateItem) {
if (activatePane) { pane.activate() } pane.activateItem(item, {pending: options.pending})
}
if (activatePane) {
pane.activate()
}
let initialLine = initialColumn = 0 let initialLine = initialColumn = 0
if (!Number.isNaN(options.initialLine)) { if (!Number.isNaN(options.initialLine)) {
({ initialLine } = options) initialLine = options.initialLine
} }
if (!Number.isNaN(options.initialColumn)) { if (!Number.isNaN(options.initialColumn)) {
({ initialColumn } = options) initialColumn = options.initialColumn
} }
if ((initialLine >= 0) || (initialColumn >= 0)) { if ((initialLine >= 0) || (initialColumn >= 0)) {
if (typeof item.setCursorBufferPosition === 'function') { if (typeof item.setCursorBufferPosition === 'function') {
@@ -619,7 +694,9 @@ module.exports = class Workspace extends Model {
fs.closeSync(fs.openSync(filePath, 'r')) fs.closeSync(fs.openSync(filePath, 'r'))
} catch (error) { } catch (error) {
// allow ENOENT errors to create an editor for paths that dont exist // allow ENOENT errors to create an editor for paths that dont exist
if (error.code !== 'ENOENT') { throw error } if (error.code !== 'ENOENT') {
throw error
}
} }
} }
@@ -630,7 +707,8 @@ module.exports = class Workspace extends Model {
const choice = this.applicationDelegate.confirm({ const choice = this.applicationDelegate.confirm({
message: 'Atom will be unresponsive during the loading of very large files.', message: 'Atom will be unresponsive during the loading of very large files.',
detailedMessage: 'Do you still want to load this file?', detailedMessage: 'Do you still want to load this file?',
buttons: ['Proceed', 'Cancel']}) buttons: ['Proceed', 'Cancel']
})
if (choice === 1) { if (choice === 1) {
const error = new Error() const error = new Error()
error.code = 'CANCELLED' error.code = 'CANCELLED'
@@ -638,15 +716,14 @@ module.exports = class Workspace extends Model {
} }
} }
return this.project.bufferForPath(filePath, options).then(buffer => { return this.project.bufferForPath(filePath, options)
.then(buffer => {
return this.textEditorRegistry.build(Object.assign({buffer, largeFileMode, autoHeight: false}, options)) return this.textEditorRegistry.build(Object.assign({buffer, largeFileMode, autoHeight: false}, options))
} })
)
} }
handleGrammarUsed (grammar) { handleGrammarUsed (grammar) {
if (grammar == null) { return } if (grammar == null) { return }
return this.packageManager.triggerActivationHook(`${grammar.packageName}:grammar-used`) return this.packageManager.triggerActivationHook(`${grammar.packageName}:grammar-used`)
} }
@@ -666,7 +743,7 @@ module.exports = class Workspace extends Model {
this.textEditorRegistry.maintainGrammar(editor), this.textEditorRegistry.maintainGrammar(editor),
this.textEditorRegistry.maintainConfig(editor) this.textEditorRegistry.maintainConfig(editor)
) )
editor.onDidDestroy(() => subscriptions.dispose()) editor.onDidDestroy(() => { subscriptions.dispose() })
return editor return editor
} }
@@ -675,8 +752,8 @@ module.exports = class Workspace extends Model {
// //
// Returns a {Promise} that is resolved when the item is opened // Returns a {Promise} that is resolved when the item is opened
reopenItem () { reopenItem () {
let uri const uri = this.destroyedItemURIs.pop()
if ((uri = this.destroyedItemURIs.pop())) { if (uri) {
return this.open(uri) return this.open(uri)
} else { } else {
return Promise.resolve() return Promise.resolve()
@@ -714,7 +791,7 @@ module.exports = class Workspace extends Model {
// can check the protocol for quux-preview and only handle those URIs that match. // can check the protocol for quux-preview and only handle those URIs that match.
addOpener (opener) { addOpener (opener) {
this.openers.push(opener) this.openers.push(opener)
return new Disposable((function () { return _.remove(this.openers, opener) }.bind(this))) return new Disposable(() => { _.remove(this.openers, opener) })
} }
getOpeners () { getOpeners () {
@@ -839,44 +916,50 @@ module.exports = class Workspace extends Model {
// Destroy (close) the active pane. // Destroy (close) the active pane.
destroyActivePane () { destroyActivePane () {
return __guard__(this.getActivePane(), x => x.destroy()) const activePane = this.getActivePane()
if (activePane != null) {
activePane.destroy()
}
} }
// Close the active pane item, or the active pane if it is empty, // Close the active pane item, or the active pane if it is empty,
// or the current window if there is only the empty root pane. // or the current window if there is only the empty root pane.
closeActivePaneItemOrEmptyPaneOrWindow () { closeActivePaneItemOrEmptyPaneOrWindow () {
if (this.getActivePaneItem() != null) { if (this.getActivePaneItem() != null) {
return this.destroyActivePaneItem() this.destroyActivePaneItem()
} else if (this.getPanes().length > 1) { } else if (this.getPanes().length > 1) {
return this.destroyActivePane() this.destroyActivePane()
} else if (this.config.get('core.closeEmptyWindows')) { } else if (this.config.get('core.closeEmptyWindows')) {
return atom.close() atom.close()
} }
} }
// Increase the editor font size by 1px. // Increase the editor font size by 1px.
increaseFontSize () { increaseFontSize () {
return this.config.set('editor.fontSize', this.config.get('editor.fontSize') + 1) this.config.set('editor.fontSize', this.config.get('editor.fontSize') + 1)
} }
// Decrease the editor font size by 1px. // Decrease the editor font size by 1px.
decreaseFontSize () { decreaseFontSize () {
const fontSize = this.config.get('editor.fontSize') const fontSize = this.config.get('editor.fontSize')
if (fontSize > 1) { return this.config.set('editor.fontSize', fontSize - 1) } if (fontSize > 1) {
this.config.set('editor.fontSize', fontSize - 1)
}
} }
// Restore to the window's original editor font size. // Restore to the window's original editor font size.
resetFontSize () { resetFontSize () {
if (this.originalFontSize) { if (this.originalFontSize) {
return this.config.set('editor.fontSize', this.originalFontSize) this.config.set('editor.fontSize', this.originalFontSize)
} }
} }
subscribeToFontSize () { subscribeToFontSize () {
return this.config.onDidChange('editor.fontSize', ({oldValue}) => { return this.config.onDidChange('editor.fontSize', ({oldValue}) => {
return this.originalFontSize != null ? this.originalFontSize : (this.originalFontSize = oldValue) if (this.originalFontSize == null) {
this.originalFontSize = oldValue
} }
) })
} }
// Removes the item's uri from the list of potential items to reopen. // Removes the item's uri from the list of potential items to reopen.
@@ -889,7 +972,7 @@ module.exports = class Workspace extends Model {
} }
if (uri != null) { if (uri != null) {
return _.remove(this.destroyedItemURIs, uri) _.remove(this.destroyedItemURIs, uri)
} }
} }
@@ -903,14 +986,16 @@ module.exports = class Workspace extends Model {
} }
if (uri != null) { if (uri != null) {
return this.destroyedItemURIs.push(uri) this.destroyedItemURIs.push(uri)
} }
} }
// Called by Model superclass when destroyed // Called by Model superclass when destroyed
destroyed () { destroyed () {
this.paneContainer.destroy() this.paneContainer.destroy()
return (this.activeItemSubscriptions != null ? this.activeItemSubscriptions.dispose() : undefined) if (this.activeItemSubscriptions != null) {
this.activeItemSubscriptions.dispose()
}
} }
/* /*
@@ -1112,7 +1197,6 @@ module.exports = class Workspace extends Model {
// Returns a {Promise} with a `cancel()` method that will cancel all // Returns a {Promise} with a `cancel()` method that will cancel all
// of the underlying searches that were started as part of this scan. // of the underlying searches that were started as part of this scan.
scan (regex, options = {}, iterator) { scan (regex, options = {}, iterator) {
let directorySearcher, onPathsSearched
if (_.isFunction(options)) { if (_.isFunction(options)) {
iterator = options iterator = options
options = {} options = {}
@@ -1121,9 +1205,9 @@ module.exports = class Workspace extends Model {
// Find a searcher for every Directory in the project. Each searcher that is matched // 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. // will be associated with an Array of Directory objects in the Map.
const directoriesForSearcher = new Map() const directoriesForSearcher = new Map()
for (let directory of this.project.getDirectories()) { for (const directory of this.project.getDirectories()) {
let searcher = this.defaultDirectorySearcher let searcher = this.defaultDirectorySearcher
for (directorySearcher of this.directorySearchers) { for (const directorySearcher of this.directorySearchers) {
if (directorySearcher.canSearchDirectory(directory)) { if (directorySearcher.canSearchDirectory(directory)) {
searcher = directorySearcher searcher = directorySearcher
break break
@@ -1138,6 +1222,7 @@ module.exports = class Workspace extends Model {
} }
// Define the onPathsSearched callback. // Define the onPathsSearched callback.
let onPathsSearched
if (_.isFunction(options.onPathsSearched)) { if (_.isFunction(options.onPathsSearched)) {
// Maintain a map of directories to the number of search results. When notified of a new count, // Maintain a map of directories to the number of search results. When notified of a new count,
// replace the entry in the map and update the total. // replace the entry in the map and update the total.
@@ -1167,26 +1252,33 @@ module.exports = class Workspace extends Model {
exclusions: this.config.get('core.ignoredNames'), exclusions: this.config.get('core.ignoredNames'),
follow: this.config.get('core.followSymlinks'), follow: this.config.get('core.followSymlinks'),
didMatch: result => { didMatch: result => {
if (!this.project.isPathModified(result.filePath)) { return iterator(result) } if (!this.project.isPathModified(result.filePath)) {
return iterator(result)
}
}, },
didError (error) { didError (error) {
return iterator(null, error) return iterator(null, error)
}, },
didSearchPaths (count) { return onPathsSearched(searcher, count) } didSearchPaths (count) {
return onPathsSearched(searcher, count)
} }
directorySearcher = searcher.search(directories, regex, searchOptions)
return allSearches.push(directorySearcher)
} }
) const directorySearcher = searcher.search(directories, regex, searchOptions)
allSearches.push(directorySearcher)
})
const searchPromise = Promise.all(allSearches) const searchPromise = Promise.all(allSearches)
for (let buffer of this.project.getBuffers()) { for (let buffer of this.project.getBuffers()) {
if (buffer.isModified()) { if (buffer.isModified()) {
const filePath = buffer.getPath() const filePath = buffer.getPath()
if (!this.project.contains(filePath)) { continue } if (!this.project.contains(filePath)) {
continue
}
var matches = [] var matches = []
buffer.scan(regex, match => matches.push(match)) buffer.scan(regex, match => matches.push(match))
if (matches.length > 0) { iterator({filePath, matches}) } if (matches.length > 0) {
iterator({filePath, matches})
}
} }
} }
@@ -1195,34 +1287,36 @@ module.exports = class Workspace extends Model {
// resolve it with the special value 'cancelled'. At least the built-in find-and-replace // resolve it with the special value 'cancelled'. At least the built-in find-and-replace
// package relies on this behavior. // package relies on this behavior.
let isCancelled = false let isCancelled = false
const cancellablePromise = new Promise(function (resolve, reject) { const cancellablePromise = new Promise((resolve, reject) => {
const onSuccess = function () { const onSuccess = function () {
if (isCancelled) { if (isCancelled) {
return resolve('cancelled') resolve('cancelled')
} else { } else {
return resolve(null) resolve(null)
} }
} }
const onFailure = function () { const onFailure = function () {
for (let promise of allSearches) { promise.cancel() } for (let promise of allSearches) { promise.cancel() }
return reject() reject()
} }
return searchPromise.then(onSuccess, onFailure) searchPromise.then(onSuccess, onFailure)
}) })
cancellablePromise.cancel = function () { cancellablePromise.cancel = () => {
isCancelled = true isCancelled = true
// Note that cancelling all of the members of allSearches will cause all of the searches // Note that cancelling all of the members of allSearches will cause all of the searches
// to resolve, which causes searchPromise to resolve, which is ultimately what causes // to resolve, which causes searchPromise to resolve, which is ultimately what causes
// cancellablePromise to resolve. // cancellablePromise to resolve.
return allSearches.map((promise) => promise.cancel()) allSearches.map((promise) => promise.cancel())
} }
// Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` // Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()`
// method in the find-and-replace package expects the object returned by this method to have a // method in the find-and-replace package expects the object returned by this method to have a
// `done()` method. Include a done() method until find-and-replace can be updated. // `done()` method. Include a done() method until find-and-replace can be updated.
cancellablePromise.done = onSuccessOrFailure => cancellablePromise.then(onSuccessOrFailure, onSuccessOrFailure) cancellablePromise.done = onSuccessOrFailure => {
cancellablePromise.then(onSuccessOrFailure, onSuccessOrFailure)
}
return cancellablePromise return cancellablePromise
} }
@@ -1236,45 +1330,50 @@ module.exports = class Workspace extends Model {
// //
// Returns a {Promise}. // Returns a {Promise}.
replace (regex, replacementText, filePaths, iterator) { replace (regex, replacementText, filePaths, iterator) {
return new Promise((function (resolve, reject) { return new Promise((resolve, reject) => {
let buffer let buffer
const openPaths = ((() => { const openPaths = this.project.getBuffers().map(buffer => buffer.getPath())
const result = []
for (buffer of this.project.getBuffers()) {
result.push(buffer.getPath())
}
return result
})())
const outOfProcessPaths = _.difference(filePaths, openPaths) const outOfProcessPaths = _.difference(filePaths, openPaths)
let inProcessFinished = !openPaths.length let inProcessFinished = !openPaths.length
let outOfProcessFinished = !outOfProcessPaths.length let outOfProcessFinished = !outOfProcessPaths.length
const checkFinished = function () { const checkFinished = () => {
if (outOfProcessFinished && inProcessFinished) { return resolve() } if (outOfProcessFinished && inProcessFinished) {
resolve()
}
} }
if (!outOfProcessFinished.length) { if (!outOfProcessFinished.length) {
let flags = 'g' let flags = 'g'
if (regex.ignoreCase) { flags += 'i' } if (regex.ignoreCase) { flags += 'i' }
const task = Task.once(require.resolve('./replace-handler'), outOfProcessPaths, regex.source, flags, replacementText, function () { const task = Task.once(
require.resolve('./replace-handler'),
outOfProcessPaths,
regex.source,
flags,
replacementText,
() => {
outOfProcessFinished = true outOfProcessFinished = true
return checkFinished() checkFinished()
}) }
)
task.on('replace:path-replaced', iterator) task.on('replace:path-replaced', iterator)
task.on('replace:file-error', function (error) { return iterator(null, error) }) task.on('replace:file-error', error => { iterator(null, error) })
} }
for (buffer of this.project.getBuffers()) { for (buffer of this.project.getBuffers()) {
if (!Array.from(filePaths).includes(buffer.getPath())) { continue } if (!filePaths.includes(buffer.getPath())) { continue }
const replacements = buffer.replace(regex, replacementText, iterator) const replacements = buffer.replace(regex, replacementText, iterator)
if (replacements) { iterator({filePath: buffer.getPath(), replacements}) } if (replacements) {
iterator({filePath: buffer.getPath(), replacements})
}
} }
inProcessFinished = true inProcessFinished = true
return checkFinished() checkFinished()
}.bind(this))) })
} }
checkoutHeadRevision (editor) { checkoutHeadRevision (editor) {
@@ -1285,7 +1384,7 @@ module.exports = class Workspace extends Model {
} }
if (this.config.get('editor.confirmCheckoutHeadRevision')) { if (this.config.get('editor.confirmCheckoutHeadRevision')) {
return this.applicationDelegate.confirm({ this.applicationDelegate.confirm({
message: 'Confirm Checkout HEAD Revision', message: 'Confirm Checkout HEAD Revision',
detailedMessage: `Are you sure you want to discard all changes to "${editor.getFileName()}" since the last Git commit?`, detailedMessage: `Are you sure you want to discard all changes to "${editor.getFileName()}" since the last Git commit?`,
buttons: { buttons: {
@@ -1301,14 +1400,3 @@ module.exports = class Workspace extends Model {
} }
} }
} }
function __guard__ (value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined
}
function __guardMethod__ (obj, methodName, transform) {
if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') {
return transform(obj, methodName)
} else {
return undefined
}
}