Comparar commits

...

80 Commits

Autor SHA1 Mensagem Data
Max Brunsfeld cffe733641 Fix config event subscription methods
Signed-off-by: Nathan Sobo <nathan@github.com>
2014-12-19 17:28:33 -08:00
Nathan Sobo 3127171b2b Fix Config::isDefault 2014-12-19 16:47:24 -08:00
Nathan Sobo 1d48cb641c Fix Config::save 2014-12-19 16:47:24 -08:00
Nathan Sobo b7b5852863 Store all settings in the scoped property store
There are a few failing specs, but I think they can all be addressed by
having a `source` for all properties and using it to target only the
user settings in various cases.
2014-12-19 16:47:18 -08:00
Max Brunsfeld d104e68342 Revert "Revert "Merge pull request #4631""
This reverts commit dc2a453986.

Conflicts:
	spec/config-spec.coffee
	src/config.coffee
2014-12-19 14:20:27 -08:00
Max Brunsfeld 9640678c29 ⬆️ snippets@0.60.0 2014-12-19 14:19:16 -08:00
Kevin Sawicki 2ce1677aa5 Prepare 0.164 2014-12-19 13:46:19 -08:00
Kevin Sawicki d5c8956d38 ⬆️ release-notes@0.43 2014-12-19 13:27:45 -08:00
Kevin Sawicki d532f506fe ⬆️ package-generator@0.34 2014-12-19 11:53:55 -08:00
Kevin Sawicki 32b414328a ⬆️ release-notes@0.42 2014-12-19 11:49:18 -08:00
Ben Ogle b1697399dc Merge pull request #4698 from atom/bo-fix-load-settings
Pass safeMode and devMode load settings to new windows
2014-12-19 11:36:31 -08:00
Ben Ogle 27eccfaf81 Upgrade notification@0.20.0 2014-12-19 11:35:46 -08:00
Ben Ogle ebbd8101ba Upgrade notifications to provide more user info 2014-12-19 10:45:19 -08:00
Ben Ogle 20504fc7a8 Pull load settings out of the focused window 2014-12-19 10:38:03 -08:00
Ben Ogle 0db1971825 Default devMode and safeMode to false 2014-12-19 10:38:03 -08:00
Ben Ogle 80c828d001 Pass the load settings through so all windows share devMode and safeMode 2014-12-19 10:38:03 -08:00
Ben Ogle e688df57f2 Add atom.inSafeMode() 2014-12-19 10:38:03 -08:00
Max Brunsfeld 0790d33e9d ⬆️ language-html@0.27.0
For handlebars template scope fix
2014-12-19 10:34:14 -08:00
Kevin Sawicki 05820a3044 ⬆️ release-notes@0.41 2014-12-19 09:08:36 -08:00
Kevin Sawicki c4ac602644 ⬆️ language-sass@0.29 2014-12-18 18:23:37 -08:00
Kevin Sawicki 12d4fae91c Fall back to system root for cmd.exe path 2014-12-18 17:58:18 -08:00
Kevin Sawicki 2f334979d5 Add explorer check using SystemRoot path
Closes #4551
2014-12-18 17:20:40 -08:00
Max Brunsfeld d9e414af27 ⬆️ scoped-property-store@0.15.4
For performance improvements
2014-12-18 16:24:20 -08:00
Kevin Sawicki 335c1e215a Prepare 0.163 2014-12-18 11:46:03 -08:00
Max Brunsfeld b9b7646d4b ⬆️ tree-view@0.139.0
For bug fixes
2014-12-18 11:27:23 -08:00
Kevin Sawicki d885fb2d13 Merge pull request #4691 from atom/ks-improve-middle-mouse-paste
Improve middle mouse paste on Linux
2014-12-18 11:23:47 -08:00
Kevin Sawicki f5ae96820a Update spec for new middle mouse paste behavior 2014-12-18 11:04:52 -08:00
Kevin Sawicki 435fee1433 Use skinny arrow 2014-12-18 10:40:44 -08:00
Kevin Sawicki c96f976162 Write to selection clipboard from setTimeout
This is so that in progress transactions aren't written to the
selection clipboard.
2014-12-18 10:40:04 -08:00
Kevin Sawicki 5115540f8e Track middle button mouse down events on Linux 2014-12-18 09:51:32 -08:00
Kevin Sawicki d642553351 Paste selection clipboard after finalizing selections 2014-12-18 09:26:14 -08:00
Kevin Sawicki fa090345a8 ⬆️ release-notes@0.40 2014-12-18 08:58:19 -08:00
Max Brunsfeld 55d291ffde ⬆️ underscore-plus@1.6.6 2014-12-18 08:50:16 -08:00
Max Brunsfeld 48f63926ab ⬆️ underscore-plus@1.6.5 2014-12-17 18:13:48 -08:00
Max Brunsfeld b0501c9cb2 Merge pull request #4672 from atom/mb-optimize-config-events
Avoid firing repeated config events while packages are loaded
2014-12-17 18:11:33 -08:00
Max Brunsfeld 355ab1eb2f ⬆️ underscore-plus@1.6.4 2014-12-17 17:35:07 -08:00
Max Brunsfeld 28ac51d140 Add Config::transact
Use this method to avoid emitting unecessary config events
when activating or deactivating multiple packages
2014-12-17 16:54:47 -08:00
Kevin Sawicki d6210b24d9 ⬆️ status-bar@0.54 2014-12-17 13:01:54 -08:00
Max Brunsfeld b0731afd4c Don't pass keyPath to Config::onDidChange callback
The keyPath field was never used by core or any package, and
for scoped settings, its value was always equal to the keyPath
specified by the caller.
2014-12-17 12:03:46 -08:00
Kevin Sawicki 1c81aa90c0 Add initial SquirrelUpdate specs 2014-12-17 10:47:43 -08:00
Kevin Sawicki bbf6930061 💄 2014-12-17 10:02:34 -08:00
Kevin Sawicki 3d149eb9d1 Only update desktop shortcut if it already exists
Delete the created shortcut if it was previously deleted
after it was first installed.

Closes #4665
2014-12-17 09:55:46 -08:00
Kevin Sawicki 5a8b96b180 Add git as debian dependency
Used by npm to install module dependencies that use git URLs

Closes #4668
2014-12-17 09:11:25 -08:00
Kevin Sawicki 5add777291 Prepare 0.162 2014-12-16 18:35:01 -08:00
Max Brunsfeld f866e69704 ⬆️ scoped-property-store@0.15.3 2014-12-16 18:06:28 -08:00
Ben Ogle b27b4387fc Upgrade solarized-dark-syntax@0.29.0 2014-12-16 16:39:40 -08:00
Ben Ogle 1f850f0af1 Upgrade solarized dark to fix some ruby highlighting 2014-12-16 16:35:14 -08:00
Kevin Sawicki 9f1bbc54de Delete docker image after running 2014-12-16 16:20:46 -08:00
Ben Ogle e7d34d4b83 Upgrade wrap guide to use scoped config 2014-12-16 16:17:36 -08:00
simurai c5a15fb50e Add a note about font-family in syntax themes
#4646
2014-12-17 09:14:21 +09:00
Kevin Sawicki 7a251f5432 Prepare 0.161 2014-12-16 15:44:41 -08:00
Max Brunsfeld dc2a453986 Revert "Merge pull request #4631 from atom/mb-new-config-api"
This reverts commit 5147fb6a8b, reversing
changes made to 9bbbb58084.
2014-12-16 15:27:39 -08:00
Kevin Sawicki fdd55dfd27 Restart Atom with project path from focused window
Closes #4653
2014-12-16 15:26:42 -08:00
Max Brunsfeld 5147fb6a8b Merge pull request #4631 from atom/mb-new-config-api
New config API
2014-12-16 15:22:15 -08:00
Ben Ogle 9bbbb58084 Fix context menu when shadow DOM is enabled
Closes #4623
2014-12-16 15:16:12 -08:00
Kevin Sawicki 9ad080cd31 ⬆️ grammar-selector@0.40 2014-12-16 15:10:33 -08:00
Ben Ogle 509976fa18 Merge pull request #4655 from atom/bo-fix-dragging
Handle the case when the editor is destroyed while dragging
2014-12-16 15:05:58 -08:00
Ben Ogle aad5700418 Merge pull request #4652 from atom/bo-fix-unmount
Properly unmount the component when the shadow DOM is enabled
2014-12-16 14:52:37 -08:00
Ben Ogle 09a0773043 Handle editor destruction when dragging.
Closes #4622
2014-12-16 14:52:07 -08:00
Ben Ogle 0829da53b0 Properly unmount the component when the shadow DOM is enabled. 2014-12-16 14:36:51 -08:00
Max Brunsfeld 9a2cc36c6b 💄 2014-12-16 14:27:57 -08:00
Max Brunsfeld 965a6243e1 Remove toBe parens 2014-12-16 14:27:57 -08:00
Max Brunsfeld 503fa30c28 Flesh out deprecation messages for Config::{is,set}Default
Also, simplify the shim in ::isDefault
2014-12-16 14:27:46 -08:00
Max Brunsfeld b8f239cd39 Deprecate Config::isDefault and ::getDefault 2014-12-16 14:00:57 -08:00
Max Brunsfeld 231da60e13 📝 new config APIs 2014-12-16 14:00:57 -08:00
Max Brunsfeld a47719eb53 Fix config priorities 2014-12-16 14:00:57 -08:00
Max Brunsfeld 9f851e55d1 Add Config::unset
Deprecate Config::restoreDefault
2014-12-16 14:00:57 -08:00
Max Brunsfeld ab89776f01 Throw when Config::set is called w/ source and no scope 2014-12-16 14:00:57 -08:00
Max Brunsfeld 2cea51b50e Take 'scope' option in Config::onDidChange
Deprecate passing the scope as an optional first argument
2014-12-16 14:00:57 -08:00
Max Brunsfeld 4e4794f3fd Take 'scope' option in Config::observe
Deprecate using the scope as an optional first argument
2014-12-16 14:00:57 -08:00
Max Brunsfeld ac6fbf100d Fix deprecation in package-manager-spec 2014-12-16 14:00:57 -08:00
Max Brunsfeld 8c8e866a97 Use a schema in all specs for Config::observeUserConfig
Before, values loaded from the config file were set in a
way that allowed any key to be set in the root object.
Now, these values are set in a way that's similar to how
::set works.
2014-12-16 14:00:56 -08:00
Max Brunsfeld f859ad5fc5 Allow null keyPath with options argument in ::get 2014-12-16 14:00:56 -08:00
Nathan Sobo d30cf35a16 Use ‘source’ option rather than internal state in Config spec 2014-12-16 14:00:56 -08:00
Nathan Sobo c35fb90653 Don’t return schema defaults when sources are specified in Config::get 2014-12-16 14:00:56 -08:00
Nathan Sobo 73df017d83 Add a ‘sources’ and ‘excludeSources’ options to Config::get
If the option is supplied, we will only retrieve values from the
specified sources.
2014-12-16 14:00:56 -08:00
Nathan Sobo 0e1ef201c1 Pass source to ::scopedSettingsStore on calls to ::set
Default it to the user’s config if no source is specified.
2014-12-16 14:00:56 -08:00
Nathan Sobo be4d23aa13 Use the user’s config.cson path as the default config source 2014-12-16 14:00:56 -08:00
Nathan Sobo c58606907a Make scope a trailing option to Config::get 2014-12-16 14:00:56 -08:00
Nathan Sobo c489a4662b Make scopeSelector a trailing option to Config::set 2014-12-16 14:00:56 -08:00
31 arquivos alterados com 954 adições e 459 exclusões
+2
Ver Arquivo
@@ -59,6 +59,8 @@ window in dev mode. To open a Dev Mode Atom window run `atom --dev .` in the
terminal, use `cmd-shift-o` or use the _View > Developer > Open in Dev Mode_
menu. When you edit your theme, changes will instantly be reflected!
> Note: It's advised to _not_ specify a `font-family` in your syntax theme because it will override the Font Family field in Atom's settings. If you still like to recommend a font that goes well with your theme, we recommend you do so in your README.
## Creating an Interface Theme
Interface themes **must** provide a `ui-variables.less` file which contains all
+1 -1
Ver Arquivo
@@ -202,7 +202,7 @@
]
'context-menu':
'.overlayer': [
'atom-text-editor, .overlayer': [
{label: 'Undo', command: 'core:undo'}
{label: 'Redo', command: 'core:redo'}
{type: 'separator'}
+1 -1
Ver Arquivo
@@ -160,7 +160,7 @@
]
'context-menu':
'.overlayer': [
'atom-text-editor, .overlayer': [
{label: 'Undo', command: 'core:undo'}
{label: 'Redo', command: 'core:redo'}
{type: 'separator'}
+1 -1
Ver Arquivo
@@ -181,7 +181,7 @@
]
'context-menu':
'.overlayer': [
'atom-text-editor, .overlayer': [
{label: 'Undo', command: 'core:undo'}
{label: 'Redo', command: 'core:redo'}
{type: 'separator'}
+14 -14
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.160.0",
"version": "0.164.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -53,7 +53,7 @@
"reactionary-atom-fork": "^1.0.0",
"runas": "1.0.1",
"scandal": "1.0.3",
"scoped-property-store": "^0.15.2",
"scoped-property-store": "^0.15.4",
"scrollbar-style": "^1.0.2",
"season": "^1.0.2",
"semver": "2.2.1",
@@ -63,7 +63,7 @@
"temp": "0.7.0",
"text-buffer": "^3.8.2",
"theorist": "^1.0.2",
"underscore-plus": "^1.6.3",
"underscore-plus": "^1.6.6",
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {
@@ -73,7 +73,7 @@
"atom-light-ui": "0.36.0",
"base16-tomorrow-dark-theme": "0.22.0",
"base16-tomorrow-light-theme": "0.5.0",
"solarized-dark-syntax": "0.27.0",
"solarized-dark-syntax": "0.29.0",
"solarized-light-syntax": "0.13.0",
"archive-view": "0.40.0",
"autocomplete": "0.34.0",
@@ -91,30 +91,30 @@
"fuzzy-finder": "0.62.0",
"git-diff": "0.45.0",
"go-to-line": "0.27.0",
"grammar-selector": "0.38.0",
"grammar-selector": "0.40.0",
"image-view": "0.44.0",
"incompatible-packages": "0.16.0",
"keybinding-resolver": "0.24.0",
"link": "0.28.0",
"markdown-preview": "0.112.0",
"metrics": "0.40.0",
"notifications": "0.18.0",
"notifications": "0.20.0",
"open-on-github": "0.31.0",
"package-generator": "0.33.0",
"release-notes": "0.39.0",
"package-generator": "0.34.0",
"release-notes": "0.43.0",
"settings-view": "0.161.0",
"snippets": "0.59.0",
"snippets": "0.60.0",
"spell-check": "0.45.0",
"status-bar": "0.53.0",
"status-bar": "0.54.0",
"styleguide": "0.36.0",
"symbols-view": "0.70.0",
"tabs": "0.58.0",
"timecop": "0.24.0",
"tree-view": "0.138.0",
"tree-view": "0.139.0",
"update-package-dependencies": "0.7.0",
"welcome": "0.21.0",
"whitespace": "0.27.0",
"wrap-guide": "0.26.0",
"wrap-guide": "0.27.0",
"language-c": "0.33.0",
"language-clojure": "0.9.0",
"language-coffee-script": "0.38.1",
@@ -122,7 +122,7 @@
"language-gfm": "0.55.0",
"language-git": "0.9.0",
"language-go": "0.19.1",
"language-html": "0.26.1",
"language-html": "0.27.0",
"language-hyperlink": "0.12.2",
"language-java": "0.13.0",
"language-javascript": "0.51.0",
@@ -137,7 +137,7 @@
"language-python": "0.26.0",
"language-ruby": "0.44.0",
"language-ruby-on-rails": "0.18.0",
"language-sass": "0.28.0",
"language-sass": "0.29.0",
"language-shellscript": "0.10.1",
"language-source": "0.8.0",
"language-sql": "0.11.0",
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
Package: <%= name %>
Version: <%= version %>
Depends: gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils
Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils
Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0
Section: <%= section %>
Priority: optional
+1
Ver Arquivo
@@ -9,3 +9,4 @@ docker run \
--env JANKY_BRANCH="$JANKY_BRANCH" \
--env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \
atom-rpm /atom/script/rpmbuild
docker rmi atom-rpm
+33
Ver Arquivo
@@ -1,3 +1,5 @@
ChildProcess = require 'child_process'
path = require 'path'
BufferedProcess = require '../src/buffered-process'
describe "BufferedProcess", ->
@@ -40,3 +42,34 @@ describe "BufferedProcess", ->
expect(window.onerror).toHaveBeenCalled()
expect(window.onerror.mostRecentCall.args[0]).toContain 'Failed to spawn command `bad-command-nope`'
expect(window.onerror.mostRecentCall.args[4].name).toBe 'BufferedProcessError'
describe "on Windows", ->
originalPlatform = null
beforeEach ->
# Prevent any commands from actually running and affecting the host
originalSpawn = ChildProcess.spawn
spyOn(ChildProcess, 'spawn').andCallFake ->
# Just spawn something that won't actually modify the host
if originalPlatform is 'win32'
originalSpawn('dir')
else
originalSpawn('ls')
originalPlatform = process.platform
Object.defineProperty process, 'platform', value: 'win32'
afterEach ->
Object.defineProperty process, 'platform', value: originalPlatform
describe "when the explorer command is spawned on Windows", ->
it "doesn't quote arguments of the form /root,C...", ->
new BufferedProcess({command: 'explorer.exe', args: ['/root,C:\\foo']})
expect(ChildProcess.spawn.argsForCall[0][1][2]).toBe '"explorer.exe /root,C:\\foo"'
it "spawns the command using a cmd.exe wrapper", ->
new BufferedProcess({command: 'dir'})
expect(path.basename(ChildProcess.spawn.argsForCall[0][0])).toBe 'cmd.exe'
expect(ChildProcess.spawn.argsForCall[0][1][0]).toBe '/s'
expect(ChildProcess.spawn.argsForCall[0][1][1]).toBe '/c'
expect(ChildProcess.spawn.argsForCall[0][1][2]).toBe '"dir"'
+348 -157
Ver Arquivo
@@ -2,6 +2,7 @@ path = require 'path'
temp = require 'temp'
CSON = require 'season'
fs = require 'fs-plus'
Grim = require 'grim'
describe "Config", ->
dotAtomPath = null
@@ -34,6 +35,36 @@ describe "Config", ->
atom.config.setDefaults("bar", baz: 7)
expect(atom.config.get("bar.baz")).toEqual {a: 3}
describe "when a 'sources' option is specified", ->
it "only retrieves values from the specified sources", ->
atom.config.set("x.y", 1, scopeSelector: ".foo", source: "a")
atom.config.set("x.y", 2, scopeSelector: ".foo", source: "b")
atom.config.set("x.y", 3, scopeSelector: ".foo", source: "c")
atom.config.setSchema("x.y", type: "integer", default: 4)
expect(atom.config.get("x.y", sources: ["a"], scope: [".foo"])).toBe 1
expect(atom.config.get("x.y", sources: ["b"], scope: [".foo"])).toBe 2
expect(atom.config.get("x.y", sources: ["c"], scope: [".foo"])).toBe 3
# Schema defaults never match a specific source. We could potentially add a special "schema" source.
expect(atom.config.get("x.y", sources: ["x"], scope: [".foo"])).toBeUndefined()
expect(atom.config.get(null, sources: ['a'], scope: [".foo"]).x.y).toBe 1
describe "when an 'excludeSources' option is specified", ->
it "only retrieves values from the specified sources", ->
atom.config.set("x.y", 0)
atom.config.set("x.y", 1, scopeSelector: ".foo", source: "a")
atom.config.set("x.y", 2, scopeSelector: ".foo", source: "b")
atom.config.set("x.y", 3, scopeSelector: ".foo", source: "c")
atom.config.setSchema("x.y", type: "integer", default: 4)
expect(atom.config.get("x.y", excludeSources: ["a"], scope: [".foo"])).toBe 3
expect(atom.config.get("x.y", excludeSources: ["c"], scope: [".foo"])).toBe 2
expect(atom.config.get("x.y", excludeSources: ["b", "c"], scope: [".foo"])).toBe 1
expect(atom.config.get("x.y", excludeSources: ["b", "c", "a"], scope: [".foo"])).toBe 0
expect(atom.config.get("x.y", excludeSources: ["b", "c", "a", atom.config.getUserConfigPath()], scope: [".foo"])).toBe 4
expect(atom.config.get("x.y", excludeSources: [atom.config.getUserConfigPath()])).toBe 4
describe ".set(keyPath, value)", ->
it "allows a key path's value to be written", ->
expect(atom.config.set("foo.bar.baz", 42)).toBe true
@@ -50,7 +81,7 @@ describe "Config", ->
expect(observeHandler).toHaveBeenCalledWith 42
describe "when the value equals the default value", ->
it "does not store the value", ->
it "does not store the value in the user's config", ->
atom.config.setDefaults "foo",
same: 1
changes: 1
@@ -66,60 +97,84 @@ describe "Config", ->
atom.config.set('foo.null', undefined)
atom.config.set('foo.undefined', null)
atom.config.set('foo.sameObject', {b: 2, a: 1})
expect(atom.config.settings.foo).toEqual {changes: 2}
expect(atom.config.get("foo.same", sources: [atom.config.getUserConfigPath()])).toBeUndefined()
expect(atom.config.get("foo.changes", sources: [atom.config.getUserConfigPath()])).toBe 2
atom.config.set('foo.changes', 1)
expect(atom.config.settings.foo).toEqual {}
expect(atom.config.get("foo.changes", sources: [atom.config.getUserConfigPath()])).toBeUndefined()
describe ".getDefault(keyPath)", ->
it "returns a clone of the default value", ->
atom.config.setDefaults("foo", same: 1, changes: 1)
spyOn(Grim, 'deprecate')
expect(atom.config.getDefault('foo.same')).toBe 1
expect(atom.config.getDefault('foo.changes')).toBe 1
expect(Grim.deprecate.callCount).toBe 2
atom.config.set('foo.same', 2)
atom.config.set('foo.changes', 3)
expect(atom.config.getDefault('foo.same')).toBe 1
expect(atom.config.getDefault('foo.changes')).toBe 1
expect(Grim.deprecate.callCount).toBe 4
initialDefaultValue = [1, 2, 3]
atom.config.setDefaults("foo", bar: initialDefaultValue)
expect(atom.config.getDefault('foo.bar')).toEqual initialDefaultValue
expect(atom.config.getDefault('foo.bar')).not.toBe initialDefaultValue
expect(Grim.deprecate.callCount).toBe 6
describe "when scoped settings are used", ->
it "returns the global default when no scoped default set", ->
atom.config.setDefaults("foo", bar: baz: 10)
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 10
it "returns the scoped default when a scoped default is set", ->
spyOn(Grim, 'deprecate')
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 10
expect(Grim.deprecate).toHaveBeenCalled()
it "returns the scoped settings not including the user's config file", ->
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42)
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
spyOn(Grim, 'deprecate')
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42
expect(Grim.deprecate.callCount).toBe 1
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42
expect(Grim.deprecate.callCount).toBe 2
describe ".isDefault(keyPath)", ->
it "returns true when the value of the key path is its default value", ->
atom.config.setDefaults("foo", same: 1, changes: 1)
spyOn(Grim, 'deprecate')
expect(atom.config.isDefault('foo.same')).toBe true
expect(atom.config.isDefault('foo.changes')).toBe true
expect(Grim.deprecate.callCount).toBe 2
atom.config.set('foo.same', 2)
atom.config.set('foo.same', 1)
atom.config.set('foo.changes', 3)
expect(atom.config.isDefault('foo.same')).toBe false
expect(atom.config.isDefault('foo.same')).toBe true
expect(atom.config.isDefault('foo.changes')).toBe false
expect(Grim.deprecate.callCount).toBe 4
describe "when scoped settings are used", ->
it "returns false when a scoped setting was set by the user", ->
spyOn(Grim, 'deprecate')
expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe true
expect(Grim.deprecate.callCount).toBe 1
atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42)
expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe true
expect(Grim.deprecate.callCount).toBe 2
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe false
expect(Grim.deprecate.callCount).toBe 3
describe ".setDefaults(keyPath)", ->
it "sets a default when the setting's key contains an escaped dot", ->
@@ -150,17 +205,17 @@ describe "Config", ->
atom.config.toggle('foo.a')
expect(atom.config.get('foo.a')).toBe false
describe ".restoreDefault(keyPath)", ->
describe ".unset(keyPath, {scope})", ->
it "sets the value of the key path to its default", ->
atom.config.setDefaults('a', b: 3)
atom.config.set('a.b', 4)
expect(atom.config.get('a.b')).toBe 4
atom.config.restoreDefault('a.b')
atom.config.unset('a.b')
expect(atom.config.get('a.b')).toBe 3
atom.config.set('a.c', 5)
expect(atom.config.get('a.c')).toBe 5
atom.config.restoreDefault('a.c')
atom.config.unset('a.c')
expect(atom.config.get('a.c')).toBeUndefined()
it "calls ::save()", ->
@@ -168,43 +223,61 @@ describe "Config", ->
atom.config.set('a.b', 4)
atom.config.save.reset()
atom.config.restoreDefault('a.c')
atom.config.unset('a.c')
expect(atom.config.save.callCount).toBe 1
describe "when scoped settings are used", ->
it "restores the global default when no scoped default set", ->
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10
atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee')
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10
it "restores the scoped default when a scoped default is set", ->
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42)
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
atom.config.set('.source.coffee', 'foo.bar.ok', 100)
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
atom.config.set('foo.bar.ok', 100, scopeSelector: '.source.coffee')
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 42
expect(atom.config.get(['.source.coffee'], 'foo.bar.ok')).toBe 100
atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee')
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 42
expect(atom.config.get('foo.bar.ok', scope: ['.source.coffee'])).toBe 100
it "calls ::save()", ->
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.addScopedSettings("default", ".source.coffee", foo: bar: baz: 42)
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
atom.config.save.reset()
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee')
expect(atom.config.save.callCount).toBe 1
it "allows removing settings for a specific source and scope selector", ->
atom.config.set('foo.bar', 55, scopeSelector: '.source.coffee', source: "source-a")
atom.config.set('foo.bar', 65, scopeSelector: '.source.coffee', source: "source-b")
expect(atom.config.get('foo.bar', scope: ['.source.coffee'])).toBe 65
atom.config.unset('foo.bar', source: "source-b", scopeSelector: ".source.coffee")
expect(atom.config.get('foo.bar', scope: ['.source.coffee', '.string'])).toBe 55
it "allows removing all settings for a specific source", ->
atom.config.set('foo.bar', 55, scopeSelector: '.source.coffee', source: "source-a")
atom.config.set('foo.bar', 65, scopeSelector: '.source.coffee', source: "source-b")
atom.config.set('foo.baz', 65, scopeSelector: '.source.coffee', source: "source-b")
expect(atom.config.get('foo.bar', scope: ['.source.coffee'])).toBe 65
atom.config.unset(null, source: "source-b", scopeSelector: ".source.coffee")
expect(atom.config.get('foo.bar', scope: ['.source.coffee', '.string'])).toBe 55
expect(atom.config.get('foo.baz', scope: ['.source.coffee', '.string'])).toBe undefined
it "does not call ::save or add a scoped property when no value has been set", ->
# see https://github.com/atom/atom/issues/4175
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10
atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee')
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10
expect(atom.config.save).not.toHaveBeenCalled()
@@ -216,14 +289,14 @@ describe "Config", ->
jasmine.unspy atom.config, 'save'
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
atom.config.set('.source.coffee', 'foo.bar.zfoo', 20)
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
atom.config.set('foo.bar.zfoo', 20, scopeSelector: '.source.coffee')
CSON.writeFileSync.reset()
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10
expect(atom.config.get(['.source.coffee'], 'foo.bar.zfoo')).toBe 20
atom.config.unset('foo.bar.baz', scopeSelector: '.source.coffee')
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10
expect(atom.config.get('foo.bar.zfoo', scope: ['.source.coffee'])).toBe 20
expect(CSON.writeFileSync).toHaveBeenCalled()
properties = CSON.writeFileSync.mostRecentCall.args[1]
expect(properties['.coffee.source']).toEqual
@@ -232,19 +305,29 @@ describe "Config", ->
zfoo: 20
CSON.writeFileSync.reset()
atom.config.restoreDefault('.source.coffee', 'foo.bar.zfoo')
atom.config.unset('foo.bar.zfoo', scopeSelector: '.source.coffee')
expect(CSON.writeFileSync).toHaveBeenCalled()
properties = CSON.writeFileSync.mostRecentCall.args[1]
expect(properties['.coffee.source']).toBeUndefined()
it "does not call ::save when the value is already at the default", ->
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
atom.config.set('foo.bar.baz', 55)
atom.config.save.reset()
atom.config.restoreDefault('.source.coffee', 'foo.bar.ok')
atom.config.unset('foo.bar.ok', scopeSelector: '.source.coffee')
expect(atom.config.save).not.toHaveBeenCalled()
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55
it "deprecates passing a scope selector as the first argument", ->
atom.config.setDefaults("foo", bar: baz: 10)
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
spyOn(Grim, 'deprecate')
atom.config.unset('.source.coffee', 'foo.bar.baz')
expect(Grim.deprecate).toHaveBeenCalled()
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10
describe ".getSettings()", ->
it "returns all settings including defaults", ->
@@ -321,56 +404,37 @@ describe "Config", ->
spyOn(CSON, 'writeFileSync')
jasmine.unspy atom.config, 'save'
describe "when ~/.atom/config.json exists", ->
it "writes any non-default properties to ~/.atom/config.json", ->
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.json")
atom.config.set("a.b.c", 1)
atom.config.set("a.b.d", 2)
atom.config.set("x.y.z", 3)
atom.config.setDefaults("a.b", e: 4, f: 5)
it "writes properties from the user config path source to the user config path", ->
atom.config.configFilePath = "/fake/config/path"
atom.config.set("a.b.c", 1)
atom.config.set("a.b.d", 2)
atom.config.set("x.y.z", 3)
atom.config.set("x.y.q", 3, source: "/not/user/config")
atom.config.set('foo.bar', 'ruby', scopeSelector: '.source.ruby')
atom.config.set('foo.omg', 'wow', scopeSelector: '.source.ruby')
atom.config.set('foo.bar', 'coffee', scopeSelector: '.source.coffee')
CSON.writeFileSync.reset()
atom.config.save()
atom.config.setDefaults("a.b", e: 4, f: 5)
expect(CSON.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.json"))
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
expect(writtenConfig).toEqual global: atom.config.settings
CSON.writeFileSync.reset()
atom.config.save()
describe "when ~/.atom/config.json doesn't exist", ->
it "writes any non-default properties to ~/.atom/config.cson", ->
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
atom.config.set("a.b.c", 1)
atom.config.set("a.b.d", 2)
atom.config.set("x.y.z", 3)
atom.config.setDefaults("a.b", e: 4, f: 5)
CSON.writeFileSync.reset()
atom.config.save()
expect(CSON.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.cson"))
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
expect(writtenConfig).toEqual global: atom.config.settings
describe "when scoped settings are defined", ->
it 'writes out explicitly set config settings', ->
atom.config.set('.source.ruby', 'foo.bar', 'ruby')
atom.config.set('.source.ruby', 'foo.omg', 'wow')
atom.config.set('.source.coffee', 'foo.bar', 'coffee')
CSON.writeFileSync.reset()
atom.config.save()
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
expect(writtenConfig).toEqualJson
global:
atom.config.settings
'.ruby.source':
foo:
bar: 'ruby'
omg: 'wow'
'.coffee.source':
foo:
bar: 'coffee'
expect(CSON.writeFileSync.argsForCall[0][0]).toBe atom.config.getUserConfigPath()
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
global.debug = true
expect(writtenConfig).toEqual
'global':
a: b:
c: 1
d: 2
x: y: z: 3
'.ruby.source':
foo:
bar: 'ruby'
omg: 'wow'
'.coffee.source':
foo:
bar: 'coffee'
describe ".setDefaults(keyPath, defaults)", ->
it "assigns any previously-unassigned keys to the object at the key path", ->
@@ -406,17 +470,26 @@ describe "Config", ->
it "fires the callback every time the observed value changes", ->
observeHandler.reset() # clear the initial call
atom.config.set('foo.bar.baz', "value 2")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1', keyPath: 'foo.bar.baz'})
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1'})
observeHandler.reset()
atom.config.set('foo.bar.baz', "value 1")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2', keyPath: 'foo.bar.baz'})
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2'})
observeHandler.reset()
atom.config.set('foo.bar', {baz: "value 3"})
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 3', oldValue: 'value 1'})
observeHandler.reset()
atom.config.set('foo.bar', null)
expect(observeHandler).toHaveBeenCalledWith({newValue: undefined, oldValue: 'value 3'})
observeHandler.reset()
describe 'when a keyPath is not specified', ->
beforeEach ->
observeHandler = jasmine.createSpy("observeHandler")
atom.config.set("foo.bar.baz", "value 1")
observeSubscription = atom.config.onDidChange observeHandler
atom.config.set("foo", bar: baz: "value 1")
observeSubscription = atom.config.onDidChange(observeHandler)
it "does not fire the given callback initially", ->
expect(observeHandler).not.toHaveBeenCalled()
@@ -424,15 +497,22 @@ describe "Config", ->
it "fires the callback every time any value changes", ->
observeHandler.reset() # clear the initial call
atom.config.set('foo.bar.baz', "value 2")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1', keyPath: 'foo.bar.baz'})
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe("value 2")
expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe("value 1")
observeHandler.reset()
atom.config.set('foo.bar.baz', "value 1")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2', keyPath: 'foo.bar.baz'})
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe("value 1")
expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe("value 2")
observeHandler.reset()
atom.config.set('foo.bar.int', 1)
expect(observeHandler).toHaveBeenCalledWith({newValue: 1, oldValue: undefined, keyPath: 'foo.bar.int'})
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.int).toBe(1)
expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.int).toBe(undefined)
describe ".observe(keyPath)", ->
[observeHandler, observeSubscription] = []
@@ -440,7 +520,7 @@ describe "Config", ->
beforeEach ->
observeHandler = jasmine.createSpy("observeHandler")
atom.config.set("foo.bar.baz", "value 1")
observeSubscription = atom.config.observe "foo.bar.baz", observeHandler
observeSubscription = atom.config.observe("foo.bar.baz", observeHandler)
it "fires the given callback with the current value at the keypath", ->
expect(observeHandler).toHaveBeenCalledWith("value 1")
@@ -453,6 +533,25 @@ describe "Config", ->
atom.config.set('foo.bar.baz', "value 1")
expect(observeHandler).toHaveBeenCalledWith("value 1")
observeHandler.reset()
atom.config.set('foo.bar', {baz: "value 3"})
expect(observeHandler).toHaveBeenCalledWith("value 3")
observeHandler.reset()
atom.config.set('foo.bar', null)
expect(observeHandler).toHaveBeenCalledWith(undefined)
observeHandler.reset()
atom.config.set('foo.bar.baz.quux', "value 4")
expect(observeHandler).toHaveBeenCalledWith({quux: "value 4"})
atom.config.set('foo.bar.baz.buzz', "value 5")
expect(observeHandler).toHaveBeenCalledWith({quux: "value 4", buzz: "value 5"})
observeHandler.reset()
atom.config.loadUserConfig()
expect(observeHandler).toHaveBeenCalledWith(undefined)
it "fires the callback when the observed value is deleted", ->
observeHandler.reset() # clear the initial call
@@ -482,6 +581,51 @@ describe "Config", ->
atom.config.set('foo.bar.baz', "value 10")
expect(bazCatHandler).not.toHaveBeenCalled()
describe "observing scoped settings", ->
otherHandler = null
beforeEach ->
observeSubscription.dispose()
otherHandler = jasmine.createSpy('otherHandler')
it "allows settings to be observed in a specific scope", ->
atom.config.observe("foo.bar.baz", scope: [".some.scope"], observeHandler)
atom.config.observe("foo.bar.baz", scope: [".another.scope"], otherHandler)
atom.config.set('foo.bar.baz', "value 2", scopeSelector: ".some")
expect(observeHandler).toHaveBeenCalledWith("value 2")
expect(otherHandler).not.toHaveBeenCalledWith("value 2")
it "deprecates using a scope descriptor as the first argument", ->
spyOn(Grim, 'deprecate')
atom.config.observe([".some.scope"], "foo.bar.baz", observeHandler)
atom.config.observe([".another.scope"], "foo.bar.baz", otherHandler)
expect(Grim.deprecate).toHaveBeenCalled()
atom.config.set('foo.bar.baz', "value 2", scopeSelector: ".some")
expect(observeHandler).toHaveBeenCalledWith("value 2")
expect(otherHandler).not.toHaveBeenCalledWith("value 2")
describe ".transact(callback)", ->
changeSpy = null
beforeEach ->
changeSpy = jasmine.createSpy('onDidChange callback')
atom.config.onDidChange("foo.bar.baz", changeSpy)
it "allows only one change event for the duration of the given callback", ->
atom.config.transact ->
atom.config.set("foo.bar.baz", 1)
atom.config.set("foo.bar.baz", 2)
atom.config.set("foo.bar.baz", 3)
expect(changeSpy.callCount).toBe(1)
expect(changeSpy.argsForCall[0][0]).toEqual(newValue: 3, oldValue: undefined)
it "does not emit an event if no changes occur while paused", ->
atom.config.transact ->
expect(changeSpy).not.toHaveBeenCalled()
describe ".initializeConfigDirectory()", ->
beforeEach ->
if fs.existsSync(dotAtomPath)
@@ -514,6 +658,15 @@ describe "Config", ->
atom.config.configDirPath = dotAtomPath
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
atom.config.setSchema 'foo',
type: 'object'
properties:
bar:
type: 'string'
default: 'def'
int:
type: 'integer'
default: 12
afterEach ->
fs.removeSync(dotAtomPath)
@@ -533,7 +686,7 @@ describe "Config", ->
it "updates the config data based on the file contents", ->
expect(atom.config.get("foo.bar")).toBe 'baz'
expect(atom.config.get(['.source.ruby'], "foo.bar")).toBe 'more-specific'
expect(atom.config.get("foo.bar", scope: ['.source.ruby'])).toBe 'more-specific'
describe "when the config file contains valid cson", ->
beforeEach ->
@@ -571,43 +724,42 @@ describe "Config", ->
expect(fs.existsSync(atom.config.configFilePath)).toBe true
expect(CSON.readFileSync(atom.config.configFilePath)).toEqual {}
describe "when a schema is specified", ->
describe "when the config file contains values that do not adhere to the schema", ->
warnSpy = null
beforeEach ->
schema =
type: 'object'
properties:
bar:
type: 'string'
default: 'def'
int:
type: 'integer'
default: 12
warnSpy = spyOn console, 'warn'
fs.writeFileSync atom.config.configFilePath, """
foo:
bar: 'baz'
int: 'bad value'
"""
atom.config.loadUserConfig()
atom.config.setSchema('foo', schema)
it "updates the only the settings that have values matching the schema", ->
expect(atom.config.get("foo.bar")).toBe 'baz'
expect(atom.config.get("foo.int")).toBe 12
describe "when the config file contains values that do not adhere to the schema", ->
warnSpy = null
beforeEach ->
warnSpy = spyOn console, 'warn'
fs.writeFileSync atom.config.configFilePath, """
foo:
bar: 'baz'
int: 'bad value'
"""
atom.config.loadUserConfig()
it "updates the only the settings that have values matching the schema", ->
expect(atom.config.get("foo.bar")).toBe 'baz'
expect(atom.config.get("foo.int")).toBe 12
expect(warnSpy).toHaveBeenCalled()
expect(warnSpy.mostRecentCall.args[0]).toContain "'foo.int' could not be set"
expect(warnSpy).toHaveBeenCalled()
expect(warnSpy.mostRecentCall.args[0]).toContain "foo.int"
describe ".observeUserConfig()", ->
updatedHandler = null
beforeEach ->
atom.config.setDefaults('foo', bar: 'def')
atom.config.setSchema 'foo',
type: 'object'
properties:
bar:
type: 'string'
default: 'def'
baz:
type: 'string'
scoped:
type: 'boolean'
int:
type: 'integer'
default: 12
atom.config.configDirPath = dotAtomPath
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
@@ -640,32 +792,38 @@ describe "Config", ->
it "does not fire a change event for paths that did not change", ->
atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy()
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: 'baz', omg: 'ok'}")
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: 'baz', baz: 'ok'}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(noChangeSpy).not.toHaveBeenCalled()
expect(atom.config.get('foo.bar')).toBe 'baz'
expect(atom.config.get('foo.omg')).toBe 'ok'
expect(atom.config.get('foo.baz')).toBe 'ok'
describe 'when the default value is a complex value', ->
beforeEach ->
atom.config.setSchema 'foo.bar',
type: 'array'
items:
type: 'string'
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok']}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs -> updatedHandler.reset()
it "does not fire a change event for paths that did not change", ->
atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy()
noChangeSpy = jasmine.createSpy()
atom.config.onDidChange('foo.bar', noChangeSpy)
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok'], omg: 'another'}")
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok'], baz: 'another'}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(noChangeSpy).not.toHaveBeenCalled()
expect(atom.config.get('foo.bar')).toEqual ['baz', 'ok']
expect(atom.config.get('foo.omg')).toBe 'another'
expect(atom.config.get('foo.baz')).toBe 'another'
describe 'when scoped settings are used', ->
it "fires a change event for scoped settings that are removed", ->
atom.config.onDidChange ['.source.ruby'], 'foo.scoped', scopedSpy = jasmine.createSpy()
scopedSpy = jasmine.createSpy()
atom.config.onDidChange('foo.scoped', scope: ['.source.ruby'], scopedSpy)
fs.writeFileSync atom.config.configFilePath, """
global:
@@ -675,10 +833,11 @@ describe "Config", ->
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(scopedSpy).toHaveBeenCalled()
expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe false
expect(atom.config.get('foo.scoped', scope: ['.source.ruby'])).toBe false
it "does not fire a change event for paths that did not change", ->
atom.config.onDidChange ['.source.ruby'], 'foo.scoped', noChangeSpy = jasmine.createSpy()
noChangeSpy = jasmine.createSpy()
atom.config.onDidChange('foo.scoped', scope: ['.source.ruby'], noChangeSpy)
fs.writeFileSync atom.config.configFilePath, """
global:
@@ -691,8 +850,8 @@ describe "Config", ->
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(noChangeSpy).not.toHaveBeenCalled()
expect(atom.config.get(['.source.ruby'], 'foo.bar')).toBe 'baz'
expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe true
expect(atom.config.get('foo.bar', scope: ['.source.ruby'])).toBe 'baz'
expect(atom.config.get('foo.scoped', scope: ['.source.ruby'])).toBe true
describe "when the config file changes to omit a setting with a default", ->
it "resets the setting back to the default", ->
@@ -1095,8 +1254,8 @@ describe "Config", ->
it 'it respects the scoped defaults', ->
expect(atom.config.get('foo.bar.str')).toBe 'ok'
expect(atom.config.get(['.source.js'], 'foo.bar.str')).toBe 'omg'
expect(atom.config.get(['.source.coffee'], 'foo.bar.str')).toBe 'ok'
expect(atom.config.get('foo.bar.str', scope: ['.source.js'])).toBe 'omg'
expect(atom.config.get('foo.bar.str', scope: ['.source.coffee'])).toBe 'ok'
describe "scoped settings", ->
describe ".get(scopeDescriptor, keyPath)", ->
@@ -1105,29 +1264,29 @@ describe "Config", ->
atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22)
atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11)
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
expect(atom.config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBe 22
expect(atom.config.get([".source.js", ".variable.assignment.js"], "foo.bar.baz")).toBe 11
expect(atom.config.get([".text"], "foo.bar.baz")).toBeUndefined()
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42
expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".string.quoted.double.js"])).toBe 22
expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".variable.assignment.js"])).toBe 11
expect(atom.config.get("foo.bar.baz", scope: [".text"])).toBeUndefined()
it "favors the most recently added properties in the event of a specificity tie", ->
atom.config.addScopedSettings("config", ".source.coffee .string.quoted.single", foo: bar: baz: 42)
atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double", foo: bar: baz: 22)
expect(atom.config.get([".source.coffee", ".string.quoted.single"], "foo.bar.baz")).toBe 42
expect(atom.config.get([".source.coffee", ".string.quoted.single.double"], "foo.bar.baz")).toBe 22
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.single"])).toBe 42
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.single.double"])).toBe 22
describe 'when there are global defaults', ->
it 'falls back to the global when there is no scoped property specified', ->
atom.config.setDefaults("foo", hasDefault: 'ok')
expect(atom.config.get([".source.coffee", ".string.quoted.single"], "foo.hasDefault")).toBe 'ok'
expect(atom.config.get("foo.hasDefault", scope: [".source.coffee", ".string.quoted.single"])).toBe 'ok'
describe 'setting priority', ->
describe 'when package settings are added after user settings', ->
it "returns the user's setting because the user's setting has higher priority", ->
atom.config.set(".source.coffee", "foo.bar.baz", 100)
atom.config.set("foo.bar.baz", 100, scopeSelector: ".source.coffee")
atom.config.addScopedSettings("some-package", ".source.coffee", foo: bar: baz: 1)
expect(atom.config.get([".source.coffee"], "foo.bar.baz")).toBe 100
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee"])).toBe 100
describe ".set(scope, keyPath, value)", ->
it "sets the value and overrides the others", ->
@@ -1135,10 +1294,10 @@ describe "Config", ->
atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22)
atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11)
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42
expect(atom.config.set(".source.coffee .string.quoted.double.coffee", "foo.bar.baz", 100)).toBe true
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 100
expect(atom.config.set("foo.bar.baz", 100, scopeSelector: ".source.coffee .string.quoted.double.coffee")).toBe true
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 100
describe ".removeScopedSettingsForName(name)", ->
it "allows properties to be removed by name", ->
@@ -1146,12 +1305,13 @@ describe "Config", ->
disposable2 = atom.config.addScopedSettings("b", ".source .string.quoted.double", foo: bar: baz: 22)
disposable2.dispose()
expect(atom.config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBeUndefined()
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".string.quoted.double.js"])).toBeUndefined()
expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42
describe ".observe(scopeDescriptor, keyPath)", ->
it 'calls the supplied callback when the value at the descriptor/keypath changes', ->
atom.config.observe [".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz", changeSpy = jasmine.createSpy()
changeSpy = jasmine.createSpy()
atom.config.observe("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"], changeSpy)
expect(changeSpy).toHaveBeenCalledWith(undefined)
changeSpy.reset()
@@ -1182,28 +1342,59 @@ describe "Config", ->
describe ".onDidChange(scopeDescriptor, keyPath)", ->
it 'calls the supplied callback when the value at the descriptor/keypath changes', ->
keyPath = "foo.bar.baz"
atom.config.onDidChange [".source.coffee", ".string.quoted.double.coffee"], keyPath, changeSpy = jasmine.createSpy()
changeSpy = jasmine.createSpy('onDidChange callback')
atom.config.onDidChange keyPath, scope: [".source.coffee", ".string.quoted.double.coffee"], changeSpy
atom.config.set("foo.bar.baz", 12)
expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12, keyPath})
expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12})
changeSpy.reset()
disposable1 = atom.config.addScopedSettings("a", ".source .string.quoted.double", foo: bar: baz: 22)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22, keyPath})
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22})
changeSpy.reset()
disposable2 = atom.config.addScopedSettings("b", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42, keyPath})
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42})
changeSpy.reset()
disposable2.dispose()
expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22, keyPath})
expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22})
changeSpy.reset()
disposable1.dispose()
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12, keyPath})
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12})
changeSpy.reset()
atom.config.set("foo.bar.baz", undefined)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined, keyPath})
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined})
changeSpy.reset()
it 'deprecates using a scope descriptor as an optional first argument', ->
keyPath = "foo.bar.baz"
spyOn(Grim, 'deprecate')
atom.config.onDidChange [".source.coffee", ".string.quoted.double.coffee"], keyPath, changeSpy = jasmine.createSpy()
expect(Grim.deprecate).toHaveBeenCalled()
atom.config.set("foo.bar.baz", 12)
expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12})
changeSpy.reset()
disposable1 = atom.config.addScopedSettings("a", ".source .string.quoted.double", foo: bar: baz: 22)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22})
changeSpy.reset()
disposable2 = atom.config.addScopedSettings("b", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42})
changeSpy.reset()
disposable2.dispose()
expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22})
changeSpy.reset()
disposable1.dispose()
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12})
changeSpy.reset()
atom.config.set("foo.bar.baz", undefined)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined})
changeSpy.reset()
+6 -6
Ver Arquivo
@@ -367,7 +367,7 @@ describe "PackageManager", ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a'
describe "converted textmate packages", ->
it "loads the package's grammars", ->
@@ -380,13 +380,13 @@ describe "PackageManager", ->
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Ruby"
it "loads the translated scoped properties", ->
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBe '# '
expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBe '# '
describe "::deactivatePackage(id)", ->
afterEach ->
@@ -493,9 +493,9 @@ describe "PackageManager", ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a'
atom.packages.deactivatePackage("package-with-scoped-properties")
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBeUndefined()
describe "textmate packages", ->
it "removes the package's grammars", ->
@@ -515,7 +515,7 @@ describe "PackageManager", ->
runs ->
atom.packages.deactivatePackage('language-ruby')
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBeUndefined()
describe "::activate()", ->
packageActivator = null
+94
Ver Arquivo
@@ -0,0 +1,94 @@
ChildProcess = require 'child_process'
{EventEmitter} = require 'events'
fs = require 'fs-plus'
path = require 'path'
temp = require 'temp'
SquirrelUpdate = require '../src/browser/squirrel-update'
describe "Windows squirrel updates", ->
tempHomeDirectory = null
beforeEach ->
# Prevent the actually home directory from being manipulated
tempHomeDirectory = temp.mkdirSync('atom-temp-home-')
spyOn(fs, 'getHomeDirectory').andReturn(tempHomeDirectory)
# Prevent any commands from actually running and affecting the host
originalSpawn = ChildProcess.spawn
spyOn(ChildProcess, 'spawn').andCallFake (command, args) ->
if path.basename(command) is 'Update.exe' and args?[0] is '--createShortcut'
fs.writeFileSync(path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk'), '')
# Just spawn something that won't actually modify the host
if process.platform is 'win32'
originalSpawn('dir')
else
originalSpawn('ls')
it "quits the app on all squirrel events", ->
app = quit: jasmine.createSpy('quit')
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-install')).toBe true
waitsFor ->
app.quit.callCount is 1
runs ->
app.quit.reset()
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated')).toBe true
waitsFor ->
app.quit.callCount is 1
runs ->
app.quit.reset()
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-uninstall')).toBe true
waitsFor ->
app.quit.callCount is 1
runs ->
app.quit.reset()
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-obsolete')).toBe true
waitsFor ->
app.quit.callCount is 1
runs ->
expect(SquirrelUpdate.handleStartupEvent(app, '--not-squirrel')).toBe false
it "keeps the desktop shortcut deleted on updates if it was previously deleted after install", ->
desktopShortcutPath = path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk')
expect(fs.existsSync(desktopShortcutPath)).toBe false
app = quit: jasmine.createSpy('quit')
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-install')).toBe true
waitsFor ->
app.quit.callCount is 1
runs ->
app.quit.reset()
expect(fs.existsSync(desktopShortcutPath)).toBe true
fs.removeSync(desktopShortcutPath)
expect(fs.existsSync(desktopShortcutPath)).toBe false
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated')).toBe true
waitsFor ->
app.quit.callCount is 1
runs ->
expect(fs.existsSync(desktopShortcutPath)).toBe false
describe ".restartAtom", ->
it "quits the app and spawns a new one", ->
app = new EventEmitter()
app.quit = jasmine.createSpy('quit')
SquirrelUpdate.restartAtom(app)
expect(app.quit.callCount).toBe 1
expect(ChildProcess.spawn.callCount).toBe 0
app.emit('will-quit')
expect(ChildProcess.spawn.callCount).toBe 1
expect(path.basename(ChildProcess.spawn.argsForCall[0][0])).toBe 'atom.cmd'
+54 -29
Ver Arquivo
@@ -1612,6 +1612,22 @@ describe "TextEditorComponent", ->
expect(nextAnimationFrame).toBe noAnimationFrame
expect(editor.getSelectedScreenRange()).toEqual [[2, 4], [6, 8]]
describe "when the editor is destroyed while dragging", ->
it "cleans up the handlers for window.mouseup and window.mousemove", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([2, 4]), which: 1))
linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([6, 8]), which: 1))
nextAnimationFrame()
spyOn(window, 'removeEventListener').andCallThrough()
linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([6, 10]), which: 1))
editor.destroy()
nextAnimationFrame()
call.args.pop() for call in window.removeEventListener.calls
expect(window.removeEventListener).toHaveBeenCalledWith('mouseup')
expect(window.removeEventListener).toHaveBeenCalledWith('mousemove')
describe "when a line is folded", ->
beforeEach ->
editor.foldBufferRow 4
@@ -2577,9 +2593,9 @@ describe "TextEditorComponent", ->
describe 'soft wrap settings', ->
beforeEach ->
atom.config.set '.source.coffee', 'editor.softWrap', true
atom.config.set '.source.coffee', 'editor.preferredLineLength', 17
atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', true
atom.config.set 'editor.softWrap', true, scopeSelector: '.source.coffee'
atom.config.set 'editor.preferredLineLength', 17, scopeSelector: '.source.coffee'
atom.config.set 'editor.softWrapAtPreferredLineLength', true, scopeSelector: '.source.coffee'
editor.setEditorWidthInChars(20)
coffeeEditor.setEditorWidthInChars(20)
@@ -2589,18 +2605,18 @@ describe "TextEditorComponent", ->
expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items '
it 'updates the wrapped lines when editor.preferredLineLength changes', ->
atom.config.set '.source.coffee', 'editor.preferredLineLength', 20
atom.config.set 'editor.preferredLineLength', 20, scopeSelector: '.source.coffee'
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if '
it 'updates the wrapped lines when editor.softWrapAtPreferredLineLength changes', ->
atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', false
atom.config.set 'editor.softWrapAtPreferredLineLength', false, scopeSelector: '.source.coffee'
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if '
it 'updates the wrapped lines when editor.softWrap changes', ->
atom.config.set '.source.coffee', 'editor.softWrap', false
atom.config.set 'editor.softWrap', false, scopeSelector: '.source.coffee'
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if items.length <= 1'
atom.config.set '.source.coffee', 'editor.softWrap', true
atom.config.set 'editor.softWrap', true, scopeSelector: '.source.coffee'
expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items '
it 'updates the wrapped lines when the grammar changes', ->
@@ -2628,11 +2644,11 @@ describe "TextEditorComponent", ->
tab: 'F'
cr: 'E'
atom.config.set '.source.js', 'editor.showInvisibles', true
atom.config.set '.source.js', 'editor.invisibles', jsInvisibles
atom.config.set 'editor.showInvisibles', true, scopeSelector: '.source.js'
atom.config.set 'editor.invisibles', jsInvisibles, scopeSelector: '.source.js'
atom.config.set '.source.coffee', 'editor.showInvisibles', false
atom.config.set '.source.coffee', 'editor.invisibles', coffeeInvisibles
atom.config.set 'editor.showInvisibles', false, scopeSelector: '.source.coffee'
atom.config.set 'editor.invisibles', coffeeInvisibles, scopeSelector: '.source.coffee'
editor.setText " a line with tabs\tand spaces \n"
nextAnimationFrame()
@@ -2648,7 +2664,7 @@ describe "TextEditorComponent", ->
it "re-renders the invisibles when the invisible settings change", ->
jsGrammar = editor.getGrammar()
editor.setGrammar(coffeeEditor.getGrammar())
atom.config.set '.source.coffee', 'editor.showInvisibles', true
atom.config.set 'editor.showInvisibles', true, scopeSelector: '.source.coffee'
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{coffeeInvisibles.space}a line with tabs#{coffeeInvisibles.tab}and spaces#{coffeeInvisibles.space}#{coffeeInvisibles.eol}"
@@ -2657,7 +2673,7 @@ describe "TextEditorComponent", ->
space: 'E'
tab: 'W'
cr: 'I'
atom.config.set '.source.coffee', 'editor.invisibles', newInvisibles
atom.config.set 'editor.invisibles', newInvisibles, scopeSelector: '.source.coffee'
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{newInvisibles.space}a line with tabs#{newInvisibles.tab}and spaces#{newInvisibles.space}#{newInvisibles.eol}"
@@ -2667,8 +2683,8 @@ describe "TextEditorComponent", ->
describe 'editor.showIndentGuide', ->
beforeEach ->
atom.config.set '.source.js', 'editor.showIndentGuide', true
atom.config.set '.source.coffee', 'editor.showIndentGuide', false
atom.config.set 'editor.showIndentGuide', true, scopeSelector: '.source.js'
atom.config.set 'editor.showIndentGuide', false, scopeSelector: '.source.coffee'
it "has an 'indent-guide' class when scoped editor.showIndentGuide is true, but not when scoped editor.showIndentGuide is false", ->
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
@@ -2689,7 +2705,7 @@ describe "TextEditorComponent", ->
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
atom.config.set '.source.js', 'editor.showIndentGuide', false
atom.config.set 'editor.showIndentGuide', false, scopeSelector: '.source.js'
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
expect(line1LeafNodes[0].textContent).toBe ' '
@@ -2697,26 +2713,35 @@ describe "TextEditorComponent", ->
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
describe "middle mouse paste on Linux", ->
it "pastes the previously selected text", ->
originalPlatform = null
beforeEach ->
originalPlatform = process.platform
Object.defineProperty process, 'platform', value: 'linux'
afterEach ->
Object.defineProperty process, 'platform', value: originalPlatform
it "pastes the previously selected text at the clicked location", ->
jasmine.unspy(window, 'setTimeout')
clipboardWrittenTo = false
spyOn(require('ipc'), 'send').andCallFake (eventName, selectedText) ->
if eventName is 'write-text-to-selection-clipboard'
require('clipboard').writeText(selectedText, 'selection')
clipboardWrittenTo = true
atom.clipboard.write('')
component.listenForMiddleMousePaste()
editor.setCursorBufferPosition([10, 0])
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', which: 2))
expect(atom.clipboard.read()).toBe ''
expect(editor.lineTextForBufferRow(10)).toBe ''
component.trackSelectionClipboard()
editor.setSelectedBufferRange([[1, 6], [1, 10]])
editor.setCursorBufferPosition([10, 0])
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', which: 2))
expect(atom.clipboard.read()).toBe 'sort'
expect(editor.lineTextForBufferRow(10)).toBe 'sort'
waitsFor ->
clipboardWrittenTo
runs ->
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([10, 0]), button: 1))
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenPosition([10, 0]), which: 2))
expect(atom.clipboard.read()).toBe 'sort'
expect(editor.lineTextForBufferRow(10)).toBe 'sort'
buildMouseEvent = (type, properties...) ->
properties = extend({bubbles: true, cancelable: true}, properties...)
+25
Ver Arquivo
@@ -32,6 +32,31 @@ describe "TextEditorElement", ->
element.setModel(model)
expect(element.hasAttribute('mini')).toBe true
describe "when the editor is attached to the DOM", ->
describe "when the editor.useShadowDOM config option is true", ->
it "mounts the react component and unmounts when removed from the dom", ->
atom.config.set('editor.useShadowDOM', true)
element = new TextEditorElement
jasmine.attachToDOM(element)
component = element.component
expect(component.isMounted()).toBe true
element.getModel().destroy()
expect(component.isMounted()).toBe false
describe "when the editor.useShadowDOM config option is false", ->
it "mounts the react component and unmounts when removed from the dom", ->
atom.config.set('editor.useShadowDOM', false)
element = new TextEditorElement
jasmine.attachToDOM(element)
component = element.component
expect(component.isMounted()).toBe true
element.getModel().destroy()
expect(component.isMounted()).toBe false
describe "focus and blur handling", ->
describe "when the editor.useShadowDOM config option is true", ->
it "proxies focus/blur events to/from the hidden input inside the shadow root", ->
+6 -6
Ver Arquivo
@@ -1327,7 +1327,7 @@ describe "TextEditor", ->
coffeeEditor.selectWordsContainingCursors()
expect(coffeeEditor.getSelectedBufferRange()).toEqual [[0, 6], [0, 15]]
atom.config.set '.source.coffee', 'editor.nonWordCharacters', 'qusort'
atom.config.set 'editor.nonWordCharacters', 'qusort', scopeSelector: '.source.coffee'
coffeeEditor.setCursorBufferPosition [0, 9]
coffeeEditor.selectWordsContainingCursors()
@@ -3276,7 +3276,7 @@ describe "TextEditor", ->
atom.packages.unloadPackages()
it 'returns correct values based on the scope of the set grammars', ->
atom.config.set '.source.coffee', 'editor.tabLength', 6
atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.coffee'
expect(editor.getTabLength()).toBe 2
expect(coffeeEditor.getTabLength()).toBe 6
@@ -3298,12 +3298,12 @@ describe "TextEditor", ->
expect(editor.getTabLength()).toBe 2
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
atom.config.set '.source.js', 'editor.tabLength', 6
atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.js'
expect(editor.getTabLength()).toBe 6
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 6
it 'updates the tab length when the grammar changes', ->
atom.config.set '.source.coffee', 'editor.tabLength', 6
atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.coffee'
expect(editor.getTabLength()).toBe 2
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
@@ -3473,8 +3473,8 @@ describe "TextEditor", ->
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
runs ->
atom.config.set('.source.js', 'editor.autoIndent', true)
atom.config.set('.source.coffee', 'editor.autoIndent', false)
atom.config.set('editor.autoIndent', true, scopeSelector: '.source.js')
atom.config.set('editor.autoIndent', false, scopeSelector: '.source.coffee')
afterEach: ->
atom.packages.deactivatePackages()
+4
Ver Arquivo
@@ -341,6 +341,10 @@ class Atom extends Model
inDevMode: ->
@getLoadSettings().devMode
# Public: Is the current window in safe mode?
inSafeMode: ->
@getLoadSettings().safeMode
# Public: Is the current window running specs?
inSpecMode: ->
@getLoadSettings().isSpec
+8 -4
Ver Arquivo
@@ -140,14 +140,18 @@ class AtomApplication
# Registers basic application commands, non-idempotent.
handleEvents: ->
getLoadSettings = =>
devMode: @focusedWindow()?.devMode
safeMode: @focusedWindow()?.safeMode
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode)
@on 'application:run-benchmarks', -> @runBenchmarks()
@on 'application:quit', -> app.quit()
@on 'application:new-window', -> @openPath(windowDimensions: @focusedWindow()?.getDimensions())
@on 'application:new-window', -> @openPath(_.extend(windowDimensions: @focusedWindow()?.getDimensions(), getLoadSettings()))
@on 'application:new-file', -> (@focusedWindow() ? this).openPath()
@on 'application:open', -> @promptForPath(type: 'all')
@on 'application:open-file', -> @promptForPath(type: 'file')
@on 'application:open-folder', -> @promptForPath(type: 'folder')
@on 'application:open', -> @promptForPath(_.extend(type: 'all', getLoadSettings()))
@on 'application:open-file', -> @promptForPath(_.extend(type: 'file', getLoadSettings()))
@on 'application:open-folder', -> @promptForPath(_.extend(type: 'folder', getLoadSettings()))
@on 'application:open-dev', -> @promptForPath(devMode: true)
@on 'application:open-safe', -> @promptForPath(safeMode: true)
@on 'application:inspect', ({x,y, atomWindow}) ->
+3 -1
Ver Arquivo
@@ -18,7 +18,7 @@ class AtomWindow
isSpec: null
constructor: (settings={}) ->
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode} = settings
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings
# Normalize to make sure drive letter case is consistent on Windows
@resourcePath = path.normalize(@resourcePath) if @resourcePath
@@ -38,6 +38,8 @@ class AtomWindow
loadSettings.windowState ?= '{}'
loadSettings.appVersion = app.getVersion()
loadSettings.resourcePath = @resourcePath
loadSettings.devMode ?= false
loadSettings.safeMode ?= false
# Only send to the first non-spec window created
if @constructor.includeShellLoadTime and not @isSpec
+1 -1
Ver Arquivo
@@ -9,7 +9,7 @@ class AutoUpdater
quitAndInstall: ->
if SquirrelUpdate.existsSync()
SquirrelUpdate.restartAtom()
SquirrelUpdate.restartAtom(require('app'))
else
require('auto-updater').quitAndInstall()
+2 -1
Ver Arquivo
@@ -26,7 +26,8 @@ fs.lstatSyncNoException = (pathToStat) ->
start = ->
if process.platform is 'win32'
SquirrelUpdate = require './squirrel-update'
return if SquirrelUpdate.handleStartupEvent()
squirrelCommand = process.argv[1]
return if SquirrelUpdate.handleStartupEvent(app, squirrelCommand)
args = parseCommandLine()
+34 -10
Ver Arquivo
@@ -1,4 +1,3 @@
app = require 'app'
ChildProcess = require 'child_process'
fs = require 'fs-plus'
path = require 'path'
@@ -166,12 +165,29 @@ removeCommandsFromPath = (callback) ->
# Create a desktop and start menu shortcut by using the command line API
# provided by Squirrel's Update.exe
createShortcut = (callback) ->
createShortcuts = (callback) ->
spawnUpdate(['--createShortcut', exeName], callback)
# Update the desktop and start menu shortcuts by using the command line API
# provided by Squirrel's Update.exe
updateShortcuts = (callback) ->
if homeDirectory = fs.getHomeDirectory()
desktopShortcutPath = path.join(homeDirectory, 'Desktop', 'Atom.lnk')
# Check if the desktop shortcut has been previously deleted and
# and keep it deleted if it was
fs.exists desktopShortcutPath, (desktopShortcutExists) ->
createShortcuts ->
if desktopShortcutExists
callback()
else
# Remove the unwanted desktop shortcut that was recreated
fs.unlink(desktopShortcutPath, callback)
else
createShortcuts(callback)
# Remove the desktop and start menu shortcuts by using the command line API
# provided by Squirrel's Update.exe
removeShortcut = (callback) ->
removeShortcuts = (callback) ->
spawnUpdate(['--removeShortcut', exeName], callback)
exports.spawn = spawnUpdate
@@ -181,21 +197,29 @@ exports.existsSync = ->
fs.existsSync(updateDotExe)
# Restart Atom using the version pointed to by the atom.cmd shim
exports.restartAtom = ->
app.once 'will-quit', -> spawn(path.join(binFolder, 'atom.cmd'))
exports.restartAtom = (app) ->
if projectPath = global.atomApplication?.lastFocusedWindow?.projectPath
args = [projectPath]
app.once 'will-quit', -> spawn(path.join(binFolder, 'atom.cmd'), args)
app.quit()
# Handle squirrel events denoted by --squirrel-* command line arguments.
exports.handleStartupEvent = ->
switch process.argv[1]
when '--squirrel-install', '--squirrel-updated'
createShortcut ->
exports.handleStartupEvent = (app, squirrelCommand) ->
switch squirrelCommand
when '--squirrel-install'
createShortcuts ->
installContextMenu ->
addCommandsToPath ->
app.quit()
true
when '--squirrel-updated'
updateShortcuts ->
installContextMenu ->
addCommandsToPath ->
app.quit()
true
when '--squirrel-uninstall'
removeShortcut ->
removeShortcuts ->
uninstallContextMenu ->
removeCommandsFromPath ->
app.quit()
+20 -4
Ver Arquivo
@@ -47,12 +47,12 @@ class BufferedProcess
@emitter = new Emitter
options ?= {}
# Related to joyent/node#2318
if process.platform is "win32"
if process.platform is 'win32'
# Quote all arguments and escapes inner quotes
if args?
cmdArgs = args.filter (arg) -> arg?
cmdArgs = cmdArgs.map (arg) ->
if command in ['explorer.exe', 'explorer'] and /^\/[a-zA-Z]+,.*$/.test(arg)
cmdArgs = cmdArgs.map (arg) =>
if @isExplorerCommand(command) and /^\/[a-zA-Z]+,.*$/.test(arg)
# Don't wrap /root,C:\folder style arguments to explorer calls in
# quotes since they will not be interpreted correctly if they are
arg
@@ -67,7 +67,7 @@ class BufferedProcess
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
cmdOptions = _.clone(options)
cmdOptions.windowsVerbatimArguments = true
@process = ChildProcess.spawn(process.env.comspec or 'cmd.exe', cmdArgs, cmdOptions)
@process = ChildProcess.spawn(@getCmdPath(), cmdArgs, cmdOptions)
else
@process = ChildProcess.spawn(command, args, options)
@killed = false
@@ -191,6 +191,22 @@ class BufferedProcess
@process?.kill()
@process = null
isExplorerCommand: (command) ->
if command is 'explorer.exe' or command is 'explorer'
true
else if process.env.SystemRoot
command is path.join(process.env.SystemRoot, 'explorer.exe') or command is path.join(process.env.SystemRoot, 'explorer')
else
false
getCmdPath: ->
if process.env.comspec
process.env.compec
else if process.env.SystemRoot
path.join(process.env.SystemRoot, 'System32', 'cmd.exe')
else
'cmd.exe'
# Public: Terminate the process.
kill: ->
return if @killed
+235 -179
Ver Arquivo
@@ -314,10 +314,12 @@ class Config
@settings = {}
@scopedSettingsStore = new ScopedPropertyStore
@usersScopedSettings = new CompositeDisposable
@usersScopedSettingPriority = {priority: 1000}
@configFileHasErrors = false
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
@configFilePath ?= path.join(@configDirPath, 'config.cson')
@transactDepth = 0
@prioritiesBySource = {}
@prioritiesBySource[@getUserConfigPath()] = 1000
###
Section: Config Subscription
@@ -337,32 +339,36 @@ class Config
# # do stuff with value
# ```
#
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
# the root of the syntax tree to a token. Get one by calling
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `keyPath` {String} name of the key to observe
# * `options` {Object}
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
# the root of the syntax tree to a token. Get one by calling
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `callback` {Function} to call when the value of the key changes.
# * `value` the new value of the key
#
# Returns a {Disposable} with the following keys on which you can call
# `.dispose()` to unsubscribe.
observe: (scopeDescriptor, keyPath, options, callback) ->
args = Array::slice.call(arguments)
if args.length is 2
# observe(keyPath, callback)
[keyPath, callback, scopeDescriptor, options] = args
else if args.length is 3 and (Array.isArray(scopeDescriptor) or scopeDescriptor instanceof ScopeDescriptor)
# observe(scopeDescriptor, keyPath, callback)
[scopeDescriptor, keyPath, callback, options] = args
else if args.length is 3 and _.isString(scopeDescriptor) and _.isObject(keyPath)
# observe(keyPath, options, callback) # Deprecated!
[keyPath, options, callback, scopeDescriptor] = args
message = ""
message = "`callNow` was set to false. Use ::onDidChange instead. Note that ::onDidChange calls back with different arguments." if options.callNow == false
Grim.deprecate "Config::observe no longer supports options; see https://atom.io/docs/api/latest/Config. #{message}"
observe: ->
if arguments.length is 2
[keyPath, callback] = arguments
else if arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor)
Grim.deprecate """
Passing a scope descriptor as the first argument to Config::observe is deprecated.
Pass a `scope` in an options hash as the third argument instead.
"""
[scopeDescriptor, keyPath, callback] = arguments
else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1]))
[keyPath, options, callback] = arguments
scopeDescriptor = options.scope
if options.callNow?
Grim.deprecate """
Config::observe no longer takes a `callNow` option. Use ::onDidChange instead.
Note that ::onDidChange passes its callback different arguments.
See https://atom.io/docs/api/latest/Config
"""
else
console.error 'An unsupported form of Config::observe is being used. See https://atom.io/docs/api/latest/Config for details'
return
@@ -375,13 +381,14 @@ class Config
# Essential: Add a listener for changes to a given key path. If `keyPath` is
# not specified, your callback will be called on changes to any key.
#
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
# the root of the syntax tree to a token. Get one by calling
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `keyPath` (optional) {String} name of the key to observe. Must be
# specified if `scopeDescriptor` is specified.
# * `optional` (optional) {Object}
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
# the root of the syntax tree to a token. Get one by calling
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `callback` {Function} to call when the value of the key changes.
# * `event` {Object}
# * `newValue` the new value of the key
@@ -390,12 +397,20 @@ class Config
#
# Returns a {Disposable} with the following keys on which you can call
# `.dispose()` to unsubscribe.
onDidChange: (scopeDescriptor, keyPath, callback) ->
args = Array::slice.call(arguments)
onDidChange: ->
if arguments.length is 1
[callback, scopeDescriptor, keyPath] = args
[callback] = arguments
else if arguments.length is 2
[keyPath, callback, scopeDescriptor] = args
[keyPath, callback] = arguments
else if _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor
Grim.deprecate """
Passing a scope descriptor as the first argument to Config::onDidChange is deprecated.
Pass a `scope` in an options hash as the third argument instead.
"""
[scopeDescriptor, keyPath, callback] = arguments
else
[keyPath, options, callback] = arguments
scopeDescriptor = options.scope
if scopeDescriptor?
@onDidChangeScopedKeyPath(scopeDescriptor, keyPath, callback)
@@ -446,24 +461,40 @@ class Config
# atom.config.get(scopeDescriptor, 'editor.tabLength') # => 2
# ```
#
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
# the root of the syntax tree to a token. Get one by calling
# {editor.getLastCursor().getScopeDescriptor()}
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `keyPath` The {String} name of the key to retrieve.
# * `options` (optional) {Object}
# * `sources` (optional) {Array} of {String} source names. If provided, only
# values that were associated with these sources during {::set} will be used.
# * `excludeSources` (optional) {Array} of {String} source names. If provided,
# values that were associated with these sources during {::set} will not
# be used.
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
# the root of the syntax tree to a token. Get one by calling
# {editor.getLastCursor().getScopeDescriptor()}
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
#
# Returns the value from Atom's default settings, the user's configuration
# file in the type specified by the configuration schema.
get: (scopeDescriptor, keyPath) ->
if arguments.length == 1
# cannot assign to keyPath for the sake of v8 optimization
globalKeyPath = scopeDescriptor
@getRawValue(globalKeyPath)
get: ->
if arguments.length > 1
if typeof arguments[0] is 'string' or not arguments[0]?
[keyPath, options] = arguments
{scope} = options
else
Grim.deprecate """
Passing a scope descriptor as the first argument to Config::get is deprecated.
Pass a `scope` in an options hash as the final argument instead.
"""
[scope, keyPath] = arguments
else
value = @getRawScopedValue(scopeDescriptor, keyPath)
value ?= @getRawValue(keyPath)
value
[keyPath] = arguments
if scope?
value = @getRawScopedValue(scope, keyPath, options)
value ? @getRawValue(keyPath, options)
else
@getRawValue(keyPath, options)
# Essential: Sets the value for a configuration setting.
#
@@ -494,63 +525,90 @@ class Config
# atom.config.get(['source.js'], 'editor.tabLength') # => 4
# ```
#
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `keyPath` The {String} name of the key.
# * `value` The value of the setting. Passing `undefined` will revert the
# setting to the default value.
# * `options` (optional) {Object}
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `source` (optional) {String} The name of a file with which the setting
# is associated. Defaults to the user's config file.
#
# Returns a {Boolean}
# * `true` if the value was set.
# * `false` if the value was not able to be coerced to the type specified in the setting's schema.
set: (scopeSelector, keyPath, value) ->
if arguments.length < 3
value = keyPath
keyPath = scopeSelector
scopeSelector = undefined
set: ->
if arguments[0]?[0] is '.'
Grim.deprecate """
Passing a scope selector as the first argument to Config::set is deprecated.
Pass a `scopeSelector` in an options hash as the final argument instead.
"""
[scopeSelector, keyPath, value] = arguments
else
[keyPath, value, options] = arguments
scopeSelector = options?.scopeSelector
source = options?.source
unless value == undefined
source ?= @getUserConfigPath()
unless value is undefined
try
value = @makeValueConformToSchema(keyPath, value)
catch e
return false
if scopeSelector?
@setRawScopedValue(scopeSelector, keyPath, value)
@setRawScopedValue(source, scopeSelector, keyPath, value)
else
@setRawValue(keyPath, value)
@setRawValue(source, keyPath, value)
@emitChangeEvent()
@save() unless @configFileHasErrors
true
# Extended: Restore the global setting at `keyPath` to its default value.
# Essential: Restore the setting at `keyPath` to its default value.
#
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
# for more information.
# * `keyPath` The {String} name of the key.
# * `options` (optional) {Object}
# * `scopeSelector` (optional) {String}. See {::set}
# * `source` (optional) {String}. See {::set}
unset: (keyPath, options) ->
if typeof options is 'string'
Grim.deprecate """
Passing a scope selector as the first argument to Config::unset is deprecated.
Pass a `scopeSelector` in an options hash as the second argument instead.
"""
scopeSelector = keyPath
keyPath = options
else
{scopeSelector, source} = options ? {}
source ?= @getUserConfigPath()
if scopeSelector?
if keyPath?
settings = @scopedSettingsStore.propertiesForSourceAndSelector(source, scopeSelector)
if _.valueForKeyPath(settings, keyPath)?
@scopedSettingsStore.removePropertiesForSourceAndSelector(source, scopeSelector)
_.setValueForKeyPath(settings, keyPath, undefined)
settings = withoutEmptyObjects(settings)
@addScopedSettings(source, scopeSelector, settings, priority: @usersScopedSettingPriority) if settings?
@save() unless @configFileHasErrors
else
@scopedSettingsStore.removePropertiesForSource(source)
else
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
# Deprecated: Restore the global setting at `keyPath` to its default value.
#
# Returns the new value.
restoreDefault: (scopeSelector, keyPath) ->
if arguments.length == 1
keyPath = scopeSelector
scopeSelector = null
Grim.deprecate("Use ::unset instead.")
@unset(scopeSelector, keyPath)
@get(keyPath)
if scopeSelector?
settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector)
if _.valueForKeyPath(settings, keyPath)?
@scopedSettingsStore.removePropertiesForSourceAndSelector('user-config', scopeSelector)
_.setValueForKeyPath(settings, keyPath, undefined)
settings = withoutEmptyObjects(settings)
@addScopedSettings('user-config', scopeSelector, settings, @usersScopedSettingPriority) if settings?
@save() unless @configFileHasErrors
@getDefault(scopeSelector, keyPath)
else
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
@get(keyPath)
# Extended: Get the global default value of the key path. _Please note_ that in most
# Deprecated: Get the global default value of the key path. _Please note_ that in most
# cases calling this is not necessary! {::get} returns the default value when
# a custom value is not specified.
#
@@ -558,35 +616,31 @@ class Config
# * `keyPath` The {String} name of the key.
#
# Returns the default value.
getDefault: (scopeSelector, keyPath) ->
if arguments.length == 1
keyPath = scopeSelector
scopeSelector = null
if scopeSelector?
defaultValue = @scopedSettingsStore.getPropertyValue(scopeSelector, keyPath, excludeSources: ['user-config'])
defaultValue ?= _.valueForKeyPath(@defaultSettings, keyPath)
getDefault: ->
Grim.deprecate("Use `::get(keyPath, {scope, excludeSources: [atom.config.getUserConfigPath()]})` instead")
if arguments.length is 1
[keyPath] = arguments
else
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
_.deepClone(defaultValue)
[scopeSelector, keyPath] = arguments
scope = [scopeSelector]
@get(keyPath, {scope, excludeSources: [@getUserConfigPath()]})
# Extended: Is the value at `keyPath` its default value?
# Deprecated: Is the value at `keyPath` its default value?
#
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
# * `keyPath` The {String} name of the key.
#
# Returns a {Boolean}, `true` if the current value is the default, `false`
# otherwise.
isDefault: (scopeSelector, keyPath) ->
if arguments.length == 1
keyPath = scopeSelector
scopeSelector = null
if scopeSelector?
settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector)
not _.valueForKeyPath(settings, keyPath)?
isDefault: ->
Grim.deprecate("Use `not ::get(keyPath, {scope, sources: [atom.config.getUserConfigPath()]})?` instead")
if arguments.length is 1
[keyPath] = arguments
scopeSelector = '*'
else
not _.valueForKeyPath(@settings, keyPath)?
[scopeSelector, keyPath] = arguments
not @get(keyPath, {scope: [scopeSelector], sources: [@getUserConfigPath()]})?
# Extended: Retrieve the schema for a specific key path. The schema will tell
# you what type the keyPath expects, and other metadata about the config
@@ -608,12 +662,25 @@ class Config
# defaults. Returns the scoped settings when a `scopeSelector` is specified.
getSettings: ->
Grim.deprecate "Use ::get(keyPath) instead"
_.deepExtend({}, @settings, @defaultSettings)
_.deepExtend({}, @defaultSettings, @scopedSettingsStore.getProperties('.xxx')...)
# Extended: Get the {String} path to the config file being used.
getUserConfigPath: ->
@configFilePath
# Extended: Suppress calls to handler functions registered with {::onDidChange}
# and {::observe} for the duration of `callback`. After `callback` executes,
# handlers will be called once if the value for their key-path has changed.
#
# * `callback` {Function} to execute while suppressing calls to handlers.
transact: (callback) ->
@transactDepth++
try
callback()
finally
@transactDepth--
@emitChangeEvent()
###
Section: Deprecated
###
@@ -738,55 +805,43 @@ class Config
console.error detail
save: ->
allSettings = global: @settings
allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource('user-config')
CSON.writeFileSync(@configFilePath, allSettings)
settings = @scopedSettingsStore.propertiesForSource(@getUserConfigPath())
settings.global = settings['*']
delete settings['*']
CSON.writeFileSync(@configFilePath, settings)
###
Section: Private methods managing global settings
###
resetUserSettings: (newSettings) ->
@scopedSettingsStore.removePropertiesForSource(@getUserConfigPath())
unless isPlainObject(newSettings)
@settings = {}
@emitter.emit 'did-change'
@emitChangeEvent()
return
if newSettings.global?
scopedSettings = newSettings
newSettings = newSettings.global
delete scopedSettings.global
@resetUserScopedSettings(scopedSettings)
unless newSettings.global?
newSettings = {global: newSettings}
unsetUnspecifiedValues = (keyPath, value) =>
if isPlainObject(value)
keys = splitKeyPath(keyPath)
for key, childValue of value
continue unless value.hasOwnProperty(key)
unsetUnspecifiedValues(keys.concat([key]).join('.'), childValue)
for selector, settings of newSettings
unless settings is undefined
try
settings = @makeValueConformToSchema(null, settings)
catch e
continue
if selector is 'global'
@setRawValue(@getUserConfigPath(), null, settings)
else
@setRawValue(keyPath, undefined) unless _.valueForKeyPath(newSettings, keyPath)?
return
@setRawScopedValue(@getUserConfigPath(), selector, null, settings)
@setRecursive(null, newSettings)
unsetUnspecifiedValues(null, @settings)
@emitChangeEvent()
setRecursive: (keyPath, value) ->
if isPlainObject(value)
keys = splitKeyPath(keyPath)
for key, childValue of value
continue unless value.hasOwnProperty(key)
@setRecursive(keys.concat([key]).join('.'), childValue)
else
try
value = @makeValueConformToSchema(keyPath, value)
@setRawValue(keyPath, value)
catch e
console.warn("'#{keyPath}' could not be set. Attempted value: #{JSON.stringify(value)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
getRawValue: (keyPath) ->
value = _.valueForKeyPath(@settings, keyPath)
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
getRawValue: (keyPath, options) ->
value = @getRawScopedValue(['xxx'], keyPath, options)
unless options?.sources?.length > 0
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
if value?
value = _.deepClone(value)
@@ -796,23 +851,17 @@ class Config
value
setRawValue: (keyPath, value) ->
setRawValue: (source, keyPath, value) ->
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
value = undefined if _.isEqual(defaultValue, value)
oldValue = _.clone(@get(keyPath))
_.setValueForKeyPath(@settings, keyPath, value)
newValue = @get(keyPath)
@emitter.emit 'did-change', {oldValue, newValue, keyPath} unless _.isEqual(newValue, oldValue)
@setRawScopedValue(source, '*', keyPath, value)
@emitChangeEvent()
observeKeyPath: (keyPath, options, callback) ->
callback(_.clone(@get(keyPath))) unless options.callNow == false
@emitter.on 'did-change', (event) =>
callback(event.newValue) if keyPath? and @isSubKeyPath(keyPath, event?.keyPath)
@observeScopedKeyPath(["xxx"], keyPath, callback)
onDidChangeKeyPath: (keyPath, callback) ->
@emitter.on 'did-change', (event) =>
callback(event) if not keyPath? or (keyPath? and @isSubKeyPath(keyPath, event?.keyPath))
@onDidChangeScopedKeyPath(["xxx"], keyPath, callback)
isSubKeyPath: (keyPath, subKeyPath) ->
return false unless keyPath? and subKeyPath?
@@ -821,10 +870,8 @@ class Config
_.isEqual(pathTokens, pathSubTokens)
setRawDefault: (keyPath, value) ->
oldValue = _.clone(@get(keyPath))
_.setValueForKeyPath(@defaultSettings, keyPath, value)
newValue = @get(keyPath)
@emitter.emit 'did-change', {oldValue, newValue, keyPath} unless _.isEqual(newValue, oldValue)
@emitChangeEvent()
setDefaults: (keyPath, defaults) ->
if defaults? and isPlainObject(defaults)
@@ -836,6 +883,7 @@ class Config
try
defaults = @makeValueConformToSchema(keyPath, defaults)
@setRawDefault(keyPath, defaults)
@emitChangeEvent()
catch e
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
@@ -882,56 +930,45 @@ class Config
Section: Private Scoped Settings
###
resetUserScopedSettings: (newScopedSettings) ->
@usersScopedSettings?.dispose()
@usersScopedSettings = new CompositeDisposable
@usersScopedSettings.add @scopedSettingsStore.addProperties('user-config', newScopedSettings, @usersScopedSettingPriority)
@emitter.emit 'did-change'
emitChangeEvent: ->
@emitter.emit 'did-change' unless @transactDepth > 0
addScopedSettings: (source, selector, value, options) ->
settingsBySelector = {}
settingsBySelector[selector] = value
disposable = @scopedSettingsStore.addProperties(source, settingsBySelector, options)
@emitter.emit 'did-change'
@emitChangeEvent()
new Disposable =>
disposable.dispose()
@emitter.emit 'did-change'
@emitChangeEvent()
setRawScopedValue: (selector, keyPath, value) ->
setRawScopedValue: (source, selector, keyPath, value) ->
if keyPath?
newValue = {}
_.setValueForKeyPath(newValue, keyPath, value)
setValueAtKeyPath(newValue, keyPath, value)
value = newValue
settingsBySelector = {}
settingsBySelector[selector] = value
@usersScopedSettings.add @scopedSettingsStore.addProperties('user-config', settingsBySelector, @usersScopedSettingPriority)
@emitter.emit 'did-change'
@usersScopedSettings.add @scopedSettingsStore.addProperties(source, settingsBySelector, priority: @prioritiesBySource[source])
getRawScopedValue: (scopeDescriptor, keyPath) ->
getRawScopedValue: (scopeDescriptor, keyPath, options) ->
scopeDescriptor = ScopeDescriptor.fromObject(scopeDescriptor)
@scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath)
value = @scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath, options)
value
observeScopedKeyPath: (scopeDescriptor, keyPath, callback) ->
oldValue = @get(scopeDescriptor, keyPath)
observeScopedKeyPath: (scope, keyPath, callback) ->
callback(@get(keyPath, {scope}))
@onDidChangeScopedKeyPath scope, keyPath, ({newValue}) ->
callback(newValue)
callback(oldValue)
didChange = =>
newValue = @get(scopeDescriptor, keyPath)
callback(newValue) unless _.isEqual(oldValue, newValue)
oldValue = newValue
@emitter.on 'did-change', didChange
onDidChangeScopedKeyPath: (scopeDescriptor, keyPath, callback) ->
oldValue = @get(scopeDescriptor, keyPath)
didChange = =>
newValue = @get(scopeDescriptor, keyPath)
callback({oldValue, newValue, keyPath}) unless _.isEqual(oldValue, newValue)
oldValue = newValue
@emitter.on 'did-change', didChange
onDidChangeScopedKeyPath: (scope, keyPath, callback) ->
oldValue = _.deepClone(@get(keyPath, {scope}))
@emitter.on 'did-change', (event) =>
newValue = @get(keyPath, {scope})
unless _.isEqual(newValue, oldValue)
callback({newValue, oldValue})
oldValue = _.deepClone(newValue)
# TODO: figure out how to change / remove this. The return value is awkward.
# * language mode uses it for one thing.
@@ -997,7 +1034,11 @@ Config.addSchemaEnforcers
for prop, childSchema of schema.properties
continue unless value.hasOwnProperty(prop)
try
newValue[prop] = @executeSchemaEnforcers("#{keyPath}.#{prop}", value[prop], childSchema)
newKeyPath = if keyPath?
"#{keyPath}.#{prop}"
else
prop
newValue[prop] = @executeSchemaEnforcers(newKeyPath, value[prop], childSchema)
catch error
console.warn "Error setting item in object: #{error.message}"
newValue
@@ -1050,6 +1091,21 @@ splitKeyPath = (keyPath) ->
keyPathArray.push keyPath.substr(startIndex, keyPath.length)
keyPathArray
getValueAtKeyPath = (object, keyPath) ->
keys = splitKeyPath(keyPath)
for key in keys
object = object[key]
return unless object?
object
setValueAtKeyPath = (object, keyPath, value) ->
keys = splitKeyPath(keyPath)
while keys.length > 1
key = keys.shift()
object[key] ?= {}
object = object[key]
object[keys.shift()] = value
withoutEmptyObjects = (object) ->
resultObject = undefined
if isPlainObject(object)
+2 -2
Ver Arquivo
@@ -202,7 +202,7 @@ class Cursor extends Model
[before, after] = @editor.getTextInBufferRange(range)
return false if /\s/.test(before) or /\s/.test(after)
nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters').split('')
nonWordCharacters = atom.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.
@@ -636,7 +636,7 @@ class Cursor extends Model
# Returns a {RegExp}.
wordRegExp: ({includeNonWordCharacters}={}) ->
includeNonWordCharacters ?= true
nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters')
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
segments = ["^[\t ]*$"]
segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
if includeNonWordCharacters
+9 -9
Ver Arquivo
@@ -67,24 +67,24 @@ class DisplayBuffer extends Model
oldConfigSettings = @configSettings
@configSettings =
scrollPastEnd: atom.config.get(scopeDescriptor, 'editor.scrollPastEnd')
softWrap: atom.config.get(scopeDescriptor, 'editor.softWrap')
softWrapAtPreferredLineLength: atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength')
preferredLineLength: atom.config.get(scopeDescriptor, 'editor.preferredLineLength')
scrollPastEnd: atom.config.get('editor.scrollPastEnd', scope: scopeDescriptor)
softWrap: atom.config.get('editor.softWrap', scope: scopeDescriptor)
softWrapAtPreferredLineLength: atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
preferredLineLength: atom.config.get('editor.preferredLineLength', scope: scopeDescriptor)
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrap', ({newValue}) =>
subscriptions.add atom.config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) =>
@configSettings.softWrap = newValue
@updateWrappedScreenLines()
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrapAtPreferredLineLength', ({newValue}) =>
subscriptions.add atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) =>
@configSettings.softWrapAtPreferredLineLength = newValue
@updateWrappedScreenLines() if @isSoftWrapped()
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.preferredLineLength', ({newValue}) =>
subscriptions.add atom.config.onDidChange 'editor.preferredLineLength', scope: scopeDescriptor, ({newValue}) =>
@configSettings.preferredLineLength = newValue
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength')
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollPastEnd', (value) =>
subscriptions.add atom.config.observe 'editor.scrollPastEnd', scope: scopeDescriptor, (value) =>
@configSettings.scrollPastEnd = value
@updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings)
+1 -1
Ver Arquivo
@@ -316,7 +316,7 @@ class LanguageMode
@editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
getRegexForProperty: (scopeDescriptor, property) ->
if pattern = atom.config.get(scopeDescriptor, property)
if pattern = atom.config.get(property, scope: scopeDescriptor)
new OnigRegExp(pattern)
increaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
+4 -2
Ver Arquivo
@@ -329,7 +329,8 @@ class PackageManager
@packageActivators.push([activator, types])
activatePackages: (packages) ->
@activatePackage(pack.name) for pack in packages
atom.config.transact =>
@activatePackage(pack.name) for pack in packages
@observeDisabledPackages()
# Activate a single package by name
@@ -344,7 +345,8 @@ class PackageManager
# Deactivate all packages
deactivatePackages: ->
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
atom.config.transact =>
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
@unobserveDisabledPackages()
# Deactivate the package with the given name
+34 -19
Ver Arquivo
@@ -404,7 +404,7 @@ TextEditorComponent = React.createClass
window.addEventListener 'resize', @requestHeightAndWidthMeasurement
@listenForIMEEvents()
@listenForMiddleMousePaste() if process.platform is 'linux'
@trackSelectionClipboard() if process.platform is 'linux'
listenForIMEEvents: ->
node = @getDOMNode()
@@ -432,21 +432,21 @@ TextEditorComponent = React.createClass
editor.insertText(selectedText, select: true, undo: 'skip')
event.target.value = ''
listenForMiddleMousePaste: ->
clipboard = require 'clipboard'
@refs.scrollView.getDOMNode().addEventListener 'mouseup', ({which}) =>
return unless which is 2
if selection = clipboard.readText('selection')
@props.editor.insertText(selection)
@subscribe @props.editor.onDidChangeSelectionRange =>
if selectedText = @props.editor.getSelectedText()
# Listen for selection changes and store the currently selected text
# in the selection clipboard. This is only applicable on Linux.
trackSelectionClipboard: ->
timeoutId = null
{editor} = @props
writeSelectedTextToSelectionClipboard = =>
return if editor.isDestroyed()
if selectedText = editor.getSelectedText()
# This uses ipc.send instead of clipboard.writeText because
# clipboard.writeText is a sync ipc call on Linux and that
# will slow down selections.
ipc.send('write-text-to-selection-clipboard', selectedText)
@subscribe editor.onDidChangeSelectionRange ->
clearTimeout(timeoutId)
timeoutId = setTimeout(writeSelectedTextToSelectionClipboard)
observeConfig: ->
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
@@ -462,9 +462,9 @@ TextEditorComponent = React.createClass
scopeDescriptor = editor.getRootScopeDescriptor()
subscriptions.add atom.config.observe scopeDescriptor, 'editor.showIndentGuide', @setShowIndentGuide
subscriptions.add atom.config.observe scopeDescriptor, 'editor.showLineNumbers', @setShowLineNumbers
subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollSensitivity', @setScrollSensitivity
subscriptions.add atom.config.observe 'editor.showIndentGuide', scope: scopeDescriptor, @setShowIndentGuide
subscriptions.add atom.config.observe 'editor.showLineNumbers', scope: scopeDescriptor, @setShowLineNumbers
subscriptions.add atom.config.observe 'editor.scrollSensitivity', scope: scopeDescriptor, @setScrollSensitivity
focused: ->
if @isMounted()
@@ -560,7 +560,11 @@ TextEditorComponent = React.createClass
scrollViewNode.scrollLeft = 0
onMouseDown: (event) ->
return unless event.button is 0 # only handle the left mouse button
unless event.button is 0 or (event.button is 1 and process.platform is 'linux')
# Only handle mouse down events for left mouse button on all platforms
# and middle mouse button on Linux since it pastes the selection clipboard
return
return if event.target?.classList.contains('horizontal-scrollbar')
{editor} = @props
@@ -750,10 +754,12 @@ TextEditorComponent = React.createClass
lastMousePosition = {}
animationLoop = =>
@requestAnimationFrame =>
if dragging
if dragging and @isMounted()
screenPosition = @screenPositionForMouseEvent(lastMousePosition)
dragHandler(screenPosition)
animationLoop()
else if not @isMounted()
stopDragging()
onMouseMove = (event) ->
lastMousePosition.clientX = event.clientX
@@ -767,11 +773,20 @@ TextEditorComponent = React.createClass
# Stop dragging when cursor enters dev tools because we can't detect mouseup
onMouseUp() if event.which is 0
onMouseUp = ->
onMouseUp = (event) ->
stopDragging()
editor.finalizeSelections()
pasteSelectionClipboard(event)
stopDragging = ->
dragging = false
window.removeEventListener('mousemove', onMouseMove)
window.removeEventListener('mouseup', onMouseUp)
editor.finalizeSelections()
pasteSelectionClipboard = (event) ->
if event?.which is 2 and process.platform is 'linux'
if selection = require('clipboard').readText('selection')
editor.insertText(selection)
window.addEventListener('mousemove', onMouseMove)
window.addEventListener('mouseup', onMouseUp)
+1 -1
Ver Arquivo
@@ -123,7 +123,7 @@ class TextEditorElement extends HTMLElement
unmountComponent: ->
return unless @component?.isMounted()
callRemoveHooks(this)
React.unmountComponentAtNode(this)
React.unmountComponentAtNode(@rootElement)
@component = null
focused: ->
+6 -6
Ver Arquivo
@@ -168,8 +168,8 @@ class TextEditor extends Model
scopeDescriptor = @getRootScopeDescriptor()
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.showInvisibles', => @updateInvisibles()
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.invisibles', => @updateInvisibles()
subscriptions.add atom.config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, => @updateInvisibles()
subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles()
getViewClass: ->
require './text-editor-view'
@@ -2812,17 +2812,17 @@ class TextEditor extends Model
###
shouldAutoIndent: ->
atom.config.get(@getRootScopeDescriptor(), "editor.autoIndent")
atom.config.get("editor.autoIndent", scope: @getRootScopeDescriptor())
shouldAutoIndentOnPaste: ->
atom.config.get(@getRootScopeDescriptor(), "editor.autoIndentOnPaste")
atom.config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor())
shouldShowInvisibles: ->
not @mini and atom.config.get(@getRootScopeDescriptor(), 'editor.showInvisibles')
not @mini and atom.config.get('editor.showInvisibles', scope: @getRootScopeDescriptor())
updateInvisibles: ->
if @shouldShowInvisibles()
@displayBuffer.setInvisibles(atom.config.get(@getRootScopeDescriptor(), 'editor.invisibles'))
@displayBuffer.setInvisibles(atom.config.get('editor.invisibles', scope: @getRootScopeDescriptor()))
else
@displayBuffer.setInvisibles(null)
+2 -2
Ver Arquivo
@@ -84,10 +84,10 @@ class TokenizedBuffer extends Model
@currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText())
@subscribe @grammar.onDidUpdate => @retokenizeLines()
@configSettings = tabLength: atom.config.get(@rootScopeDescriptor, 'editor.tabLength')
@configSettings = tabLength: atom.config.get('editor.tabLength', scope: @rootScopeDescriptor)
@grammarTabLengthSubscription?.dispose()
@grammarTabLengthSubscription = atom.config.onDidChange @rootScopeDescriptor, 'editor.tabLength', ({newValue}) =>
@grammarTabLengthSubscription = atom.config.onDidChange 'editor.tabLength', scope: @rootScopeDescriptor, ({newValue}) =>
@configSettings.tabLength = newValue
@retokenizeLines()
@subscribe @grammarTabLengthSubscription
+1 -1
Ver Arquivo
@@ -645,7 +645,7 @@ class Workspace extends Model
# Restore to a default editor font size.
resetFontSize: ->
atom.config.restoreDefault("editor.fontSize")
atom.config.unset("editor.fontSize")
# Removes the item's uri from the list of potential items to reopen.
itemOpened: (item) ->