mirror of
https://github.com/atom/atom.git
synced 2026-01-22 21:38:10 -05:00
Merge remote-tracking branch 'remotes/origin/master' into dh-async-repo
This commit is contained in:
@@ -13,6 +13,7 @@ By participating, you are expected to uphold this code. Please report unacceptab
|
||||
#### Table Of Contents
|
||||
|
||||
* [Submitting Issues](#submitting-issues)
|
||||
* [Your First Contribution](#your-first-contribution)
|
||||
* [Pull Requests](#pull-requests)
|
||||
* [Git Commit Messages](#git-commit-messages)
|
||||
* [CoffeeScript Styleguide](#coffeescript-styleguide)
|
||||
@@ -60,6 +61,13 @@ you're having an issue with Atom core, open an issue on this repository.
|
||||
For more information on how to work with Atom's official packages, see
|
||||
[Contributing to Atom Packages](https://github.com/atom/atom/blob/master/docs/contributing-to-packages.md)
|
||||
|
||||
## Your First Contribution
|
||||
|
||||
Unsure where to begin contributing to Atom? You can start by looking through these `beginner` and `help-wanted` issues:
|
||||
|
||||
* [Beginner issues][beginner]
|
||||
* [Help wanted issues][help-wanted]
|
||||
|
||||
## Pull Requests
|
||||
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
@@ -352,3 +360,6 @@ Please open an issue on `atom/atom` if you have suggestions for new labels, and
|
||||
[search-atom-org-label-requires-changes]: https://github.com/pulls?q=is%3Aopen+is%3Apr+user%3Aatom+label%3Arequires-changes
|
||||
[search-atom-repo-label-needs-testing]: https://github.com/pulls?q=is%3Aopen+is%3Apr+repo%3Aatom%2Fatom+label%3Aneeds-testing
|
||||
[search-atom-org-label-needs-testing]: https://github.com/pulls?q=is%3Aopen+is%3Apr+user%3Aatom+label%3Aneeds-testing
|
||||
|
||||
[beginner]:https://github.com/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3Abeginner+label%3Ahelp-wanted+user%3Aatom+sort%3Acomments-desc
|
||||
[help-wanted]:https://github.com/issues?q=is%3Aopen+is%3Aissue+label%3Ahelp-wanted+user%3Aatom+sort%3Acomments-desc
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "1.1.1"
|
||||
"atom-package-manager": "1.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"dependencies": {
|
||||
"asar": "^0.8.0",
|
||||
"async": "~0.2.9",
|
||||
"donna": "1.0.10",
|
||||
"donna": "^1.0.13",
|
||||
"formidable": "~1.0.14",
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.3.0",
|
||||
|
||||
@@ -54,14 +54,14 @@ module.exports = (grunt) ->
|
||||
if process.platform in ['darwin', 'linux']
|
||||
options =
|
||||
cmd: appPath
|
||||
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"]
|
||||
args: ['--test', "--resource-path=#{resourcePath}", path.join(packagePath, 'spec')]
|
||||
opts:
|
||||
cwd: packagePath
|
||||
env: _.extend({}, process.env, ATOM_PATH: rootDir)
|
||||
else if process.platform is 'win32'
|
||||
options =
|
||||
cmd: process.env.comspec
|
||||
args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"]
|
||||
args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--log-file=ci.log", path.join(packagePath, 'spec')]
|
||||
opts:
|
||||
cwd: packagePath
|
||||
env: _.extend({}, process.env, ATOM_PATH: rootDir)
|
||||
@@ -95,7 +95,7 @@ module.exports = (grunt) ->
|
||||
if process.platform in ['darwin', 'linux']
|
||||
options =
|
||||
cmd: appPath
|
||||
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"]
|
||||
args: ['--test', "--resource-path=#{resourcePath}", coreSpecsPath]
|
||||
opts:
|
||||
env: _.extend({}, process.env,
|
||||
ATOM_INTEGRATION_TESTS_ENABLED: true
|
||||
@@ -104,7 +104,7 @@ module.exports = (grunt) ->
|
||||
else if process.platform is 'win32'
|
||||
options =
|
||||
cmd: process.env.comspec
|
||||
args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", '--log-file=ci.log']
|
||||
args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", '--log-file=ci.log', coreSpecsPath]
|
||||
opts:
|
||||
env: _.extend({}, process.env,
|
||||
ATOM_INTEGRATION_TESTS_ENABLED: true
|
||||
|
||||
@@ -7,8 +7,8 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
* OS with 64-bit or 32-bit architecture
|
||||
* C++ toolchain
|
||||
* [Git](http://git-scm.com/)
|
||||
* [node.js](http://nodejs.org/download/) (0.10.x or 0.12.x) or [io.js](https://iojs.org) (1.x or 2.x)
|
||||
* [npm](https://www.npmjs.com/) v1.4.x (bundled with Node.js)
|
||||
* [Node.js](http://nodejs.org/download/) (0.10.x or above)
|
||||
* [npm](https://www.npmjs.com/) v1.4.x or above (automatically bundled with Node.js)
|
||||
* `npm -v` to check the version.
|
||||
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
|
||||
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
@@ -17,7 +17,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
### Ubuntu / Debian
|
||||
|
||||
* `sudo apt-get install build-essential git libgnome-keyring-dev fakeroot`
|
||||
* Instructions for [Node.js](https://github.com/nodejs/node-v0.x-archive/wiki/Installing-Node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions).
|
||||
* Instructions for [Node.js](https://github.com/nodejs/node-v0.x-archive/wiki/Installing-Node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions).
|
||||
* Make sure the command `node` is available after Node.js installation (some systems install it as `nodejs`).
|
||||
* Use `which node` to check if it is available.
|
||||
* Use `sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10` to update it.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Requirements
|
||||
|
||||
* OS X 10.8 or later
|
||||
* [node.js](http://nodejs.org/download/) (0.10.x or 0.12.x) or [io.js](https://iojs.org) (1.x or 2.x)
|
||||
* [Node.js](http://nodejs.org/download/) (0.10.x or above)
|
||||
* Command Line Tools for [Xcode](https://developer.apple.com/xcode/downloads/) (run `xcode-select --install` to install)
|
||||
|
||||
## Instructions
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
### On Windows 7
|
||||
* [Visual C++ 2010 Express](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_4)
|
||||
* [Visual Studio 2010 Service Pack 1](http://www.microsoft.com/en-us/download/details.aspx?id=23691)
|
||||
* [node.js](http://nodejs.org/download/) (0.10.x or 0.12.x) or [io.js](https://iojs.org) (1.x or 2.x)
|
||||
* [Node.js](http://nodejs.org/download/) (0.10.x or above)
|
||||
* For 64-bit builds of node and native modules you **must** have the
|
||||
[Windows 7 64-bit SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
||||
You may also need the [compiler update for the Windows SDK 7.1](http://www.microsoft.com/en-us/download/details.aspx?id=4422)
|
||||
@@ -20,7 +20,7 @@
|
||||
* [Visual Studio Express 2013 or 2015 for Windows Desktop](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_2)
|
||||
* For VS 2015, be sure to customize the installation to include Visual C++. It's not installed by default.
|
||||
* Some have experienced issues with Node locating C++ on VS 2015. If so, try VS 2013.
|
||||
* [node.js](http://nodejs.org/download/) (0.10.x, 0.12.x or 4.x) or [io.js](https://iojs.org) (1.x or 2.x)
|
||||
* [Node.js](http://nodejs.org/download/) (0.10.x or above)
|
||||
* [Python](https://www.python.org/downloads/) v2.7.x (required by [node-gyp](https://github.com/TooTallNate/node-gyp))
|
||||
* [GitHub Desktop](http://desktop.github.com/)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ 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'
|
||||
@@ -21,4 +22,20 @@ module.exports =
|
||||
# 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'
|
||||
module.exports.TextEditor = require '../src/text-editor'
|
||||
|
||||
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, look for for the existence of
|
||||
a public method that you're using (e.g. `::getText`).
|
||||
"""
|
||||
TextEditor
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
'ctrl-d': 'core:delete'
|
||||
|
||||
# Atom Specific
|
||||
'cmd-alt-ctrl-s': 'application:run-all-specs'
|
||||
'enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
'ctrl-alt-r': 'window:reload'
|
||||
'ctrl-shift-i': 'window:toggle-dev-tools'
|
||||
'ctrl-alt-p': 'window:run-package-specs'
|
||||
'ctrl-alt-s': 'application:run-all-specs'
|
||||
'ctrl-shift-o': 'application:open-folder'
|
||||
'ctrl-alt-o': 'application:add-project-folder'
|
||||
'ctrl-shift-pageup': 'pane:move-item-left'
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
'ctrl-alt-r': 'window:reload'
|
||||
'ctrl-alt-i': 'window:toggle-dev-tools'
|
||||
'ctrl-alt-p': 'window:run-package-specs'
|
||||
'ctrl-alt-s': 'application:run-all-specs'
|
||||
'ctrl-shift-o': 'application:open-folder'
|
||||
'ctrl-alt-o': 'application:add-project-folder'
|
||||
'ctrl-shift-left': 'pane:move-item-left'
|
||||
|
||||
@@ -164,7 +164,6 @@
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
{ label: 'Open In Dev Mode…', command: 'application:open-dev' }
|
||||
{ label: 'Run Atom Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package Specs', command: 'window:run-package-specs' }
|
||||
{ label: 'Toggle Developer Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
|
||||
@@ -121,7 +121,6 @@
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
{ label: 'Open In &Dev Mode…', command: 'application:open-dev' }
|
||||
{ label: 'Run &Atom Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package &Specs', command: 'window:run-package-specs' }
|
||||
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
|
||||
@@ -120,7 +120,6 @@
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
{ label: 'Open In &Dev Mode…', command: 'application:open-dev' }
|
||||
{ label: 'Run &Atom Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package &Specs', command: 'window:run-package-specs' }
|
||||
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
|
||||
66
package.json
66
package.json
@@ -12,26 +12,27 @@
|
||||
"url": "https://github.com/atom/atom/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"electronVersion": "0.30.7",
|
||||
"electronVersion": "0.33.6",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^6.0.0",
|
||||
"atom-keymap": "^6.1.0",
|
||||
"babel-core": "^5.8.21",
|
||||
"bootstrap": "^3.3.4",
|
||||
"clear-cut": "^2.0.1",
|
||||
"coffee-script": "1.8.0",
|
||||
"color": "^0.7.3",
|
||||
"event-kit": "^1.3.0",
|
||||
"first-mate": "^5.0.0",
|
||||
"find-parent-dir": "^0.3.0",
|
||||
"first-mate": "^5.1.0",
|
||||
"fs-plus": "^2.8.0",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^2.1",
|
||||
"git-utils": "^4",
|
||||
"grim": "1.4.2",
|
||||
"grim": "1.5.0",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-tagged": "^1.1.4",
|
||||
"jquery": "^2.1.1",
|
||||
"key-path-helpers": "^0.3.0",
|
||||
"key-path-helpers": "^0.4.0",
|
||||
"less-cache": "0.22",
|
||||
"marked": "^0.3.4",
|
||||
"nodegit": "~0.5.0",
|
||||
@@ -41,13 +42,14 @@
|
||||
"pathwatcher": "^6.2",
|
||||
"property-accessors": "^1.1.3",
|
||||
"random-words": "0.0.1",
|
||||
"resolve": "^1.1.6",
|
||||
"runas": "^3.1",
|
||||
"scandal": "^2.2",
|
||||
"scoped-property-store": "^0.17.0",
|
||||
"scrollbar-style": "^3.2",
|
||||
"season": "^5.3",
|
||||
"semver": "^4.3.3",
|
||||
"service-hub": "^0.6.2",
|
||||
"service-hub": "^0.7.0",
|
||||
"source-map-support": "^0.3.2",
|
||||
"stacktrace-parser": "0.1.1",
|
||||
"temp": "0.8.1",
|
||||
@@ -67,17 +69,17 @@
|
||||
"one-dark-syntax": "1.1.1",
|
||||
"one-light-syntax": "1.1.1",
|
||||
"one-light-ui": "1.1.5",
|
||||
"solarized-dark-syntax": "0.38.1",
|
||||
"solarized-light-syntax": "0.22.1",
|
||||
"solarized-dark-syntax": "0.39.0",
|
||||
"solarized-light-syntax": "0.23.0",
|
||||
"about": "1.1.0",
|
||||
"archive-view": "0.61.0",
|
||||
"autocomplete-atom-api": "0.9.2",
|
||||
"autocomplete-css": "0.11.0",
|
||||
"autocomplete-html": "0.7.2",
|
||||
"autocomplete-plus": "2.22.0",
|
||||
"autocomplete-plus": "2.23.0",
|
||||
"autocomplete-snippets": "1.7.1",
|
||||
"autoflow": "0.26.0",
|
||||
"autosave": "0.22.0",
|
||||
"autosave": "0.23.0",
|
||||
"background-tips": "0.26.0",
|
||||
"bookmarks": "0.38.0",
|
||||
"bracket-matcher": "0.78.0",
|
||||
@@ -86,36 +88,36 @@
|
||||
"dev-live-reload": "0.47.0",
|
||||
"encoding-selector": "0.21.0",
|
||||
"exception-reporting": "0.37.0",
|
||||
"find-and-replace": "0.185.0",
|
||||
"fuzzy-finder": "0.90.0",
|
||||
"find-and-replace": "0.187.1",
|
||||
"fuzzy-finder": "0.91.0",
|
||||
"git-diff": "0.56.0",
|
||||
"go-to-line": "0.30.0",
|
||||
"grammar-selector": "0.47.0",
|
||||
"image-view": "0.55.0",
|
||||
"incompatible-packages": "0.25.0",
|
||||
"keybinding-resolver": "0.33.0",
|
||||
"line-ending-selector": "0.1.0",
|
||||
"line-ending-selector": "0.3.0",
|
||||
"link": "0.31.0",
|
||||
"markdown-preview": "0.154.0",
|
||||
"metrics": "0.52.0",
|
||||
"notifications": "0.59.0",
|
||||
"markdown-preview": "0.155.0",
|
||||
"metrics": "0.53.0",
|
||||
"notifications": "0.60.0",
|
||||
"open-on-github": "0.38.0",
|
||||
"package-generator": "0.40.0",
|
||||
"release-notes": "0.53.0",
|
||||
"settings-view": "0.229.0",
|
||||
"snippets": "0.100.0",
|
||||
"spell-check": "0.61.0",
|
||||
"status-bar": "0.79.0",
|
||||
"settings-view": "0.230.1",
|
||||
"snippets": "0.101.0",
|
||||
"spell-check": "0.61.1",
|
||||
"status-bar": "0.80.0",
|
||||
"styleguide": "0.44.0",
|
||||
"symbols-view": "0.109.0",
|
||||
"tabs": "0.84.0",
|
||||
"tabs": "0.85.0",
|
||||
"timecop": "0.33.0",
|
||||
"tree-view": "0.190.0",
|
||||
"tree-view": "0.192.2",
|
||||
"update-package-dependencies": "0.10.0",
|
||||
"welcome": "0.30.0",
|
||||
"welcome": "0.31.0",
|
||||
"whitespace": "0.31.0",
|
||||
"wrap-guide": "0.38.0",
|
||||
"language-c": "0.48.0",
|
||||
"wrap-guide": "0.38.1",
|
||||
"language-c": "0.49.0",
|
||||
"language-clojure": "0.18.0",
|
||||
"language-coffee-script": "0.42.0",
|
||||
"language-csharp": "0.11.0",
|
||||
@@ -126,26 +128,26 @@
|
||||
"language-html": "0.42.0",
|
||||
"language-hyperlink": "0.14.0",
|
||||
"language-java": "0.16.0",
|
||||
"language-javascript": "0.96.0",
|
||||
"language-json": "0.17.0",
|
||||
"language-less": "0.28.2",
|
||||
"language-javascript": "0.97.0",
|
||||
"language-json": "0.17.1",
|
||||
"language-less": "0.28.3",
|
||||
"language-make": "0.19.0",
|
||||
"language-mustache": "0.13.0",
|
||||
"language-objective-c": "0.15.0",
|
||||
"language-perl": "0.30.0",
|
||||
"language-php": "0.30.0",
|
||||
"language-php": "0.32.0",
|
||||
"language-property-list": "0.8.0",
|
||||
"language-python": "0.40.0",
|
||||
"language-python": "0.41.0",
|
||||
"language-ruby": "0.60.0",
|
||||
"language-ruby-on-rails": "0.23.0",
|
||||
"language-sass": "0.42.0",
|
||||
"language-shellscript": "0.19.0",
|
||||
"language-source": "0.9.0",
|
||||
"language-sql": "0.17.0",
|
||||
"language-sql": "0.18.0",
|
||||
"language-text": "0.7.0",
|
||||
"language-todo": "0.27.0",
|
||||
"language-toml": "0.16.0",
|
||||
"language-xml": "0.33.0",
|
||||
"language-xml": "0.33.1",
|
||||
"language-yaml": "0.24.0"
|
||||
},
|
||||
"private": true,
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
Exec = require('child_process').exec
|
||||
_ = require "underscore-plus"
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Package = require '../src/package'
|
||||
ThemeManager = require '../src/theme-manager'
|
||||
_ = require "underscore-plus"
|
||||
temp = require "temp"
|
||||
AtomEnvironment = require '../src/atom-environment'
|
||||
|
||||
describe "the `atom` global", ->
|
||||
describe "AtomEnvironment", ->
|
||||
describe 'window sizing methods', ->
|
||||
describe '::getPosition and ::setPosition', ->
|
||||
originalPosition = null
|
||||
beforeEach ->
|
||||
originalPosition = atom.getPosition()
|
||||
|
||||
afterEach ->
|
||||
atom.setPosition(originalPosition.x, originalPosition.y)
|
||||
|
||||
it 'sets the position of the window, and can retrieve the position just set', ->
|
||||
atom.setPosition(22, 45)
|
||||
expect(atom.getPosition()).toEqual x: 22, y: 45
|
||||
@@ -31,28 +38,8 @@ describe "the `atom` global", ->
|
||||
version = '36b5518'
|
||||
expect(atom.isReleasedVersion()).toBe false
|
||||
|
||||
describe "when an update becomes available", ->
|
||||
subscription = null
|
||||
|
||||
afterEach ->
|
||||
subscription?.dispose()
|
||||
|
||||
it "invokes onUpdateAvailable listeners", ->
|
||||
updateAvailableHandler = jasmine.createSpy("update-available-handler")
|
||||
subscription = atom.onUpdateAvailable updateAvailableHandler
|
||||
|
||||
autoUpdater = require('remote').require('auto-updater')
|
||||
autoUpdater.emit 'update-downloaded', null, "notes", "version"
|
||||
|
||||
waitsFor ->
|
||||
updateAvailableHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
{releaseVersion} = updateAvailableHandler.mostRecentCall.args[0]
|
||||
expect(releaseVersion).toBe 'version'
|
||||
|
||||
describe "loading default config", ->
|
||||
it 'loads the default core config', ->
|
||||
it 'loads the default core config schema', ->
|
||||
expect(atom.config.get('core.excludeVcsIgnoredPaths')).toBe true
|
||||
expect(atom.config.get('core.followSymlinks')).toBe true
|
||||
expect(atom.config.get('editor.showInvisibles')).toBe false
|
||||
@@ -139,7 +126,7 @@ describe "the `atom` global", ->
|
||||
expect(result).toBe false
|
||||
expect(errors.length).toBe 1
|
||||
expect(errors[0].message).toBe "Assertion failed: a == b"
|
||||
expect(errors[0].stack).toContain('atom-spec')
|
||||
expect(errors[0].stack).toContain('atom-environment-spec')
|
||||
|
||||
describe "if passed a callback function", ->
|
||||
it "calls the callback with the assertion failure's error object", ->
|
||||
@@ -154,30 +141,34 @@ describe "the `atom` global", ->
|
||||
expect(errors).toEqual []
|
||||
|
||||
describe "saving and loading", ->
|
||||
afterEach -> atom.mode = "spec"
|
||||
beforeEach ->
|
||||
atom.enablePersistence = true
|
||||
|
||||
afterEach ->
|
||||
atom.enablePersistence = false
|
||||
|
||||
it "selects the state based on the current project paths", ->
|
||||
Atom = atom.constructor
|
||||
[dir1, dir2] = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")]
|
||||
|
||||
loadSettings = _.extend Atom.getLoadSettings(),
|
||||
loadSettings = _.extend atom.getLoadSettings(),
|
||||
initialPaths: [dir1]
|
||||
windowState: null
|
||||
|
||||
spyOn(Atom, 'getLoadSettings').andCallFake -> loadSettings
|
||||
spyOn(Atom.getStorageFolder(), 'getPath').andReturn(temp.mkdirSync("storage-dir-"))
|
||||
spyOn(atom, 'getLoadSettings').andCallFake -> loadSettings
|
||||
spyOn(atom.getStorageFolder(), 'getPath').andReturn(temp.mkdirSync("storage-dir-"))
|
||||
|
||||
atom.mode = "editor"
|
||||
atom.state.stuff = "cool"
|
||||
atom.project.setPaths([dir1, dir2])
|
||||
atom.saveSync.originalValue.call(atom)
|
||||
atom.saveStateSync()
|
||||
|
||||
atom1 = Atom.loadOrCreate("editor")
|
||||
expect(atom1.state.stuff).toBeUndefined()
|
||||
atom.state = {}
|
||||
atom.loadStateSync()
|
||||
expect(atom.state.stuff).toBeUndefined()
|
||||
|
||||
loadSettings.initialPaths = [dir2, dir1]
|
||||
atom2 = Atom.loadOrCreate("editor")
|
||||
expect(atom2.state.stuff).toBe("cool")
|
||||
atom.state = {}
|
||||
atom.loadStateSync()
|
||||
expect(atom.state.stuff).toBe("cool")
|
||||
|
||||
describe "openInitialEmptyEditorIfNecessary", ->
|
||||
describe "when there are no paths set", ->
|
||||
@@ -225,28 +216,92 @@ describe "the `atom` global", ->
|
||||
|
||||
describe "::unloadEditorWindow()", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
syntaxState = atom.grammars.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document})
|
||||
spyOn(atomEnvironment, 'saveStateSync')
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
workspaceState = atomEnvironment.workspace.serialize()
|
||||
grammarsState = {grammarOverridesByPath: atomEnvironment.grammars.grammarOverridesByPath}
|
||||
projectState = atomEnvironment.project.serialize()
|
||||
|
||||
expect(atom.state.workspace).toEqual workspaceState
|
||||
expect(atom.state.grammars).toEqual syntaxState
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
atomEnvironment.unloadEditorWindow()
|
||||
|
||||
describe "::removeEditorWindow()", ->
|
||||
expect(atomEnvironment.state.workspace).toEqual workspaceState
|
||||
expect(atomEnvironment.state.grammars).toEqual grammarsState
|
||||
expect(atomEnvironment.state.project).toEqual projectState
|
||||
expect(atomEnvironment.saveStateSync).toHaveBeenCalled()
|
||||
|
||||
atomEnvironment.destroy()
|
||||
|
||||
describe "::destroy()", ->
|
||||
it "unsubscribes from all buffers", ->
|
||||
atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document})
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js")
|
||||
atomEnvironment.workspace.open("sample.js")
|
||||
|
||||
runs ->
|
||||
buffer = atom.workspace.getActivePaneItem().buffer
|
||||
pane = atom.workspace.getActivePane()
|
||||
buffer = atomEnvironment.workspace.getActivePaneItem().buffer
|
||||
pane = atomEnvironment.workspace.getActivePane()
|
||||
pane.splitRight(copyActiveItem: true)
|
||||
expect(atom.workspace.getTextEditors().length).toBe 2
|
||||
expect(atomEnvironment.workspace.getTextEditors().length).toBe 2
|
||||
|
||||
atom.removeEditorWindow()
|
||||
atomEnvironment.destroy()
|
||||
|
||||
expect(buffer.getSubscriptionCount()).toBe 0
|
||||
|
||||
describe "::openLocations(locations) (called via IPC from browser process)", ->
|
||||
beforeEach ->
|
||||
spyOn(atom.workspace, 'open')
|
||||
atom.project.setPaths([])
|
||||
|
||||
describe "when the opened path exists", ->
|
||||
it "adds it to the project's paths", ->
|
||||
pathToOpen = __filename
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "adds the parent directory to the project paths", ->
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path is a file", ->
|
||||
it "opens it in the workspace", ->
|
||||
pathToOpen = __filename
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename
|
||||
|
||||
describe "when the opened path is a directory", ->
|
||||
it "does not open it in the workspace", ->
|
||||
pathToOpen = __dirname
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.open.callCount).toBe 0
|
||||
|
||||
describe "when the opened path is a uri", ->
|
||||
it "adds it to the project's paths as is", ->
|
||||
pathToOpen = 'remote://server:7644/some/dir/path'
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe pathToOpen
|
||||
|
||||
describe "::updateAvailable(info) (called via IPC from browser process)", ->
|
||||
subscription = null
|
||||
|
||||
afterEach ->
|
||||
subscription?.dispose()
|
||||
|
||||
it "invokes onUpdateAvailable listeners", ->
|
||||
atom.listenForUpdates()
|
||||
|
||||
updateAvailableHandler = jasmine.createSpy("update-available-handler")
|
||||
subscription = atom.onUpdateAvailable updateAvailableHandler
|
||||
|
||||
autoUpdater = require('remote').require('auto-updater')
|
||||
autoUpdater.emit 'update-downloaded', null, "notes", "version"
|
||||
|
||||
waitsFor ->
|
||||
updateAvailableHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
{releaseVersion} = updateAvailableHandler.mostRecentCall.args[0]
|
||||
expect(releaseVersion).toBe 'version'
|
||||
@@ -22,7 +22,8 @@ describe "CommandInstaller on #darwin", ->
|
||||
|
||||
describe "when using a stable version of atom", ->
|
||||
beforeEach ->
|
||||
installer = new CommandInstaller("2.0.2")
|
||||
confirm = ->
|
||||
installer = new CommandInstaller("2.0.2", confirm)
|
||||
|
||||
it "symlinks the atom command as 'atom'", ->
|
||||
installedAtomPath = path.join(installationPath, 'atom')
|
||||
|
||||
@@ -16,6 +16,7 @@ describe "CommandRegistry", ->
|
||||
document.querySelector('#jasmine-content').appendChild(parent)
|
||||
|
||||
registry = new CommandRegistry
|
||||
registry.attach(parent)
|
||||
|
||||
afterEach ->
|
||||
registry.destroy()
|
||||
@@ -277,3 +278,18 @@ describe "CommandRegistry", ->
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]
|
||||
|
||||
describe "::attach(rootNode)", ->
|
||||
it "adds event listeners for any previously-added commands", ->
|
||||
registry2 = new CommandRegistry
|
||||
|
||||
commandSpy = jasmine.createSpy('command-callback')
|
||||
registry2.add '.grandchild', 'command-1', commandSpy
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', bubbles: true))
|
||||
expect(commandSpy).not.toHaveBeenCalled()
|
||||
|
||||
registry2.attach(parent)
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', bubbles: true))
|
||||
expect(commandSpy).toHaveBeenCalled()
|
||||
|
||||
@@ -18,7 +18,7 @@ describe 'CompileCache', ->
|
||||
CompileCache.resetCacheStats()
|
||||
|
||||
spyOn(Babel, 'transform').andReturn {code: 'the-babel-code'}
|
||||
spyOn(CoffeeScript, 'compile').andReturn {js: 'the-coffee-code', v3SourceMap: {}}
|
||||
spyOn(CoffeeScript, 'compile').andReturn {js: 'the-coffee-code', v3SourceMap: "{}"}
|
||||
spyOn(TypeScriptSimple::, 'compile').andReturn 'the-typescript-code'
|
||||
spyOn(CSONParser, 'parse').andReturn {the: 'cson-data'}
|
||||
|
||||
|
||||
@@ -7,10 +7,16 @@ describe "Config", ->
|
||||
dotAtomPath = null
|
||||
|
||||
beforeEach ->
|
||||
spyOn(atom.config, "load")
|
||||
spyOn(atom.config, "save")
|
||||
dotAtomPath = temp.path('dot-atom-dir')
|
||||
atom.config.configDirPath = dotAtomPath
|
||||
atom.config.enablePersistence = true
|
||||
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
|
||||
|
||||
afterEach ->
|
||||
atom.config.enablePersistence = false
|
||||
|
||||
describe ".get(keyPath, {scope, sources, excludeSources})", ->
|
||||
it "allows a key path's value to be read", ->
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe true
|
||||
@@ -153,13 +159,27 @@ describe "Config", ->
|
||||
|
||||
describe "when the value equals the default value", ->
|
||||
it "does not store the value in the user's config", ->
|
||||
atom.config.setDefaults "foo",
|
||||
same: 1
|
||||
changes: 1
|
||||
sameArray: [1, 2, 3]
|
||||
sameObject: {a: 1, b: 2}
|
||||
null: null
|
||||
undefined: undefined
|
||||
atom.config.setSchema "foo",
|
||||
type: 'object'
|
||||
properties:
|
||||
same:
|
||||
type: 'number'
|
||||
default: 1
|
||||
changes:
|
||||
type: 'number'
|
||||
default: 1
|
||||
sameArray:
|
||||
type: 'array'
|
||||
default: [1, 2, 3]
|
||||
sameObject:
|
||||
type: 'object'
|
||||
default: {a: 1, b: 2}
|
||||
null:
|
||||
type: '*'
|
||||
default: null
|
||||
undefined:
|
||||
type: '*'
|
||||
default: undefined
|
||||
expect(atom.config.settings.foo).toBeUndefined()
|
||||
|
||||
atom.config.set('foo.same', 1)
|
||||
@@ -169,11 +189,15 @@ describe "Config", ->
|
||||
atom.config.set('foo.undefined', null)
|
||||
atom.config.set('foo.sameObject', {b: 2, a: 1})
|
||||
|
||||
expect(atom.config.get("foo.same", sources: [atom.config.getUserConfigPath()])).toBeUndefined()
|
||||
userConfigPath = atom.config.getUserConfigPath()
|
||||
|
||||
expect(atom.config.get("foo.same", sources: [userConfigPath])).toBeUndefined()
|
||||
|
||||
expect(atom.config.get("foo.changes")).toBe 2
|
||||
expect(atom.config.get("foo.changes", sources: [userConfigPath])).toBe 2
|
||||
|
||||
expect(atom.config.get("foo.changes", sources: [atom.config.getUserConfigPath()])).toBe 2
|
||||
atom.config.set('foo.changes', 1)
|
||||
expect(atom.config.get("foo.changes", sources: [atom.config.getUserConfigPath()])).toBeUndefined()
|
||||
expect(atom.config.get("foo.changes", sources: [userConfigPath])).toBeUndefined()
|
||||
|
||||
describe "when a 'scopeSelector' is given", ->
|
||||
it "sets the value and overrides the others", ->
|
||||
|
||||
@@ -5,7 +5,7 @@ describe "ContextMenuManager", ->
|
||||
|
||||
beforeEach ->
|
||||
{resourcePath} = atom.getLoadSettings()
|
||||
contextMenu = new ContextMenuManager({resourcePath})
|
||||
contextMenu = new ContextMenuManager({resourcePath, keymapManager: atom.keymaps})
|
||||
|
||||
parent = document.createElement("div")
|
||||
child = document.createElement("div")
|
||||
|
||||
@@ -7,7 +7,7 @@ describe "CustomGutterComponent", ->
|
||||
beforeEach ->
|
||||
mockGutterContainer = {}
|
||||
gutter = new Gutter(mockGutterContainer, {name: 'test-gutter'})
|
||||
gutterComponent = new CustomGutterComponent({gutter})
|
||||
gutterComponent = new CustomGutterComponent({gutter, views: atom.views})
|
||||
|
||||
it "creates a gutter DOM node with only an empty 'custom-decorations' child node when it is initialized", ->
|
||||
expect(gutterComponent.getDomNode().classList.contains('gutter')).toBe true
|
||||
|
||||
@@ -7,7 +7,10 @@ describe "DisplayBuffer", ->
|
||||
tabLength = 2
|
||||
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
displayBuffer = new DisplayBuffer({
|
||||
buffer, tabLength, config: atom.config, grammarRegistry: atom.grammars,
|
||||
packageManager: atom.packages, assert: ->
|
||||
})
|
||||
changeHandler = jasmine.createSpy 'changeHandler'
|
||||
displayBuffer.onDidChange changeHandler
|
||||
|
||||
@@ -49,16 +52,50 @@ describe "DisplayBuffer", ->
|
||||
|
||||
it "updates the display buffer prior to invoking change handlers registered on the buffer", ->
|
||||
buffer.onDidChange -> expect(displayBuffer2.tokenizedLineForScreenRow(0).text).toBe "testing"
|
||||
displayBuffer2 = new DisplayBuffer({buffer, tabLength})
|
||||
displayBuffer2 = new DisplayBuffer({
|
||||
buffer, tabLength, config: atom.config, grammarRegistry: atom.grammars,
|
||||
packageManager: atom.packages, assert: ->
|
||||
})
|
||||
buffer.setText("testing")
|
||||
|
||||
describe "soft wrapping", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
displayBuffer.setEditorWidthInChars(50)
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
displayBuffer.setDefaultCharWidth(1)
|
||||
changeHandler.reset()
|
||||
|
||||
describe "rendering of soft-wrapped lines", ->
|
||||
describe "when there are double width characters", ->
|
||||
it "takes them into account when finding the soft wrap column", ->
|
||||
buffer.setText("私たちのフ是一个地方,数千名学生12345业余爱们的板作为hello world this is a pretty long latin line")
|
||||
displayBuffer.setDefaultCharWidth(1, 5, 0, 0)
|
||||
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("私たちのフ是一个地方")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe(",数千名学生12345业余爱")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("们的板作为hello world this is a ")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe("pretty long latin line")
|
||||
|
||||
describe "when there are half width characters", ->
|
||||
it "takes them into account when finding the soft wrap column", ->
|
||||
displayBuffer.setDefaultCharWidth(1, 0, 5, 0)
|
||||
buffer.setText("abcᆰᆱᆲネヌネノハヒフヒフヌᄡ○○○hello world this is a pretty long line")
|
||||
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("abcᆰᆱᆲネヌネノハヒ")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe("フヒフヌᄡ○○○hello ")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("world this is a pretty long line")
|
||||
|
||||
describe "when there are korean characters", ->
|
||||
it "takes them into account when finding the soft wrap column", ->
|
||||
displayBuffer.setDefaultCharWidth(1, 0, 0, 10)
|
||||
buffer.setText("1234세계를 향한 대화, 유니코 제10회유니코드국제")
|
||||
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("1234세계를 ")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe("향한 대화, ")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("유니코 ")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe("제10회유니")
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe("코드국제")
|
||||
|
||||
describe "when editor.softWrapAtPreferredLineLength is set", ->
|
||||
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
|
||||
atom.config.set('editor.preferredLineLength', 100)
|
||||
@@ -232,7 +269,11 @@ describe "DisplayBuffer", ->
|
||||
describe "when a newline is inserted, deleted, and re-inserted at the end of a wrapped line (regression)", ->
|
||||
it "correctly renders the original wrapped line", ->
|
||||
buffer = atom.project.buildBufferSync(null, '')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30})
|
||||
displayBuffer = new DisplayBuffer({
|
||||
buffer, tabLength, editorWidthInChars: 30, config: atom.config,
|
||||
grammarRegistry: atom.grammars, packageManager: atom.packages, assert: ->
|
||||
})
|
||||
displayBuffer.setDefaultCharWidth(1)
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
|
||||
buffer.insert([0, 0], "the quick brown fox jumps over the lazy dog.")
|
||||
@@ -294,7 +335,10 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.destroy()
|
||||
buffer.release()
|
||||
buffer = atom.project.bufferForPathSync('two-hundred.txt')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
displayBuffer = new DisplayBuffer({
|
||||
buffer, tabLength, config: atom.config, grammarRegistry: atom.grammars,
|
||||
packageManager: atom.packages, assert: ->
|
||||
})
|
||||
displayBuffer.onDidChange changeHandler
|
||||
|
||||
describe "when folds are created and destroyed", ->
|
||||
@@ -408,7 +452,10 @@ describe "DisplayBuffer", ->
|
||||
|
||||
describe "when there is another display buffer pointing to the same buffer", ->
|
||||
it "does not consider folds to be nested inside of folds from the other display buffer", ->
|
||||
otherDisplayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
otherDisplayBuffer = new DisplayBuffer({
|
||||
buffer, tabLength, config: atom.config, grammarRegistry: atom.grammars,
|
||||
packageManager: atom.packages, assert: ->
|
||||
})
|
||||
otherDisplayBuffer.createFold(1, 5)
|
||||
|
||||
displayBuffer.createFold(2, 4)
|
||||
@@ -636,6 +683,7 @@ describe "DisplayBuffer", ->
|
||||
beforeEach ->
|
||||
tabLength = 4
|
||||
|
||||
displayBuffer.setDefaultCharWidth(1)
|
||||
displayBuffer.setTabLength(tabLength)
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
displayBuffer.setEditorWidthInChars(50)
|
||||
@@ -753,6 +801,7 @@ describe "DisplayBuffer", ->
|
||||
it "correctly translates positions on soft wrapped lines containing tabs", ->
|
||||
buffer.setText('\t\taa bb cc dd ee ff gg')
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
displayBuffer.setDefaultCharWidth(1)
|
||||
displayBuffer.setEditorWidthInChars(10)
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 10], wrapAtSoftNewlines: true)).toEqual [1, 4]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([1, 0])).toEqual [0, 9]
|
||||
@@ -1154,7 +1203,10 @@ describe "DisplayBuffer", ->
|
||||
describe 'when there are multiple DisplayBuffers for a buffer', ->
|
||||
describe 'when a marker is created', ->
|
||||
it 'the second display buffer will not emit a marker-created event when the marker has been deleted in the first marker-created event', ->
|
||||
displayBuffer2 = new DisplayBuffer({buffer, tabLength})
|
||||
displayBuffer2 = new DisplayBuffer({
|
||||
buffer, tabLength, config: atom.config, grammarRegistry: atom.grammars,
|
||||
packageManager: atom.packages, assert: ->
|
||||
})
|
||||
displayBuffer.onDidCreateMarker markerCreated1 = jasmine.createSpy().andCallFake (marker) -> marker.destroy()
|
||||
displayBuffer2.onDidCreateMarker markerCreated2 = jasmine.createSpy()
|
||||
|
||||
|
||||
2
spec/fixtures/babel/invalid.js
vendored
2
spec/fixtures/babel/invalid.js
vendored
@@ -1,3 +1,3 @@
|
||||
'use 6to6';
|
||||
|
||||
module.exports = v => v + 1
|
||||
module.exports = async function hello() {}
|
||||
|
||||
@@ -6,11 +6,15 @@ GitRepository = require '../src/git-repository'
|
||||
GitRepositoryProvider = require '../src/git-repository-provider'
|
||||
|
||||
describe "GitRepositoryProvider", ->
|
||||
provider = null
|
||||
|
||||
beforeEach ->
|
||||
provider = new GitRepositoryProvider(atom.project, atom.config, atom.confirm)
|
||||
|
||||
describe ".repositoryForDirectory(directory)", ->
|
||||
describe "when specified a Directory with a Git repository", ->
|
||||
it "returns a Promise that resolves to a GitRepository", ->
|
||||
waitsForPromise ->
|
||||
provider = new GitRepositoryProvider atom.project
|
||||
directory = new Directory path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
provider.repositoryForDirectory(directory).then (result) ->
|
||||
expect(result).toBeInstanceOf GitRepository
|
||||
@@ -19,7 +23,6 @@ describe "GitRepositoryProvider", ->
|
||||
expect(result.getType()).toBe 'git'
|
||||
|
||||
it "returns the same GitRepository for different Directory objects in the same repo", ->
|
||||
provider = new GitRepositoryProvider atom.project
|
||||
firstRepo = null
|
||||
secondRepo = null
|
||||
|
||||
@@ -38,7 +41,6 @@ describe "GitRepositoryProvider", ->
|
||||
describe "when specified a Directory without a Git repository", ->
|
||||
it "returns a Promise that resolves to null", ->
|
||||
waitsForPromise ->
|
||||
provider = new GitRepositoryProvider atom.project
|
||||
directory = new Directory temp.mkdirSync('dir')
|
||||
provider.repositoryForDirectory(directory).then (result) ->
|
||||
expect(result).toBe null
|
||||
@@ -46,7 +48,6 @@ describe "GitRepositoryProvider", ->
|
||||
describe "when specified a Directory with an invalid Git repository", ->
|
||||
it "returns a Promise that resolves to null", ->
|
||||
waitsForPromise ->
|
||||
provider = new GitRepositoryProvider atom.project
|
||||
dirPath = temp.mkdirSync('dir')
|
||||
fs.writeFileSync(path.join(dirPath, '.git', 'objects'), '')
|
||||
fs.writeFileSync(path.join(dirPath, '.git', 'HEAD'), '')
|
||||
@@ -59,7 +60,6 @@ describe "GitRepositoryProvider", ->
|
||||
describe "when specified a Directory with a valid gitfile-linked repository", ->
|
||||
it "returns a Promise that resolves to a GitRepository", ->
|
||||
waitsForPromise ->
|
||||
provider = new GitRepositoryProvider atom.project
|
||||
gitDirPath = path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
workDirPath = temp.mkdirSync('git-workdir')
|
||||
fs.writeFileSync(path.join(workDirPath, '.git'), 'gitdir: ' + gitDirPath+'\n')
|
||||
@@ -75,8 +75,6 @@ describe "GitRepositoryProvider", ->
|
||||
directory = null
|
||||
provider = null
|
||||
beforeEach ->
|
||||
provider = new GitRepositoryProvider atom.project
|
||||
|
||||
# An implementation of Directory that does not implement existsSync().
|
||||
subdirectory = {}
|
||||
directory =
|
||||
|
||||
@@ -134,8 +134,10 @@ describe "GitRepository", ->
|
||||
[filePath, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
spyOn(atom, "confirm")
|
||||
|
||||
workingDirPath = copyRepository()
|
||||
repo = new GitRepository(workingDirPath)
|
||||
repo = new GitRepository(workingDirPath, {project: atom.project, config: atom.config, confirm: atom.confirm})
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
|
||||
@@ -146,7 +148,7 @@ describe "GitRepository", ->
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
|
||||
it "displays a confirmation dialog by default", ->
|
||||
spyOn(atom, 'confirm').andCallFake ({buttons}) -> buttons.OK()
|
||||
atom.confirm.andCallFake ({buttons}) -> buttons.OK()
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', true)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
@@ -154,7 +156,6 @@ describe "GitRepository", ->
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
|
||||
|
||||
it "does not display a dialog when confirmation is disabled", ->
|
||||
spyOn(atom, 'confirm')
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', false)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
@@ -287,7 +288,8 @@ describe "GitRepository", ->
|
||||
atom.workspace.open('file.txt')
|
||||
|
||||
runs ->
|
||||
project2 = Project.deserialize(atom.project.serialize())
|
||||
project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
|
||||
project2.deserialize(atom.project.serialize(), atom.deserializers)
|
||||
buffer = project2.getBuffers()[0]
|
||||
|
||||
waitsFor ->
|
||||
|
||||
@@ -24,18 +24,9 @@ describe "the `grammars` global", ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe "serialization", ->
|
||||
it "remembers grammar overrides by path", ->
|
||||
filePath = '/foo/bar/file.js'
|
||||
expect(atom.grammars.selectGrammar(filePath).name).not.toBe 'Ruby'
|
||||
atom.grammars.setGrammarOverrideForPath(filePath, 'source.ruby')
|
||||
grammars2 = atom.deserializers.deserialize(atom.grammars.serialize())
|
||||
grammars2.addGrammar(grammar) for grammar in atom.grammars.grammars when grammar isnt atom.grammars.nullGrammar
|
||||
expect(grammars2.selectGrammar(filePath).name).toBe 'Ruby'
|
||||
|
||||
describe ".selectGrammar(filePath)", ->
|
||||
it "always returns a grammar", ->
|
||||
registry = new GrammarRegistry()
|
||||
registry = new GrammarRegistry(config: atom.config)
|
||||
expect(registry.selectGrammar().scopeName).toBe 'text.plain.null-grammar'
|
||||
|
||||
it "selects the text.plain grammar over the null grammar", ->
|
||||
|
||||
@@ -26,7 +26,7 @@ describe "GutterContainerComponent", ->
|
||||
domElementPool = new DOMElementPool
|
||||
mockEditor = {}
|
||||
mockMouseDown = ->
|
||||
gutterContainerComponent = new GutterContainerComponent({editor: mockEditor, onMouseDown: mockMouseDown, domElementPool})
|
||||
gutterContainerComponent = new GutterContainerComponent({editor: mockEditor, onMouseDown: mockMouseDown, domElementPool, views: atom.views})
|
||||
|
||||
it "creates a DOM node with no child gutter nodes when it is initialized", ->
|
||||
expect(gutterContainerComponent.getDomNode() instanceof HTMLElement).toBe true
|
||||
|
||||
@@ -91,7 +91,8 @@ buildAtomClient = (args, env) ->
|
||||
cb(null)
|
||||
|
||||
.addCommand "treeViewRootDirectories", (cb) ->
|
||||
@execute(->
|
||||
@waitForExist('.tree-view', 10000)
|
||||
.execute(->
|
||||
for element in document.querySelectorAll(".tree-view .project-root > .header .name")
|
||||
element.dataset.path
|
||||
, cb)
|
||||
@@ -104,7 +105,8 @@ buildAtomClient = (args, env) ->
|
||||
.then ({value: newWindowHandles}) ->
|
||||
[newWindowHandle] = difference(newWindowHandles, oldWindowHandles)
|
||||
return done() unless newWindowHandle
|
||||
@window(newWindowHandle, done)
|
||||
@window(newWindowHandle)
|
||||
.waitForExist('atom-workspace', 10000, done)
|
||||
|
||||
.addCommand "startAnotherAtom", (args, env, done) ->
|
||||
@call ->
|
||||
@@ -168,7 +170,11 @@ module.exports = (args, env, fn) ->
|
||||
jasmine.getEnv().currentSpec.fail(new Error(err.response?.body?.value?.message))
|
||||
finish()
|
||||
|
||||
fn(client.init()).then(finish)
|
||||
fn(
|
||||
client.init()
|
||||
.waitUntil((-> @windowHandles().then ({value}) -> value.length > 0), 10000)
|
||||
.waitForExist("atom-workspace", 10000)
|
||||
).then(finish)
|
||||
, 30000)
|
||||
|
||||
waitsFor("webdriver to stop", chromeDriverDown, 15000)
|
||||
|
||||
@@ -28,8 +28,6 @@ describe "Starting Atom", ->
|
||||
it "opens the parent directory and creates an empty text editor", ->
|
||||
runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForWindowCount(1, 1000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
|
||||
.treeViewRootDirectories()
|
||||
@@ -54,8 +52,6 @@ describe "Starting Atom", ->
|
||||
|
||||
runAtom ["#{filePath}:3"], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForWindowCount(1, 1000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.then (exists) -> expect(exists).toBe true
|
||||
@@ -79,8 +75,6 @@ describe "Starting Atom", ->
|
||||
|
||||
runAtom ["#{filePath}:2:2"], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForWindowCount(1, 1000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.then (exists) -> expect(exists).toBe true
|
||||
@@ -97,8 +91,6 @@ describe "Starting Atom", ->
|
||||
filePath = path.join(tempDirPath, "new-file")
|
||||
runAtom ["#{filePath}: "], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForWindowCount(1, 1000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.then (exists) -> expect(exists).toBe true
|
||||
@@ -113,8 +105,6 @@ describe "Starting Atom", ->
|
||||
|
||||
runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForWindowCount(1, 1000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(1, 5000)
|
||||
|
||||
# Opening another file reuses the same window and does not change the
|
||||
@@ -131,7 +121,6 @@ describe "Starting Atom", ->
|
||||
.waitForNewWindow(->
|
||||
@startAnotherAtom([otherTempDirPath], ATOM_HOME: atomHome)
|
||||
, 5000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(0, 1000)
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([otherTempDirPath])
|
||||
@@ -140,14 +129,12 @@ describe "Starting Atom", ->
|
||||
it "remembers the state of the window", ->
|
||||
runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(0, 3000)
|
||||
.execute -> atom.workspace.open()
|
||||
.waitForPaneItemCount(1, 3000)
|
||||
|
||||
runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.waitForPaneItemCount(1, 5000)
|
||||
|
||||
describe "opening multiple directories simultaneously", ->
|
||||
@@ -157,14 +144,12 @@ describe "Starting Atom", ->
|
||||
|
||||
runAtom [tempDirPath, otherTempDirPath], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath])
|
||||
|
||||
# Opening one of those directories again reuses the same window and
|
||||
# does not change the project paths.
|
||||
.startAnotherAtom([nestedDir], ATOM_HOME: atomHome)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath])
|
||||
|
||||
@@ -172,7 +157,6 @@ describe "Starting Atom", ->
|
||||
it "reuses that window to open a directory", ->
|
||||
runAtom [], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace")
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([])
|
||||
|
||||
@@ -188,7 +172,6 @@ describe "Starting Atom", ->
|
||||
it "opens a new window with a single untitled buffer", ->
|
||||
runAtom [], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace")
|
||||
.waitForPaneItemCount(1, 5000)
|
||||
|
||||
# Opening with no file paths always creates a new window, even if
|
||||
@@ -196,7 +179,6 @@ describe "Starting Atom", ->
|
||||
.waitForNewWindow(->
|
||||
@startAnotherAtom([], ATOM_HOME: atomHome)
|
||||
, 5000)
|
||||
.waitForExist("atom-workspace")
|
||||
.waitForPaneItemCount(1, 5000)
|
||||
|
||||
it "doesn't open a new window if openEmptyEditorOnStart is disabled", ->
|
||||
@@ -207,17 +189,14 @@ describe "Starting Atom", ->
|
||||
|
||||
runAtom [], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace")
|
||||
.waitForPaneItemCount(0, 5000)
|
||||
|
||||
it "reopens any previously opened windows", ->
|
||||
runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace")
|
||||
.waitForNewWindow(->
|
||||
@startAnotherAtom([otherTempDirPath], ATOM_HOME: atomHome)
|
||||
, 5000)
|
||||
.waitForExist("atom-workspace")
|
||||
|
||||
runAtom [], {ATOM_HOME: atomHome}, (client) ->
|
||||
windowProjectPaths = []
|
||||
@@ -226,12 +205,10 @@ describe "Starting Atom", ->
|
||||
.waitForWindowCount(2, 10000)
|
||||
.then ({value: windowHandles}) ->
|
||||
@window(windowHandles[0])
|
||||
.waitForExist("atom-workspace")
|
||||
.treeViewRootDirectories()
|
||||
.then ({value: directories}) -> windowProjectPaths.push(directories)
|
||||
|
||||
.window(windowHandles[1])
|
||||
.waitForExist("atom-workspace")
|
||||
.treeViewRootDirectories()
|
||||
.then ({value: directories}) -> windowProjectPaths.push(directories)
|
||||
|
||||
@@ -246,7 +223,5 @@ describe "Starting Atom", ->
|
||||
remoteDirectory = 'remote://server:3437/some/directory/path'
|
||||
runAtom [remoteDirectory], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForWindowCount(1, 1000)
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([remoteDirectory])
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
window[key] = value for key, value of require '../vendor/jasmine'
|
||||
|
||||
{TerminalReporter} = require 'jasmine-tagged'
|
||||
|
||||
disableFocusMethods() if process.env.JANKY_SHA1 or process.env.CI
|
||||
|
||||
TimeReporter = require './time-reporter'
|
||||
timeReporter = new TimeReporter()
|
||||
|
||||
logStream = fs.openSync(logFile, 'w') if logFile?
|
||||
log = (str) ->
|
||||
if logStream?
|
||||
fs.writeSync(logStream, str)
|
||||
else
|
||||
process.stderr.write(str)
|
||||
|
||||
if atom.getLoadSettings().exitWhenDone
|
||||
reporter = new TerminalReporter
|
||||
print: (str) ->
|
||||
log(str)
|
||||
onComplete: (runner) ->
|
||||
fs.closeSync(logStream) if logStream?
|
||||
if process.env.JANKY_SHA1 or process.env.CI
|
||||
grim = require 'grim'
|
||||
|
||||
if grim.getDeprecationsLength() > 0
|
||||
grim.logDeprecations()
|
||||
return atom.exit(1)
|
||||
|
||||
if runner.results().failedCount > 0
|
||||
atom.exit(1)
|
||||
else
|
||||
atom.exit(0)
|
||||
else
|
||||
AtomReporter = require './atom-reporter'
|
||||
reporter = new AtomReporter()
|
||||
|
||||
require specSuite
|
||||
|
||||
jasmineEnv = jasmine.getEnv()
|
||||
jasmineEnv.addReporter(reporter)
|
||||
jasmineEnv.addReporter(timeReporter)
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
|
||||
jasmineContent = document.createElement('div')
|
||||
jasmineContent.setAttribute('id', 'jasmine-content')
|
||||
document.body.appendChild(jasmineContent)
|
||||
|
||||
jasmineEnv.execute()
|
||||
|
||||
disableFocusMethods = ->
|
||||
['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach (methodName) ->
|
||||
focusMethod = window[methodName]
|
||||
window[methodName] = (description) ->
|
||||
error = new Error('Focused spec is running on CI')
|
||||
focusMethod description, -> throw error
|
||||
111
spec/jasmine-test-runner.coffee
Normal file
111
spec/jasmine-test-runner.coffee
Normal file
@@ -0,0 +1,111 @@
|
||||
fs = require 'fs'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
ipc = require 'ipc'
|
||||
|
||||
module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) ->
|
||||
window[key] = value for key, value of require '../vendor/jasmine'
|
||||
require 'jasmine-tagged'
|
||||
|
||||
# Allow document.title to be assigned in specs without screwing up spec window title
|
||||
documentTitle = null
|
||||
Object.defineProperty document, 'title',
|
||||
get: -> documentTitle
|
||||
set: (title) -> documentTitle = title
|
||||
|
||||
ApplicationDelegate = require '../src/application-delegate'
|
||||
applicationDelegate = new ApplicationDelegate()
|
||||
applicationDelegate.setRepresentedFilename = ->
|
||||
applicationDelegate.setWindowDocumentEdited = ->
|
||||
window.atom = buildAtomEnvironment({
|
||||
applicationDelegate, window, document,
|
||||
configDirPath: process.env.ATOM_HOME
|
||||
enablePersistence: false
|
||||
})
|
||||
|
||||
require './spec-helper'
|
||||
disableFocusMethods() if process.env.JANKY_SHA1 or process.env.CI
|
||||
requireSpecs(testPath) for testPath in testPaths
|
||||
|
||||
setSpecType('user')
|
||||
|
||||
resolveWithExitCode = null
|
||||
promise = new Promise (resolve, reject) -> resolveWithExitCode = resolve
|
||||
jasmineEnv = jasmine.getEnv()
|
||||
jasmineEnv.addReporter(buildReporter({logFile, headless, resolveWithExitCode}))
|
||||
TimeReporter = require './time-reporter'
|
||||
jasmineEnv.addReporter(new TimeReporter())
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
|
||||
jasmineContent = document.createElement('div')
|
||||
jasmineContent.setAttribute('id', 'jasmine-content')
|
||||
|
||||
document.body.appendChild(jasmineContent)
|
||||
|
||||
jasmineEnv.execute()
|
||||
promise
|
||||
|
||||
disableFocusMethods = ->
|
||||
['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach (methodName) ->
|
||||
focusMethod = window[methodName]
|
||||
window[methodName] = (description) ->
|
||||
error = new Error('Focused spec is running on CI')
|
||||
focusMethod description, -> throw error
|
||||
|
||||
requireSpecs = (testPath, specType) ->
|
||||
if fs.isDirectorySync(testPath)
|
||||
for testFilePath in fs.listTreeSync(testPath) when /-spec\.(coffee|js)$/.test testFilePath
|
||||
require(testFilePath)
|
||||
# Set spec directory on spec for setting up the project in spec-helper
|
||||
setSpecDirectory(testPath)
|
||||
else
|
||||
require(testPath)
|
||||
setSpecDirectory(path.dirname(testPath))
|
||||
|
||||
setSpecField = (name, value) ->
|
||||
specs = jasmine.getEnv().currentRunner().specs()
|
||||
return if specs.length is 0
|
||||
for index in [specs.length-1..0]
|
||||
break if specs[index][name]?
|
||||
specs[index][name] = value
|
||||
|
||||
setSpecType = (specType) ->
|
||||
setSpecField('specType', specType)
|
||||
|
||||
setSpecDirectory = (specDirectory) ->
|
||||
setSpecField('specDirectory', specDirectory)
|
||||
|
||||
buildReporter = ({logFile, headless, resolveWithExitCode}) ->
|
||||
if headless
|
||||
buildTerminalReporter(logFile, resolveWithExitCode)
|
||||
else
|
||||
AtomReporter = require './atom-reporter'
|
||||
reporter = new AtomReporter()
|
||||
|
||||
buildTerminalReporter = (logFile, resolveWithExitCode) ->
|
||||
logStream = fs.openSync(logFile, 'w') if logFile?
|
||||
log = (str) ->
|
||||
if logStream?
|
||||
fs.writeSync(logStream, str)
|
||||
else
|
||||
ipc.send 'write-to-stderr', str
|
||||
|
||||
{TerminalReporter} = require 'jasmine-tagged'
|
||||
new TerminalReporter
|
||||
print: (str) ->
|
||||
log(str)
|
||||
onComplete: (runner) ->
|
||||
fs.closeSync(logStream) if logStream?
|
||||
if process.env.JANKY_SHA1 or process.env.CI
|
||||
grim = require 'grim'
|
||||
|
||||
if grim.getDeprecationsLength() > 0
|
||||
grim.logDeprecations()
|
||||
resolveWithExitCode(1)
|
||||
return
|
||||
|
||||
if runner.results().failedCount > 0
|
||||
resolveWithExitCode(1)
|
||||
else
|
||||
resolveWithExitCode(0)
|
||||
@@ -9,7 +9,7 @@ describe "LinesYardstick", ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
createdLineNodes = []
|
||||
@@ -56,7 +56,7 @@ describe "LinesYardstick", ->
|
||||
textNodes
|
||||
|
||||
editor.setLineHeightInPixels(14)
|
||||
linesYardstick = new LinesYardstick(editor, mockPresenter, mockLineNodesProvider)
|
||||
linesYardstick = new LinesYardstick(editor, mockPresenter, mockLineNodesProvider, atom.grammars)
|
||||
|
||||
afterEach ->
|
||||
lineNode.remove() for lineNode in createdLineNodes
|
||||
@@ -76,10 +76,10 @@ describe "LinesYardstick", ->
|
||||
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 0])).toEqual({left: 0, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 1])).toEqual({left: 7, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 5])).toEqual({left: 37.8046875, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 6])).toEqual({left: 43.20703125, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 9])).toEqual({left: 72.20703125, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, Infinity])).toEqual({left: 288.046875, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 5])).toEqual({left: 37.78125, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 6])).toEqual({left: 43.171875, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 9])).toEqual({left: 72.171875, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, Infinity])).toEqual({left: 287.859375, top: 28})
|
||||
|
||||
it "reuses already computed pixel positions unless it is invalidated", ->
|
||||
atom.styles.addStyleSheet """
|
||||
@@ -105,9 +105,9 @@ describe "LinesYardstick", ->
|
||||
|
||||
linesYardstick.invalidateCache()
|
||||
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 24.00390625, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 72.01171875, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 120.01171875, top: 70})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 24, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 72, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 120, top: 70})
|
||||
|
||||
it "correctly handles RTL characters", ->
|
||||
atom.styles.addStyleSheet """
|
||||
@@ -156,7 +156,7 @@ describe "LinesYardstick", ->
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 32, left: 24.3})).toEqual([2, 3])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 46, left: 66.5})).toEqual([3, 9])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 99.9})).toEqual([5, 14])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 224.4365234375})).toEqual([5, 29])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 224.2365234375})).toEqual([5, 29])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 225})).toEqual([5, 30])
|
||||
|
||||
it "clips pixel positions above buffer start", ->
|
||||
|
||||
@@ -5,7 +5,11 @@ describe "MenuManager", ->
|
||||
menu = null
|
||||
|
||||
beforeEach ->
|
||||
menu = new MenuManager(resourcePath: atom.getLoadSettings().resourcePath)
|
||||
menu = new MenuManager(
|
||||
resourcePath: atom.getLoadSettings().resourcePath
|
||||
keymapManager: atom.keymaps
|
||||
packageManager: atom.packages
|
||||
)
|
||||
|
||||
describe "::add(items)", ->
|
||||
it "can add new menus that can be removed with the returned disposable", ->
|
||||
@@ -67,7 +71,7 @@ describe "MenuManager", ->
|
||||
atom.keymaps.add 'test', 'atom-workspace': 'ctrl-b': 'b'
|
||||
atom.keymaps.add 'test', 'atom-text-editor': 'ctrl-b': 'unset!'
|
||||
|
||||
waits 1
|
||||
waits 50
|
||||
|
||||
runs -> expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined()
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ describe 'ModuleCache', ->
|
||||
exports.load = function() { require('underscore-plus'); };
|
||||
"""
|
||||
|
||||
spyOn(process, 'cwd').andReturn('/') # Required when running this test from CLI
|
||||
packageMain = require(indexPath)
|
||||
Module._findPath.reset()
|
||||
expect(-> packageMain.load()).toThrow()
|
||||
|
||||
@@ -770,8 +770,6 @@ describe "PackageManager", ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
GrammarRegistry = require '../src/grammar-registry'
|
||||
atom.grammars = window.syntax = new GrammarRegistry()
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "activates all the packages, and none of the themes", ->
|
||||
|
||||
@@ -3,9 +3,22 @@ Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
|
||||
describe "Package", ->
|
||||
build = (constructor, path) ->
|
||||
new constructor(
|
||||
path: path, packageManager: atom.packages, config: atom.config,
|
||||
styleManager: atom.styles, notificationManager: atom.notifications,
|
||||
keymapManager: atom.keymaps, commandRegistry: atom.command,
|
||||
grammarRegistry: atom.grammars, themeManager: atom.themes,
|
||||
menuManager: atom.menu, contextMenuManager: atom.contextMenu,
|
||||
devMode: false
|
||||
)
|
||||
|
||||
buildPackage = (packagePath) -> build(Package, packagePath)
|
||||
|
||||
buildThemePackage = (themePath) -> build(ThemePackage, themePath)
|
||||
|
||||
describe "when the package contains incompatible native modules", ->
|
||||
beforeEach ->
|
||||
spyOn(atom, 'inDevMode').andReturn(false)
|
||||
items = {}
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item; undefined
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null
|
||||
@@ -13,35 +26,34 @@ describe "Package", ->
|
||||
|
||||
it "does not activate it", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module')
|
||||
pack = new Package(packagePath)
|
||||
pack = buildPackage(packagePath)
|
||||
expect(pack.isCompatible()).toBe false
|
||||
expect(pack.incompatibleModules[0].name).toBe 'native-module'
|
||||
expect(pack.incompatibleModules[0].path).toBe path.join(packagePath, 'node_modules', 'native-module')
|
||||
|
||||
it "utilizes _atomModuleCache if present to determine the package's native dependencies", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-ignored-incompatible-native-module')
|
||||
pack = new Package(packagePath)
|
||||
pack = buildPackage(packagePath)
|
||||
expect(pack.getNativeModuleDependencyPaths().length).toBe(1) # doesn't see the incompatible module
|
||||
expect(pack.isCompatible()).toBe true
|
||||
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-cached-incompatible-native-module')
|
||||
pack = new Package(packagePath)
|
||||
pack = buildPackage(packagePath)
|
||||
expect(pack.isCompatible()).toBe false
|
||||
|
||||
it "caches the incompatible native modules in local storage", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module')
|
||||
|
||||
expect(new Package(packagePath).isCompatible()).toBe false
|
||||
expect(buildPackage(packagePath).isCompatible()).toBe false
|
||||
expect(global.localStorage.getItem.callCount).toBe 1
|
||||
expect(global.localStorage.setItem.callCount).toBe 1
|
||||
|
||||
expect(new Package(packagePath).isCompatible()).toBe false
|
||||
expect(buildPackage(packagePath).isCompatible()).toBe false
|
||||
expect(global.localStorage.getItem.callCount).toBe 2
|
||||
expect(global.localStorage.setItem.callCount).toBe 1
|
||||
|
||||
describe "::rebuild()", ->
|
||||
beforeEach ->
|
||||
spyOn(atom, 'inDevMode').andReturn(false)
|
||||
items = {}
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item; undefined
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null
|
||||
@@ -49,7 +61,7 @@ describe "Package", ->
|
||||
|
||||
it "returns a promise resolving to the results of `apm rebuild`", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-index')
|
||||
pack = new Package(packagePath)
|
||||
pack = buildPackage(packagePath)
|
||||
rebuildCallbacks = []
|
||||
spyOn(pack, 'runRebuildProcess').andCallFake ((callback) -> rebuildCallbacks.push(callback))
|
||||
|
||||
@@ -63,7 +75,7 @@ describe "Package", ->
|
||||
|
||||
it "persists build failures in local storage", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-index')
|
||||
pack = new Package(packagePath)
|
||||
pack = buildPackage(packagePath)
|
||||
|
||||
expect(pack.isCompatible()).toBe true
|
||||
expect(pack.getBuildFailureOutput()).toBeNull()
|
||||
@@ -79,7 +91,7 @@ describe "Package", ->
|
||||
expect(pack.isCompatible()).toBe false
|
||||
|
||||
# A different package instance has the same failure output (simulates reload)
|
||||
pack2 = new Package(packagePath)
|
||||
pack2 = buildPackage(packagePath)
|
||||
expect(pack2.getBuildFailureOutput()).toBe 'It is broken'
|
||||
expect(pack2.isCompatible()).toBe false
|
||||
|
||||
@@ -92,7 +104,7 @@ describe "Package", ->
|
||||
|
||||
it "sets cached incompatible modules to an empty array when the rebuild completes (there may be a build error, but rebuilding *deletes* native modules)", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module')
|
||||
pack = new Package(packagePath)
|
||||
pack = buildPackage(packagePath)
|
||||
|
||||
expect(pack.getIncompatibleNativeModules().length).toBeGreaterThan(0)
|
||||
|
||||
@@ -118,14 +130,14 @@ describe "Package", ->
|
||||
it "loads and applies css", ->
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe "1234px"
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-index-css')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme = buildThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe "1234px"
|
||||
|
||||
it "parses, loads and applies less", ->
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe "1234px"
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-index-less')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme = buildThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe "4321px"
|
||||
|
||||
@@ -136,7 +148,7 @@ describe "Package", ->
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe("103px")
|
||||
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme = buildThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe("101px")
|
||||
expect(getComputedStyle(editorElement).paddingRight).toBe("102px")
|
||||
@@ -149,7 +161,7 @@ describe "Package", ->
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe "30px"
|
||||
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-without-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme = buildThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe "10px"
|
||||
expect(getComputedStyle(editorElement).paddingRight).toBe "20px"
|
||||
@@ -158,7 +170,7 @@ describe "Package", ->
|
||||
describe "reloading a theme", ->
|
||||
beforeEach ->
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme = buildThemePackage(themePath)
|
||||
theme.activate()
|
||||
|
||||
it "reloads without readding to the stylesheets list", ->
|
||||
@@ -169,7 +181,7 @@ describe "Package", ->
|
||||
describe "events", ->
|
||||
beforeEach ->
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme = buildThemePackage(themePath)
|
||||
theme.activate()
|
||||
|
||||
it "deactivated event fires on .deactivate()", ->
|
||||
@@ -182,7 +194,7 @@ describe "Package", ->
|
||||
|
||||
beforeEach ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-different-directory-name')
|
||||
metadata = Package.loadMetadata(packagePath, true)
|
||||
metadata = atom.packages.loadPackageMetadata(packagePath, true)
|
||||
|
||||
it "uses the package name defined in package.json", ->
|
||||
expect(metadata.name).toBe 'package-with-a-totally-different-name'
|
||||
|
||||
@@ -9,7 +9,7 @@ describe "PaneContainerElement", ->
|
||||
child.nodeName.toLowerCase() for child in paneAxisElement.children
|
||||
|
||||
paneAxis = new PaneAxis
|
||||
paneAxisElement = new PaneAxisElement().initialize(paneAxis)
|
||||
paneAxisElement = new PaneAxisElement().initialize(paneAxis, atom)
|
||||
|
||||
expect(childTagNames()).toEqual []
|
||||
|
||||
@@ -42,7 +42,7 @@ describe "PaneContainerElement", ->
|
||||
]
|
||||
|
||||
it "transfers focus to the next pane if a focused pane is removed", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom))
|
||||
containerElement = atom.views.getView(container)
|
||||
leftPane = container.getActivePane()
|
||||
leftPaneElement = atom.views.getView(leftPane)
|
||||
@@ -58,10 +58,10 @@ describe "PaneContainerElement", ->
|
||||
|
||||
describe "when a pane is split", ->
|
||||
it "builds appropriately-oriented atom-pane-axis elements", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom))
|
||||
containerElement = atom.views.getView(container)
|
||||
|
||||
pane1 = container.getRoot()
|
||||
pane1 = container.getActivePane()
|
||||
pane2 = pane1.splitRight()
|
||||
pane3 = pane2.splitDown()
|
||||
|
||||
@@ -84,7 +84,7 @@ describe "PaneContainerElement", ->
|
||||
[container, containerElement] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom))
|
||||
containerElement = atom.views.getView(container)
|
||||
document.querySelector('#jasmine-content').appendChild(containerElement)
|
||||
|
||||
@@ -201,7 +201,7 @@ describe "PaneContainerElement", ->
|
||||
[leftPane, rightPane] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom))
|
||||
leftPane = container.getActivePane()
|
||||
rightPane = leftPane.splitRight()
|
||||
|
||||
@@ -252,8 +252,8 @@ describe "PaneContainerElement", ->
|
||||
element.tabIndex = -1
|
||||
element
|
||||
|
||||
container = new PaneContainer
|
||||
pane1 = container.getRoot()
|
||||
container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom))
|
||||
pane1 = container.getActivePane()
|
||||
pane1.activateItem(buildElement('1'))
|
||||
pane4 = pane1.splitDown(items: [buildElement('4')])
|
||||
pane7 = pane4.splitDown(items: [buildElement('7')])
|
||||
|
||||
@@ -2,6 +2,16 @@ PaneContainer = require '../src/pane-container'
|
||||
Pane = require '../src/pane'
|
||||
|
||||
describe "PaneContainer", ->
|
||||
[confirm, params] = []
|
||||
|
||||
beforeEach ->
|
||||
confirm = spyOn(atom.applicationDelegate, 'confirm').andReturn(0)
|
||||
params = {
|
||||
config: atom.config,
|
||||
deserializerManager: atom.deserializers
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
}
|
||||
|
||||
describe "serialization", ->
|
||||
[containerA, pane1A, pane2A, pane3A] = []
|
||||
|
||||
@@ -12,8 +22,9 @@ describe "PaneContainer", ->
|
||||
@deserialize: -> new this
|
||||
serialize: -> deserializer: 'Item'
|
||||
|
||||
pane1A = new Pane(items: [new Item])
|
||||
containerA = new PaneContainer(root: pane1A)
|
||||
containerA = new PaneContainer(params)
|
||||
pane1A = containerA.getActivePane()
|
||||
pane1A.addItem(new Item)
|
||||
pane2A = pane1A.splitRight(items: [new Item])
|
||||
pane3A = pane2A.splitDown(items: [new Item])
|
||||
pane3A.focus()
|
||||
@@ -21,7 +32,8 @@ describe "PaneContainer", ->
|
||||
it "preserves the focused pane across serialization", ->
|
||||
expect(pane3A.focused).toBe true
|
||||
|
||||
containerB = PaneContainer.deserialize(containerA.serialize())
|
||||
containerB = new PaneContainer(params)
|
||||
containerB.deserialize(containerA.serialize(), atom.deserializers)
|
||||
[pane1B, pane2B, pane3B] = containerB.getPanes()
|
||||
expect(pane3B.focused).toBe true
|
||||
|
||||
@@ -29,7 +41,8 @@ describe "PaneContainer", ->
|
||||
pane3A.activate()
|
||||
expect(containerA.getActivePane()).toBe pane3A
|
||||
|
||||
containerB = PaneContainer.deserialize(containerA.serialize())
|
||||
containerB = new PaneContainer(params)
|
||||
containerB.deserialize(containerA.serialize(), atom.deserializers)
|
||||
[pane1B, pane2B, pane3B] = containerB.getPanes()
|
||||
expect(containerB.getActivePane()).toBe pane3B
|
||||
|
||||
@@ -37,7 +50,8 @@ describe "PaneContainer", ->
|
||||
pane3A.activate()
|
||||
state = containerA.serialize()
|
||||
state.activePaneId = -22
|
||||
containerB = atom.deserializers.deserialize(state)
|
||||
containerB = new PaneContainer(params)
|
||||
containerB.deserialize(state, atom.deserializers)
|
||||
expect(containerB.getActivePane()).toBe containerB.getPanes()[0]
|
||||
|
||||
describe "if there are empty panes after deserialization", ->
|
||||
@@ -47,7 +61,8 @@ describe "PaneContainer", ->
|
||||
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
|
||||
it "leaves the empty panes intact", ->
|
||||
state = containerA.serialize()
|
||||
containerB = atom.deserializers.deserialize(state)
|
||||
containerB = new PaneContainer(params)
|
||||
containerB.deserialize(state, atom.deserializers)
|
||||
[leftPane, column] = containerB.getRoot().getChildren()
|
||||
[topPane, bottomPane] = column.getChildren()
|
||||
|
||||
@@ -60,14 +75,15 @@ describe "PaneContainer", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
|
||||
state = containerA.serialize()
|
||||
containerB = atom.deserializers.deserialize(state)
|
||||
containerB = new PaneContainer(params)
|
||||
containerB.deserialize(state, atom.deserializers)
|
||||
[leftPane, rightPane] = containerB.getRoot().getChildren()
|
||||
|
||||
expect(leftPane.getItems().length).toBe 1
|
||||
expect(rightPane.getItems().length).toBe 1
|
||||
|
||||
it "does not allow the root pane to be destroyed", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().destroy()
|
||||
expect(container.getRoot()).toBeDefined()
|
||||
expect(container.getRoot().isDestroyed()).toBe false
|
||||
@@ -76,7 +92,7 @@ describe "PaneContainer", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
pane1 = container.getRoot()
|
||||
|
||||
it "returns the first pane if no pane has been made active", ->
|
||||
@@ -105,7 +121,8 @@ describe "PaneContainer", ->
|
||||
[container, pane1, pane2, observed] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().addItems([new Object, new Object])
|
||||
container.getRoot().splitRight(items: [new Object, new Object])
|
||||
[pane1, pane2] = container.getPanes()
|
||||
|
||||
@@ -147,7 +164,7 @@ describe "PaneContainer", ->
|
||||
|
||||
describe "::observePanes()", ->
|
||||
it "invokes observers with all current and future panes", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
|
||||
@@ -161,7 +178,8 @@ describe "PaneContainer", ->
|
||||
|
||||
describe "::observePaneItems()", ->
|
||||
it "invokes observers with all current and future pane items", ->
|
||||
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().addItems([new Object, new Object])
|
||||
container.getRoot().splitRight(items: [new Object])
|
||||
[pane1, pane2] = container.getPanes()
|
||||
observed = []
|
||||
@@ -180,27 +198,27 @@ describe "PaneContainer", ->
|
||||
shouldPromptToSave: -> true
|
||||
getURI: -> 'test'
|
||||
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
pane1.addItem(new TestItem)
|
||||
pane2.addItem(new TestItem)
|
||||
|
||||
it "returns true if the user saves all modified files when prompted", ->
|
||||
spyOn(atom, "confirm").andReturn(0)
|
||||
confirm.andReturn(0)
|
||||
saved = container.confirmClose()
|
||||
expect(saved).toBeTruthy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
|
||||
it "returns false if the user cancels saving any modified file", ->
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
confirm.andReturn(1)
|
||||
saved = container.confirmClose()
|
||||
expect(saved).toBeFalsy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
|
||||
describe "::onDidAddPane(callback)", ->
|
||||
it "invokes the given callback when panes are added", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
events = []
|
||||
container.onDidAddPane (event) -> events.push(event)
|
||||
|
||||
@@ -217,7 +235,7 @@ describe "PaneContainer", ->
|
||||
destroy: -> @_isDestroyed = true
|
||||
isDestroyed: -> @_isDestroyed
|
||||
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
events = []
|
||||
container.onWillDestroyPane (event) ->
|
||||
itemsDestroyed = (item.isDestroyed() for item in event.pane.getItems())
|
||||
@@ -233,7 +251,7 @@ describe "PaneContainer", ->
|
||||
|
||||
describe "::onDidDestroyPane(callback)", ->
|
||||
it "invokes the given callback when panes are destroyed", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
events = []
|
||||
container.onDidDestroyPane (event) -> events.push(event)
|
||||
|
||||
@@ -248,7 +266,7 @@ describe "PaneContainer", ->
|
||||
|
||||
describe "::onWillDestroyPaneItem() and ::onDidDestroyPaneItem", ->
|
||||
it "invokes the given callbacks when an item will be destroyed on any pane", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
pane1 = container.getRoot()
|
||||
item1 = new Object
|
||||
item2 = new Object
|
||||
@@ -275,7 +293,7 @@ describe "PaneContainer", ->
|
||||
|
||||
describe "::saveAll()", ->
|
||||
it "saves all open pane items", ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(params)
|
||||
pane1 = container.getRoot()
|
||||
pane2 = pane1.splitRight()
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ describe "PaneElement", ->
|
||||
[paneElement, container, pane] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
pane = container.getRoot()
|
||||
spyOn(atom, "open")
|
||||
|
||||
container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom))
|
||||
pane = container.getActivePane()
|
||||
paneElement = atom.views.getView(pane)
|
||||
|
||||
describe "when the pane's active status changes", ->
|
||||
@@ -183,7 +185,6 @@ describe "PaneElement", ->
|
||||
|
||||
describe "when a file is dragged to the pane", ->
|
||||
it "opens it", ->
|
||||
spyOn(atom, "open")
|
||||
event = buildDragEvent("drop", [{path: "/fake1"}, {path: "/fake2"}])
|
||||
paneElement.dispatchEvent(event)
|
||||
expect(atom.open.callCount).toBe 1
|
||||
@@ -191,7 +192,6 @@ describe "PaneElement", ->
|
||||
|
||||
describe "when a non-file is dragged to the pane", ->
|
||||
it "does nothing", ->
|
||||
spyOn(atom, "open")
|
||||
event = buildDragEvent("drop", [])
|
||||
paneElement.dispatchEvent(event)
|
||||
expect(atom.open).not.toHaveBeenCalled()
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
{extend} = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
Pane = require '../src/pane'
|
||||
PaneAxis = require '../src/pane-axis'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
|
||||
describe "Pane", ->
|
||||
deserializerDisposable = null
|
||||
[confirm, showSaveDialog, deserializerDisposable] = []
|
||||
|
||||
class Item
|
||||
@deserialize: ({name, uri}) -> new this(name, uri)
|
||||
@@ -19,18 +20,28 @@ describe "Pane", ->
|
||||
isDestroyed: -> @destroyed
|
||||
|
||||
beforeEach ->
|
||||
confirm = spyOn(atom.applicationDelegate, 'confirm')
|
||||
showSaveDialog = spyOn(atom.applicationDelegate, 'showSaveDialog')
|
||||
deserializerDisposable = atom.deserializers.add(Item)
|
||||
|
||||
afterEach ->
|
||||
deserializerDisposable.dispose()
|
||||
|
||||
paneParams = (params) ->
|
||||
extend({
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
config: atom.config,
|
||||
deserializerManager: atom.deserializers,
|
||||
notificationManager: atom.notifications
|
||||
}, params)
|
||||
|
||||
describe "construction", ->
|
||||
it "sets the active item to the first item", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
|
||||
|
||||
it "compacts the items array", ->
|
||||
pane = new Pane(items: [undefined, new Item("A"), null, new Item("B")])
|
||||
pane = new Pane(paneParams(items: [undefined, new Item("A"), null, new Item("B")]))
|
||||
expect(pane.getItems().length).toBe 2
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
|
||||
|
||||
@@ -38,8 +49,8 @@ describe "Pane", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer(root: new Pane)
|
||||
container.getRoot().splitRight()
|
||||
container = new PaneContainer(config: atom.config, applicationDelegate: atom.applicationDelegate)
|
||||
container.getActivePane().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
|
||||
it "changes the active pane on the container", ->
|
||||
@@ -76,14 +87,14 @@ describe "Pane", ->
|
||||
|
||||
describe "::addItem(item, index)", ->
|
||||
it "adds the item at the given index", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
[item1, item2] = pane.getItems()
|
||||
item3 = new Item("C")
|
||||
pane.addItem(item3, 1)
|
||||
expect(pane.getItems()).toEqual [item1, item3, item2]
|
||||
|
||||
it "adds the item after the active item if no index is provided", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.activateItem(item2)
|
||||
item4 = new Item("D")
|
||||
@@ -91,13 +102,13 @@ describe "Pane", ->
|
||||
expect(pane.getItems()).toEqual [item1, item2, item4, item3]
|
||||
|
||||
it "sets the active item after adding the first item", ->
|
||||
pane = new Pane
|
||||
pane = new Pane(paneParams())
|
||||
item = new Item("A")
|
||||
pane.addItem(item)
|
||||
expect(pane.getActiveItem()).toBe item
|
||||
|
||||
it "invokes ::onDidAddItem() observers", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
events = []
|
||||
pane.onDidAddItem (event) -> events.push(event)
|
||||
|
||||
@@ -107,13 +118,14 @@ describe "Pane", ->
|
||||
|
||||
it "throws an exception if the item is already present on a pane", ->
|
||||
item = new Item("A")
|
||||
pane1 = new Pane(items: [item])
|
||||
container = new PaneContainer(root: pane1)
|
||||
container = new PaneContainer(config: atom.config, applicationDelegate: atom.applicationDelegate)
|
||||
pane1 = container.getActivePane()
|
||||
pane1.addItem(item)
|
||||
pane2 = pane1.splitRight()
|
||||
expect(-> pane2.addItem(item)).toThrow()
|
||||
|
||||
it "throws an exception if the item isn't an object", ->
|
||||
pane = new Pane(items: [])
|
||||
pane = new Pane(paneParams(items: []))
|
||||
expect(-> pane.addItem(null)).toThrow()
|
||||
expect(-> pane.addItem('foo')).toThrow()
|
||||
expect(-> pane.addItem(1)).toThrow()
|
||||
@@ -122,7 +134,7 @@ describe "Pane", ->
|
||||
pane = null
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
|
||||
it "changes the active item to the current item", ->
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
|
||||
@@ -143,7 +155,7 @@ describe "Pane", ->
|
||||
|
||||
describe "::activateNextItem() and ::activatePreviousItem()", ->
|
||||
it "sets the active item to the next/previous item, looping around at either end", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
@@ -158,7 +170,7 @@ describe "Pane", ->
|
||||
|
||||
describe "::moveItemRight() and ::moveItemLeft()", ->
|
||||
it "moves the active item to the right and left, without looping around at either end", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
|
||||
pane.activateItemAtIndex(0)
|
||||
@@ -176,7 +188,7 @@ describe "Pane", ->
|
||||
|
||||
describe "::activateItemAtIndex(index)", ->
|
||||
it "activates the item at the given index", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.activateItemAtIndex(2)
|
||||
expect(pane.getActiveItem()).toBe item3
|
||||
@@ -195,7 +207,7 @@ describe "Pane", ->
|
||||
[pane, item1, item2, item3] = []
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
|
||||
it "removes the item from the items list and destroyes it", ->
|
||||
@@ -259,7 +271,7 @@ describe "Pane", ->
|
||||
describe "when the item has a uri", ->
|
||||
it "saves the item before destroying it", ->
|
||||
itemURI = "test"
|
||||
spyOn(atom, 'confirm').andReturn(0)
|
||||
confirm.andReturn(0)
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
@@ -270,18 +282,18 @@ describe "Pane", ->
|
||||
it "presents a save-as dialog, then saves the item with the given uri before removing and destroying it", ->
|
||||
itemURI = null
|
||||
|
||||
spyOn(atom, 'showSaveDialogSync').andReturn("/selected/path")
|
||||
spyOn(atom, 'confirm').andReturn(0)
|
||||
showSaveDialog.andReturn("/selected/path")
|
||||
confirm.andReturn(0)
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalled()
|
||||
expect(showSaveDialog).toHaveBeenCalled()
|
||||
expect(item1.saveAs).toHaveBeenCalledWith("/selected/path")
|
||||
expect(item1 in pane.getItems()).toBe false
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
|
||||
describe "if the [Don't Save] option is selected", ->
|
||||
it "removes and destroys the item without saving it", ->
|
||||
spyOn(atom, 'confirm').andReturn(2)
|
||||
confirm.andReturn(2)
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
@@ -290,7 +302,7 @@ describe "Pane", ->
|
||||
|
||||
describe "if the [Cancel] option is selected", ->
|
||||
it "does not save, remove, or destroy the item", ->
|
||||
spyOn(atom, 'confirm').andReturn(1)
|
||||
confirm.andReturn(1)
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
@@ -315,19 +327,19 @@ describe "Pane", ->
|
||||
|
||||
describe "::destroyActiveItem()", ->
|
||||
it "destroys the active item", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
activeItem = pane.getActiveItem()
|
||||
pane.destroyActiveItem()
|
||||
expect(activeItem.isDestroyed()).toBe true
|
||||
expect(activeItem in pane.getItems()).toBe false
|
||||
|
||||
it "does not throw an exception if there are no more items", ->
|
||||
pane = new Pane
|
||||
pane = new Pane(paneParams())
|
||||
pane.destroyActiveItem()
|
||||
|
||||
describe "::destroyItems()", ->
|
||||
it "destroys all items", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.destroyItems()
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
@@ -337,7 +349,7 @@ describe "Pane", ->
|
||||
|
||||
describe "::observeItems()", ->
|
||||
it "invokes the observer with all current and future items", ->
|
||||
pane = new Pane(items: [new Item, new Item])
|
||||
pane = new Pane(paneParams(items: [new Item, new Item]))
|
||||
[item1, item2] = pane.getItems()
|
||||
|
||||
observed = []
|
||||
@@ -350,14 +362,14 @@ describe "Pane", ->
|
||||
|
||||
describe "when an item emits a destroyed event", ->
|
||||
it "removes it from the list of items", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.itemAtIndex(1).destroy()
|
||||
expect(pane.getItems()).toEqual [item1, item3]
|
||||
|
||||
describe "::destroyInactiveItems()", ->
|
||||
it "destroys all items but the active item", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.activateItem(item2)
|
||||
pane.destroyInactiveItems()
|
||||
@@ -367,8 +379,8 @@ describe "Pane", ->
|
||||
pane = null
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A")])
|
||||
spyOn(atom, 'showSaveDialogSync').andReturn('/selected/path')
|
||||
pane = new Pane(paneParams(items: [new Item("A")]))
|
||||
showSaveDialog.andReturn('/selected/path')
|
||||
|
||||
describe "when the active item has a uri", ->
|
||||
beforeEach ->
|
||||
@@ -390,14 +402,14 @@ describe "Pane", ->
|
||||
it "opens a save dialog and saves the current item as the selected path", ->
|
||||
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
|
||||
pane.saveActiveItem()
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalled()
|
||||
expect(showSaveDialog).toHaveBeenCalled()
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
|
||||
describe "when the current item has no saveAs method", ->
|
||||
it "does nothing", ->
|
||||
expect(pane.getActiveItem().saveAs).toBeUndefined()
|
||||
pane.saveActiveItem()
|
||||
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
|
||||
expect(showSaveDialog).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the item's saveAs method throws a well-known IO error", ->
|
||||
notificationSpy = null
|
||||
@@ -422,22 +434,22 @@ describe "Pane", ->
|
||||
pane = null
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A")])
|
||||
spyOn(atom, 'showSaveDialogSync').andReturn('/selected/path')
|
||||
pane = new Pane(paneParams(items: [new Item("A")]))
|
||||
showSaveDialog.andReturn('/selected/path')
|
||||
|
||||
describe "when the current item has a saveAs method", ->
|
||||
it "opens the save dialog and calls saveAs on the item with the selected path", ->
|
||||
pane.getActiveItem().path = __filename
|
||||
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
|
||||
pane.saveActiveItemAs()
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(defaultPath: __filename)
|
||||
expect(showSaveDialog).toHaveBeenCalledWith(defaultPath: __filename)
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
|
||||
describe "when the current item does not have a saveAs method", ->
|
||||
it "does nothing", ->
|
||||
expect(pane.getActiveItem().saveAs).toBeUndefined()
|
||||
pane.saveActiveItemAs()
|
||||
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
|
||||
expect(showSaveDialog).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the item's saveAs method throws a well-known IO error", ->
|
||||
notificationSpy = null
|
||||
@@ -460,7 +472,7 @@ describe "Pane", ->
|
||||
|
||||
describe "::itemForURI(uri)", ->
|
||||
it "returns the item for which a call to .getURI() returns the given uri", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")]))
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
item1.uri = "a"
|
||||
item2.uri = "b"
|
||||
@@ -472,7 +484,7 @@ describe "Pane", ->
|
||||
[pane, item1, item2, item3, item4] = []
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")]))
|
||||
[item1, item2, item3, item4] = pane.getItems()
|
||||
|
||||
it "moves the item to the given index and invokes ::onDidMoveItem observers", ->
|
||||
@@ -501,8 +513,9 @@ describe "Pane", ->
|
||||
[item1, item2, item3, item4, item5] = []
|
||||
|
||||
beforeEach ->
|
||||
pane1 = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
container = new PaneContainer(root: pane1)
|
||||
container = new PaneContainer(config: atom.config, confirm: confirm)
|
||||
pane1 = container.getActivePane()
|
||||
pane1.addItems([new Item("A"), new Item("B"), new Item("C")])
|
||||
pane2 = pane1.splitRight(items: [new Item("D"), new Item("E")])
|
||||
[item1, item2, item3] = pane1.getItems()
|
||||
[item4, item5] = pane2.getItems()
|
||||
@@ -553,8 +566,9 @@ describe "Pane", ->
|
||||
[pane1, container] = []
|
||||
|
||||
beforeEach ->
|
||||
pane1 = new Pane(items: [new Item("A")])
|
||||
container = new PaneContainer(root: pane1)
|
||||
container = new PaneContainer(config: atom.config, confirm: confirm, deserializerManager: atom.deserializers)
|
||||
pane1 = container.getActivePane()
|
||||
pane1.addItem(new Item("A"))
|
||||
|
||||
describe "::splitLeft(params)", ->
|
||||
describe "when the parent is the container root", ->
|
||||
@@ -652,32 +666,32 @@ describe "Pane", ->
|
||||
|
||||
describe "::close()", ->
|
||||
it "prompts to save unsaved items before destroying the pane", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
[item1, item2] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = -> true
|
||||
item1.getURI = -> "/test/path"
|
||||
item1.save = jasmine.createSpy("save")
|
||||
|
||||
spyOn(atom, 'confirm').andReturn(0)
|
||||
confirm.andReturn(0)
|
||||
pane.close()
|
||||
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe true
|
||||
|
||||
it "does not destroy the pane if cancel is called", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
pane = new Pane(paneParams(items: [new Item("A"), new Item("B")]))
|
||||
[item1, item2] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = -> true
|
||||
item1.getURI = -> "/test/path"
|
||||
item1.save = jasmine.createSpy("save")
|
||||
|
||||
spyOn(atom, 'confirm').andReturn(1)
|
||||
confirm.andReturn(1)
|
||||
pane.close()
|
||||
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe false
|
||||
|
||||
@@ -685,7 +699,7 @@ describe "Pane", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
container = new PaneContainer(config: atom.config, confirm: confirm)
|
||||
pane1 = container.root
|
||||
pane1.addItems([new Item("A"), new Item("B")])
|
||||
pane2 = pane1.splitRight()
|
||||
@@ -732,18 +746,18 @@ describe "Pane", ->
|
||||
pane = null
|
||||
|
||||
beforeEach ->
|
||||
params =
|
||||
pane = new Pane(paneParams(
|
||||
items: [new Item("A", "a"), new Item("B", "b"), new Item("C", "c")]
|
||||
flexScale: 2
|
||||
pane = new Pane(params)
|
||||
))
|
||||
|
||||
it "can serialize and deserialize the pane and all its items", ->
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.getItems()).toEqual pane.getItems()
|
||||
|
||||
it "restores the active item on deserialization", ->
|
||||
pane.activateItemAtIndex(1)
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
|
||||
|
||||
it "does not include items that cannot be deserialized", ->
|
||||
@@ -751,11 +765,11 @@ describe "Pane", ->
|
||||
unserializable = {}
|
||||
pane.activateItem(unserializable)
|
||||
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.getActiveItem()).toEqual pane.itemAtIndex(0)
|
||||
expect(newPane.getItems().length).toBe pane.getItems().length - 1
|
||||
|
||||
it "includes the pane's focus state in the serialized state", ->
|
||||
pane.focus()
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.focused).toBe true
|
||||
|
||||
@@ -20,10 +20,6 @@ describe "PanelContainerElement", ->
|
||||
beforeEach ->
|
||||
jasmineContent = document.body.querySelector('#jasmine-content')
|
||||
|
||||
atom.views.addViewProvider Panel, (model) ->
|
||||
new PanelElement().initialize(model)
|
||||
atom.views.addViewProvider PanelContainer, (model) ->
|
||||
new PaneContainerElement().initialize(model)
|
||||
atom.views.addViewProvider TestPanelContainerItem, (model) ->
|
||||
new TestPanelContainerItemElement().initialize(model)
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ describe "PanelElement", ->
|
||||
beforeEach ->
|
||||
jasmineContent = document.body.querySelector('#jasmine-content')
|
||||
|
||||
atom.views.addViewProvider Panel, (model) ->
|
||||
new PanelElement().initialize(model)
|
||||
atom.views.addViewProvider Panel, (model, env) ->
|
||||
new PanelElement().initialize(model, env)
|
||||
atom.views.addViewProvider TestPanelItem, (model) ->
|
||||
new TestPanelItemElement().initialize(model)
|
||||
|
||||
|
||||
@@ -16,44 +16,6 @@ describe "Project", ->
|
||||
# Wait for project's service consumers to be asynchronously added
|
||||
waits(1)
|
||||
|
||||
describe "when a new repository-provider is added", ->
|
||||
it "uses it to create repositories for any directories that need one", ->
|
||||
projectPath = temp.mkdirSync('atom-project')
|
||||
atom.project.setPaths([projectPath])
|
||||
expect(atom.project.getRepositories()).toEqual [null]
|
||||
expect(atom.project.repositoryProviders.length).toEqual 1
|
||||
|
||||
dummyRepository = {destroy: -> null}
|
||||
|
||||
atom.packages.serviceHub.provide("atom.repository-provider", "0.1.0", {
|
||||
repositoryForDirectory: (directory) -> Promise.resolve(dummyRepository)
|
||||
repositoryForDirectorySync: (directory) -> dummyRepository
|
||||
})
|
||||
|
||||
repository = null
|
||||
|
||||
waitsFor "repository to be updated", ->
|
||||
repository = atom.project.getRepositories()[0]
|
||||
|
||||
runs ->
|
||||
expect(repository).toBe dummyRepository
|
||||
|
||||
it "does not create any new repositories if every directory has a repository", ->
|
||||
repositories = atom.project.getRepositories()
|
||||
expect(repositories.length).toEqual 1
|
||||
[repository] = repositories
|
||||
expect(repository).toBeTruthy()
|
||||
|
||||
# Register a new RepositoryProvider.
|
||||
dummyRepository = destroy: ->
|
||||
repositoryProvider =
|
||||
repositoryForDirectory: (directory) -> Promise.resolve(dummyRepository)
|
||||
repositoryForDirectorySync: (directory) -> dummyRepository
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.repository-provider", "0.1.0", repositoryProvider)
|
||||
|
||||
expect(atom.project.getRepositories()).toBe repositories
|
||||
|
||||
describe "serialization", ->
|
||||
deserializedProject = null
|
||||
|
||||
@@ -66,16 +28,19 @@ describe "Project", ->
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
|
||||
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
|
||||
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('a')
|
||||
atom.workspace.open('a')
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
|
||||
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
|
||||
|
||||
expect(deserializedProject.getBuffers().length).toBe 1
|
||||
deserializedProject.getBuffers()[0].destroy()
|
||||
@@ -86,12 +51,13 @@ describe "Project", ->
|
||||
pathToOpen = path.join(temp.mkdirSync(), 'file.txt')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(pathToOpen)
|
||||
atom.workspace.open(pathToOpen)
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
fs.mkdirSync(pathToOpen)
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
|
||||
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
it "does not deserialize buffers when their path is inaccessible", ->
|
||||
@@ -99,12 +65,13 @@ describe "Project", ->
|
||||
fs.writeFileSync(pathToOpen, '')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(pathToOpen)
|
||||
atom.workspace.open(pathToOpen)
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
fs.chmodSync(pathToOpen, '000')
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
|
||||
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
describe "when an editor is saved and the project has no path", ->
|
||||
@@ -115,7 +82,7 @@ describe "Project", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open().then (o) -> editor = o
|
||||
atom.workspace.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.saveAs(tempFile)
|
||||
@@ -125,7 +92,7 @@ describe "Project", ->
|
||||
editor = null
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.project.open(require.resolve('./fixtures/dir/a')).then (o) -> editor = o
|
||||
atom.workspace.open(require.resolve('./fixtures/dir/a')).then (o) -> editor = o
|
||||
|
||||
it "creates a warning notification", ->
|
||||
atom.notifications.onDidAddNotification noteSpy = jasmine.createSpy()
|
||||
@@ -144,6 +111,106 @@ describe "Project", ->
|
||||
expect(notification.getMessage()).toContain '`resurrect`'
|
||||
expect(notification.getMessage()).toContain 'fixtures/dir/a'
|
||||
|
||||
describe "when a custom repository-provider service is provided", ->
|
||||
[fakeRepositoryProvider, fakeRepository] = []
|
||||
|
||||
beforeEach ->
|
||||
fakeRepository = {destroy: -> null}
|
||||
fakeRepositoryProvider = {
|
||||
repositoryForDirectory: (directory) -> Promise.resolve(fakeRepository)
|
||||
repositoryForDirectorySync: (directory) -> fakeRepository
|
||||
}
|
||||
|
||||
it "uses it to create repositories for any directories that need one", ->
|
||||
projectPath = temp.mkdirSync('atom-project')
|
||||
atom.project.setPaths([projectPath])
|
||||
expect(atom.project.getRepositories()).toEqual [null]
|
||||
|
||||
atom.packages.serviceHub.provide("atom.repository-provider", "0.1.0", fakeRepositoryProvider)
|
||||
waitsFor -> atom.project.repositoryProviders.length > 1
|
||||
runs -> atom.project.getRepositories()[0] is fakeRepository
|
||||
|
||||
it "does not create any new repositories if every directory has a repository", ->
|
||||
repositories = atom.project.getRepositories()
|
||||
expect(repositories.length).toEqual 1
|
||||
expect(repositories[0]).toBeTruthy()
|
||||
|
||||
atom.packages.serviceHub.provide("atom.repository-provider", "0.1.0", fakeRepositoryProvider)
|
||||
waitsFor -> atom.project.repositoryProviders.length > 1
|
||||
runs -> expect(atom.project.getRepositories()).toBe repositories
|
||||
|
||||
it "stops using it to create repositories when the service is removed", ->
|
||||
atom.project.setPaths([])
|
||||
|
||||
disposable = atom.packages.serviceHub.provide("atom.repository-provider", "0.1.0", fakeRepositoryProvider)
|
||||
waitsFor -> atom.project.repositoryProviders.length > 1
|
||||
runs ->
|
||||
disposable.dispose()
|
||||
atom.project.addPath(temp.mkdirSync('atom-project'))
|
||||
expect(atom.project.getRepositories()).toEqual [null]
|
||||
|
||||
describe "when a custom directory-provider service is provided", ->
|
||||
class DummyDirectory
|
||||
constructor: (@path) ->
|
||||
getPath: -> @path
|
||||
getFile: -> {existsSync: -> false}
|
||||
getSubdirectory: -> {existsSync: -> false}
|
||||
isRoot: -> true
|
||||
existsSync: -> @path.endsWith('does-exist')
|
||||
contains: (filePath) -> filePath.startsWith(@path)
|
||||
|
||||
serviceDisposable = null
|
||||
|
||||
beforeEach ->
|
||||
serviceDisposable = atom.packages.serviceHub.provide("atom.directory-provider", "0.1.0", {
|
||||
directoryForURISync: (uri) ->
|
||||
if uri.startsWith("ssh://")
|
||||
new DummyDirectory(uri)
|
||||
else
|
||||
null
|
||||
})
|
||||
|
||||
waitsFor ->
|
||||
atom.project.directoryProviders.length > 0
|
||||
|
||||
it "uses the provider's custom directories for any paths that it handles", ->
|
||||
localPath = temp.mkdirSync('local-path')
|
||||
remotePath = "ssh://foreign-directory:8080/does-exist"
|
||||
|
||||
atom.project.setPaths([localPath, remotePath])
|
||||
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories[0].getPath()).toBe localPath
|
||||
expect(directories[0] instanceof Directory).toBe true
|
||||
expect(directories[1].getPath()).toBe remotePath
|
||||
expect(directories[1] instanceof DummyDirectory).toBe true
|
||||
|
||||
# It does not add new remote paths if their directories do not exist
|
||||
# and they are contained by existing remote paths.
|
||||
childRemotePath = remotePath + "/subdirectory/that/does-not-exist"
|
||||
atom.project.addPath(childRemotePath)
|
||||
expect(atom.project.getDirectories().length).toBe 2
|
||||
|
||||
# It does add new remote paths if their directories exist.
|
||||
childRemotePath = remotePath + "/subdirectory/that/does-exist"
|
||||
atom.project.addPath(childRemotePath)
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories[2].getPath()).toBe childRemotePath
|
||||
expect(directories[2] instanceof DummyDirectory).toBe true
|
||||
|
||||
# It does add new remote paths to be added if they are not contained by
|
||||
# previous remote paths.
|
||||
otherRemotePath = "ssh://other-foreign-directory:8080/"
|
||||
atom.project.addPath(otherRemotePath)
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories[3].getPath()).toBe otherRemotePath
|
||||
expect(directories[3] instanceof DummyDirectory).toBe true
|
||||
|
||||
it "stops using the provider when the service is removed", ->
|
||||
serviceDisposable.dispose()
|
||||
atom.project.setPaths(["ssh://foreign-directory:8080/does-exist"])
|
||||
expect(atom.project.getDirectories()[0] instanceof Directory).toBe true
|
||||
|
||||
describe ".open(path)", ->
|
||||
[absolutePath, newBufferHandler] = []
|
||||
|
||||
@@ -156,7 +223,7 @@ describe "Project", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created'", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
atom.workspace.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
@@ -166,7 +233,7 @@ describe "Project", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
atom.workspace.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
@@ -177,17 +244,17 @@ describe "Project", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
atom.workspace.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
newBufferHandler.reset()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then ({buffer}) ->
|
||||
atom.workspace.open(absolutePath).then ({buffer}) ->
|
||||
expect(buffer).toBe editor.buffer
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then ({buffer}) ->
|
||||
atom.workspace.open('a').then ({buffer}) ->
|
||||
expect(buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
|
||||
@@ -195,7 +262,7 @@ describe "Project", ->
|
||||
it "returns a new edit session and emits 'buffer-created'", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open().then (o) -> editor = o
|
||||
atom.workspace.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
@@ -305,68 +372,6 @@ describe "Project", ->
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe path.normalize(nonLocalFsDirectory)
|
||||
|
||||
describe "when a custom directory provider has been added", ->
|
||||
describe "when custom provider handles the given path", ->
|
||||
it "creates a directory using that provider", ->
|
||||
class DummyDirectory
|
||||
constructor: (@path) ->
|
||||
getPath: -> @path
|
||||
getFile: -> {existsSync: -> false}
|
||||
getSubdirectory: -> {existsSync: -> false}
|
||||
isRoot: -> true
|
||||
existsSync: -> /does-exist/.test(@path)
|
||||
off: ->
|
||||
contains: (filePath) -> filePath.startsWith(@path)
|
||||
|
||||
atom.packages.serviceHub.provide("atom.directory-provider", "0.1.0", {
|
||||
directoryForURISync: (uri) ->
|
||||
if uri.startsWith("ssh://")
|
||||
new DummyDirectory(uri)
|
||||
else
|
||||
null
|
||||
})
|
||||
|
||||
localPath = temp.mkdirSync('local-path')
|
||||
remotePath = "ssh://foreign-directory:8080/exists"
|
||||
|
||||
atom.project.setPaths([localPath, remotePath])
|
||||
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories[0].getPath()).toBe localPath
|
||||
expect(directories[0] instanceof Directory).toBe true
|
||||
expect(directories[1].getPath()).toBe remotePath
|
||||
expect(directories[1] instanceof DummyDirectory).toBe true
|
||||
|
||||
# Make sure that DummyDirectory.contains() is honored.
|
||||
remotePathSubdirectory = remotePath + "a/subdirectory"
|
||||
atom.project.addPath(remotePathSubdirectory)
|
||||
expect(atom.project.getDirectories().length).toBe 2
|
||||
|
||||
# Make sure that a new DummyDirectory that is not contained by the first
|
||||
# DummyDirectory can be added.
|
||||
otherRemotePath = "ssh://other-foreign-directory:8080/"
|
||||
atom.project.addPath(otherRemotePath)
|
||||
newDirectories = atom.project.getDirectories()
|
||||
expect(newDirectories.length).toBe 3
|
||||
otherDummyDirectory = newDirectories[2]
|
||||
expect(otherDummyDirectory.getPath()).toBe otherRemotePath
|
||||
expect(otherDummyDirectory instanceof DummyDirectory).toBe true
|
||||
|
||||
describe "when a custom provider does not handle the path", ->
|
||||
it "creates a local directory for the path", ->
|
||||
directoryProvider =
|
||||
directoryForURISync: (uri) -> null
|
||||
directoryForURI: (uri) -> throw new Error("This should not be called.")
|
||||
|
||||
atom.packages.serviceHub.provide(
|
||||
"atom.directory-provider", "0.1.0", directoryProvider)
|
||||
|
||||
tmp = temp.mkdirSync()
|
||||
atom.project.setPaths([tmp])
|
||||
directories = atom.project.getDirectories()
|
||||
expect(directories.length).toBe 1
|
||||
expect(directories[0].getPath()).toBe tmp
|
||||
|
||||
describe ".addPath(path)", ->
|
||||
it "calls callbacks registered with ::onDidChangePaths", ->
|
||||
onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy')
|
||||
|
||||
@@ -15,7 +15,7 @@ describe "TextEditor", ->
|
||||
it "properly renders soft-wrapped lines when randomly mutated", ->
|
||||
times 10, (i) ->
|
||||
buffer = new TextBuffer
|
||||
editor = new TextEditor({buffer})
|
||||
editor = atom.workspace.buildTextEditor({buffer})
|
||||
editor.setEditorWidthInChars(80)
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
steps = []
|
||||
@@ -80,7 +80,7 @@ describe "TextEditor", ->
|
||||
text
|
||||
|
||||
getReferenceScreenLines = ->
|
||||
referenceEditor = new TextEditor({})
|
||||
referenceEditor = atom.workspace.buildTextEditor()
|
||||
referenceEditor.setEditorWidthInChars(80)
|
||||
referenceEditor.setText(editor.getText())
|
||||
referenceEditor.setSoftWrapped(editor.isSoftWrapped())
|
||||
|
||||
1
spec/sample-with-comments.js
Normal file
1
spec/sample-with-comments.js
Normal file
@@ -0,0 +1 @@
|
||||
undefined
|
||||
1
spec/sample.js
Normal file
1
spec/sample.js
Normal file
@@ -0,0 +1 @@
|
||||
undefined
|
||||
@@ -5,7 +5,7 @@ describe "Selection", ->
|
||||
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
editor = new TextEditor(buffer: buffer, tabLength: 2)
|
||||
editor = atom.workspace.buildTextEditor(buffer: buffer, tabLength: 2)
|
||||
selection = editor.getLastSelection()
|
||||
|
||||
afterEach ->
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# Start the crash reporter before anything else.
|
||||
require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub')
|
||||
|
||||
path = require 'path'
|
||||
|
||||
try
|
||||
require '../src/window'
|
||||
Atom = require '../src/atom'
|
||||
window.atom = Atom.loadOrCreate('spec')
|
||||
|
||||
# Show window synchronously so a focusout doesn't fire on input elements
|
||||
# that are focused in the very first spec run.
|
||||
atom.getCurrentWindow().show() unless atom.getLoadSettings().exitWhenDone
|
||||
|
||||
{runSpecSuite} = require './jasmine-helper'
|
||||
|
||||
# Add 'exports' to module search path.
|
||||
exportsPath = path.join(atom.getLoadSettings().resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
document.title = "Spec Suite"
|
||||
runSpecSuite './spec-suite', atom.getLoadSettings().logFile
|
||||
catch error
|
||||
if atom?.getLoadSettings().exitWhenDone
|
||||
console.error(error.stack ? error)
|
||||
atom.exit(1)
|
||||
else
|
||||
throw error
|
||||
@@ -1,52 +1,28 @@
|
||||
require '../src/window'
|
||||
atom.initialize()
|
||||
atom.restoreWindowDimensions()
|
||||
|
||||
require 'jasmine-json'
|
||||
require '../src/window'
|
||||
require '../vendor/jasmine-jquery'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
KeymapManager = require '../src/keymap-extensions'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
FindParentDir = require 'find-parent-dir'
|
||||
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
Workspace = require '../src/workspace'
|
||||
ServiceHub = require 'service-hub'
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
clipboard = require '../src/safe-clipboard'
|
||||
|
||||
atom.themes.loadBaseStylesheets()
|
||||
atom.themes.requireStylesheet '../static/jasmine'
|
||||
atom.themes.initialLoadComplete = true
|
||||
jasmineStyle = document.createElement('style')
|
||||
jasmineStyle.textContent = atom.themes.loadStylesheet(atom.themes.resolveStylesheet('../static/jasmine'))
|
||||
document.head.appendChild(jasmineStyle)
|
||||
|
||||
fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
|
||||
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
|
||||
atom.keymaps.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymaps.getKeyBindings()
|
||||
commandsToRestore = atom.commands.getSnapshot()
|
||||
styleElementsToRestore = atom.styles.getSnapshot()
|
||||
|
||||
window.addEventListener 'core:close', -> window.close()
|
||||
window.addEventListener 'beforeunload', ->
|
||||
atom.storeWindowDimensions()
|
||||
atom.saveSync()
|
||||
|
||||
document.querySelector('html').style.overflow = 'auto'
|
||||
document.body.style.overflow = 'auto'
|
||||
|
||||
# Allow document.title to be assigned in specs without screwing up spec window title
|
||||
documentTitle = null
|
||||
Object.defineProperty document, 'title',
|
||||
get: -> documentTitle
|
||||
set: (title) -> documentTitle = title
|
||||
|
||||
Set.prototype.jasmineToString = ->
|
||||
result = "Set {"
|
||||
first = true
|
||||
@@ -73,46 +49,27 @@ if process.env.CI
|
||||
else
|
||||
jasmine.getEnv().defaultTimeoutInterval = 5000
|
||||
|
||||
specPackageName = null
|
||||
specPackagePath = null
|
||||
specProjectPath = null
|
||||
isCoreSpec = false
|
||||
{resourcePath, testPaths} = atom.getLoadSettings()
|
||||
|
||||
{specDirectory, resourcePath} = atom.getLoadSettings()
|
||||
if specPackagePath = FindParentDir.sync(testPaths[0], 'package.json')
|
||||
packageMetadata = require(path.join(specPackagePath, 'package.json'))
|
||||
specPackageName = packageMetadata.name
|
||||
|
||||
if specDirectory
|
||||
specPackagePath = path.resolve(specDirectory, '..')
|
||||
try
|
||||
specPackageName = JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json')))?.name
|
||||
if specDirectory = FindParentDir.sync(testPaths[0], 'fixtures')
|
||||
specProjectPath = path.join(specDirectory, 'fixtures')
|
||||
|
||||
isCoreSpec = specDirectory is fs.realpathSync(__dirname)
|
||||
else
|
||||
specProjectPath = path.join(__dirname, 'fixtures')
|
||||
|
||||
beforeEach ->
|
||||
documentTitle = null
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.packages.serviceHub = new ServiceHub
|
||||
atom.project = new Project(paths: [projectPath])
|
||||
atom.workspace = new Workspace()
|
||||
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
|
||||
atom.commands.restoreSnapshot(commandsToRestore)
|
||||
atom.styles.restoreSnapshot(styleElementsToRestore)
|
||||
atom.views.clearDocumentRequests()
|
||||
|
||||
atom.workspaceParentSelectorctor = '#jasmine-content'
|
||||
atom.project.setPaths([specProjectPath])
|
||||
|
||||
window.resetTimeouts()
|
||||
spyOn(_._, "now").andCallFake -> window.now
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
|
||||
atom.packages.packageStates = {}
|
||||
|
||||
serializedWindowState = null
|
||||
|
||||
spyOn(atom, 'saveSync')
|
||||
atom.grammars.clearGrammarOverrides()
|
||||
|
||||
spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
|
||||
if specPackageName and packageName is specPackageName
|
||||
resolvePackagePath(specPackagePath)
|
||||
@@ -123,28 +80,20 @@ beforeEach ->
|
||||
# prevent specs from modifying Atom's menus
|
||||
spyOn(atom.menu, 'sendToBrowserProcess')
|
||||
|
||||
# reset config before each spec; don't load or save from/to `config.json`
|
||||
spyOn(Config::, 'load')
|
||||
spyOn(Config::, 'save')
|
||||
config = new Config({resourcePath, configDirPath: atom.getConfigDirPath()})
|
||||
atom.config = config
|
||||
atom.loadConfig()
|
||||
config.set "core.destroyEmptyPanes", false
|
||||
config.set "editor.fontFamily", "Courier"
|
||||
config.set "editor.fontSize", 16
|
||||
config.set "editor.autoIndent", false
|
||||
config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
# reset config before each spec
|
||||
atom.config.set "core.destroyEmptyPanes", false
|
||||
atom.config.set "editor.fontFamily", "Courier"
|
||||
atom.config.set "editor.fontSize", 16
|
||||
atom.config.set "editor.autoIndent", false
|
||||
atom.config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]
|
||||
config.set "editor.useShadowDOM", true
|
||||
atom.config.set "editor.useShadowDOM", true
|
||||
advanceClock(1000)
|
||||
window.setTimeout.reset()
|
||||
config.load.reset()
|
||||
config.save.reset()
|
||||
|
||||
# make editor display updates synchronous
|
||||
TextEditorElement::setUpdatedSynchronously(true)
|
||||
|
||||
spyOn(atom, "setRepresentedFilename")
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn false
|
||||
|
||||
@@ -159,25 +108,10 @@ beforeEach ->
|
||||
addCustomMatchers(this)
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.menu.template = []
|
||||
atom.contextMenu.clear()
|
||||
atom.notifications.clear()
|
||||
|
||||
atom.workspace?.destroy()
|
||||
atom.workspace = null
|
||||
delete atom.state.workspace
|
||||
|
||||
atom.project?.destroy()
|
||||
atom.project = null
|
||||
|
||||
atom.themes.removeStylesheet('global-editor-styles')
|
||||
|
||||
delete atom.state.packageStates
|
||||
atom.reset()
|
||||
|
||||
document.getElementById('jasmine-content').innerHTML = '' unless window.debugContent
|
||||
|
||||
jasmine.unspy(atom, 'saveSync')
|
||||
ensureNoPathSubscriptions()
|
||||
waits(0) # yield to ui thread to make screen update more frequently
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
require './spec-helper'
|
||||
|
||||
requireSpecs = (specDirectory, specType) ->
|
||||
for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.(coffee|js)$/.test specFilePath
|
||||
require specFilePath
|
||||
|
||||
# Set spec directory on spec for setting up the project in spec-helper
|
||||
setSpecDirectory(specDirectory)
|
||||
|
||||
setSpecField = (name, value) ->
|
||||
specs = jasmine.getEnv().currentRunner().specs()
|
||||
return if specs.length is 0
|
||||
for index in [specs.length-1..0]
|
||||
break if specs[index][name]?
|
||||
specs[index][name] = value
|
||||
|
||||
setSpecType = (specType) ->
|
||||
setSpecField('specType', specType)
|
||||
|
||||
setSpecDirectory = (specDirectory) ->
|
||||
setSpecField('specDirectory', specDirectory)
|
||||
|
||||
runAllSpecs = ->
|
||||
{resourcePath} = atom.getLoadSettings()
|
||||
|
||||
requireSpecs(path.join(resourcePath, 'spec'))
|
||||
setSpecType('core')
|
||||
|
||||
fixturesPackagesPath = path.join(__dirname, 'fixtures', 'packages')
|
||||
packagePaths = atom.packages.getAvailablePackageNames().map (packageName) ->
|
||||
atom.packages.resolvePackagePath(packageName)
|
||||
packagePaths = _.groupBy packagePaths, (packagePath) ->
|
||||
if packagePath.indexOf("#{fixturesPackagesPath}#{path.sep}") is 0
|
||||
'fixtures'
|
||||
else if packagePath.indexOf("#{resourcePath}#{path.sep}") is 0
|
||||
'bundled'
|
||||
else
|
||||
'user'
|
||||
|
||||
# Run bundled package specs
|
||||
requireSpecs(path.join(packagePath, 'spec')) for packagePath in packagePaths.bundled ? []
|
||||
setSpecType('bundled')
|
||||
|
||||
# Run user package specs
|
||||
requireSpecs(path.join(packagePath, 'spec')) for packagePath in packagePaths.user ? []
|
||||
setSpecType('user')
|
||||
|
||||
if specDirectory = atom.getLoadSettings().specDirectory
|
||||
requireSpecs(specDirectory)
|
||||
setSpecType('user')
|
||||
else
|
||||
runAllSpecs()
|
||||
@@ -4,7 +4,7 @@ describe "StyleManager", ->
|
||||
[manager, addEvents, removeEvents, updateEvents] = []
|
||||
|
||||
beforeEach ->
|
||||
manager = new StyleManager
|
||||
manager = new StyleManager(configDirPath: atom.getConfigDirPath())
|
||||
addEvents = []
|
||||
removeEvents = []
|
||||
updateEvents = []
|
||||
|
||||
@@ -6,6 +6,7 @@ describe "StylesElement", ->
|
||||
|
||||
beforeEach ->
|
||||
element = new StylesElement
|
||||
element.initialize(atom.styles)
|
||||
document.querySelector('#jasmine-content').appendChild(element)
|
||||
addedStyleElements = []
|
||||
removedStyleElements = []
|
||||
@@ -99,8 +100,8 @@ describe "StylesElement", ->
|
||||
|
||||
it "defers selector upgrade until the element is attached", ->
|
||||
element = new StylesElement
|
||||
element.initialize(atom.styles)
|
||||
element.setAttribute('context', 'atom-text-editor')
|
||||
element.initialize()
|
||||
|
||||
atom.styles.addStyleSheet ".editor {background: black;}", context: 'atom-text-editor'
|
||||
expect(element.firstChild.sheet).toBeNull()
|
||||
|
||||
@@ -27,7 +27,7 @@ describe "TextEditorComponent", ->
|
||||
fn()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
contentNode = document.querySelector('#jasmine-content')
|
||||
@@ -35,7 +35,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
wrapperNode = new TextEditorElement()
|
||||
wrapperNode.tileSize = tileSize
|
||||
wrapperNode.initialize(editor)
|
||||
wrapperNode.initialize(editor, atom)
|
||||
wrapperNode.setUpdatedSynchronously(false)
|
||||
jasmine.attachToDOM(wrapperNode)
|
||||
|
||||
@@ -54,6 +54,10 @@ describe "TextEditorComponent", ->
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
# Mutating the DOM in the previous frame causes a document poll; clear it here
|
||||
waits 0
|
||||
runs -> nextAnimationFrame()
|
||||
|
||||
afterEach ->
|
||||
contentNode.style.width = ''
|
||||
|
||||
@@ -2891,6 +2895,18 @@ describe "TextEditorComponent", ->
|
||||
expect(editor.consolidateSelections).toHaveBeenCalled()
|
||||
expect(event.abortKeyBinding).toHaveBeenCalled()
|
||||
|
||||
describe "when changing the font", ->
|
||||
it "measures the default char, the korean char, the double width char and the half width char widths", ->
|
||||
expect(editor.getDefaultCharWidth()).toBeCloseTo(12, 0)
|
||||
|
||||
component.setFontSize(10)
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getDefaultCharWidth()).toBeCloseTo(6, 0)
|
||||
expect(editor.getKoreanCharWidth()).toBeCloseTo(9, 0)
|
||||
expect(editor.getDoubleWidthCharWidth()).toBe(10)
|
||||
expect(editor.getHalfWidthCharWidth()).toBe(5)
|
||||
|
||||
describe "hiding and showing the editor", ->
|
||||
describe "when the editor is hidden when it is mounted", ->
|
||||
it "defers measurement and rendering until the editor becomes visible", ->
|
||||
@@ -2902,7 +2918,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
wrapperNode = new TextEditorElement()
|
||||
wrapperNode.tileSize = tileSize
|
||||
wrapperNode.initialize(editor)
|
||||
wrapperNode.initialize(editor, atom)
|
||||
hiddenParent.appendChild(wrapperNode)
|
||||
|
||||
{component} = wrapperNode
|
||||
@@ -3196,7 +3212,7 @@ describe "TextEditorComponent", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
atom.workspace.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
@@ -3208,7 +3224,9 @@ describe "TextEditorComponent", ->
|
||||
atom.config.set 'editor.preferredLineLength', 17, scopeSelector: '.source.coffee'
|
||||
atom.config.set 'editor.softWrapAtPreferredLineLength', true, scopeSelector: '.source.coffee'
|
||||
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(20)
|
||||
coffeeEditor.setDefaultCharWidth(1)
|
||||
coffeeEditor.setEditorWidthInChars(20)
|
||||
|
||||
it "wraps lines when editor.softWrap is true for a matching scope", ->
|
||||
@@ -3464,12 +3482,14 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
right = wrapperNode.pixelPositionForScreenPosition([0, 6]).left
|
||||
|
||||
margin = component.presenter.getHorizontalScrollMarginInPixels()
|
||||
right = wrapperNode.pixelPositionForScreenPosition([0, 4]).left + margin
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
right = wrapperNode.pixelPositionForScreenPosition([0, 7]).left
|
||||
right = wrapperNode.pixelPositionForScreenPosition([0, 5]).left + margin
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
it "scrolls left when the last cursor gets closer than ::horizontalScrollMargin to the left of the editor", ->
|
||||
@@ -3481,12 +3501,14 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.moveLeft()
|
||||
nextAnimationFrame()
|
||||
left = wrapperNode.pixelPositionForScreenPosition([6, 59]).left
|
||||
|
||||
margin = component.presenter.getHorizontalScrollMarginInPixels()
|
||||
left = wrapperNode.pixelPositionForScreenPosition([6, 61]).left - margin
|
||||
expect(wrapperNode.getScrollLeft()).toBeCloseTo left, 0
|
||||
|
||||
editor.moveLeft()
|
||||
nextAnimationFrame()
|
||||
left = wrapperNode.pixelPositionForScreenPosition([6, 58]).left
|
||||
left = wrapperNode.pixelPositionForScreenPosition([6, 60]).left - margin
|
||||
expect(wrapperNode.getScrollLeft()).toBeCloseTo left, 0
|
||||
|
||||
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
TextEditor = require '../src/text-editor'
|
||||
{Disposable} = require 'event-kit'
|
||||
|
||||
# The rest of text-editor-component-spec will be moved to this file when React
|
||||
# is eliminated. This covers only concerns related to the wrapper element for now
|
||||
@@ -33,7 +34,7 @@ describe "TextEditorElement", ->
|
||||
describe "when the model is assigned", ->
|
||||
it "adds the 'mini' attribute if .isMini() returns true on the model", ->
|
||||
element = new TextEditorElement
|
||||
model = new TextEditor(mini: true)
|
||||
model = atom.workspace.buildTextEditor(mini: true)
|
||||
element.setModel(model)
|
||||
expect(element.hasAttribute('mini')).toBe true
|
||||
|
||||
@@ -67,7 +68,7 @@ describe "TextEditorElement", ->
|
||||
|
||||
describe "when the editor is detached from the DOM and then reattached", ->
|
||||
it "does not render duplicate line numbers", ->
|
||||
editor = new TextEditor
|
||||
editor = atom.workspace.buildTextEditor()
|
||||
editor.setText('1\n2\n3')
|
||||
element = atom.views.getView(editor)
|
||||
|
||||
@@ -80,7 +81,7 @@ describe "TextEditorElement", ->
|
||||
expect(element.shadowRoot.querySelectorAll('.line-number').length).toBe initialCount
|
||||
|
||||
it "does not render duplicate decorations in custom gutters", ->
|
||||
editor = new TextEditor
|
||||
editor = atom.workspace.buildTextEditor()
|
||||
editor.setText('1\n2\n3')
|
||||
editor.addGutter({name: 'test-gutter'})
|
||||
marker = editor.markBufferRange([[0, 0], [2, 0]])
|
||||
@@ -159,6 +160,7 @@ describe "TextEditorElement", ->
|
||||
initialThemeLoadComplete
|
||||
spyOn(atom.themes, 'onDidChangeActiveThemes').andCallFake (fn) ->
|
||||
themeReloadCallback = fn
|
||||
new Disposable
|
||||
|
||||
atom.config.set("editor.useShadowDOM", false)
|
||||
|
||||
@@ -234,6 +236,27 @@ describe "TextEditorElement", ->
|
||||
jasmine.attachToDOM(element)
|
||||
expect(element.getDefaultCharacterWidth()).toBeGreaterThan(0)
|
||||
|
||||
describe "::getMaxScrollTop", ->
|
||||
it "returns the maximum scroll top that can be applied to the element", ->
|
||||
editor = atom.workspace.buildTextEditor()
|
||||
editor.setText('1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16')
|
||||
element = atom.views.getView(editor)
|
||||
element.style.lineHeight = "10px"
|
||||
element.style.width = "200px"
|
||||
|
||||
expect(element.getMaxScrollTop()).toBe(0)
|
||||
|
||||
jasmine.attachToDOM(element)
|
||||
|
||||
element.setHeight(100)
|
||||
expect(element.getMaxScrollTop()).toBe(60)
|
||||
|
||||
element.setHeight(120)
|
||||
expect(element.getMaxScrollTop()).toBe(40)
|
||||
|
||||
element.setHeight(200)
|
||||
expect(element.getMaxScrollTop()).toBe(0)
|
||||
|
||||
describe "on TextEditor::setMini", ->
|
||||
it "changes the element's 'mini' attribute", ->
|
||||
element = new TextEditorElement
|
||||
|
||||
@@ -18,7 +18,7 @@ describe "TextEditorPresenter", ->
|
||||
spyOn(window, "clearInterval").andCallFake window.fakeClearInterval
|
||||
|
||||
buffer = new TextBuffer(filePath: require.resolve('./fixtures/sample.js'))
|
||||
editor = new TextEditor({buffer})
|
||||
editor = atom.workspace.buildTextEditor({buffer})
|
||||
waitsForPromise -> buffer.load()
|
||||
|
||||
afterEach ->
|
||||
@@ -40,6 +40,7 @@ describe "TextEditorPresenter", ->
|
||||
verticalScrollbarWidth: 10
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
config: atom.config
|
||||
|
||||
presenter = new TextEditorPresenter(params)
|
||||
presenter.setLinesYardstick(new FakeLinesYardstick(editor, presenter))
|
||||
@@ -724,6 +725,20 @@ describe "TextEditorPresenter", ->
|
||||
expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
|
||||
describe ".scrollTop", ->
|
||||
it "doesn't get stuck when repeatedly setting the same non-integer position in a scroll event listener", ->
|
||||
presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20)
|
||||
expect(presenter.getState().content.scrollTop).toBe(0)
|
||||
|
||||
presenter.onDidChangeScrollTop ->
|
||||
presenter.setScrollTop(1.5)
|
||||
presenter.getState() # trigger scroll update
|
||||
|
||||
presenter.setScrollTop(1.5)
|
||||
presenter.getState() # trigger scroll update
|
||||
|
||||
expect(presenter.getScrollTop()).toBe(2)
|
||||
expect(presenter.getRealScrollTop()).toBe(1.5)
|
||||
|
||||
it "changes based on the scroll operation that was performed last", ->
|
||||
presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20)
|
||||
expect(presenter.getState().content.scrollTop).toBe(0)
|
||||
@@ -837,6 +852,20 @@ describe "TextEditorPresenter", ->
|
||||
expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight
|
||||
|
||||
describe ".scrollLeft", ->
|
||||
it "doesn't get stuck when repeatedly setting the same non-integer position in a scroll event listener", ->
|
||||
presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10)
|
||||
expect(presenter.getState().content.scrollLeft).toBe(0)
|
||||
|
||||
presenter.onDidChangeScrollLeft ->
|
||||
presenter.setScrollLeft(1.5)
|
||||
presenter.getState() # trigger scroll update
|
||||
|
||||
presenter.setScrollLeft(1.5)
|
||||
presenter.getState() # trigger scroll update
|
||||
|
||||
expect(presenter.getScrollLeft()).toBe(2)
|
||||
expect(presenter.getRealScrollLeft()).toBe(1.5)
|
||||
|
||||
it "changes based on the scroll operation that was performed last", ->
|
||||
presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10)
|
||||
expect(presenter.getState().content.scrollLeft).toBe(0)
|
||||
@@ -1230,6 +1259,7 @@ describe "TextEditorPresenter", ->
|
||||
it "only applies decorations to screen rows that are spanned by their marker when lines are soft-wrapped", ->
|
||||
editor.setText("a line that wraps, ok")
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(16)
|
||||
marker = editor.markBufferRange([[0, 0], [0, 2]])
|
||||
editor.decorateMarker(marker, type: 'line', class: 'a')
|
||||
@@ -2215,6 +2245,7 @@ describe "TextEditorPresenter", ->
|
||||
it "contains states for line numbers that are visible on screen", ->
|
||||
editor.foldBufferRow(4)
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(50)
|
||||
presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, tileSize: 2)
|
||||
|
||||
@@ -2230,6 +2261,7 @@ describe "TextEditorPresenter", ->
|
||||
it "updates when the editor's content changes", ->
|
||||
editor.foldBufferRow(4)
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(50)
|
||||
presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, tileSize: 2)
|
||||
|
||||
@@ -2260,6 +2292,7 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
it "correctly handles the first screen line being soft-wrapped", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(30)
|
||||
presenter = buildPresenter(explicitHeight: 25, scrollTop: 50, tileSize: 2)
|
||||
|
||||
@@ -2388,6 +2421,7 @@ describe "TextEditorPresenter", ->
|
||||
it "only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped", ->
|
||||
editor.setText("a line that wraps, ok")
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(16)
|
||||
marker = editor.markBufferRange([[0, 0], [0, 2]])
|
||||
editor.decorateMarker(marker, type: 'line-number', class: 'a')
|
||||
@@ -2827,7 +2861,7 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
performSetup = ->
|
||||
buffer = new TextBuffer
|
||||
editor = new TextEditor({buffer})
|
||||
editor = atom.workspace.buildTextEditor({buffer})
|
||||
editor.setEditorWidthInChars(80)
|
||||
presenterParams =
|
||||
model: editor
|
||||
|
||||
@@ -12,7 +12,7 @@ describe "TextEditor", ->
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js', autoIndent: false).then (o) -> editor = o
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
@@ -27,11 +27,11 @@ describe "TextEditor", ->
|
||||
editor1 = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(pathToOpen).then (o) -> editor1 = o
|
||||
atom.workspace.open(pathToOpen).then (o) -> editor1 = o
|
||||
|
||||
runs ->
|
||||
fs.mkdirSync(pathToOpen)
|
||||
expect(TextEditor.deserialize(editor1.serialize())).toBeUndefined()
|
||||
expect(TextEditor.deserialize(editor1.serialize(), atom)).toBeUndefined()
|
||||
|
||||
it "restores selections and folds based on markers in the buffer", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
@@ -39,7 +39,7 @@ describe "TextEditor", ->
|
||||
editor.foldBufferRow(4)
|
||||
expect(editor.isFoldedAtBufferRow(4)).toBeTruthy()
|
||||
|
||||
editor2 = TextEditor.deserialize(editor.serialize())
|
||||
editor2 = TextEditor.deserialize(editor.serialize(), atom)
|
||||
|
||||
expect(editor2.id).toBe editor.id
|
||||
expect(editor2.getBuffer().getPath()).toBe editor.getBuffer().getPath()
|
||||
@@ -52,7 +52,7 @@ describe "TextEditor", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
previousInvisibles = editor.tokenizedLineForScreenRow(0).invisibles
|
||||
|
||||
editor2 = TextEditor.deserialize(editor.serialize())
|
||||
editor2 = TextEditor.deserialize(editor.serialize(), atom)
|
||||
|
||||
expect(previousInvisibles).toBeDefined()
|
||||
expect(editor2.displayBuffer.tokenizedLineForScreenRow(0).invisibles).toEqual previousInvisibles
|
||||
@@ -62,7 +62,7 @@ describe "TextEditor", ->
|
||||
|
||||
state = editor.serialize()
|
||||
atom.config.set('editor.invisibles', eol: '?')
|
||||
editor2 = TextEditor.deserialize(state)
|
||||
editor2 = TextEditor.deserialize(state, atom)
|
||||
|
||||
expect(editor.tokenizedLineForScreenRow(0).invisibles.eol).toBe '?'
|
||||
|
||||
@@ -71,7 +71,7 @@ describe "TextEditor", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js', largeFileMode: true).then (o) -> editor = o
|
||||
atom.workspace.openTextFile('sample.js', largeFileMode: true).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.getBuffer()
|
||||
@@ -114,7 +114,7 @@ describe "TextEditor", ->
|
||||
atom.config.set('core.fileEncoding', 'utf16le')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('a').then (o) -> editor1 = o
|
||||
atom.workspace.open('dir/a').then (o) -> editor1 = o
|
||||
|
||||
runs ->
|
||||
expect(editor1.getTabLength()).toBe 4
|
||||
@@ -128,7 +128,7 @@ describe "TextEditor", ->
|
||||
atom.config.set('core.fileEncoding', 'macroman')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b').then (o) -> editor2 = o
|
||||
atom.workspace.open('dir/b').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor2.getTabLength()).toBe 8
|
||||
@@ -144,13 +144,13 @@ describe "TextEditor", ->
|
||||
atom.config.set('core.fileEncoding', 'macroman', scopeSelector: '.js')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('a').then (o) -> editor1 = o
|
||||
atom.workspace.open('dir/a').then (o) -> editor1 = o
|
||||
|
||||
runs ->
|
||||
expect(editor1.getEncoding()).toBe 'utf16le'
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('test.js').then (o) -> editor2 = o
|
||||
atom.workspace.open('sample-with-comments.js').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor2.getEncoding()).toBe 'macroman'
|
||||
@@ -272,6 +272,7 @@ describe "TextEditor", ->
|
||||
describe "when soft-wrap is enabled and code is folded", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(50)
|
||||
editor.createFold(2, 3)
|
||||
|
||||
@@ -327,6 +328,7 @@ describe "TextEditor", ->
|
||||
describe "when the cursor was moved down from the beginning of an indented soft-wrapped line", ->
|
||||
it "moves to the beginning of the previous line", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(50)
|
||||
|
||||
editor.setCursorScreenPosition([3, 0])
|
||||
@@ -379,6 +381,7 @@ describe "TextEditor", ->
|
||||
describe "when the cursor is at the beginning of an indented soft-wrapped line", ->
|
||||
it "moves to the beginning of the line's continuation on the next screen row", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(50)
|
||||
|
||||
editor.setCursorScreenPosition([3, 0])
|
||||
@@ -446,6 +449,7 @@ describe "TextEditor", ->
|
||||
describe "when line is wrapped and follow previous line indentation", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(50)
|
||||
|
||||
it "wraps to the end of the previous line", ->
|
||||
@@ -604,6 +608,7 @@ describe "TextEditor", ->
|
||||
describe "when soft wrap is on", ->
|
||||
it "moves cursor to the beginning of the screen line", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(10)
|
||||
editor.setCursorScreenPosition([1, 2])
|
||||
editor.moveToEndOfScreenLine()
|
||||
@@ -623,6 +628,7 @@ describe "TextEditor", ->
|
||||
describe ".moveToBeginningOfLine()", ->
|
||||
it "moves cursor to the beginning of the buffer line", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(10)
|
||||
editor.setCursorScreenPosition([1, 2])
|
||||
editor.moveToBeginningOfLine()
|
||||
@@ -632,6 +638,7 @@ describe "TextEditor", ->
|
||||
describe ".moveToEndOfLine()", ->
|
||||
it "moves cursor to the end of the buffer line", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(10)
|
||||
editor.setCursorScreenPosition([0, 2])
|
||||
editor.moveToEndOfLine()
|
||||
@@ -642,6 +649,7 @@ describe "TextEditor", ->
|
||||
describe "when soft wrap is on", ->
|
||||
it "moves to the first character of the current screen line or the beginning of the screen line if it's already on the first character", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(10)
|
||||
editor.setCursorScreenPosition [2, 5]
|
||||
editor.addCursorAtScreenPosition [8, 7]
|
||||
@@ -1331,7 +1339,7 @@ describe "TextEditor", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
atom.workspace.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
it 'selects the correct surrounding word for the given scoped setting', ->
|
||||
coffeeEditor.setCursorBufferPosition [0, 9] # in the middle of quicksort
|
||||
@@ -1523,6 +1531,7 @@ describe "TextEditor", ->
|
||||
it "can add selections to soft-wrapped line segments", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setEditorWidthInChars(40)
|
||||
editor.setDefaultCharWidth(1)
|
||||
|
||||
editor.setSelectedScreenRange([[3, 10], [3, 15]])
|
||||
editor.addSelectionBelow()
|
||||
@@ -1533,7 +1542,7 @@ describe "TextEditor", ->
|
||||
|
||||
it "takes atomic tokens into account", ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o
|
||||
atom.workspace.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.setSelectedBufferRange([[2, 1], [2, 3]])
|
||||
@@ -1548,6 +1557,7 @@ describe "TextEditor", ->
|
||||
describe "when lines are soft-wrapped", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
it "skips soft-wrap indentation tokens", ->
|
||||
@@ -1633,6 +1643,7 @@ describe "TextEditor", ->
|
||||
|
||||
it "can add selections to soft-wrapped line segments", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
editor.setSelectedScreenRange([[4, 10], [4, 15]])
|
||||
@@ -1644,7 +1655,7 @@ describe "TextEditor", ->
|
||||
|
||||
it "takes atomic tokens into account", ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o
|
||||
atom.workspace.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.setSelectedBufferRange([[3, 1], [3, 2]])
|
||||
@@ -1659,6 +1670,7 @@ describe "TextEditor", ->
|
||||
describe "when lines are soft-wrapped", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
it "skips soft-wrap indentation tokens", ->
|
||||
@@ -1769,9 +1781,11 @@ describe "TextEditor", ->
|
||||
it "does not share selections between different edit sessions for the same buffer", ->
|
||||
editor2 = null
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor2 = o
|
||||
atom.workspace.getActivePane().splitRight()
|
||||
atom.workspace.open(editor.getPath()).then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor2.getText()).toBe(editor.getText())
|
||||
editor.setSelectedBufferRanges([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
|
||||
editor2.setSelectedBufferRanges([[[8, 7], [6, 5]], [[4, 3], [2, 1]]])
|
||||
expect(editor2.getSelectedBufferRanges()).not.toEqual editor.getSelectedBufferRanges()
|
||||
@@ -2703,6 +2717,7 @@ describe "TextEditor", ->
|
||||
describe "when soft wrap is on", ->
|
||||
it "cuts up to the end of the line", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setDefaultCharWidth(1)
|
||||
editor.setEditorWidthInChars(10)
|
||||
editor.setCursorScreenPosition([2, 2])
|
||||
editor.cutToEndOfLine()
|
||||
@@ -3673,7 +3688,7 @@ describe "TextEditor", ->
|
||||
editor.destroy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
|
||||
atom.workspace.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.softTabs).toBe true
|
||||
@@ -3746,7 +3761,7 @@ describe "TextEditor", ->
|
||||
editor.destroy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
|
||||
atom.workspace.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.softTabs).toBe true
|
||||
@@ -3801,7 +3816,7 @@ describe "TextEditor", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
atom.workspace.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
@@ -4004,7 +4019,7 @@ describe "TextEditor", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
atom.workspace.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
runs ->
|
||||
atom.config.set('editor.autoIndent', true, scopeSelector: '.source.js')
|
||||
@@ -4154,7 +4169,8 @@ describe "TextEditor", ->
|
||||
|
||||
editor2 = null
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js', autoIndent: false).then (o) -> editor2 = o
|
||||
atom.workspace.getActivePane().splitRight()
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor.shouldPromptToSave()).toBeFalsy()
|
||||
@@ -4408,11 +4424,10 @@ describe "TextEditor", ->
|
||||
|
||||
describe '.get/setPlaceholderText()', ->
|
||||
it 'can be created with placeholderText', ->
|
||||
TextBuffer = require 'text-buffer'
|
||||
newEditor = new TextEditor
|
||||
buffer: new TextBuffer
|
||||
newEditor = atom.workspace.buildTextEditor(
|
||||
mini: true
|
||||
placeholderText: 'yep'
|
||||
)
|
||||
expect(newEditor.getPlaceholderText()).toBe 'yep'
|
||||
|
||||
it 'models placeholderText and emits an event when changed', ->
|
||||
@@ -4440,7 +4455,7 @@ describe "TextEditor", ->
|
||||
|
||||
describe "when there's no repository for the editor's file", ->
|
||||
it "doesn't do anything", ->
|
||||
editor = new TextEditor({})
|
||||
editor = atom.workspace.buildTextEditor()
|
||||
editor.setText("stuff")
|
||||
editor.checkoutHeadRevision()
|
||||
|
||||
|
||||
@@ -44,3 +44,33 @@ describe 'text utilities', ->
|
||||
expect(textUtils.isPairedCharacter('ae\u0301c', 2)).toBe false
|
||||
expect(textUtils.isPairedCharacter('ae\u0301c', 3)).toBe false
|
||||
expect(textUtils.isPairedCharacter('ae\u0301c', 4)).toBe false
|
||||
|
||||
describe ".isDoubleWidthCharacter(character)", ->
|
||||
it "returns true when the character is either japanese, chinese or a full width form", ->
|
||||
expect(textUtils.isDoubleWidthCharacter("我")).toBe(true)
|
||||
|
||||
expect(textUtils.isDoubleWidthCharacter("私")).toBe(true)
|
||||
|
||||
expect(textUtils.isDoubleWidthCharacter("B")).toBe(true)
|
||||
expect(textUtils.isDoubleWidthCharacter(",")).toBe(true)
|
||||
expect(textUtils.isDoubleWidthCharacter("¢")).toBe(true)
|
||||
|
||||
expect(textUtils.isDoubleWidthCharacter("a")).toBe(false)
|
||||
|
||||
describe ".isHalfWidthCharacter(character)", ->
|
||||
it "returns true when the character is an half width form", ->
|
||||
expect(textUtils.isHalfWidthCharacter("ハ")).toBe(true)
|
||||
expect(textUtils.isHalfWidthCharacter("ヒ")).toBe(true)
|
||||
expect(textUtils.isHalfWidthCharacter("ᆲ")).toBe(true)
|
||||
expect(textUtils.isHalfWidthCharacter("■")).toBe(true)
|
||||
|
||||
expect(textUtils.isHalfWidthCharacter("B")).toBe(false)
|
||||
|
||||
describe ".isKoreanCharacter(character)", ->
|
||||
it "returns true when the character is a korean character", ->
|
||||
expect(textUtils.isKoreanCharacter("우")).toBe(true)
|
||||
expect(textUtils.isKoreanCharacter("가")).toBe(true)
|
||||
expect(textUtils.isKoreanCharacter("ㅢ")).toBe(true)
|
||||
expect(textUtils.isKoreanCharacter("ㄼ")).toBe(true)
|
||||
|
||||
expect(textUtils.isKoreanCharacter("O")).toBe(false)
|
||||
|
||||
@@ -24,7 +24,9 @@ describe "TokenIterator", ->
|
||||
end x
|
||||
x
|
||||
""")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
tokenizedBuffer.setGrammar(grammar)
|
||||
|
||||
tokenIterator = tokenizedBuffer.tokenizedLineForRow(1).getTokenIterator()
|
||||
|
||||
@@ -27,7 +27,9 @@ describe "TokenizedBuffer", ->
|
||||
describe "when the buffer is destroyed", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
|
||||
it "stops tokenization", ->
|
||||
@@ -39,7 +41,9 @@ describe "TokenizedBuffer", ->
|
||||
describe "when the buffer contains soft-tabs", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
tokenizedBuffer.onDidChange changeHandler = jasmine.createSpy('changeHandler')
|
||||
|
||||
@@ -345,7 +349,9 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
@@ -450,7 +456,9 @@ describe "TokenizedBuffer", ->
|
||||
'abc\uD835\uDF97def'
|
||||
//\uD835\uDF97xyz
|
||||
"""
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
@@ -487,7 +495,7 @@ describe "TokenizedBuffer", ->
|
||||
tokenizedHandler = jasmine.createSpy("tokenized handler")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
@@ -500,7 +508,7 @@ describe "TokenizedBuffer", ->
|
||||
tokenizedHandler = jasmine.createSpy("tokenized handler")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
@@ -518,7 +526,7 @@ describe "TokenizedBuffer", ->
|
||||
tokenizedHandler = jasmine.createSpy("tokenized handler")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee').then (o) -> editor = o
|
||||
atom.workspace.open('coffee.coffee').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
@@ -544,7 +552,9 @@ describe "TokenizedBuffer", ->
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
tokenizedBuffer.setGrammar(atom.grammars.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
@@ -566,7 +576,9 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
it "returns the correct token (regression)", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedBuffer.tokenForPosition([1, 0]).scopes).toEqual ["source.js"]
|
||||
expect(tokenizedBuffer.tokenForPosition([1, 1]).scopes).toEqual ["source.js"]
|
||||
@@ -575,7 +587,10 @@ describe "TokenizedBuffer", ->
|
||||
describe ".bufferRangeForScopeAtPosition(selector, position)", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars,
|
||||
packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
describe "when the selector does not match the token at the position", ->
|
||||
@@ -595,7 +610,9 @@ describe "TokenizedBuffer", ->
|
||||
it "updates the tab length of the tokenized lines", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
buffer.setText('\ttest')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 6)
|
||||
@@ -604,7 +621,9 @@ describe "TokenizedBuffer", ->
|
||||
it "does not allow the tab length to be less than 1", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
buffer.setText('\ttest')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 1)
|
||||
@@ -617,7 +636,9 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
it "updates the tokens with the appropriate invisible characters", ->
|
||||
buffer = new TextBuffer(text: " \t a line with tabs\tand \tspaces \t ")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
@@ -630,7 +651,9 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
it "assigns endOfLineInvisibles to tokenized lines", ->
|
||||
buffer = new TextBuffer(text: "a line that ends in a carriage-return-line-feed \r\na line that ends in just a line-feed\na line with no ending")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
atom.config.set("editor.invisibles", cr: 'R', eol: 'N')
|
||||
@@ -651,7 +674,9 @@ describe "TokenizedBuffer", ->
|
||||
describe "leading and trailing whitespace", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
it "assigns ::firstNonWhitespaceIndex on tokens that have leading whitespace", ->
|
||||
@@ -709,7 +734,9 @@ describe "TokenizedBuffer", ->
|
||||
describe ".indentLevel on tokenized lines", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
describe "when the line is non-empty", ->
|
||||
@@ -804,7 +831,9 @@ describe "TokenizedBuffer", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
buffer.insert [10, 0], " // multi-line\n // comment\n // block\n"
|
||||
buffer.insert [0, 0], "// multi-line\n// comment\n// block\n"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
tokenizedBuffer.onDidChange (change) ->
|
||||
delete change.bufferChange
|
||||
@@ -881,7 +910,9 @@ describe "TokenizedBuffer", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.will-use-the-null-grammar')
|
||||
buffer.setText('a\nb\nc')
|
||||
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer = new TokenizedBuffer({
|
||||
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
|
||||
})
|
||||
tokenizeCallback = jasmine.createSpy('onDidTokenize')
|
||||
tokenizedBuffer.onDidTokenize(tokenizeCallback)
|
||||
|
||||
@@ -905,7 +936,7 @@ describe "TokenizedBuffer", ->
|
||||
registration = atom.packages.onDidTriggerActivationHook('language-javascript:grammar-used', -> called = true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js', autoIndent: false).then (o) ->
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -7,7 +7,7 @@ describe "TokenizedLine", ->
|
||||
describe "::isOnlyWhitespace()", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee').then (o) -> editor = o
|
||||
atom.workspace.open('coffee.coffee').then (o) -> editor = o
|
||||
|
||||
it "returns true when the line is only whitespace", ->
|
||||
expect(editor.tokenizedLineForScreenRow(3).isOnlyWhitespace()).toBe true
|
||||
|
||||
@@ -8,7 +8,7 @@ describe "TooltipManager", ->
|
||||
ctrlY = _.humanizeKeystroke("ctrl-y")
|
||||
|
||||
beforeEach ->
|
||||
manager = new TooltipManager
|
||||
manager = new TooltipManager(keymapManager: atom.keymaps)
|
||||
element = document.createElement('div')
|
||||
element.classList.add('foo')
|
||||
jasmine.attachToDOM(element)
|
||||
|
||||
@@ -4,11 +4,13 @@ fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
TextEditor = require '../src/text-editor'
|
||||
WindowEventHandler = require '../src/window-event-handler'
|
||||
ipc = require 'ipc'
|
||||
|
||||
describe "Window", ->
|
||||
describe "WindowEventHandler", ->
|
||||
[projectPath, windowEventHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.uninstallWindowEventHandler()
|
||||
spyOn(atom, 'hide')
|
||||
initialPath = atom.project.getPaths()[0]
|
||||
spyOn(atom, 'getLoadSettings').andCallFake ->
|
||||
@@ -16,12 +18,12 @@ describe "Window", ->
|
||||
loadSettings.initialPath = initialPath
|
||||
loadSettings
|
||||
atom.project.destroy()
|
||||
atom.windowEventHandler.unsubscribe()
|
||||
windowEventHandler = new WindowEventHandler
|
||||
windowEventHandler = new WindowEventHandler({atomEnvironment: atom, applicationDelegate: atom.applicationDelegate, window, document})
|
||||
projectPath = atom.project.getPaths()[0]
|
||||
|
||||
afterEach ->
|
||||
windowEventHandler.unsubscribe()
|
||||
atom.installWindowEventHandler()
|
||||
|
||||
describe "when the window is loaded", ->
|
||||
it "doesn't have .is-blurred on the body tag", ->
|
||||
@@ -51,64 +53,25 @@ describe "Window", ->
|
||||
describe "beforeunload event", ->
|
||||
beforeEach ->
|
||||
jasmine.unspy(TextEditor.prototype, "shouldPromptToSave")
|
||||
spyOn(ipc, 'send')
|
||||
|
||||
describe "when pane items are modified", ->
|
||||
it "prompts user to save and calls atom.workspace.confirmClose", ->
|
||||
editor = null
|
||||
spyOn(atom.workspace, 'confirmClose').andCallThrough()
|
||||
spyOn(atom, "confirm").andReturn(2)
|
||||
editor = null
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
runs -> editor.insertText("I look different, I feel different.")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
it "prompts the user to save them, and allows the unload to continue if they confirm", ->
|
||||
spyOn(atom.workspace, 'confirmClose').andReturn(true)
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(ipc.send).not.toHaveBeenCalledWith('did-cancel-window-unload')
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns true if don't save", ->
|
||||
editor = null
|
||||
spyOn(atom, "confirm").andReturn(2)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns false if dialog is canceled", ->
|
||||
editor = null
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
describe "when the same path is modified in multiple panes", ->
|
||||
it "prompts to save the item", ->
|
||||
return
|
||||
editor = null
|
||||
filePath = path.join(temp.mkdirSync('atom-file'), 'file.txt')
|
||||
fs.writeFileSync(filePath, 'hello')
|
||||
spyOn(atom.workspace, 'confirmClose').andCallThrough()
|
||||
spyOn(atom, 'confirm').andReturn(0)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
atom.workspace.getActivePane().splitRight(copyActiveItem: true)
|
||||
editor.setText('world')
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm.callCount).toBe 1
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe 'world'
|
||||
it "cancels the unload if the user selects cancel", ->
|
||||
spyOn(atom.workspace, 'confirmClose').andReturn(false)
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(ipc.send).toHaveBeenCalledWith('did-cancel-window-unload')
|
||||
|
||||
describe "when a link is clicked", ->
|
||||
it "opens the http/https links in an external application", ->
|
||||
@@ -225,62 +188,6 @@ describe "Window", ->
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 7
|
||||
|
||||
describe "the window:open-locations event", ->
|
||||
beforeEach ->
|
||||
spyOn(atom.workspace, 'open')
|
||||
atom.project.setPaths([])
|
||||
|
||||
describe "when the opened path exists", ->
|
||||
it "adds it to the project's paths", ->
|
||||
pathToOpen = __filename
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
|
||||
waitsFor ->
|
||||
atom.project.getPaths().length is 1
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "adds the parent directory to the project paths", ->
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
|
||||
waitsFor ->
|
||||
atom.project.getPaths().length is 1
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path is a file", ->
|
||||
it "opens it in the workspace", ->
|
||||
pathToOpen = __filename
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
|
||||
waitsFor ->
|
||||
atom.workspace.open.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename
|
||||
|
||||
|
||||
describe "when the opened path is a directory", ->
|
||||
it "does not open it in the workspace", ->
|
||||
pathToOpen = __dirname
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
expect(atom.workspace.open.callCount).toBe 0
|
||||
|
||||
describe "when the opened path is a uri", ->
|
||||
it "adds it to the project's paths as is", ->
|
||||
pathToOpen = 'remote://server:7644/some/dir/path'
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
|
||||
waitsFor ->
|
||||
atom.project.getPaths().length is 1
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getPaths()[0]).toBe pathToOpen
|
||||
|
||||
describe "when keydown events occur on the document", ->
|
||||
it "dispatches the event via the KeymapManager and CommandRegistry", ->
|
||||
dispatchedCommands = []
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
Project = require '../src/project'
|
||||
Pane = require '../src/pane'
|
||||
platform = require './spec-helper-platform'
|
||||
_ = require 'underscore-plus'
|
||||
@@ -8,11 +9,14 @@ fstream = require 'fstream'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
describe "Workspace", ->
|
||||
workspace = null
|
||||
[workspace, setDocumentEdited] = []
|
||||
|
||||
beforeEach ->
|
||||
workspace = atom.workspace
|
||||
workspace.resetFontSize()
|
||||
spyOn(atom.applicationDelegate, "confirm")
|
||||
setDocumentEdited = spyOn(atom.applicationDelegate, 'setWindowDocumentEdited')
|
||||
atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')])
|
||||
atom.workspace = workspace = new Workspace
|
||||
waits(1)
|
||||
|
||||
describe "serialization", ->
|
||||
@@ -21,8 +25,16 @@ describe "Workspace", ->
|
||||
projectState = atom.project.serialize()
|
||||
atom.workspace.destroy()
|
||||
atom.project.destroy()
|
||||
atom.project = atom.deserializers.deserialize(projectState)
|
||||
atom.workspace = Workspace.deserialize(workspaceState)
|
||||
atom.project = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm.bind(atom)})
|
||||
atom.project.deserialize(projectState, atom.deserializers)
|
||||
atom.workspace = new Workspace({
|
||||
config: atom.config, project: atom.project, packageManager: atom.packages,
|
||||
grammarRegistry: atom.grammars, deserializerManager: atom.deserializers,
|
||||
notificationManager: atom.notifications, clipboard: atom.clipboard,
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
viewRegistry: atom.views, assert: atom.assert.bind(atom),
|
||||
})
|
||||
atom.workspace.deserialize(workspaceState, atom.deserializers)
|
||||
|
||||
describe "when the workspace contains text editors", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
@@ -333,7 +345,8 @@ describe "Workspace", ->
|
||||
describe "when the file is over 20MB", ->
|
||||
it "prompts the user to make sure they want to open a file this big", ->
|
||||
spyOn(fs, 'getSizeSync').andReturn 20 * 1048577 # 20MB
|
||||
spyOn(atom, 'confirm').andCallFake -> selectedButtonIndex
|
||||
atom.applicationDelegate.confirm.andCallFake -> selectedButtonIndex
|
||||
atom.applicationDelegate.confirm()
|
||||
selectedButtonIndex = 1 # cancel
|
||||
|
||||
editor = null
|
||||
@@ -342,16 +355,16 @@ describe "Workspace", ->
|
||||
|
||||
runs ->
|
||||
expect(editor).toBeUndefined()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
|
||||
atom.confirm.reset()
|
||||
atom.applicationDelegate.confirm.reset()
|
||||
selectedButtonIndex = 0 # open the file
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('sample.js').then (e) -> editor = e
|
||||
|
||||
runs ->
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(editor.displayBuffer.largeFileMode).toBe true
|
||||
|
||||
describe "when passed a path that matches a custom opener", ->
|
||||
@@ -614,7 +627,13 @@ describe "Workspace", ->
|
||||
spyOn(jsPackage, 'loadGrammarsSync')
|
||||
spyOn(coffeePackage, 'loadGrammarsSync')
|
||||
|
||||
workspace2 = Workspace.deserialize(state)
|
||||
workspace2 = new Workspace({
|
||||
config: atom.config, project: atom.project, packageManager: atom.packages,
|
||||
notificationManager: atom.notifications, deserializerManager: atom.deserializers,
|
||||
clipboard: atom.clipboard, viewRegistry: atom.views, grammarRegistry: atom.grammars,
|
||||
applicationDelegate: atom.applicationDelegate, assert: atom.assert.bind(atom)
|
||||
})
|
||||
workspace2.deserialize(state, atom.deserializers)
|
||||
expect(jsPackage.loadGrammarsSync.callCount).toBe 1
|
||||
expect(coffeePackage.loadGrammarsSync.callCount).toBe 1
|
||||
|
||||
@@ -666,7 +685,13 @@ describe "Workspace", ->
|
||||
|
||||
it "updates the title to contain the project's path", ->
|
||||
document.title = null
|
||||
workspace2 = Workspace.deserialize(atom.workspace.serialize())
|
||||
workspace2 = new Workspace({
|
||||
config: atom.config, project: atom.project, packageManager: atom.packages,
|
||||
notificationManager: atom.notifications, deserializerManager: atom.deserializers,
|
||||
clipboard: atom.clipboard, viewRegistry: atom.views, grammarRegistry: atom.grammars,
|
||||
applicationDelegate: atom.applicationDelegate, assert: atom.assert.bind(atom)
|
||||
})
|
||||
workspace2.deserialize(atom.workspace.serialize(), atom.deserializers)
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom"
|
||||
workspace2.destroy()
|
||||
@@ -679,15 +704,14 @@ describe "Workspace", ->
|
||||
waitsForPromise -> atom.workspace.open('b')
|
||||
runs ->
|
||||
[item1, item2] = atom.workspace.getPaneItems()
|
||||
spyOn(atom, 'setDocumentEdited')
|
||||
|
||||
it "calls atom.setDocumentEdited when the active item changes", ->
|
||||
it "calls setDocumentEdited when the active item changes", ->
|
||||
expect(atom.workspace.getActivePaneItem()).toBe item2
|
||||
item1.insertText('a')
|
||||
expect(item1.isModified()).toBe true
|
||||
atom.workspace.getActivePane().activateNextItem()
|
||||
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
expect(setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
|
||||
it "calls atom.setDocumentEdited when the active item's modified status changes", ->
|
||||
expect(atom.workspace.getActivePaneItem()).toBe item2
|
||||
@@ -695,13 +719,13 @@ describe "Workspace", ->
|
||||
advanceClock(item2.getBuffer().getStoppedChangingDelay())
|
||||
|
||||
expect(item2.isModified()).toBe true
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
expect(setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
|
||||
item2.undo()
|
||||
advanceClock(item2.getBuffer().getStoppedChangingDelay())
|
||||
|
||||
expect(item2.isModified()).toBe false
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(false)
|
||||
expect(setDocumentEdited).toHaveBeenCalledWith(false)
|
||||
|
||||
describe "adding panels", ->
|
||||
class TestItem
|
||||
@@ -956,7 +980,7 @@ describe "Workspace", ->
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then (o) ->
|
||||
atom.workspace.open('a').then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
@@ -974,7 +998,7 @@ describe "Workspace", ->
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(temp.openSync().path).then (o) ->
|
||||
atom.workspace.open(temp.openSync().path).then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
@@ -1070,6 +1094,9 @@ describe "Workspace", ->
|
||||
search: (directory, regex, options) -> fakeSearch = new FakeSearch(options)
|
||||
})
|
||||
|
||||
waitsFor ->
|
||||
atom.workspace.directorySearchers.length > 0
|
||||
|
||||
it "can override the DefaultDirectorySearcher on a per-directory basis", ->
|
||||
foreignFilePath = 'ssh://foreign-directory:8080/hello.txt'
|
||||
numPathsSearchedInDir2 = 1
|
||||
@@ -1193,7 +1220,7 @@ describe "Workspace", ->
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
@@ -1214,7 +1241,7 @@ describe "Workspace", ->
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-comments.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample-with-comments.js').then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.replace /items/gi, 'items', [commentFilePath], (result) ->
|
||||
@@ -1229,7 +1256,7 @@ describe "Workspace", ->
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.buffer.setTextInRange([[0, 0], [0, 0]], 'omg')
|
||||
|
||||
169
src/application-delegate.coffee
Normal file
169
src/application-delegate.coffee
Normal file
@@ -0,0 +1,169 @@
|
||||
_ = require 'underscore-plus'
|
||||
ipc = require 'ipc'
|
||||
remote = require 'remote'
|
||||
shell = require 'shell'
|
||||
webFrame = require 'web-frame'
|
||||
{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)
|
||||
|
||||
disablePinchToZoom: ->
|
||||
webFrame.setZoomLevelLimits(1, 1)
|
||||
@@ -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,199 @@ 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)
|
||||
|
||||
@applicationDelegate.disablePinchToZoom()
|
||||
|
||||
@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 +383,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 +397,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 +408,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 +417,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 +426,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 +576,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 +594,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 +629,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 +701,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 +710,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 +735,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 +757,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 +822,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
|
||||
|
||||
@@ -85,11 +87,11 @@ class AtomApplication
|
||||
if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test
|
||||
@openWithOptions(options)
|
||||
else
|
||||
@loadState() or @openPath(options)
|
||||
@loadState(options) 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, devMode, @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
|
||||
@@ -439,15 +441,15 @@ class AtomApplication
|
||||
if states.length > 0 or allowEmpty
|
||||
@storageFolder.store('application.json', states)
|
||||
|
||||
loadState: ->
|
||||
loadState: (options) ->
|
||||
if (states = @storageFolder.load('application.json'))?.length > 0
|
||||
for state in states
|
||||
@openWithOptions({
|
||||
@openWithOptions(_.extend(options, {
|
||||
pathsToOpen: state.initialPaths
|
||||
urlsToOpen: []
|
||||
devMode: @devMode
|
||||
safeMode: @safeMode
|
||||
})
|
||||
}))
|
||||
true
|
||||
else
|
||||
false
|
||||
@@ -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,63 @@ 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, devMode, 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
|
||||
|
||||
@@ -29,7 +29,7 @@ class AtomProtocolHandler
|
||||
|
||||
# Creates the 'atom' custom protocol handler.
|
||||
registerAtomProtocol: ->
|
||||
protocol.registerProtocol 'atom', (request) =>
|
||||
protocol.registerFileProtocol 'atom', (request, callback) =>
|
||||
relativePath = path.normalize(request.url.substr(7))
|
||||
|
||||
if relativePath.indexOf('assets/') is 0
|
||||
@@ -41,4 +41,4 @@ class AtomProtocolHandler
|
||||
filePath = path.join(loadPath, relativePath)
|
||||
break if fs.statSyncNoException(filePath).isFile?()
|
||||
|
||||
new protocol.RequestFileJob(filePath)
|
||||
callback(filePath)
|
||||
|
||||
@@ -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'
|
||||
@@ -84,7 +88,7 @@ class AtomWindow
|
||||
hash: encodeURIComponent(JSON.stringify(loadSettings))
|
||||
|
||||
getLoadSettings: ->
|
||||
if @browserWindow.webContents?.loaded
|
||||
if @browserWindow.webContents? and not @browserWindow.webContents.isLoading()
|
||||
hash = url.parse(@browserWindow.webContents.getUrl()).hash.substr(1)
|
||||
JSON.parse(decodeURIComponent(hash))
|
||||
|
||||
@@ -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'
|
||||
@@ -142,7 +146,9 @@ class AtomWindow
|
||||
when 0 then @browserWindow.destroy()
|
||||
when 1 then @browserWindow.restart()
|
||||
|
||||
@browserWindow.webContents.on 'will-navigate', (event) -> event.preventDefault()
|
||||
@browserWindow.webContents.on 'will-navigate', (event, url) =>
|
||||
unless url is @browserWindow.webContents.getUrl()
|
||||
event.preventDefault()
|
||||
|
||||
@setupContextMenu()
|
||||
|
||||
|
||||
@@ -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,9 @@ 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
|
||||
devMode = true if test
|
||||
resourcePath ?= devResourcePath if devMode
|
||||
|
||||
unless fs.statSyncNoException(resourcePath)
|
||||
resourcePath = path.dirname(path.dirname(__dirname))
|
||||
@@ -157,7 +148,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
|
||||
|
||||
@@ -44,11 +44,11 @@ class CommandInstaller
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
@installApmCommand true, (error) ->
|
||||
@installApmCommand true, (error) =>
|
||||
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
|
||||
|
||||
@@ -158,6 +158,27 @@ require('source-map-support').install({
|
||||
}
|
||||
})
|
||||
|
||||
var sourceMapPrepareStackTrace = Error.prepareStackTrace
|
||||
var prepareStackTrace = sourceMapPrepareStackTrace
|
||||
|
||||
// Prevent coffee-script from reassigning Error.prepareStackTrace
|
||||
Object.defineProperty(Error, 'prepareStackTrace', {
|
||||
get: function () { return prepareStackTrace },
|
||||
set: function (newValue) {}
|
||||
})
|
||||
|
||||
// Enable Grim to access the raw stack without reassigning Error.prepareStackTrace
|
||||
Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native
|
||||
prepareStackTrace = getRawStack
|
||||
var result = this.stack
|
||||
prepareStackTrace = sourceMapPrepareStackTrace
|
||||
return result
|
||||
}
|
||||
|
||||
function getRawStack (_, stack) {
|
||||
return stack
|
||||
}
|
||||
|
||||
Object.keys(COMPILERS).forEach(function (extension) {
|
||||
var compiler = COMPILERS[extension]
|
||||
|
||||
|
||||
@@ -12,24 +12,27 @@ module.exports =
|
||||
default: [".git", ".hg", ".svn", ".DS_Store", "._*", "Thumbs.db"]
|
||||
items:
|
||||
type: 'string'
|
||||
description: 'List of string glob patterns. Files and directories matching these patterns will be ignored by some packages, such as the fuzzy finder and tree view. Individual packages might have additional config settings for ignoring names.'
|
||||
excludeVcsIgnoredPaths:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
title: 'Exclude VCS Ignored Paths'
|
||||
description: 'Files and directories ignored by the current project\'s VCS system will be ignored by some packages, such as the fuzzy finder and find and replace. For example, projects using Git have these paths defined in the .gitignore file. Individual packages might have additional config settings for ignoring VCS ignored files and folders.'
|
||||
followSymlinks:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
title: 'Follow symlinks'
|
||||
description: 'Used when searching and when opening files with the fuzzy finder.'
|
||||
description: 'Follow symbolic links when searching files and when opening files with the fuzzy finder.'
|
||||
disabledPackages:
|
||||
type: 'array'
|
||||
default: []
|
||||
items:
|
||||
type: 'string'
|
||||
description: 'List of names of installed packages which are not loaded at startup.'
|
||||
customFileTypes:
|
||||
type: 'object'
|
||||
default: {}
|
||||
description: 'Associates scope names (e.g. "source.js") with arrays of file extensions and file names (e.g. ["Somefile", ".js2"])'
|
||||
description: 'Associates scope names (e.g. `"source.js"`) with arrays of file extensions and file names (e.g. `["Somefile", ".js2"]`)'
|
||||
additionalProperties:
|
||||
type: 'array'
|
||||
items:
|
||||
@@ -39,15 +42,19 @@ module.exports =
|
||||
default: ['one-dark-ui', 'one-dark-syntax']
|
||||
items:
|
||||
type: 'string'
|
||||
description: 'Names of UI and syntax themes which will be used when Atom starts.'
|
||||
projectHome:
|
||||
type: 'string'
|
||||
default: path.join(fs.getHomeDirectory(), 'github')
|
||||
description: 'The directory where projects are assumed to be located. Packages created using the Package Generator will be stored here by default.'
|
||||
audioBeep:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'Trigger the system\'s beep sound when certain actions cannot be executed or there are no results.'
|
||||
destroyEmptyPanes:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'When the last item of a pane is removed, remove that pane as well.'
|
||||
fileEncoding:
|
||||
description: 'Default character set encoding to use when reading and writing files.'
|
||||
type: 'string'
|
||||
@@ -90,7 +97,7 @@ module.exports =
|
||||
'windows866'
|
||||
]
|
||||
openEmptyEditorOnStart:
|
||||
description: 'Automatically opens an empty editor when atom starts.'
|
||||
description: 'Automatically open an empty editor on startup.'
|
||||
type: 'boolean'
|
||||
default: true
|
||||
|
||||
@@ -113,41 +120,51 @@ module.exports =
|
||||
fontFamily:
|
||||
type: 'string'
|
||||
default: ''
|
||||
description: 'The name of the font family used for editor text.'
|
||||
fontSize:
|
||||
type: 'integer'
|
||||
default: 14
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
description: 'Height in pixels of editor text.'
|
||||
lineHeight:
|
||||
type: ['string', 'number']
|
||||
default: 1.5
|
||||
description: 'Height of editor lines, as a multiplier of font size.'
|
||||
showInvisibles:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
description: 'Render placeholders for invisible characters, such as tabs, spaces and newlines.'
|
||||
showIndentGuide:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
description: 'Show indentation indicators in the editor.'
|
||||
showLineNumbers:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'Show line numbers in the editor\'s gutter.'
|
||||
autoIndent:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'Automatically indent the cursor when inserting a newline'
|
||||
description: 'Automatically indent the cursor when inserting a newline.'
|
||||
autoIndentOnPaste:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'Automatically indent pasted text based on the indentation of the previous line.'
|
||||
nonWordCharacters:
|
||||
type: 'string'
|
||||
default: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-…"
|
||||
description: 'A string of non-word characters to define word boundaries.'
|
||||
preferredLineLength:
|
||||
type: 'integer'
|
||||
default: 80
|
||||
minimum: 1
|
||||
description: 'Identifies the length of a line which is used when wrapping text with the `Soft Wrap At Preferred Line Length` setting enabled, in number of characters.'
|
||||
tabLength:
|
||||
type: 'integer'
|
||||
default: 2
|
||||
enum: [1, 2, 3, 4, 6, 8]
|
||||
description: 'Number of spaces used to represent a tab.'
|
||||
softWrap:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
@@ -155,32 +172,36 @@ module.exports =
|
||||
softTabs:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'If the `Tab Type` config setting is set to "auto" and autodetection of tab type from buffer content fails, then this config setting determines whether a soft tab or a hard tab will be inserted when the Tab key is pressed.'
|
||||
tabType:
|
||||
type: 'string'
|
||||
default: 'auto'
|
||||
enum: ['auto', 'soft', 'hard']
|
||||
description: 'Determine character inserted during Tab keypress.'
|
||||
description: 'Determine character inserted when Tab key is pressed. Possible values: "auto", "soft" and "hard". When set to "soft" or "hard", soft tabs (spaces) or hard tabs (tab characters) are used. When set to "auto", the editor auto-detects the tab type based on the contents of the buffer (it uses the first leading whitespace on a non-comment line), or uses the value of the Soft Tabs config setting if auto-detection fails.'
|
||||
softWrapAtPreferredLineLength:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
description: 'Will wrap to the number of characters defined by the `Preferred Line Length` setting. This will only take effect when soft wrap is enabled globally or for the current language.'
|
||||
description: 'Instead of wrapping lines to the window\'s width, wrap lines to the number of characters defined by the `Preferred Line Length` setting. This will only take effect when the soft wrap config setting is enabled globally or for the current language.'
|
||||
softWrapHangingIndent:
|
||||
type: 'integer'
|
||||
default: 0
|
||||
minimum: 0
|
||||
description: 'When soft wrap is enabled, defines length of additional indentation applied to wrapped lines, in number of characters.'
|
||||
scrollSensitivity:
|
||||
type: 'integer'
|
||||
default: 40
|
||||
minimum: 10
|
||||
maximum: 200
|
||||
description: 'Determines how fast the editor scrolls when using a mouse or trackpad.'
|
||||
scrollPastEnd:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
description: 'Allow the editor to be scrolled past the end of the last line.'
|
||||
undoGroupingInterval:
|
||||
type: 'integer'
|
||||
default: 300
|
||||
minimum: 0
|
||||
description: 'Time interval in milliseconds within which operations will be grouped together in the undo history'
|
||||
description: 'Time interval in milliseconds within which text editing operations will be grouped together in the undo history.'
|
||||
useShadowDOM:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
@@ -190,33 +211,39 @@ module.exports =
|
||||
type: 'boolean'
|
||||
default: true
|
||||
title: 'Confirm Checkout HEAD Revision'
|
||||
description: 'Show confirmation dialog when checking out the HEAD revision and discarding changes to current file since last commit.'
|
||||
backUpBeforeSaving:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
description: 'Ensure file contents aren\'t lost if there is an I/O error during save by making a temporary backup copy.'
|
||||
invisibles:
|
||||
type: 'object'
|
||||
description: 'A hash of characters Atom will use to render whitespace characters. Keys are whitespace character types, values are rendered characters (use value false to turn off individual whitespace character types).'
|
||||
properties:
|
||||
eol:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00ac'
|
||||
maximumLength: 1
|
||||
description: 'Character used to render newline characters (\\n) when the `Show Invisibles` setting is enabled. '
|
||||
space:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00b7'
|
||||
maximumLength: 1
|
||||
description: 'Character used to render leading and trailing space characters when the `Show Invisibles` setting is enabled.'
|
||||
tab:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00bb'
|
||||
maximumLength: 1
|
||||
description: 'Character used to render hard tab characters (\\t) when the `Show Invisibles` setting is enabled.'
|
||||
cr:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00a4'
|
||||
maximumLength: 1
|
||||
description: 'Character used to render carriage return characters (for Microsoft-style line endings) when the `Show Invisibles` setting is enabled.'
|
||||
zoomFontWhenCtrlScrolling:
|
||||
type: 'boolean'
|
||||
default: process.platform isnt 'darwin'
|
||||
description: 'Increase/decrease the editor font size when pressing the Ctrl key and scrolling the mouse up/down.'
|
||||
description: 'Change the editor font size when pressing the Ctrl key and scrolling the mouse up/down.'
|
||||
|
||||
if process.platform in ['win32', 'linux']
|
||||
module.exports.core.properties.autoHideMenuBar =
|
||||
|
||||
@@ -5,7 +5,10 @@ CSON = require 'season'
|
||||
path = require 'path'
|
||||
async = require 'async'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
{pushKeyPath, splitKeyPath, getValueAtKeyPath, setValueAtKeyPath} = require 'key-path-helpers'
|
||||
{
|
||||
getValueAtKeyPath, setValueAtKeyPath, deleteValueAtKeyPath,
|
||||
pushKeyPath, splitKeyPath,
|
||||
} = require 'key-path-helpers'
|
||||
|
||||
Color = require './color'
|
||||
ScopedPropertyStore = require 'scoped-property-store'
|
||||
@@ -331,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'
|
||||
@@ -340,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
|
||||
@@ -354,6 +360,8 @@ class Config
|
||||
@save()
|
||||
debouncedSave = _.debounce(save, 100)
|
||||
|
||||
shouldNotAccessFileSystem: -> not @enablePersistence
|
||||
|
||||
###
|
||||
Section: Config Subscription
|
||||
###
|
||||
@@ -724,7 +732,7 @@ class Config
|
||||
###
|
||||
|
||||
initializeConfigDirectory: (done) ->
|
||||
return if fs.existsSync(@configDirPath)
|
||||
return if fs.existsSync(@configDirPath) or @shouldNotAccessFileSystem()
|
||||
|
||||
fs.makeTreeSync(@configDirPath)
|
||||
|
||||
@@ -740,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, {})
|
||||
@@ -763,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?
|
||||
@@ -779,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
|
||||
@@ -832,12 +846,16 @@ class Config
|
||||
|
||||
setRawValue: (keyPath, value) ->
|
||||
defaultValue = getValueAtKeyPath(@defaultSettings, keyPath)
|
||||
value = undefined if _.isEqual(defaultValue, value)
|
||||
|
||||
if keyPath?
|
||||
setValueAtKeyPath(@settings, keyPath, value)
|
||||
if _.isEqual(defaultValue, value)
|
||||
if keyPath?
|
||||
deleteValueAtKeyPath(@settings, keyPath)
|
||||
else
|
||||
@settings = null
|
||||
else
|
||||
@settings = value
|
||||
if keyPath?
|
||||
setValueAtKeyPath(@settings, keyPath, value)
|
||||
else
|
||||
@settings = value
|
||||
@emitChangeEvent()
|
||||
|
||||
observeKeyPath: (keyPath, options, callback) ->
|
||||
|
||||
@@ -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)
|
||||
@@ -189,10 +204,24 @@ class DisplayBuffer extends Model
|
||||
getLineHeightInPixels: -> @lineHeightInPixels
|
||||
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
|
||||
|
||||
getKoreanCharWidth: -> @koreanCharWidth
|
||||
|
||||
getHalfWidthCharWidth: -> @halfWidthCharWidth
|
||||
|
||||
getDoubleWidthCharWidth: -> @doubleWidthCharWidth
|
||||
|
||||
getDefaultCharWidth: -> @defaultCharWidth
|
||||
setDefaultCharWidth: (defaultCharWidth) ->
|
||||
if defaultCharWidth isnt @defaultCharWidth
|
||||
|
||||
setDefaultCharWidth: (defaultCharWidth, doubleWidthCharWidth, halfWidthCharWidth, koreanCharWidth) ->
|
||||
doubleWidthCharWidth ?= defaultCharWidth
|
||||
halfWidthCharWidth ?= defaultCharWidth
|
||||
koreanCharWidth ?= defaultCharWidth
|
||||
if defaultCharWidth isnt @defaultCharWidth or doubleWidthCharWidth isnt @doubleWidthCharWidth and halfWidthCharWidth isnt @halfWidthCharWidth and koreanCharWidth isnt @koreanCharWidth
|
||||
@defaultCharWidth = defaultCharWidth
|
||||
@doubleWidthCharWidth = doubleWidthCharWidth
|
||||
@halfWidthCharWidth = halfWidthCharWidth
|
||||
@koreanCharWidth = koreanCharWidth
|
||||
@updateWrappedScreenLines() if @isSoftWrapped() and @getEditorWidthInChars()?
|
||||
defaultCharWidth
|
||||
|
||||
getCursorWidth: -> 1
|
||||
@@ -262,6 +291,40 @@ class DisplayBuffer extends Model
|
||||
else
|
||||
@getEditorWidthInChars()
|
||||
|
||||
getSoftWrapColumnForTokenizedLine: (tokenizedLine) ->
|
||||
lineMaxWidth = @getSoftWrapColumn() * @getDefaultCharWidth()
|
||||
|
||||
return if Number.isNaN(lineMaxWidth)
|
||||
return 0 if lineMaxWidth is 0
|
||||
|
||||
iterator = tokenizedLine.getTokenIterator(false)
|
||||
column = 0
|
||||
currentWidth = 0
|
||||
while iterator.next()
|
||||
textIndex = 0
|
||||
text = iterator.getText()
|
||||
while textIndex < text.length
|
||||
if iterator.isPairedCharacter()
|
||||
charLength = 2
|
||||
else
|
||||
charLength = 1
|
||||
|
||||
if iterator.hasDoubleWidthCharacterAt(textIndex)
|
||||
charWidth = @getDoubleWidthCharWidth()
|
||||
else if iterator.hasHalfWidthCharacterAt(textIndex)
|
||||
charWidth = @getHalfWidthCharWidth()
|
||||
else if iterator.hasKoreanCharacterAt(textIndex)
|
||||
charWidth = @getKoreanCharWidth()
|
||||
else
|
||||
charWidth = @getDefaultCharWidth()
|
||||
|
||||
return column if currentWidth + charWidth > lineMaxWidth
|
||||
|
||||
currentWidth += charWidth
|
||||
column += charLength
|
||||
textIndex += charLength
|
||||
column
|
||||
|
||||
# Gets the screen line for the given screen row.
|
||||
#
|
||||
# * `screenRow` - A {Number} indicating the screen row.
|
||||
@@ -958,7 +1021,7 @@ class DisplayBuffer extends Model
|
||||
else
|
||||
softWraps = 0
|
||||
if @isSoftWrapped()
|
||||
while wrapScreenColumn = tokenizedLine.findWrapColumn(@getSoftWrapColumn())
|
||||
while wrapScreenColumn = tokenizedLine.findWrapColumn(@getSoftWrapColumnForTokenizedLine(tokenizedLine))
|
||||
[wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(
|
||||
wrapScreenColumn,
|
||||
@configSettings.softWrapHangingIndent
|
||||
@@ -1036,8 +1099,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
|
||||
|
||||
@@ -83,7 +83,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
|
||||
@@ -449,25 +449,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)
|
||||
69
src/initialize-test-window.coffee
Normal file
69
src/initialize-test-window.coffee
Normal file
@@ -0,0 +1,69 @@
|
||||
# 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'
|
||||
|
||||
{testRunnerPath, legacyTestRunnerPath, headless, logFile, testPaths} = getWindowLoadSettings()
|
||||
|
||||
if headless
|
||||
# Override logging in headless mode so it goes to the console, regardless
|
||||
# of the --enable-logging flag to Electron.
|
||||
console.log = (args...) ->
|
||||
ipc.send 'write-to-stdout', args.join(' ') + '\n'
|
||||
console.warn = (args...) ->
|
||||
ipc.send 'write-to-stderr', args.join(' ') + '\n'
|
||||
console.error = (args...) ->
|
||||
ipc.send 'write-to-stderr', args.join(' ') + '\n'
|
||||
else
|
||||
# Show window synchronously so a focusout doesn't fire on input elements
|
||||
# that are focused in the very first spec run.
|
||||
remote.getCurrentWindow().show()
|
||||
|
||||
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"
|
||||
|
||||
testRunner = require(testRunnerPath)
|
||||
legacyTestRunner = require(legacyTestRunnerPath)
|
||||
buildAtomEnvironment = (params) -> new AtomEnvironment(params)
|
||||
buildDefaultApplicationDelegate = (params) -> new ApplicationDelegate()
|
||||
|
||||
promise = testRunner({
|
||||
logFile, headless, testPaths, buildAtomEnvironment, buildDefaultApplicationDelegate, 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 = ''
|
||||
|
||||
|
||||
@@ -7,13 +7,21 @@ DummyLineNode.className = 'line'
|
||||
DummyLineNode.style.position = 'absolute'
|
||||
DummyLineNode.style.visibility = 'hidden'
|
||||
DummyLineNode.appendChild(document.createElement('span'))
|
||||
DummyLineNode.firstChild.textContent = 'x'
|
||||
DummyLineNode.appendChild(document.createElement('span'))
|
||||
DummyLineNode.appendChild(document.createElement('span'))
|
||||
DummyLineNode.appendChild(document.createElement('span'))
|
||||
DummyLineNode.children[0].textContent = 'x'
|
||||
DummyLineNode.children[1].textContent = '我'
|
||||
DummyLineNode.children[2].textContent = 'ハ'
|
||||
DummyLineNode.children[3].textContent = '세'
|
||||
|
||||
RangeForMeasurement = document.createRange()
|
||||
|
||||
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")
|
||||
@@ -64,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: {}}
|
||||
@@ -76,12 +84,18 @@ class LinesComponent extends TiledComponent
|
||||
|
||||
measureLineHeightAndDefaultCharWidth: ->
|
||||
@domNode.appendChild(DummyLineNode)
|
||||
textNode = DummyLineNode.firstChild.childNodes[0]
|
||||
|
||||
lineHeightInPixels = DummyLineNode.getBoundingClientRect().height
|
||||
charWidth = DummyLineNode.firstChild.getBoundingClientRect().width
|
||||
defaultCharWidth = DummyLineNode.children[0].getBoundingClientRect().width
|
||||
doubleWidthCharWidth = DummyLineNode.children[1].getBoundingClientRect().width
|
||||
halfWidthCharWidth = DummyLineNode.children[2].getBoundingClientRect().width
|
||||
koreanCharWidth = DummyLineNode.children[3].getBoundingClientRect().width
|
||||
|
||||
@domNode.removeChild(DummyLineNode)
|
||||
|
||||
@presenter.setLineHeight(lineHeightInPixels)
|
||||
@presenter.setBaseCharacterWidth(charWidth)
|
||||
@presenter.setBaseCharacterWidth(defaultCharWidth, doubleWidthCharWidth, halfWidthCharWidth, koreanCharWidth)
|
||||
|
||||
lineNodeForLineIdAndScreenRow: (lineId, screenRow) ->
|
||||
tile = @presenter.tileForRow(screenRow)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -40,7 +40,7 @@ class LinesYardstick
|
||||
previousColumn = 0
|
||||
previousLeft = 0
|
||||
|
||||
@tokenIterator.reset(line)
|
||||
@tokenIterator.reset(line, false)
|
||||
while @tokenIterator.next()
|
||||
text = @tokenIterator.getText()
|
||||
textIndex = 0
|
||||
@@ -112,7 +112,7 @@ class LinesYardstick
|
||||
indexWithinTextNode = null
|
||||
charIndex = 0
|
||||
|
||||
@tokenIterator.reset(line)
|
||||
@tokenIterator.reset(line, false)
|
||||
while @tokenIterator.next()
|
||||
break if foundIndexWithinTextNode?
|
||||
|
||||
|
||||
@@ -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'))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user