diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 837961e6a..c8a79b4e0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -285,8 +285,8 @@ If you want to read about using Atom or developing packages in Atom, the [Atom F
All JavaScript must adhere to [JavaScript Standard Style](http://standardjs.com/).
-* Prefer `Object.assign()` to the object spread operator (`{...anotherObj}`)
-* Inline `export`s with expressions
+* Prefer the object spread operator (`{...anotherObj}`) to `Object.assign()`
+* Inline `export`s with expressions whenever possible
```js
// Use this:
export default class ClassName {
diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee
index f6f297bec..a4f9ff072 100644
--- a/build/tasks/compile-packages-slug-task.coffee
+++ b/build/tasks/compile-packages-slug-task.coffee
@@ -8,13 +8,12 @@ semver = require 'semver'
OtherPlatforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32'].filter (platform) -> platform isnt process.platform
module.exports = (grunt) ->
- {spawn, rm} = require('./task-helpers')(grunt)
+ {spawn} = require('./task-helpers')(grunt)
getMenu = (appDir) ->
menusPath = path.join(appDir, 'menus')
menuPath = path.join(menusPath, "#{process.platform}.json")
menu = CSON.readFileSync(menuPath) if fs.isFileSync(menuPath)
- rm menusPath
menu
getKeymaps = (appDir) ->
@@ -26,7 +25,6 @@ module.exports = (grunt) ->
keymap = CSON.readFileSync(keymapPath)
keymaps[path.basename(keymapPath)] = keymap
- rm keymapsPath
keymaps
grunt.registerTask 'compile-packages-slug', 'Add bundled package metadata information to the main package.json file', ->
@@ -54,7 +52,6 @@ module.exports = (grunt) ->
moduleCache = metadata._atomModuleCache ? {}
- rm metadataPath
_.remove(moduleCache.extensions?['.json'] ? [], 'package.json')
for property in ['_from', '_id', 'dist', 'readme', 'readmeFilename']
@@ -70,15 +67,11 @@ module.exports = (grunt) ->
for keymapPath in fs.listSync(keymapsPath, ['.cson', '.json'])
relativePath = path.relative(appDir, keymapPath)
pack.keymaps[relativePath] = CSON.readFileSync(keymapPath)
- rm keymapPath
- rm keymapsPath if fs.listSync(keymapsPath).length is 0
menusPath = path.join(moduleDirectory, 'menus')
for menuPath in fs.listSync(menusPath, ['.cson', '.json'])
relativePath = path.relative(appDir, menuPath)
pack.menus[relativePath] = CSON.readFileSync(menuPath)
- rm menuPath
- rm menusPath if fs.listSync(menusPath).length is 0
packages[metadata.name] = pack
diff --git a/exports/atom.coffee b/exports/atom.coffee
deleted file mode 100644
index bd8a1b62c..000000000
--- a/exports/atom.coffee
+++ /dev/null
@@ -1,44 +0,0 @@
-TextBuffer = require 'text-buffer'
-{Point, Range} = TextBuffer
-{File, Directory} = require 'pathwatcher'
-{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
-Grim = require 'grim'
-
-module.exports =
- BufferedNodeProcess: require '../src/buffered-node-process'
- BufferedProcess: require '../src/buffered-process'
- GitRepository: require '../src/git-repository'
- Notification: require '../src/notification'
- TextBuffer: TextBuffer
- Point: Point
- Range: Range
- File: File
- Directory: Directory
- Emitter: Emitter
- Disposable: Disposable
- CompositeDisposable: CompositeDisposable
-
-# Shell integration is required by both Squirrel and Settings-View
-if process.platform is 'win32'
- module.exports.WinShell = require '../src/main-process/win-shell'
-
-# The following classes can't be used from a Task handler and should therefore
-# only be exported when not running as a child node process
-unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
- module.exports.Task = require '../src/task'
-
- TextEditor = (params) ->
- atom.workspace.buildTextEditor(params)
-
- TextEditor.prototype = require('../src/text-editor').prototype
-
- Object.defineProperty module.exports, 'TextEditor',
- enumerable: true
- get: ->
- Grim.deprecate """
- The `TextEditor` constructor is no longer public.
-
- To construct a text editor, use `atom.workspace.buildTextEditor()`.
- To check if an object is a text editor, use `atom.workspace.isTextEditor(object)`.
- """
- TextEditor
diff --git a/exports/atom.js b/exports/atom.js
new file mode 100644
index 000000000..50c8c687f
--- /dev/null
+++ b/exports/atom.js
@@ -0,0 +1,58 @@
+/** @babel */
+
+import TextBuffer, {Point, Range} from 'text-buffer'
+import {File, Directory} from 'pathwatcher'
+import {Emitter, Disposable, CompositeDisposable} from 'event-kit'
+import Grim from 'grim'
+import dedent from 'dedent'
+import BufferedNodeProcess from '../src/buffered-node-process'
+import BufferedProcess from '../src/buffered-process'
+import GitRepository from '../src/git-repository'
+import Notification from '../src/notification'
+
+const atomExport = {
+ BufferedNodeProcess,
+ BufferedProcess,
+ GitRepository,
+ Notification,
+ TextBuffer,
+ Point,
+ Range,
+ File,
+ Directory,
+ Emitter,
+ Disposable,
+ CompositeDisposable
+}
+
+// Shell integration is required by both Squirrel and Settings-View
+if (process.platform === 'win32') {
+ atomExport.WinShell = require('../src/main-process/win-shell')
+}
+
+// The following classes can't be used from a Task handler and should therefore
+// only be exported when not running as a child node process
+if (!process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE) {
+ atomExport.Task = require('../src/task')
+
+ const TextEditor = (params) => {
+ return atom.workspace.buildTextEditor(params)
+ }
+
+ TextEditor.prototype = require('../src/text-editor').prototype
+
+ Object.defineProperty(atomExport, 'TextEditor', {
+ enumerable: true,
+ get () {
+ Grim.deprecate(dedent`
+ The \`TextEditor\` constructor is no longer public.
+
+ To construct a text editor, use \`atom.workspace.buildTextEditor()\`.
+ To check if an object is a text editor, use \`atom.workspace.isTextEditor(object)\`.
+ `)
+ return TextEditor
+ }
+ })
+}
+
+export default atomExport
diff --git a/package.json b/package.json
index bbac58d5e..cac285ee0 100644
--- a/package.json
+++ b/package.json
@@ -93,7 +93,7 @@
"deprecation-cop": "0.54.1",
"dev-live-reload": "0.47.0",
"encoding-selector": "0.22.0",
- "exception-reporting": "0.38.2",
+ "exception-reporting": "0.39.0",
"find-and-replace": "0.201.0",
"fuzzy-finder": "1.3.0",
"git-diff": "1.1.0",
@@ -112,7 +112,7 @@
"settings-view": "0.241.1",
"snippets": "1.0.2",
"spell-check": "0.67.1",
- "status-bar": "1.4.0",
+ "status-bar": "1.4.1",
"styleguide": "0.47.0",
"symbols-view": "0.113.1",
"tabs": "0.100.0",
diff --git a/resources/linux/atom.desktop.in b/resources/linux/atom.desktop.in
index 290d368d2..6fa5d79c8 100644
--- a/resources/linux/atom.desktop.in
+++ b/resources/linux/atom.desktop.in
@@ -2,7 +2,7 @@
Name=<%= appName %>
Comment=<%= description %>
GenericName=Text Editor
-Exec=<%= installDir %>/share/<%= appFileName %>/atom %U
+Exec=<%= installDir %>/share/<%= appFileName %>/atom %F
Icon=<%= iconPath %>
Type=Application
StartupNotify=true
diff --git a/spec/git-spec.coffee b/spec/git-repository-spec.coffee
similarity index 94%
rename from spec/git-spec.coffee
rename to spec/git-repository-spec.coffee
index ef87d83ee..d427fc3b9 100644
--- a/spec/git-spec.coffee
+++ b/spec/git-repository-spec.coffee
@@ -199,7 +199,7 @@ describe "GitRepository", ->
beforeEach ->
workingDirectory = copyRepository()
- repo = new GitRepository(workingDirectory)
+ repo = new GitRepository(workingDirectory, {project: atom.project, config: atom.config})
modifiedPath = path.join(workingDirectory, 'file.txt')
newPath = path.join(workingDirectory, 'untracked.txt')
cleanPath = path.join(workingDirectory, 'other.txt')
@@ -249,6 +249,22 @@ describe "GitRepository", ->
expect(repo.isStatusModified(status)).toBe false
expect(repo.isStatusNew(status)).toBe false
+ it "works correctly when the project has multiple folders (regression)", ->
+ atom.project.addPath(workingDirectory)
+ atom.project.addPath(path.join(__dirname, 'fixtures', 'dir'))
+ statusHandler = jasmine.createSpy('statusHandler')
+ repo.onDidChangeStatuses statusHandler
+
+ repo.refreshStatus()
+
+ waitsFor ->
+ statusHandler.callCount > 0
+
+ runs ->
+ expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined()
+ expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy()
+ expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy()
+
it 'caches statuses that were looked up synchronously', ->
originalContent = 'undefined'
fs.writeFileSync(modifiedPath, 'making this path modified')
diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js
index 4ef292b51..e3b4f7c42 100644
--- a/spec/text-editor-component-spec.js
+++ b/spec/text-editor-component-spec.js
@@ -2252,6 +2252,17 @@ describe('TextEditorComponent', function () {
expect(overlay.style.left).toBe(windowWidth - itemWidth + 'px')
expect(overlay.style.top).toBe(position.top + editor.getLineHeightInPixels() + 'px')
+
+ // window size change
+
+ windowWidth = Math.round(gutterWidth + 29 * editor.getDefaultCharWidth())
+ await atom.setWindowDimensions({
+ width: windowWidth,
+ height: windowHeight,
+ })
+ atom.views.performDocumentPoll()
+ expect(overlay.style.left).toBe(windowWidth - itemWidth + 'px')
+ expect(overlay.style.top).toBe(position.top + editor.getLineHeightInPixels() + 'px')
})
})
})
diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee
index 74c498e78..3372962be 100644
--- a/src/application-delegate.coffee
+++ b/src/application-delegate.coffee
@@ -1,5 +1,5 @@
_ = require 'underscore-plus'
-{screen, ipcRenderer, remote, shell, webFrame} = require 'electron'
+{screen, ipcRenderer, remote, shell, systemPreferences, webFrame} = require 'electron'
ipcHelpers = require './ipc-helpers'
{Disposable} = require 'event-kit'
{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers'
@@ -57,12 +57,18 @@ class ApplicationDelegate
reloadWindow: ->
ipcRenderer.send("call-window-method", "reload")
+ minimizeWindow: ->
+ ipcRenderer.send("call-window-method", "minimize")
+
isWindowMaximized: ->
remote.getCurrentWindow().isMaximized()
maximizeWindow: ->
ipcRenderer.send("call-window-method", "maximize")
+ unmaximizeWindow: ->
+ ipcRenderer.send("call-window-method", "unmaximize")
+
isWindowFullScreen: ->
remote.getCurrentWindow().isFullScreen()
@@ -130,6 +136,9 @@ class ApplicationDelegate
getPrimaryDisplayWorkAreaSize: ->
remote.screen.getPrimaryDisplay().workAreaSize
+ getUserDefault: (key, type) ->
+ remote.systemPreferences.getUserDefault(key, type)
+
confirm: ({message, detailedMessage, buttons}) ->
buttons ?= {}
if _.isArray(buttons)
diff --git a/src/config-schema.coffee b/src/config-schema.coffee
index 67f3a430f..173056ee0 100644
--- a/src/config-schema.coffee
+++ b/src/config-schema.coffee
@@ -266,4 +266,4 @@ if process.platform is 'darwin'
module.exports.core.properties.useCustomTitleBar =
type: 'boolean'
default: false
- description: 'Use custom, theme-aware title-bar.
Note: Note: This currently does not include a proxy icon.
This setting will require a relaunch of Atom to take effect.'
+ description: 'Use custom, theme-aware title bar.
Note: This currently does not include a proxy icon.
This setting will require a relaunch of Atom to take effect.'
diff --git a/src/git-repository.coffee b/src/git-repository.coffee
index 85600bba7..e0d7dfb25 100644
--- a/src/git-repository.coffee
+++ b/src/git-repository.coffee
@@ -3,6 +3,7 @@
_ = require 'underscore-plus'
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
fs = require 'fs-plus'
+path = require 'path'
GitUtils = require 'git-utils'
Task = require './task'
@@ -309,8 +310,8 @@ class GitRepository
getDirectoryStatus: (directoryPath) ->
directoryPath = "#{@relativize(directoryPath)}/"
directoryStatus = 0
- for path, status of @statuses
- directoryStatus |= status if path.indexOf(directoryPath) is 0
+ for statusPath, status of @statuses
+ directoryStatus |= status if statusPath.indexOf(directoryPath) is 0
directoryStatus
# Public: Get the status of a single path in the repository.
@@ -432,8 +433,8 @@ class GitRepository
# Subscribes to buffer events.
subscribeToBuffer: (buffer) ->
getBufferPathStatus = =>
- if path = buffer.getPath()
- @getPathStatus(path)
+ if bufferPath = buffer.getPath()
+ @getPathStatus(bufferPath)
bufferSubscriptions = new CompositeDisposable
bufferSubscriptions.add buffer.onDidSave(getBufferPathStatus)
@@ -468,8 +469,8 @@ class GitRepository
@handlerPath ?= require.resolve('./repository-status-handler')
relativeProjectPaths = @project?.getPaths()
- .map (path) => @relativize(path)
- .filter (path) -> path.length > 0
+ .map (projectPath) => @relativize(projectPath)
+ .filter (projectPath) -> projectPath.length > 0 and not path.isAbsolute(projectPath)
@statusTask?.terminate()
new Promise (resolve) =>
diff --git a/src/module-cache.coffee b/src/module-cache.coffee
index 39bdfa244..8c6a7c312 100644
--- a/src/module-cache.coffee
+++ b/src/module-cache.coffee
@@ -196,8 +196,8 @@ resolveModulePath = (relativePath, parentModule) ->
registerBuiltins = (devMode) ->
if devMode or not cache.resourcePath.startsWith("#{process.resourcesPath}#{path.sep}")
fs = require 'fs-plus'
- atomCoffeePath = path.join(cache.resourcePath, 'exports', 'atom.coffee')
- cache.builtins.atom = atomCoffeePath if fs.isFileSync(atomCoffeePath)
+ atomJsPath = path.join(cache.resourcePath, 'exports', 'atom.js')
+ cache.builtins.atom = atomJsPath if fs.isFileSync(atomJsPath)
cache.builtins.atom ?= path.join(cache.resourcePath, 'exports', 'atom.js')
electronAsarRoot = path.join(process.resourcesPath, 'electron.asar')
diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee
index a8ed9b6c1..744f82770 100644
--- a/src/text-editor-component.coffee
+++ b/src/text-editor-component.coffee
@@ -727,6 +727,7 @@ class TextEditorComponent
pollDOM: =>
unless @checkForVisibilityChange()
@sampleBackgroundColors()
+ @measureWindowSize()
@measureDimensions()
@sampleFontStyling()
@overlayManager?.measureOverlays()
diff --git a/src/title-bar.coffee b/src/title-bar.coffee
index e2da3ed62..b81b08060 100644
--- a/src/title-bar.coffee
+++ b/src/title-bar.coffee
@@ -8,12 +8,25 @@ class TitleBar
@titleElement.classList.add('title')
@element.appendChild(@titleElement)
+ @element.addEventListener 'dblclick', @dblclickHandler
+
@workspace.onDidChangeActivePaneItem => @updateTitle()
@themes.onDidChangeActiveThemes => @updateWindowSheetOffset()
@updateTitle()
@updateWindowSheetOffset()
+ dblclickHandler: =>
+ # User preference deciding which action to take on a title bar double-click
+ switch @applicationDelegate.getUserDefault('AppleActionOnDoubleClick', 'string')
+ when 'Minimize'
+ @applicationDelegate.minimizeWindow()
+ when 'Maximize'
+ if @applicationDelegate.isWindowMaximized()
+ @applicationDelegate.unmaximizeWindow()
+ else
+ @applicationDelegate.maximizeWindow()
+
updateTitle: ->
@titleElement.textContent = document.title
diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee
index 7bb568474..d68069170 100644
--- a/src/tokenized-buffer.coffee
+++ b/src/tokenized-buffer.coffee
@@ -195,6 +195,17 @@ class TokenizedBuffer extends Model
row + delta
handleBufferChange: (e) ->
+ if @lastBufferChangeEventId?
+ @assert(
+ @lastBufferChangeEventId is e.eventId - 1,
+ 'Buffer Change Event Ids are not sequential',
+ (error) =>
+ error.metadata = {
+ tokenizedBufferEventId: @lastBufferChangeEventId,
+ nextTokenizedBufferEventId: e.eventId,
+ }
+ )
+ @lastBufferChangeEventId = e.eventId
@changeCount = @buffer.changeCount
{oldRange, newRange} = e