Comparar commits
95 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 0b2599565e | |||
| 34bd103c3d | |||
| b00441bee7 | |||
| e33e5df467 | |||
| 212fbd915d | |||
| 8bd3e848e0 | |||
| 400c8f3dcd | |||
| fff752d944 | |||
| f843d07403 | |||
| d7efa9bb37 | |||
| d12a2cf284 | |||
| a807619906 | |||
| e3245ec4b8 | |||
| 4231d69421 | |||
| 64cc7f98ea | |||
| 062fa29895 | |||
| 4e3c8406ee | |||
| 47d5b46a1d | |||
| a711e908d5 | |||
| 27da0669f3 | |||
| 16fd53c123 | |||
| 2475e1a9a6 | |||
| f724c7fca8 | |||
| f8a3ae6104 | |||
| 899929a1ce | |||
| e5d67bb2ff | |||
| 3732bdf1e9 | |||
| aedf02a3e3 | |||
| d47dbede29 | |||
| b1f8c6a6e8 | |||
| a8fad6a0fb | |||
| e2ac19c17f | |||
| 82990cfc77 | |||
| d72b179b3b | |||
| 9a957fe0a4 | |||
| 21feab322f | |||
| dd05c6cec1 | |||
| f61a7d0c62 | |||
| 7a5054027e | |||
| 778d9fafc5 | |||
| 38e889b7d8 | |||
| 356f4bec7c | |||
| 8533286114 | |||
| 98d31a1d30 | |||
| 59aa3a446c | |||
| 679031ce83 | |||
| 3860091c62 | |||
| 06af3f38c0 | |||
| da6f664903 | |||
| 4c124b8174 | |||
| 4a818d76d6 | |||
| 811758aec7 | |||
| 5cb31c874f | |||
| b24e1fa405 | |||
| f004f8c45d | |||
| 19ff2bd986 | |||
| be7d093a4a | |||
| 0ebedeec3a | |||
| aa1eb94fa7 | |||
| 8723e69f1c | |||
| b1c5442f93 | |||
| 756a389ccf | |||
| 5a72d12026 | |||
| 06e0919597 | |||
| 0afe2a55e9 | |||
| 3442157e16 | |||
| 039d87caa0 | |||
| edaf1e2ced | |||
| 4b746deb73 | |||
| 442223f97b | |||
| 4207752a08 | |||
| a5781d65c3 | |||
| 9d2bb71109 | |||
| eaa90e6158 | |||
| 187e300167 | |||
| 670f3e4946 | |||
| ae488fc7fe | |||
| 28deb9dec5 | |||
| 186335d619 | |||
| 1c58438124 | |||
| 3e0477ffcb | |||
| 368ef59b85 | |||
| 465d2afd95 | |||
| 32f0eb4f76 | |||
| 60a551b308 | |||
| f76f7e17d3 | |||
| da87f321e8 | |||
| 11ede2d436 | |||
| 2cc6c9e4c0 | |||
| 887a7bcaf4 | |||
| df37d77895 | |||
| cf8dc29cc5 | |||
| de29ca6906 | |||
| 4ba3162f3e | |||
| 2710c06313 |
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.98.0"
|
||||
"atom-package-manager": "0.101.0"
|
||||
}
|
||||
}
|
||||
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.135.0",
|
||||
"version": "0.136.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -50,14 +50,14 @@
|
||||
"reactionary-atom-fork": "^1.0.0",
|
||||
"runas": "1.0.1",
|
||||
"scandal": "1.0.2",
|
||||
"scoped-property-store": "^0.9.0",
|
||||
"scoped-property-store": "^0.11.0",
|
||||
"scrollbar-style": "^1.0.2",
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.4.7",
|
||||
"space-pen": "3.6.1",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.2.6",
|
||||
"text-buffer": "^3.2.8",
|
||||
"theorist": "^1.0.2",
|
||||
"underscore-plus": "^1.5.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
@@ -74,11 +74,11 @@
|
||||
"archive-view": "0.37.0",
|
||||
"autocomplete": "0.32.0",
|
||||
"autoflow": "0.18.0",
|
||||
"autosave": "0.17.0",
|
||||
"autosave": "0.18.0",
|
||||
"background-tips": "0.17.0",
|
||||
"bookmarks": "0.28.0",
|
||||
"bracket-matcher": "0.61.0",
|
||||
"command-palette": "0.26.0",
|
||||
"command-palette": "0.27.0",
|
||||
"deprecation-cop": "0.10.0",
|
||||
"dev-live-reload": "0.34.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
@@ -98,24 +98,24 @@
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.149.0",
|
||||
"snippets": "0.53.0",
|
||||
"snippets": "0.55.0",
|
||||
"spell-check": "0.42.0",
|
||||
"status-bar": "0.45.0",
|
||||
"status-bar": "0.46.0",
|
||||
"styleguide": "0.30.0",
|
||||
"symbols-view": "0.66.0",
|
||||
"tabs": "0.54.0",
|
||||
"timecop": "0.22.0",
|
||||
"tree-view": "0.127.0",
|
||||
"tree-view": "0.128.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.18.0",
|
||||
"whitespace": "0.25.0",
|
||||
"wrap-guide": "0.22.0",
|
||||
"language-c": "0.28.0",
|
||||
"language-coffee-script": "0.35.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.50.0",
|
||||
"language-css": "0.18.0",
|
||||
"language-gfm": "0.51.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.17.0",
|
||||
"language-go": "0.18.0",
|
||||
"language-html": "0.26.0",
|
||||
"language-hyperlink": "0.12.0",
|
||||
"language-java": "0.11.0",
|
||||
@@ -129,7 +129,7 @@
|
||||
"language-php": "0.16.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.19.0",
|
||||
"language-ruby": "0.38.0",
|
||||
"language-ruby": "0.39.0",
|
||||
"language-ruby-on-rails": "0.18.0",
|
||||
"language-sass": "0.22.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
@@ -139,7 +139,7 @@
|
||||
"language-todo": "0.12.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.22.0",
|
||||
"language-yaml": "0.17.0"
|
||||
"language-yaml": "0.18.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -20,7 +20,7 @@ describe "install(commandPath, callback)", ->
|
||||
|
||||
installDone = false
|
||||
installError = null
|
||||
installer.install commandFilePath, false, (error) ->
|
||||
installer.createSymlink commandFilePath, false, (error) ->
|
||||
installDone = true
|
||||
installError = error
|
||||
|
||||
|
||||
@@ -862,3 +862,106 @@ describe "Config", ->
|
||||
|
||||
expect(atom.config.set('foo.bar.arr', ['two', 'three'])).toBe true
|
||||
expect(atom.config.get('foo.bar.arr')).toEqual ['two', 'three']
|
||||
|
||||
describe "scoped settings", ->
|
||||
describe ".get(scopeDescriptor, keyPath)", ->
|
||||
it "returns the property with the most specific scope selector", ->
|
||||
atom.config.addScopedSettings(".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
atom.config.addScopedSettings(".source .string.quoted.double", foo: bar: baz: 22)
|
||||
atom.config.addScopedSettings(".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()
|
||||
|
||||
it "favors the most recently added properties in the event of a specificity tie", ->
|
||||
atom.config.addScopedSettings(".source.coffee .string.quoted.single", foo: bar: baz: 42)
|
||||
atom.config.addScopedSettings(".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
|
||||
|
||||
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'
|
||||
|
||||
describe ".set(scope, keyPath, value)", ->
|
||||
it "sets the value and overrides the others", ->
|
||||
atom.config.addScopedSettings(".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
atom.config.addScopedSettings(".source .string.quoted.double", foo: bar: baz: 22)
|
||||
atom.config.addScopedSettings(".source", foo: bar: baz: 11)
|
||||
|
||||
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).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
|
||||
|
||||
describe ".removeScopedSettingsForName(name)", ->
|
||||
it "allows properties to be removed by name", ->
|
||||
disposable1 = atom.config.addScopedSettings("a", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
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
|
||||
|
||||
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()
|
||||
expect(changeSpy).toHaveBeenCalledWith(undefined)
|
||||
changeSpy.reset()
|
||||
|
||||
atom.config.set("foo.bar.baz", 12)
|
||||
expect(changeSpy).toHaveBeenCalledWith(12)
|
||||
changeSpy.reset()
|
||||
|
||||
disposable1 = atom.config.addScopedSettings(".source .string.quoted.double", foo: bar: baz: 22)
|
||||
expect(changeSpy).toHaveBeenCalledWith(22)
|
||||
changeSpy.reset()
|
||||
|
||||
disposable2 = atom.config.addScopedSettings("a", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
expect(changeSpy).toHaveBeenCalledWith(42)
|
||||
changeSpy.reset()
|
||||
|
||||
disposable2.dispose()
|
||||
expect(changeSpy).toHaveBeenCalledWith(22)
|
||||
changeSpy.reset()
|
||||
|
||||
disposable1.dispose()
|
||||
expect(changeSpy).toHaveBeenCalledWith(12)
|
||||
changeSpy.reset()
|
||||
|
||||
atom.config.set("foo.bar.baz", undefined)
|
||||
expect(changeSpy).toHaveBeenCalledWith(undefined)
|
||||
changeSpy.reset()
|
||||
|
||||
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()
|
||||
|
||||
atom.config.set("foo.bar.baz", 12)
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12, keyPath})
|
||||
changeSpy.reset()
|
||||
|
||||
disposable1 = atom.config.addScopedSettings(".source .string.quoted.double", foo: bar: baz: 22)
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22, keyPath})
|
||||
changeSpy.reset()
|
||||
|
||||
disposable2 = atom.config.addScopedSettings("a", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42, keyPath})
|
||||
changeSpy.reset()
|
||||
|
||||
disposable2.dispose()
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22, keyPath})
|
||||
changeSpy.reset()
|
||||
|
||||
disposable1.dispose()
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12, keyPath})
|
||||
changeSpy.reset()
|
||||
|
||||
atom.config.set("foo.bar.baz", undefined)
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined, keyPath})
|
||||
changeSpy.reset()
|
||||
|
||||
@@ -3,7 +3,7 @@ Package = require '../src/package'
|
||||
|
||||
describe "PackageManager", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
|
||||
|
||||
describe "::loadPackage(name)", ->
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
@@ -313,7 +313,7 @@ describe "PackageManager", ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
|
||||
describe "converted textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
@@ -326,15 +326,18 @@ describe "PackageManager", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "loads the translated scoped properties", ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
|
||||
describe "::deactivatePackage(id)", ->
|
||||
afterEach ->
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe "atom packages", ->
|
||||
it "calls `deactivate` on the package's main module if activate was successful", ->
|
||||
pack = null
|
||||
@@ -436,9 +439,9 @@ describe "PackageManager", ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.packages.deactivatePackage("package-with-scoped-properties")
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
@@ -458,7 +461,7 @@ describe "PackageManager", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
describe "::activate()", ->
|
||||
packageActivator = null
|
||||
|
||||
@@ -115,3 +115,29 @@ describe "PaneContainer", ->
|
||||
pane3.addItems([new Object, new Object])
|
||||
|
||||
expect(observed).toEqual container.getPaneItems()
|
||||
|
||||
describe "::confirmClose()", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
class TestItem
|
||||
shouldPromptToSave: -> true
|
||||
getUri: -> 'test'
|
||||
|
||||
container = new PaneContainer
|
||||
container.getRoot().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
pane1.addItem(new TestItem)
|
||||
pane2.addItem(new TestItem)
|
||||
|
||||
it "returns true if the user saves all modified files when prompted", ->
|
||||
spyOn(atom, "confirm").andReturn(0)
|
||||
saved = container.confirmClose()
|
||||
expect(saved).toBeTruthy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "returns false if the user cancels saving any modified file", ->
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
saved = container.confirmClose()
|
||||
expect(saved).toBeFalsy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
{$, View, $$} = require 'atom'
|
||||
@@ -18,7 +19,7 @@ describe "PaneContainerView", ->
|
||||
save: -> @saved = true
|
||||
isEqual: (other) -> @name is other?.name
|
||||
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(atom.workspace.paneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane2 = pane1.splitRight(new TestView('2'))
|
||||
@@ -70,32 +71,9 @@ describe "PaneContainerView", ->
|
||||
for item in pane.getItems()
|
||||
expect(item.saved).toBeTruthy()
|
||||
|
||||
describe ".confirmClose()", ->
|
||||
it "returns true after modified files are saved", ->
|
||||
pane1.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
pane2.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
spyOn(atom, "confirm").andReturn(0)
|
||||
|
||||
saved = container.confirmClose()
|
||||
|
||||
runs ->
|
||||
expect(saved).toBeTruthy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "returns false if the user cancels saving", ->
|
||||
pane1.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
pane2.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
|
||||
saved = container.confirmClose()
|
||||
|
||||
runs ->
|
||||
expect(saved).toBeFalsy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
describe "serialization", ->
|
||||
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
|
||||
newContainer = new PaneContainerView(container.model.testSerialization())
|
||||
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('.pane-row > :contains(1)')).toExist()
|
||||
expect(newContainer.find('.pane-row > .pane-column > :contains(2)')).toExist()
|
||||
expect(newContainer.find('.pane-row > .pane-column > :contains(3)')).toExist()
|
||||
@@ -111,14 +89,14 @@ describe "PaneContainerView", ->
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
|
||||
it "leaves the empty panes intact", ->
|
||||
newContainer = new PaneContainerView(container.model.testSerialization())
|
||||
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('.pane-row > :contains(1)')).toExist()
|
||||
expect(newContainer.find('.pane-row > .pane-column > .pane').length).toBe 2
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is true", ->
|
||||
it "removes empty panes on deserialization", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
newContainer = new PaneContainerView(container.model.testSerialization())
|
||||
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('.pane-row, .pane-column')).not.toExist()
|
||||
expect(newContainer.find('> :contains(1)')).toExist()
|
||||
|
||||
@@ -131,7 +109,7 @@ describe "PaneContainerView", ->
|
||||
item2b = new TestView('2b')
|
||||
item3a = new TestView('3a')
|
||||
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(new PaneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(item1a)
|
||||
container.attachToDom()
|
||||
@@ -281,7 +259,7 @@ describe "PaneContainerView", ->
|
||||
# |7|8|9|
|
||||
# -------
|
||||
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(new PaneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane4 = pane1.splitDown(new TestView('4'))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneView = require '../src/pane-view'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
@@ -24,7 +24,7 @@ describe "PaneView", ->
|
||||
|
||||
beforeEach ->
|
||||
deserializerDisposable = atom.deserializers.add(TestView)
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(new PaneContainer).__spacePenView
|
||||
containerModel = container.model
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
view2 = new TestView(id: 'view-2', text: 'View 2')
|
||||
@@ -311,13 +311,13 @@ describe "PaneView", ->
|
||||
container.attachToDom()
|
||||
pane.focus()
|
||||
|
||||
container2 = new PaneContainerView(container.model.testSerialization())
|
||||
container2 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
pane2 = container2.getRoot()
|
||||
container2.attachToDom()
|
||||
expect(pane2).toMatchSelector(':has(:focus)')
|
||||
|
||||
$(document.activeElement).blur()
|
||||
container3 = new PaneContainerView(container.model.testSerialization())
|
||||
container3 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
pane3 = container3.getRoot()
|
||||
container3.attachToDom()
|
||||
expect(pane3).not.toMatchSelector(':has(:focus)')
|
||||
|
||||
@@ -29,12 +29,18 @@ atom.keymaps.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymaps.getKeyBindings()
|
||||
commandsToRestore = atom.commands.getSnapshot()
|
||||
|
||||
$(window).on 'core:close', -> window.close()
|
||||
$(window).on 'beforeunload', ->
|
||||
window.addEventListener 'core:close', -> window.close()
|
||||
window.addEventListener 'beforeunload', ->
|
||||
atom.storeWindowDimensions()
|
||||
atom.saveSync()
|
||||
$('html,body').css('overflow', 'auto')
|
||||
|
||||
# Allow document.title to be assigned in specs without screwing up spec window title
|
||||
documentTitle = null
|
||||
Object.defineProperty document, 'title',
|
||||
get: -> documentTitle
|
||||
set: (title) -> documentTitle = title
|
||||
|
||||
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
|
||||
|
||||
if process.platform is 'win32' and process.env.JANKY_SHA1
|
||||
@@ -61,6 +67,7 @@ isCoreSpec = specDirectory == fs.realpathSync(__dirname)
|
||||
beforeEach ->
|
||||
Grim.clearDeprecations() if isCoreSpec
|
||||
$.fx.off = true
|
||||
documentTitle = null
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.project = new Project(paths: [projectPath])
|
||||
atom.workspace = new Workspace()
|
||||
@@ -75,7 +82,6 @@ beforeEach ->
|
||||
|
||||
spyOn(atom, 'saveSync')
|
||||
atom.syntax.clearGrammarOverrides()
|
||||
atom.syntax.clearProperties()
|
||||
|
||||
spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
|
||||
if specPackageName and packageName is specPackageName
|
||||
@@ -106,7 +112,7 @@ beforeEach ->
|
||||
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
|
||||
TextEditorComponent.performSyncUpdates = true
|
||||
|
||||
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
|
||||
spyOn(atom, "setRepresentedFilename")
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
@@ -351,7 +357,7 @@ $.fn.enableKeymap = ->
|
||||
not e.originalEvent.defaultPrevented
|
||||
|
||||
$.fn.attachToDom = ->
|
||||
@appendTo($('#jasmine-content'))
|
||||
@appendTo($('#jasmine-content')) unless @isOnDom()
|
||||
|
||||
$.fn.simulateDomAttachment = ->
|
||||
$('<html>').append(this)
|
||||
|
||||
@@ -63,9 +63,9 @@ describe "Window", ->
|
||||
beforeUnloadEvent = $.Event(new Event('beforeunload'))
|
||||
|
||||
describe "when pane items are are modified", ->
|
||||
it "prompts user to save and and calls workspaceView.confirmClose", ->
|
||||
it "prompts user to save and calls atom.workspace.confirmClose", ->
|
||||
editor = null
|
||||
spyOn(atom.workspaceView, 'confirmClose').andCallThrough()
|
||||
spyOn(atom.workspace, 'confirmClose').andCallThrough()
|
||||
spyOn(atom, "confirm").andReturn(2)
|
||||
|
||||
waitsForPromise ->
|
||||
@@ -74,7 +74,7 @@ describe "Window", ->
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.workspaceView.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns true if don't save", ->
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
|
||||
@@ -369,3 +371,88 @@ describe "Workspace", ->
|
||||
workspace2 = Workspace.deserialize(state)
|
||||
expect(jsPackage.loadGrammarsSync.callCount).toBe 1
|
||||
expect(coffeePackage.loadGrammarsSync.callCount).toBe 1
|
||||
|
||||
describe "document.title", ->
|
||||
describe "when the project has no path", ->
|
||||
it "sets the title to 'untitled'", ->
|
||||
atom.project.setPath(undefined)
|
||||
expect(document.title).toBe 'untitled'
|
||||
|
||||
describe "when the project has a path", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b')
|
||||
|
||||
describe "when there is an active pane item", ->
|
||||
it "sets the title to the pane item's title plus the project path", ->
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the title of the active pane item changes", ->
|
||||
it "updates the window title based on the item's new title", ->
|
||||
editor = atom.workspace.getActivePaneItem()
|
||||
editor.buffer.setPath(path.join(temp.dir, 'hi'))
|
||||
expect(document.title).toBe "#{editor.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the active pane's item changes", ->
|
||||
it "updates the title to the new item's title plus the project path", ->
|
||||
atom.workspace.getActivePane().activateNextItem()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the last pane item is removed", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
atom.workspace.getActivePane().destroy()
|
||||
expect(atom.workspace.getActivePaneItem()).toBeUndefined()
|
||||
expect(document.title).toBe atom.project.getPaths()[0]
|
||||
|
||||
describe "when an inactive pane's item changes", ->
|
||||
it "does not update the title", ->
|
||||
pane = atom.workspace.getActivePane()
|
||||
pane.splitRight()
|
||||
initialTitle = document.title
|
||||
pane.activateNextItem()
|
||||
expect(document.title).toBe initialTitle
|
||||
|
||||
describe "when the workspace is deserialized", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open('a')
|
||||
|
||||
it "updates the title to contain the project's path", ->
|
||||
document.title = null
|
||||
workspace2 = atom.workspace.testSerialization()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
workspace2.destroy()
|
||||
|
||||
describe "document edited status", ->
|
||||
[item1, item2] = []
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open('a')
|
||||
waitsForPromise -> atom.workspace.open('b')
|
||||
runs ->
|
||||
[item1, item2] = atom.workspace.getPaneItems()
|
||||
spyOn(atom, 'setDocumentEdited')
|
||||
|
||||
it "calls atom.setDocumentEdited when the active item changes", ->
|
||||
expect(atom.workspace.getActivePaneItem()).toBe item2
|
||||
item1.insertText('a')
|
||||
expect(item1.isModified()).toBe true
|
||||
atom.workspace.getActivePane().activateNextItem()
|
||||
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
|
||||
it "calls atom.setDocumentEdited when the active item's modified status changes", ->
|
||||
expect(atom.workspace.getActivePaneItem()).toBe item2
|
||||
item2.insertText('a')
|
||||
advanceClock(item2.getBuffer().getStoppedChangingDelay())
|
||||
|
||||
expect(item2.isModified()).toBe true
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
|
||||
item2.undo()
|
||||
advanceClock(item2.getBuffer().getStoppedChangingDelay())
|
||||
|
||||
expect(item2.isModified()).toBe false
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(false)
|
||||
|
||||
@@ -49,7 +49,7 @@ describe "WorkspaceView", ->
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 2
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
expect(atom.workspaceView.title).toBe "untitled - #{atom.project.getPaths()[0]}"
|
||||
expect(document.title).toBe "untitled - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when there are open editors", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
@@ -106,7 +106,7 @@ describe "WorkspaceView", ->
|
||||
expect(editorView3).not.toHaveFocus()
|
||||
expect(editorView4).not.toHaveFocus()
|
||||
|
||||
expect(atom.workspaceView.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPaths()[0]}"
|
||||
expect(document.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "where there are no open editors", ->
|
||||
it "constructs the view with no open editors", ->
|
||||
@@ -141,56 +141,6 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.trigger(event)
|
||||
expect(commandHandler).toHaveBeenCalled()
|
||||
|
||||
describe "window title", ->
|
||||
describe "when the project has no path", ->
|
||||
it "sets the title to 'untitled'", ->
|
||||
atom.project.setPaths([])
|
||||
expect(atom.workspaceView.title).toBe 'untitled'
|
||||
|
||||
describe "when the project has a path", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b')
|
||||
|
||||
describe "when there is an active pane item", ->
|
||||
it "sets the title to the pane item's title plus the project path", ->
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the title of the active pane item changes", ->
|
||||
it "updates the window title based on the item's new title", ->
|
||||
editor = atom.workspace.getActivePaneItem()
|
||||
editor.buffer.setPath(path.join(temp.dir, 'hi'))
|
||||
expect(atom.workspaceView.title).toBe "#{editor.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the active pane's item changes", ->
|
||||
it "updates the title to the new item's title plus the project path", ->
|
||||
atom.workspaceView.getActivePaneView().activateNextItem()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the last pane item is removed", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
atom.workspaceView.getActivePaneView().remove()
|
||||
expect(atom.workspace.getActivePaneItem()).toBeUndefined()
|
||||
expect(atom.workspaceView.title).toBe atom.project.getPaths()[0]
|
||||
|
||||
describe "when an inactive pane's item changes", ->
|
||||
it "does not update the title", ->
|
||||
pane = atom.workspaceView.getActivePaneView()
|
||||
pane.splitRight()
|
||||
initialTitle = atom.workspaceView.title
|
||||
pane.activateNextItem()
|
||||
expect(atom.workspaceView.title).toBe initialTitle
|
||||
|
||||
describe "when the root view is deserialized", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
workspace2 = atom.workspace.testSerialization()
|
||||
workspaceView2 = workspace2.getView(workspace2).__spacePenView
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(workspaceView2.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
workspaceView2.remove()
|
||||
|
||||
describe "window:toggle-invisibles event", ->
|
||||
it "shows/hides invisibles in all open and future editors", ->
|
||||
atom.workspaceView.height(200)
|
||||
|
||||
@@ -30,14 +30,41 @@ module.exports =
|
||||
getInstallDirectory: ->
|
||||
"/usr/local/bin"
|
||||
|
||||
install: (commandPath, askForPrivilege, callback) ->
|
||||
installShellCommandsInteractively: ->
|
||||
showErrorDialog = (error) ->
|
||||
atom.confirm
|
||||
message: "Failed to install shell commands"
|
||||
detailedMessage: error.message
|
||||
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
@installAtomCommand resourcePath, true, (error) =>
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
@installApmCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
atom.confirm
|
||||
message: "Commands installed."
|
||||
detailedMessage: "The shell commands `atom` and `apm` are installed."
|
||||
|
||||
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'atom.sh')
|
||||
@createSymlink commandPath, askForPrivilege, callback
|
||||
|
||||
installApmCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
|
||||
@createSymlink commandPath, askForPrivilege, callback
|
||||
|
||||
createSymlink: (commandPath, askForPrivilege, callback) ->
|
||||
return unless process.platform is 'darwin'
|
||||
|
||||
commandName = path.basename(commandPath, path.extname(commandPath))
|
||||
destinationPath = path.join(@getInstallDirectory(), commandName)
|
||||
|
||||
fs.readlink destinationPath, (error, realpath) ->
|
||||
if realpath == commandPath
|
||||
if realpath is commandPath
|
||||
callback()
|
||||
return
|
||||
|
||||
@@ -49,11 +76,3 @@ module.exports =
|
||||
catch error
|
||||
|
||||
callback?(error)
|
||||
|
||||
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'atom.sh')
|
||||
@install commandPath, askForPrivilege, callback
|
||||
|
||||
installApmCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
|
||||
@install commandPath, askForPrivilege, callback
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
# This is loaded by atom.coffee
|
||||
# This is loaded by atom.coffee. See https://atom.io/docs/api/latest/Config for
|
||||
# more information about config schemas.
|
||||
module.exports =
|
||||
core:
|
||||
type: 'object'
|
||||
@@ -38,6 +39,19 @@ module.exports =
|
||||
editor:
|
||||
type: 'object'
|
||||
properties:
|
||||
# These settings are used in scoped fashion only. No defaults.
|
||||
commentStart:
|
||||
type: ['string', 'null']
|
||||
commentEnd:
|
||||
type: ['string', 'null']
|
||||
increaseIndentPattern:
|
||||
type: ['string', 'null']
|
||||
decreaseIndentPattern:
|
||||
type: ['string', 'null']
|
||||
foldEndPattern:
|
||||
type: ['string', 'null']
|
||||
|
||||
# These can be used as globals or scoped, thus defaults.
|
||||
fontFamily:
|
||||
type: 'string'
|
||||
default: ''
|
||||
@@ -73,7 +87,7 @@ module.exports =
|
||||
tabLength:
|
||||
type: 'integer'
|
||||
default: 2
|
||||
enum: [1, 2, 4, 6, 8]
|
||||
enum: [1, 2, 3, 4, 6, 8]
|
||||
softWrap:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
|
||||
+285
-89
@@ -1,13 +1,15 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
{Emitter} = require 'event-kit'
|
||||
{Disposable, Emitter} = require 'event-kit'
|
||||
CSON = require 'season'
|
||||
path = require 'path'
|
||||
async = require 'async'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
ScopedPropertyStore = require 'scoped-property-store'
|
||||
|
||||
# Essential: Used to access all of Atom's configuration details.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.config` global.
|
||||
@@ -219,7 +221,7 @@ pathWatcher = require 'pathwatcher'
|
||||
#
|
||||
# All types support an `enum` key. The enum key lets you specify all values
|
||||
# that the config setting can possibly be. `enum` _must_ be an array of values
|
||||
# of your specified type.
|
||||
# of your specified type. Schema:
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
@@ -229,6 +231,8 @@ pathWatcher = require 'pathwatcher'
|
||||
# enum: [2, 4, 6, 8]
|
||||
# ```
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.set('my-package.someSetting', '2')
|
||||
# atom.config.get('my-package.someSetting') # -> 2
|
||||
@@ -307,6 +311,7 @@ class Config
|
||||
properties: {}
|
||||
@defaultSettings = {}
|
||||
@settings = {}
|
||||
@scopedSettingsStore = new ScopedPropertyStore
|
||||
@configFileHasErrors = false
|
||||
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
|
||||
@configFilePath ?= path.join(@configDirPath, 'config.cson')
|
||||
@@ -319,29 +324,57 @@ class Config
|
||||
# than {::onDidChange} in that it will immediately call your callback with the
|
||||
# current value of the config entry.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# You might want to be notified when the themes change. We'll watch
|
||||
# `core.themes` for changes
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.observe 'core.themes', (value) ->
|
||||
# # do stuff with value
|
||||
# ```
|
||||
#
|
||||
# * `scopeDescriptor` (optional) {Array} of {String}s describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {TextEditor::scopesAtCursor}. See {::get} for examples.
|
||||
# * `keyPath` {String} name of the key to observe
|
||||
# * `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: (keyPath, options={}, callback) ->
|
||||
if _.isFunction(options)
|
||||
callback = options
|
||||
options = {}
|
||||
else
|
||||
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)
|
||||
# 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
|
||||
deprecate "Config::observe no longer supports options. #{message}"
|
||||
deprecate "Config::observe no longer supports options; see https://atom.io/docs/api/latest/Config. #{message}"
|
||||
else
|
||||
console.error 'An unsupported form of Config::observe is being used. See https://atom.io/docs/api/latest/Config for details'
|
||||
return
|
||||
|
||||
callback(_.clone(@get(keyPath))) unless options.callNow == false
|
||||
@emitter.on 'did-change', (event) ->
|
||||
callback(event.newValue) if keyPath? and keyPath.indexOf(event?.keyPath) is 0
|
||||
if scopeDescriptor?
|
||||
@observeScopedKeyPath(scopeDescriptor, keyPath, callback)
|
||||
else
|
||||
@observeKeyPath(keyPath, options ? {}, callback)
|
||||
|
||||
# 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.
|
||||
#
|
||||
# * `keyPath` (optional) {String} name of the key to observe
|
||||
# * `scopeDescriptor` (optional) {Array} of {String}s describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {TextEditor::scopesAtCursor}. See {::get} for examples.
|
||||
# * `keyPath` (optional) {String} name of the key to observe. Must be
|
||||
# specified if `scopeDescriptor` is specified.
|
||||
# * `callback` {Function} to call when the value of the key changes.
|
||||
# * `event` {Object}
|
||||
# * `newValue` the new value of the key
|
||||
@@ -350,13 +383,17 @@ class Config
|
||||
#
|
||||
# Returns a {Disposable} with the following keys on which you can call
|
||||
# `.dispose()` to unsubscribe.
|
||||
onDidChange: (keyPath, callback) ->
|
||||
onDidChange: (scopeDescriptor, keyPath, callback) ->
|
||||
args = Array::slice.call(arguments)
|
||||
if arguments.length is 1
|
||||
callback = keyPath
|
||||
keyPath = undefined
|
||||
[callback, scopeDescriptor, keyPath] = args
|
||||
else if arguments.length is 2
|
||||
[keyPath, callback, scopeDescriptor] = args
|
||||
|
||||
@emitter.on 'did-change', (event) ->
|
||||
callback(event) if not keyPath? or (keyPath? and keyPath.indexOf(event?.keyPath) is 0)
|
||||
if scopeDescriptor?
|
||||
@onDidChangeScopedKeyPath(scopeDescriptor, keyPath, callback)
|
||||
else
|
||||
@onDidChangeKeyPath(keyPath, callback)
|
||||
|
||||
###
|
||||
Section: Managing Settings
|
||||
@@ -364,29 +401,84 @@ class Config
|
||||
|
||||
# Essential: Retrieves the setting for the given key.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# You might want to know what themes are enabled, so check `core.themes`
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get('core.themes')
|
||||
# ```
|
||||
#
|
||||
# With scope descriptors you can get settings within a specific editor
|
||||
# scope. For example, you might want to know `editor.tabLength` for ruby
|
||||
# files.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 2
|
||||
# ```
|
||||
#
|
||||
# This setting in ruby files might be different than the global tabLength setting
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get('editor.tabLength') # => 4
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 2
|
||||
# ```
|
||||
#
|
||||
# Additionally, you can get the setting at the specific cursor position.
|
||||
#
|
||||
# ```coffee
|
||||
# scopeDescriptor = @editor.scopesAtCursor()
|
||||
# atom.config.get(scopeDescriptor, 'editor.tabLength') # => 2
|
||||
# ```
|
||||
#
|
||||
# * `scopeDescriptor` (optional) {Array} of {String}s describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {TextEditor::scopesAtCursor}
|
||||
# * `keyPath` The {String} name of the key to retrieve.
|
||||
#
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file in the type specified by the configuration schema.
|
||||
get: (keyPath) ->
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
get: (scopeDescriptor, keyPath) ->
|
||||
if arguments.length == 1
|
||||
keyPath = scopeDescriptor
|
||||
scopeDescriptor = undefined
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
valueIsObject = _.isObject(value) and not _.isArray(value)
|
||||
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
|
||||
if valueIsObject and defaultValueIsObject
|
||||
_.defaults(value, defaultValue)
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
if scopeDescriptor?
|
||||
value = @getRawScopedValue(scopeDescriptor, keyPath)
|
||||
return value if value?
|
||||
|
||||
value
|
||||
@getRawValue(keyPath)
|
||||
|
||||
# Essential: Sets the value for a configuration setting.
|
||||
#
|
||||
# This value is stored in Atom's internal configuration file.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# You might want to change the themes programmatically:
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.set('core.themes', ['atom-light-ui', 'atom-light-syntax'])
|
||||
# ```
|
||||
#
|
||||
# You can also set scoped settings. For example, you might want change the
|
||||
# `editor.tabLength` only for ruby files.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get('editor.tabLength') # => 4
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 4
|
||||
# atom.config.get(['source.js'], 'editor.tabLength') # => 4
|
||||
#
|
||||
# # Set ruby to 2
|
||||
# atom.config.set('source.ruby', 'editor.tabLength', 2) # => true
|
||||
#
|
||||
# # Notice it's only set to 2 in the case of ruby
|
||||
# atom.config.get('editor.tabLength') # => 4
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 2
|
||||
# atom.config.get(['source.js'], 'editor.tabLength') # => 4
|
||||
# ```
|
||||
#
|
||||
# * `scope` (optional) {String}. eg. '.source.ruby'
|
||||
# * `keyPath` The {String} name of the key.
|
||||
# * `value` The value of the setting. Passing `undefined` will revert the
|
||||
# setting to the default value.
|
||||
@@ -394,18 +486,27 @@ class Config
|
||||
# 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: (keyPath, value) ->
|
||||
set: (scope, keyPath, value) ->
|
||||
if arguments.length < 3
|
||||
value = keyPath
|
||||
keyPath = scope
|
||||
scope = undefined
|
||||
|
||||
unless value == undefined
|
||||
try
|
||||
value = @makeValueConformToSchema(keyPath, value)
|
||||
catch e
|
||||
return false
|
||||
|
||||
@setRawValue(keyPath, value)
|
||||
if scope?
|
||||
@setRawScopedValue(scope, keyPath, value)
|
||||
else
|
||||
@setRawValue(keyPath, value)
|
||||
|
||||
@save() unless @configFileHasErrors
|
||||
true
|
||||
|
||||
# Extended: Restore the key path to its default value.
|
||||
# Extended: Restore the global setting at `keyPath` to its default value.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
@@ -414,7 +515,7 @@ class Config
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
@get(keyPath)
|
||||
|
||||
# Extended: Get the default value of the key path. _Please note_ that in most
|
||||
# Extended: 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.
|
||||
#
|
||||
@@ -425,7 +526,7 @@ class Config
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
_.deepClone(defaultValue)
|
||||
|
||||
# Extended: Is the key path value its default value?
|
||||
# Extended: Is the value at `keyPath` its default value?
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
@@ -434,7 +535,7 @@ class Config
|
||||
isDefault: (keyPath) ->
|
||||
not _.valueForKeyPath(@settings, keyPath)?
|
||||
|
||||
# Extended: Retrieve the schema for a specific key path. The shema will tell
|
||||
# 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
|
||||
# option.
|
||||
#
|
||||
@@ -450,7 +551,8 @@ class Config
|
||||
schema = schema.properties[key]
|
||||
schema
|
||||
|
||||
# Extended: Returns a new {Object} containing all of settings and defaults.
|
||||
# Extended: Returns a new {Object} containing all of the global settings and
|
||||
# defaults. This does not include scoped settings.
|
||||
getSettings: ->
|
||||
_.deepExtend(@settings, @defaultSettings)
|
||||
|
||||
@@ -484,7 +586,7 @@ class Config
|
||||
deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.'
|
||||
|
||||
###
|
||||
Section: Private
|
||||
Section: Internal methods used by core
|
||||
###
|
||||
|
||||
pushAtKeyPath: (keyPath, value) ->
|
||||
@@ -505,6 +607,34 @@ class Config
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
setSchema: (keyPath, schema) ->
|
||||
unless isPlainObject(schema)
|
||||
throw new Error("Error loading schema for #{keyPath}: schemas can only be objects!")
|
||||
|
||||
unless typeof schema.type?
|
||||
throw new Error("Error loading schema for #{keyPath}: schema objects must have a type attribute")
|
||||
|
||||
rootSchema = @schema
|
||||
if keyPath
|
||||
for key in keyPath.split('.')
|
||||
rootSchema.type = 'object'
|
||||
rootSchema.properties ?= {}
|
||||
properties = rootSchema.properties
|
||||
properties[key] ?= {}
|
||||
rootSchema = properties[key]
|
||||
|
||||
_.extend rootSchema, schema
|
||||
@setDefaults(keyPath, @extractDefaultsFromSchema(schema))
|
||||
|
||||
load: ->
|
||||
@initializeConfigDirectory()
|
||||
@loadUserConfig()
|
||||
@observeUserConfig()
|
||||
|
||||
###
|
||||
Section: Private methods managing the user's config file
|
||||
###
|
||||
|
||||
initializeConfigDirectory: (done) ->
|
||||
return if fs.existsSync(@configDirPath)
|
||||
|
||||
@@ -521,11 +651,6 @@ class Config
|
||||
queue.push({sourcePath, destinationPath})
|
||||
fs.traverseTree(templateConfigDirPath, onConfigDirFile, (path) -> true)
|
||||
|
||||
load: ->
|
||||
@initializeConfigDirectory()
|
||||
@loadUserConfig()
|
||||
@observeUserConfig()
|
||||
|
||||
loadUserConfig: ->
|
||||
unless fs.existsSync(@configFilePath)
|
||||
fs.makeTreeSync(path.dirname(@configFilePath))
|
||||
@@ -555,33 +680,9 @@ class Config
|
||||
save: ->
|
||||
CSON.writeFileSync(@configFilePath, @settings)
|
||||
|
||||
setRawValue: (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)
|
||||
|
||||
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)
|
||||
|
||||
setRecursive: (keyPath, value) ->
|
||||
if isPlainObject(value)
|
||||
keys = if keyPath? then keyPath.split('.') else []
|
||||
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))}")
|
||||
###
|
||||
Section: Private methods managing global settings
|
||||
###
|
||||
|
||||
setAll: (newSettings) ->
|
||||
unless isPlainObject(newSettings)
|
||||
@@ -602,6 +703,55 @@ class Config
|
||||
@setRecursive(null, newSettings)
|
||||
unsetUnspecifiedValues(null, @settings)
|
||||
|
||||
setRecursive: (keyPath, value) ->
|
||||
if isPlainObject(value)
|
||||
keys = if keyPath? then keyPath.split('.') else []
|
||||
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)
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
_.defaults(value, defaultValue) if isPlainObject(value) and isPlainObject(defaultValue)
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
|
||||
value
|
||||
|
||||
setRawValue: (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)
|
||||
|
||||
observeKeyPath: (keyPath, options, callback) ->
|
||||
callback(_.clone(@get(keyPath))) unless options.callNow == false
|
||||
@emitter.on 'did-change', (event) ->
|
||||
callback(event.newValue) if keyPath? and keyPath.indexOf(event?.keyPath) is 0
|
||||
|
||||
onDidChangeKeyPath: (keyPath, callback) ->
|
||||
@emitter.on 'did-change', (event) ->
|
||||
callback(event) if not keyPath? or (keyPath? and keyPath.indexOf(event?.keyPath) is 0)
|
||||
|
||||
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)
|
||||
|
||||
setDefaults: (keyPath, defaults) ->
|
||||
if defaults? and isPlainObject(defaults)
|
||||
keys = if keyPath? then keyPath.split('.') else []
|
||||
@@ -615,25 +765,6 @@ class Config
|
||||
catch e
|
||||
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
|
||||
|
||||
setSchema: (keyPath, schema) ->
|
||||
unless isPlainObject(schema)
|
||||
throw new Error("Error loading schema for #{keyPath}: schemas can only be objects!")
|
||||
|
||||
unless typeof schema.type?
|
||||
throw new Error("Error loading schema for #{keyPath}: schema objects must have a type attribute")
|
||||
|
||||
rootSchema = @schema
|
||||
if keyPath
|
||||
for key in keyPath.split('.')
|
||||
rootSchema.type = 'object'
|
||||
rootSchema.properties ?= {}
|
||||
properties = rootSchema.properties
|
||||
properties[key] ?= {}
|
||||
rootSchema = properties[key]
|
||||
|
||||
_.extend rootSchema, schema
|
||||
@setDefaults(keyPath, @extractDefaultsFromSchema(schema))
|
||||
|
||||
extractDefaultsFromSchema: (schema) ->
|
||||
if schema.default?
|
||||
schema.default
|
||||
@@ -647,6 +778,71 @@ class Config
|
||||
value = @constructor.executeSchemaEnforcers(keyPath, value, schema) if schema = @getSchema(keyPath)
|
||||
value
|
||||
|
||||
###
|
||||
Section: Private Scoped Settings
|
||||
###
|
||||
|
||||
addScopedSettings: (name, selector, value) ->
|
||||
if arguments.length < 3
|
||||
value = selector
|
||||
selector = name
|
||||
name = null
|
||||
|
||||
settingsBySelector = {}
|
||||
settingsBySelector[selector] = value
|
||||
disposable = @scopedSettingsStore.addProperties(name, settingsBySelector)
|
||||
@emitter.emit 'did-change'
|
||||
new Disposable =>
|
||||
disposable.dispose()
|
||||
@emitter.emit 'did-change'
|
||||
|
||||
setRawScopedValue: (selector, keyPath, value) ->
|
||||
if keyPath?
|
||||
newValue = {}
|
||||
_.setValueForKeyPath(newValue, keyPath, value)
|
||||
value = newValue
|
||||
@addScopedSettings(null, selector, value)
|
||||
|
||||
getRawScopedValue: (scopeDescriptor, keyPath) ->
|
||||
scopeChain = scopeDescriptor
|
||||
.map (scope) ->
|
||||
scope = ".#{scope}" unless scope[0] is '.'
|
||||
scope
|
||||
.join(' ')
|
||||
@scopedSettingsStore.getPropertyValue(scopeChain, keyPath)
|
||||
|
||||
observeScopedKeyPath: (scopeDescriptor, keyPath, callback) ->
|
||||
oldValue = @get(scopeDescriptor, keyPath)
|
||||
|
||||
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
|
||||
|
||||
# TODO: figure out how to change / remove this. The return value is awkward.
|
||||
# * language mode uses it for one thing.
|
||||
# * autocomplete uses it for editor.completions
|
||||
settingsForScopeDescriptor: (scopeDescriptor, keyPath) ->
|
||||
scopeChain = scopeDescriptor
|
||||
.map (scope) ->
|
||||
scope = ".#{scope}" unless scope[0] is '.'
|
||||
scope
|
||||
.join(' ')
|
||||
@scopedSettingsStore.getProperties(scopeChain, keyPath)
|
||||
|
||||
# Base schema enforcers. These will coerce raw input into the specified type,
|
||||
# and will throw an error when the value cannot be coerced. Throwing the error
|
||||
# will indicate that the value should not be set.
|
||||
@@ -692,7 +888,7 @@ Config.addSchemaEnforcers
|
||||
'null':
|
||||
# null sort of isnt supported. It will just unset in this case
|
||||
coerce: (keyPath, value, schema) ->
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be null") unless value == null
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be null") unless value in [undefined, null]
|
||||
value
|
||||
|
||||
'object':
|
||||
|
||||
@@ -30,11 +30,11 @@ class LanguageMode
|
||||
# Returns an {Array} of the commented {Ranges}.
|
||||
toggleLineCommentsForBufferRows: (start, end) ->
|
||||
scopes = @editor.scopesForBufferPosition([start, 0])
|
||||
properties = atom.syntax.propertiesForScope(scopes, "editor.commentStart")[0]
|
||||
properties = atom.config.settingsForScopeDescriptor(scopes, 'editor.commentStart')[0]
|
||||
return unless properties
|
||||
|
||||
commentStartString = _.valueForKeyPath(properties, "editor.commentStart")
|
||||
commentEndString = _.valueForKeyPath(properties, "editor.commentEnd")
|
||||
commentStartString = _.valueForKeyPath(properties, 'editor.commentStart')
|
||||
commentEndString = _.valueForKeyPath(properties, 'editor.commentEnd')
|
||||
|
||||
return unless commentStartString
|
||||
|
||||
@@ -312,7 +312,7 @@ class LanguageMode
|
||||
@editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
|
||||
|
||||
getRegexForProperty: (scopes, property) ->
|
||||
if pattern = atom.syntax.getProperty(scopes, property)
|
||||
if pattern = atom.config.get(scopes, property)
|
||||
new OnigRegExp(pattern)
|
||||
|
||||
increaseIndentRegexForScopes: (scopes) ->
|
||||
|
||||
@@ -133,10 +133,10 @@ class MenuManager
|
||||
element?.classList.toString().split(' ') ? []
|
||||
|
||||
sortPackagesMenu: ->
|
||||
packagesMenu = @template.find ({label}) => MenuHelpers.normalizeLabel(label) is 'Packages'
|
||||
packagesMenu = @template.find ({label}) -> MenuHelpers.normalizeLabel(label) is 'Packages'
|
||||
return unless packagesMenu?.submenu?
|
||||
|
||||
packagesMenu.submenu.sort (item1, item2) =>
|
||||
packagesMenu.submenu.sort (item1, item2) ->
|
||||
if item1.label and item2.label
|
||||
MenuHelpers.normalizeLabel(item1.label).localeCompare(MenuHelpers.normalizeLabel(item2.label))
|
||||
else
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{callAttachHooks} = require './space-pen-extensions'
|
||||
|
||||
class PaneAxisElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
detachedCallback: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.onDidAddChild(@childAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this))
|
||||
|
||||
@childAdded({child, index}) for child, index in @model.getChildren()
|
||||
|
||||
switch @model.getOrientation()
|
||||
when 'horizontal'
|
||||
@classList.add('pane-row')
|
||||
when 'vertical'
|
||||
@classList.add('pane-column')
|
||||
|
||||
childAdded: ({child, index}) ->
|
||||
view = @model.getView(child)
|
||||
@insertBefore(view, @children[index])
|
||||
callAttachHooks(view) # for backward compatibility with SpacePen views
|
||||
|
||||
childRemoved: ({child}) ->
|
||||
view = @model.getView(child)
|
||||
view.remove()
|
||||
|
||||
childReplaced: ({index, oldChild, newChild}) ->
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@childRemoved({child: oldChild, index})
|
||||
@childAdded({child: newChild, index})
|
||||
focusedElement?.focus() if document.activeElement is document.body
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
module.exports = PaneAxisElement = document.registerElement 'atom-pane-axis',
|
||||
prototype: PaneAxisElement.prototype
|
||||
extends: 'div'
|
||||
@@ -1,37 +0,0 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{View} = require './space-pen-extensions'
|
||||
PaneView = null
|
||||
|
||||
module.exports =
|
||||
class PaneAxisView extends View
|
||||
initialize: (@model) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@onChildAdded({child, index}) for child, index in @model.getChildren()
|
||||
|
||||
@subscriptions.add @model.onDidAddChild(@onChildAdded)
|
||||
@subscriptions.add @model.onDidRemoveChild(@onChildRemoved)
|
||||
@subscriptions.add @model.onDidReplaceChild(@onChildReplaced)
|
||||
|
||||
afterAttach: ->
|
||||
@container = @closest('.panes').view()
|
||||
|
||||
onChildReplaced: ({index, oldChild, newChild}) =>
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@onChildRemoved({child: oldChild, index})
|
||||
@onChildAdded({child: newChild, index})
|
||||
focusedElement?.focus() if document.activeElement is document.body
|
||||
|
||||
onChildAdded: ({child, index}) =>
|
||||
view = @model.getView(child).__spacePenView
|
||||
@insertAt(index, view)
|
||||
|
||||
onChildRemoved: ({child}) =>
|
||||
view = @model.getView(child).__spacePenView
|
||||
view.detach()
|
||||
PaneView ?= require './pane-view'
|
||||
if view instanceof PaneView and view.model.isDestroyed()
|
||||
@container?.trigger 'pane:removed', [view]
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
@@ -3,9 +3,6 @@
|
||||
{flatten} = require 'underscore-plus'
|
||||
Serializable = require 'serializable'
|
||||
|
||||
PaneRowView = null
|
||||
PaneColumnView = null
|
||||
|
||||
module.exports =
|
||||
class PaneAxis extends Model
|
||||
atom.deserializers.add(this)
|
||||
@@ -40,11 +37,7 @@ class PaneAxis extends Model
|
||||
|
||||
setContainer: (@container) -> @container
|
||||
|
||||
getViewClass: ->
|
||||
if @orientation is 'vertical'
|
||||
PaneColumnView ?= require './pane-column-view'
|
||||
else
|
||||
PaneRowView ?= require './pane-row-view'
|
||||
getOrientation: -> @orientation
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{$} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
PaneAxisView = require './pane-axis-view'
|
||||
|
||||
module.exports =
|
||||
class PaneColumnView extends PaneAxisView
|
||||
|
||||
@content: ->
|
||||
@div class: 'pane-column'
|
||||
|
||||
className: ->
|
||||
"PaneColumn"
|
||||
@@ -0,0 +1,80 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{callAttachHooks} = require './space-pen-extensions'
|
||||
PaneContainerView = null
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
class PaneContainerElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@classList.add 'panes'
|
||||
PaneContainerView ?= require './pane-container-view'
|
||||
@__spacePenView = new PaneContainerView(this)
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.observeRoot(@rootChanged.bind(this))
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
rootChanged: (root) ->
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@firstChild?.remove()
|
||||
if root?
|
||||
view = @model.getView(root)
|
||||
@appendChild(view)
|
||||
callAttachHooks(view)
|
||||
focusedElement?.focus()
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
focusPaneViewAbove: ->
|
||||
@nearestPaneInDirection('above')?.focus()
|
||||
|
||||
focusPaneViewBelow: ->
|
||||
@nearestPaneInDirection('below')?.focus()
|
||||
|
||||
focusPaneViewOnLeft: ->
|
||||
@nearestPaneInDirection('left')?.focus()
|
||||
|
||||
focusPaneViewOnRight: ->
|
||||
@nearestPaneInDirection('right')?.focus()
|
||||
|
||||
nearestPaneInDirection: (direction) ->
|
||||
distance = (pointA, pointB) ->
|
||||
x = pointB.x - pointA.x
|
||||
y = pointB.y - pointA.y
|
||||
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
|
||||
paneView = @model.getView(@model.getActivePane())
|
||||
box = @boundingBoxForPaneView(paneView)
|
||||
|
||||
paneViews = _.toArray(@querySelectorAll('.pane'))
|
||||
.filter (otherPaneView) =>
|
||||
otherBox = @boundingBoxForPaneView(otherPaneView)
|
||||
switch direction
|
||||
when 'left' then otherBox.right.x <= box.left.x
|
||||
when 'right' then otherBox.left.x >= box.right.x
|
||||
when 'above' then otherBox.bottom.y <= box.top.y
|
||||
when 'below' then otherBox.top.y >= box.bottom.y
|
||||
.sort (paneViewA, paneViewB) =>
|
||||
boxA = @boundingBoxForPaneView(paneViewA)
|
||||
boxB = @boundingBoxForPaneView(paneViewB)
|
||||
switch direction
|
||||
when 'left' then distance(box.left, boxA.right) - distance(box.left, boxB.right)
|
||||
when 'right' then distance(box.right, boxA.left) - distance(box.right, boxB.left)
|
||||
when 'above' then distance(box.top, boxA.bottom) - distance(box.top, boxB.bottom)
|
||||
when 'below' then distance(box.bottom, boxA.top) - distance(box.bottom, boxB.top)
|
||||
|
||||
paneViews[0]
|
||||
|
||||
boundingBoxForPaneView: (paneView) ->
|
||||
boundingBox = paneView.getBoundingClientRect()
|
||||
|
||||
left: {x: boundingBox.left, y: boundingBox.top}
|
||||
right: {x: boundingBox.right, y: boundingBox.top}
|
||||
top: {x: boundingBox.left, y: boundingBox.top}
|
||||
bottom: {x: boundingBox.left, y: boundingBox.bottom}
|
||||
|
||||
module.exports = PaneContainerElement = document.registerElement 'atom-pane-container',
|
||||
prototype: PaneContainerElement.prototype
|
||||
extends: 'div'
|
||||
@@ -1,7 +1,7 @@
|
||||
{deprecate} = require 'grim'
|
||||
Delegator = require 'delegato'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{$, View} = require './space-pen-extensions'
|
||||
{$, View, callAttachHooks} = require './space-pen-extensions'
|
||||
PaneView = require './pane-view'
|
||||
PaneContainer = require './pane-container'
|
||||
|
||||
@@ -15,50 +15,22 @@ class PaneContainerView extends View
|
||||
@content: ->
|
||||
@div class: 'panes'
|
||||
|
||||
initialize: (params) ->
|
||||
constructor: (@element) ->
|
||||
super
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
if params instanceof PaneContainer
|
||||
@model = params
|
||||
else
|
||||
@model = new PaneContainer({root: params?.root?.model})
|
||||
|
||||
@subscriptions.add @model.observeRoot(@onRootChanged)
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged)
|
||||
|
||||
getRoot: ->
|
||||
@children().first().view()
|
||||
|
||||
onRootChanged: (root) =>
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
|
||||
oldRoot = @getRoot()
|
||||
if oldRoot instanceof PaneView and oldRoot.model.isDestroyed()
|
||||
@trigger 'pane:removed', [oldRoot]
|
||||
oldRoot?.detach()
|
||||
if root?
|
||||
view = @model.getView(root).__spacePenView
|
||||
@append(view)
|
||||
focusedElement?.focus()
|
||||
else
|
||||
atom.workspaceView?.focus() if focusedElement?
|
||||
view = @model.getView(@model.getRoot())
|
||||
view.__spacePenView ? view
|
||||
|
||||
onActivePaneItemChanged: (activeItem) =>
|
||||
@trigger 'pane-container:active-pane-item-changed', [activeItem]
|
||||
|
||||
removeChild: (child) ->
|
||||
throw new Error("Removing non-existant child") unless @getRoot() is child
|
||||
@setRoot(null)
|
||||
@trigger 'pane:removed', [child] if child instanceof PaneView
|
||||
|
||||
confirmClose: ->
|
||||
saved = true
|
||||
for paneView in @getPaneViews()
|
||||
for item in paneView.getItems()
|
||||
if not paneView.promptToSaveItem(item)
|
||||
saved = false
|
||||
break
|
||||
saved
|
||||
@model.confirmClose()
|
||||
|
||||
getPaneViews: ->
|
||||
@find('.pane').views()
|
||||
@@ -101,56 +73,17 @@ class PaneContainerView extends View
|
||||
@model.activatePreviousPane()
|
||||
|
||||
focusPaneViewAbove: ->
|
||||
@nearestPaneInDirection('above')?.focus()
|
||||
@element.focusPaneViewAbove()
|
||||
|
||||
focusPaneViewBelow: ->
|
||||
@nearestPaneInDirection('below')?.focus()
|
||||
@element.focusPaneViewBelow()
|
||||
|
||||
focusPaneViewOnLeft: ->
|
||||
@nearestPaneInDirection('left')?.focus()
|
||||
@element.focusPaneViewOnLeft()
|
||||
|
||||
focusPaneViewOnRight: ->
|
||||
@nearestPaneInDirection('right')?.focus()
|
||||
@element.focusPaneViewOnRight()
|
||||
|
||||
nearestPaneInDirection: (direction) ->
|
||||
distance = (pointA, pointB) ->
|
||||
x = pointB.x - pointA.x
|
||||
y = pointB.y - pointA.y
|
||||
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
|
||||
paneView = @getActivePaneView()
|
||||
box = @boundingBoxForPaneView(paneView)
|
||||
paneViews = @getPaneViews()
|
||||
.filter (otherPaneView) =>
|
||||
otherBox = @boundingBoxForPaneView(otherPaneView)
|
||||
switch direction
|
||||
when 'left' then otherBox.right.x <= box.left.x
|
||||
when 'right' then otherBox.left.x >= box.right.x
|
||||
when 'above' then otherBox.bottom.y <= box.top.y
|
||||
when 'below' then otherBox.top.y >= box.bottom.y
|
||||
.sort (paneViewA, paneViewB) =>
|
||||
boxA = @boundingBoxForPaneView(paneViewA)
|
||||
boxB = @boundingBoxForPaneView(paneViewB)
|
||||
switch direction
|
||||
when 'left' then distance(box.left, boxA.right) - distance(box.left, boxB.right)
|
||||
when 'right' then distance(box.right, boxA.left) - distance(box.right, boxB.left)
|
||||
when 'above' then distance(box.top, boxA.bottom) - distance(box.top, boxB.bottom)
|
||||
when 'below' then distance(box.bottom, boxA.top) - distance(box.bottom, boxB.top)
|
||||
|
||||
paneViews[0]
|
||||
|
||||
boundingBoxForPaneView: (paneView) ->
|
||||
boundingBox = paneView[0].getBoundingClientRect()
|
||||
|
||||
left: {x: boundingBox.left, y: boundingBox.top}
|
||||
right: {x: boundingBox.right, y: boundingBox.top}
|
||||
top: {x: boundingBox.left, y: boundingBox.top}
|
||||
bottom: {x: boundingBox.left, y: boundingBox.bottom}
|
||||
|
||||
# Deprecated
|
||||
getPanes: ->
|
||||
deprecate("Use PaneContainerView::getPaneViews() instead")
|
||||
@getPaneViews()
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Pane = require './pane'
|
||||
PaneElement = require './pane-element'
|
||||
PaneContainerElement = require './pane-container-element'
|
||||
PaneAxisElement = require './pane-axis-element'
|
||||
PaneAxis = require './pane-axis'
|
||||
ViewRegistry = require './view-registry'
|
||||
ItemRegistry = require './item-registry'
|
||||
PaneContainerView = null
|
||||
|
||||
module.exports =
|
||||
class PaneContainer extends Model
|
||||
@@ -30,8 +33,10 @@ class PaneContainer extends Model
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@viewRegistry = params?.viewRegistry ? new ViewRegistry
|
||||
@itemRegistry = new ItemRegistry
|
||||
@viewRegistry = params?.viewRegistry ? new ViewRegistry
|
||||
@registerViewProviders()
|
||||
|
||||
@setRoot(params?.root ? new Pane)
|
||||
@destroyEmptyPanes() if params?.destroyEmptyPanes
|
||||
|
||||
@@ -48,8 +53,18 @@ class PaneContainer extends Model
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
getViewClass: ->
|
||||
PaneContainerView ?= require './pane-container-view'
|
||||
registerViewProviders: ->
|
||||
@viewRegistry.addViewProvider
|
||||
modelConstructor: PaneContainer
|
||||
viewConstructor: PaneContainerElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
modelConstructor: PaneAxis
|
||||
viewConstructor: PaneAxisElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
modelConstructor: Pane
|
||||
viewConstructor: PaneElement
|
||||
|
||||
getView: (object) ->
|
||||
@viewRegistry.getView(object)
|
||||
@@ -129,6 +144,17 @@ class PaneContainer extends Model
|
||||
saveAll: ->
|
||||
pane.saveItems() for pane in @getPanes()
|
||||
|
||||
confirmClose: ->
|
||||
allSaved = true
|
||||
|
||||
for pane in @getPanes()
|
||||
for item in pane.getItems()
|
||||
unless pane.promptToSaveItem(item)
|
||||
allSaved = false
|
||||
break
|
||||
|
||||
allSaved
|
||||
|
||||
activateNextPane: ->
|
||||
panes = @getPanes()
|
||||
if panes.length > 1
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{$} = require './space-pen-extensions'
|
||||
PaneView = require './pane-view'
|
||||
|
||||
class PaneElement extends HTMLElement
|
||||
attached: false
|
||||
|
||||
createdCallback: ->
|
||||
@attached = false
|
||||
@subscriptions = new CompositeDisposable
|
||||
@initializeContent()
|
||||
@subscribeToDOMEvents()
|
||||
@createSpacePenShim()
|
||||
|
||||
attachedCallback: ->
|
||||
@attached = true
|
||||
@focus() if @model.isFocused()
|
||||
|
||||
detachedCallback: ->
|
||||
@attached = false
|
||||
|
||||
initializeContent: ->
|
||||
@setAttribute 'class', 'pane'
|
||||
@setAttribute 'tabindex', -1
|
||||
@appendChild @itemViews = document.createElement('div')
|
||||
@itemViews.setAttribute 'class', 'item-views'
|
||||
|
||||
subscribeToDOMEvents: ->
|
||||
@addEventListener 'focusin', => @model.focus()
|
||||
@addEventListener 'focusout', => @model.blur()
|
||||
@addEventListener 'focus', => @getActiveView()?.focus()
|
||||
|
||||
createSpacePenShim: ->
|
||||
@__spacePenView = new PaneView(this)
|
||||
|
||||
addCommands = (handlersByName) =>
|
||||
for name, handler of handlersByName
|
||||
do (handler) =>
|
||||
@__spacePenView.command name, => handler.apply(this, arguments)
|
||||
|
||||
addCommands(
|
||||
'pane:save-items': -> @getModel().saveItems()
|
||||
'pane:show-next-item': -> @getModel().activateNextItem()
|
||||
'pane:show-previous-item': -> @getModel().activatePreviousItem()
|
||||
'pane:show-item-1': -> @getModel().activateItemAtIndex(0)
|
||||
'pane:show-item-2': -> @getModel().activateItemAtIndex(1)
|
||||
'pane:show-item-3': -> @getModel().activateItemAtIndex(2)
|
||||
'pane:show-item-4': -> @getModel().activateItemAtIndex(3)
|
||||
'pane:show-item-5': -> @getModel().activateItemAtIndex(4)
|
||||
'pane:show-item-6': -> @getModel().activateItemAtIndex(5)
|
||||
'pane:show-item-7': -> @getModel().activateItemAtIndex(6)
|
||||
'pane:show-item-8': -> @getModel().activateItemAtIndex(7)
|
||||
'pane:show-item-9': -> @getModel().activateItemAtIndex(8)
|
||||
'pane:split-left': -> @getModel().splitLeft(copyActiveItem: true)
|
||||
'pane:split-right': -> @getModel().splitRight(copyActiveItem: true)
|
||||
'pane:split-up': -> @getModel().splitUp(copyActiveItem: true)
|
||||
'pane:split-down': -> @getModel().splitDown(copyActiveItem: true)
|
||||
'pane:close': -> @getModel().destroy()
|
||||
'pane:close-other-items': -> @getModel().destroyInactiveItems()
|
||||
)
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.onDidActivate(@activated.bind(this))
|
||||
@subscriptions.add @model.observeActive(@activeStatusChanged.bind(this))
|
||||
@subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this))
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
activated: ->
|
||||
@focus() unless @hasFocus()
|
||||
|
||||
activeStatusChanged: (active) ->
|
||||
if active
|
||||
@classList.add('active')
|
||||
else
|
||||
@classList.remove('active')
|
||||
|
||||
activeItemChanged: (item) ->
|
||||
return unless item?
|
||||
|
||||
$itemViews = $(@itemViews)
|
||||
view = @model.getView(item).__spacePenView
|
||||
otherView.hide() for otherView in $itemViews.children().not(view).views()
|
||||
$itemViews.append(view) unless view.parent().is($itemViews)
|
||||
view.show() if @attached
|
||||
view.focus() if @hasFocus()
|
||||
|
||||
itemRemoved: ({item, index, destroyed}) ->
|
||||
if item instanceof $
|
||||
viewToRemove = item
|
||||
else
|
||||
viewToRemove = @model.getView(item).__spacePenView
|
||||
|
||||
if viewToRemove?
|
||||
if destroyed
|
||||
viewToRemove.remove()
|
||||
else
|
||||
viewToRemove.detach()
|
||||
|
||||
paneDestroyed: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
getActiveView: -> @model.getView(@model.getActiveItem())
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
module.exports = PaneElement = document.registerElement 'atom-pane',
|
||||
prototype: PaneElement.prototype
|
||||
extends: 'div'
|
||||
@@ -1,11 +0,0 @@
|
||||
{$} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
PaneAxisView = require './pane-axis-view'
|
||||
|
||||
module.exports =
|
||||
class PaneRowView extends PaneAxisView
|
||||
@content: ->
|
||||
@div class: 'pane-row'
|
||||
|
||||
className: ->
|
||||
"PaneRow"
|
||||
+20
-76
@@ -17,12 +17,6 @@ class PaneView extends View
|
||||
Delegator.includeInto(this)
|
||||
PropertyAccessors.includeInto(this)
|
||||
|
||||
@version: 1
|
||||
|
||||
@content: (wrappedView) ->
|
||||
@div class: 'pane', tabindex: -1, =>
|
||||
@div class: 'item-views', outlet: 'itemViews'
|
||||
|
||||
@delegatesProperties 'items', 'activeItem', toProperty: 'model'
|
||||
@delegatesMethods 'getItems', 'activateNextItem', 'activatePreviousItem', 'getActiveItemIndex',
|
||||
'activateItemAtIndex', 'activateItem', 'addItem', 'itemAtIndex', 'moveItem', 'moveItemToPane',
|
||||
@@ -32,49 +26,33 @@ class PaneView extends View
|
||||
'activate', 'getActiveItem', toProperty: 'model'
|
||||
|
||||
previousActiveItem: null
|
||||
attached: false
|
||||
|
||||
initialize: (@model) ->
|
||||
constructor: (@element) ->
|
||||
@itemViews = $(element.itemViews)
|
||||
super
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@onItemAdded(item) for item in @items
|
||||
@handleEvents()
|
||||
|
||||
handleEvents: ->
|
||||
@subscriptions.add @model.observeActiveItem(@onActiveItemChanged)
|
||||
@subscriptions.add @model.onDidAddItem(@onItemAdded)
|
||||
@subscriptions.add @model.onDidRemoveItem(@onItemRemoved)
|
||||
@subscriptions.add @model.onDidMoveItem(@onItemMoved)
|
||||
@subscriptions.add @model.onWillDestroyItem(@onBeforeItemDestroyed)
|
||||
@subscriptions.add @model.onDidActivate(@onActivated)
|
||||
@subscriptions.add @model.observeActive(@onActiveStatusChanged)
|
||||
@subscriptions.add @model.onDidDestroy(@onPaneDestroyed)
|
||||
|
||||
@subscribe this, 'focusin', => @model.focus()
|
||||
@subscribe this, 'focusout', => @model.blur()
|
||||
@subscribe this, 'focus', =>
|
||||
@activeView?.focus()
|
||||
false
|
||||
afterAttach: ->
|
||||
@container ?= @closest('.panes').view()
|
||||
@trigger('pane:attached', [this]) unless @attached
|
||||
@attached = true
|
||||
|
||||
@command 'pane:save-items', => @saveItems()
|
||||
@command 'pane:show-next-item', => @activateNextItem()
|
||||
@command 'pane:show-previous-item', => @activatePreviousItem()
|
||||
onPaneDestroyed: =>
|
||||
@container?.trigger 'pane:removed', [this]
|
||||
@subscriptions.dispose()
|
||||
|
||||
@command 'pane:show-item-1', => @activateItemAtIndex(0)
|
||||
@command 'pane:show-item-2', => @activateItemAtIndex(1)
|
||||
@command 'pane:show-item-3', => @activateItemAtIndex(2)
|
||||
@command 'pane:show-item-4', => @activateItemAtIndex(3)
|
||||
@command 'pane:show-item-5', => @activateItemAtIndex(4)
|
||||
@command 'pane:show-item-6', => @activateItemAtIndex(5)
|
||||
@command 'pane:show-item-7', => @activateItemAtIndex(6)
|
||||
@command 'pane:show-item-8', => @activateItemAtIndex(7)
|
||||
@command 'pane:show-item-9', => @activateItemAtIndex(8)
|
||||
|
||||
@command 'pane:split-left', => @model.splitLeft(copyActiveItem: true)
|
||||
@command 'pane:split-right', => @model.splitRight(copyActiveItem: true)
|
||||
@command 'pane:split-up', => @model.splitUp(copyActiveItem: true)
|
||||
@command 'pane:split-down', => @model.splitDown(copyActiveItem: true)
|
||||
@command 'pane:close', =>
|
||||
@model.destroyItems()
|
||||
@model.destroy()
|
||||
@command 'pane:close-other-items', => @destroyInactiveItems()
|
||||
remove: ->
|
||||
@model.destroy() unless @model.isDestroyed()
|
||||
|
||||
# Essential: Returns the {Pane} model underlying this pane view
|
||||
getModel: -> @model
|
||||
@@ -109,23 +87,10 @@ class PaneView extends View
|
||||
deprecate("Use PaneView::activatePreviousItem instead")
|
||||
@activatePreviousItem()
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
@focus() if @model.focused and onDom
|
||||
|
||||
return if @attached
|
||||
@container = @closest('.panes').view()
|
||||
@attached = true
|
||||
@trigger 'pane:attached', [this]
|
||||
|
||||
onActivated: =>
|
||||
@focus() unless @hasFocus()
|
||||
|
||||
onActiveStatusChanged: (active) =>
|
||||
if active
|
||||
@addClass('active')
|
||||
@trigger 'pane:became-active'
|
||||
else
|
||||
@removeClass('active')
|
||||
@trigger 'pane:became-inactive'
|
||||
|
||||
# Public: Returns the next pane, ordered by creation.
|
||||
@@ -179,23 +144,12 @@ class PaneView extends View
|
||||
@trigger 'pane:item-added', [item, index]
|
||||
|
||||
onItemRemoved: ({item, index, destroyed}) =>
|
||||
if item instanceof $
|
||||
viewToRemove = item
|
||||
else
|
||||
viewToRemove = @model.getView(item).__spacePenView
|
||||
|
||||
if viewToRemove?
|
||||
if destroyed
|
||||
viewToRemove.remove()
|
||||
else
|
||||
viewToRemove.detach()
|
||||
|
||||
@trigger 'pane:item-removed', [item, index]
|
||||
|
||||
onItemMoved: ({item, newIndex}) =>
|
||||
@trigger 'pane:item-moved', [item, newIndex]
|
||||
|
||||
onBeforeItemDestroyed: (item) =>
|
||||
onBeforeItemDestroyed: ({item}) =>
|
||||
@unsubscribe(item) if typeof item.off is 'function'
|
||||
@trigger 'pane:before-item-destroyed', [item]
|
||||
|
||||
@@ -215,17 +169,7 @@ class PaneView extends View
|
||||
|
||||
splitDown: (items...) -> @model.getView(@model.splitDown({items})).__spacePenView
|
||||
|
||||
# Public: Get the container view housing this pane.
|
||||
#
|
||||
# Returns a {View}.
|
||||
getContainer: ->
|
||||
@closest('.panes').view()
|
||||
getContainer: -> @closest('.panes').view()
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
@model.destroy() unless @model.isDestroyed()
|
||||
|
||||
remove: (selector, keepData) ->
|
||||
return super if keepData
|
||||
@unsubscribe()
|
||||
super
|
||||
focus: ->
|
||||
@element.focus()
|
||||
|
||||
+3
-5
@@ -53,9 +53,6 @@ class Pane extends Model
|
||||
params.activeItem = find params.items, (item) -> item.getUri?() is activeItemUri
|
||||
params
|
||||
|
||||
# Called by the view layer to construct a view for this model.
|
||||
getViewClass: -> PaneView ?= require './pane-view'
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
@@ -238,6 +235,8 @@ class Pane extends Model
|
||||
@focused = false
|
||||
true # if this is called from an event handler, don't cancel it
|
||||
|
||||
isFocused: -> @focused
|
||||
|
||||
getPanes: -> [this]
|
||||
|
||||
###
|
||||
@@ -414,9 +413,8 @@ class Pane extends Model
|
||||
@destroyItem(item) for item in @getItems() when item isnt @activeItem
|
||||
|
||||
promptToSaveItem: (item) ->
|
||||
return true unless item.shouldPromptToSave?()
|
||||
return true unless typeof item.getUri is 'function' and item.shouldPromptToSave?()
|
||||
|
||||
uri = item.getUri()
|
||||
chosen = atom.confirm
|
||||
message: "'#{item.getTitle?() ? item.getUri()}' has changes, do you want to save them?"
|
||||
detailedMessage: "Your changes will be lost if you close this item without saving."
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
CSON = require 'season'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
|
||||
module.exports =
|
||||
class ScopedProperties
|
||||
@@ -10,10 +11,12 @@ class ScopedProperties
|
||||
callback(null, new ScopedProperties(scopedPropertiesPath, scopedProperties))
|
||||
|
||||
constructor: (@path, @scopedProperties) ->
|
||||
@propertyDisposable = new CompositeDisposable
|
||||
|
||||
activate: ->
|
||||
for selector, properties of @scopedProperties
|
||||
atom.syntax.addProperties(@path, selector, properties)
|
||||
@propertyDisposable.add atom.config.addScopedSettings(@path, selector, properties)
|
||||
return
|
||||
|
||||
deactivate: ->
|
||||
atom.syntax.removeProperties(@path)
|
||||
@propertyDisposable.dispose()
|
||||
|
||||
+11
-42
@@ -28,7 +28,6 @@ class Syntax extends GrammarRegistry
|
||||
|
||||
constructor: ->
|
||||
super(maxTokensPerLine: 100)
|
||||
@propertyStore = new ScopedPropertyStore
|
||||
|
||||
serialize: ->
|
||||
{deserializer: @constructor.name, @grammarOverridesByPath}
|
||||
@@ -36,52 +35,22 @@ class Syntax extends GrammarRegistry
|
||||
createToken: (value, scopes) -> new Token({value, scopes})
|
||||
|
||||
# Deprecated: Used by settings-view to display snippets for packages
|
||||
@::accessor 'scopedProperties', ->
|
||||
deprecate("Use Syntax::getProperty instead")
|
||||
@propertyStore.propertySets
|
||||
@::accessor 'propertyStore', ->
|
||||
deprecate("Do not use this. Use a public method on Config")
|
||||
atom.config.scopedSettingsStore
|
||||
|
||||
addProperties: (args...) ->
|
||||
name = args.shift() if args.length > 2
|
||||
[selector, properties] = args
|
||||
propertiesBySelector = {}
|
||||
propertiesBySelector[selector] = properties
|
||||
@propertyStore.addProperties(name, propertiesBySelector)
|
||||
deprecate 'Consider using atom.config.set() instead. A direct (but private) replacement is available at atom.config.addScopedSettings().'
|
||||
atom.config.addScopedSettings(args...)
|
||||
|
||||
removeProperties: (name) ->
|
||||
@propertyStore.removeProperties(name)
|
||||
deprecate 'atom.config.addScopedSettings() now returns a disposable you can call .dispose() on'
|
||||
atom.config.scopedSettingsStore.removeProperties(name)
|
||||
|
||||
clearProperties: ->
|
||||
@propertyStore = new ScopedPropertyStore
|
||||
|
||||
# Public: Get a property for the given scope and key path.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ```coffee
|
||||
# comment = atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')
|
||||
# console.log(comment) # '# '
|
||||
# ```
|
||||
#
|
||||
# * `scope` An {Array} of {String} scopes.
|
||||
# * `keyPath` A {String} key path.
|
||||
#
|
||||
# Returns a {String} property value or undefined.
|
||||
getProperty: (scope, keyPath) ->
|
||||
scopeChain = scope
|
||||
.map (scope) ->
|
||||
scope = ".#{scope}" unless scope[0] is '.'
|
||||
scope
|
||||
.join(' ')
|
||||
@propertyStore.getPropertyValue(scopeChain, keyPath)
|
||||
deprecate 'A direct (but private) replacement is available at atom.config.getRawScopedValue().'
|
||||
atom.config.getRawScopedValue(scope, keyPath)
|
||||
|
||||
propertiesForScope: (scope, keyPath) ->
|
||||
scopeChain = scope
|
||||
.map (scope) ->
|
||||
scope = ".#{scope}" unless scope[0] is '.'
|
||||
scope
|
||||
.join(' ')
|
||||
|
||||
@propertyStore.getProperties(scopeChain, keyPath)
|
||||
|
||||
cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
new ScopeSelector(scopeSelector).toCssSelector()
|
||||
deprecate 'A direct (but private) replacement is available at atom.config.scopedSettingsForScopeDescriptor().'
|
||||
atom.config.settingsForScopeDescriptor(scope, keyPath)
|
||||
|
||||
@@ -9,3 +9,9 @@ atom.initialize()
|
||||
atom.startEditorWindow()
|
||||
window.atom.loadTime = Date.now() - startTime
|
||||
console.log "Window load time: #{atom.getWindowLoadTime()}ms"
|
||||
|
||||
# Workaround for focus getting cleared upon window creation
|
||||
windowFocused = ->
|
||||
window.removeEventListener('focus', windowFocused)
|
||||
setTimeout (-> document.querySelector('.workspace').focus()), 0
|
||||
window.addEventListener('focus', windowFocused)
|
||||
|
||||
@@ -37,7 +37,7 @@ class WindowEventHandler
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
@subscribe $(window), 'beforeunload', =>
|
||||
confirmed = atom.workspaceView?.confirmClose()
|
||||
confirmed = atom.workspace?.confirmClose()
|
||||
atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
|
||||
@reloadRequested = false
|
||||
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
ipc = require 'ipc'
|
||||
path = require 'path'
|
||||
{Disposable, CompositeDisposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{callAttachHooks} = require 'space-pen'
|
||||
WorkspaceView = null
|
||||
|
||||
module.exports =
|
||||
class WorkspaceElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
atom.commands.setRootNode(this)
|
||||
@initializeContent()
|
||||
@observeScrollbarStyle()
|
||||
@observeTextEditorFontConfig()
|
||||
@createSpacePenShim()
|
||||
|
||||
attachedCallback: ->
|
||||
callAttachHooks(this)
|
||||
@focus()
|
||||
|
||||
detachedCallback: ->
|
||||
@model.destroy()
|
||||
|
||||
initializeContent: ->
|
||||
@classList.add 'workspace'
|
||||
@setAttribute 'tabindex', -1
|
||||
|
||||
|
||||
@verticalAxis = document.createElement('div')
|
||||
@verticalAxis.classList.add('vertical')
|
||||
|
||||
@horizontalAxis = document.createElement('div')
|
||||
@horizontalAxis.classList.add('horizontal')
|
||||
@horizontalAxis.appendChild(@verticalAxis)
|
||||
|
||||
@appendChild(@horizontalAxis)
|
||||
|
||||
observeScrollbarStyle: ->
|
||||
@subscriptions.add scrollbarStyle.onValue (style) =>
|
||||
switch style
|
||||
when 'legacy'
|
||||
@classList.remove('scrollbars-visible-when-scrolling')
|
||||
@classList.add("scrollbars-visible-always")
|
||||
when 'overlay'
|
||||
@classList.remove('scrollbars-visible-always')
|
||||
@classList.add("scrollbars-visible-when-scrolling")
|
||||
|
||||
observeTextEditorFontConfig: ->
|
||||
@subscriptions.add atom.config.observe 'editor.fontSize', @setTextEditorFontSize
|
||||
@subscriptions.add atom.config.observe 'editor.fontFamily', @setTextEditorFontFamily
|
||||
@subscriptions.add atom.config.observe 'editor.lineHeight', @setTextEditorLineHeight
|
||||
|
||||
createSpacePenShim: ->
|
||||
WorkspaceView ?= require './workspace-view'
|
||||
@__spacePenView = new WorkspaceView(this)
|
||||
|
||||
addCommands = (handlersByName) =>
|
||||
for name, handler of handlersByName
|
||||
do (handler) =>
|
||||
@__spacePenView.command name, => handler.apply(this, arguments)
|
||||
|
||||
addCommands(
|
||||
'window:increase-font-size': -> @getModel().increaseFontSize()
|
||||
'window:decrease-font-size': -> @getModel().decreaseFontSize()
|
||||
'window:reset-font-size': -> @getModel().resetFontSize()
|
||||
'application:about': -> ipc.send('command', 'application:about')
|
||||
'application:run-all-specs': -> ipc.send('command', 'application:run-all-specs')
|
||||
'application:run-benchmarks': -> ipc.send('command', 'application:run-benchmarks')
|
||||
'application:show-settings': -> ipc.send('command', 'application:show-settings')
|
||||
'application:quit': -> ipc.send('command', 'application:quit')
|
||||
'application:hide': -> ipc.send('command', 'application:hide')
|
||||
'application:hide-other-applications': -> ipc.send('command', 'application:hide-other-applications')
|
||||
'application:install-update': -> ipc.send('command', 'application:install-update')
|
||||
'application:unhide-all-applications': -> ipc.send('command', 'application:unhide-all-applications')
|
||||
'application:new-window': -> ipc.send('command', 'application:new-window')
|
||||
'application:new-file': -> ipc.send('command', 'application:new-file')
|
||||
'application:open': -> ipc.send('command', 'application:open')
|
||||
'application:open-file': -> ipc.send('command', 'application:open-file')
|
||||
'application:open-folder': -> ipc.send('command', 'application:open-folder')
|
||||
'application:open-dev': -> ipc.send('command', 'application:open-dev')
|
||||
'application:open-safe': -> ipc.send('command', 'application:open-safe')
|
||||
'application:minimize': -> ipc.send('command', 'application:minimize')
|
||||
'application:zoom': -> ipc.send('command', 'application:zoom')
|
||||
'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front')
|
||||
'application:open-your-config': -> ipc.send('command', 'application:open-your-config')
|
||||
'application:open-your-init-script': -> ipc.send('command', 'application:open-your-init-script')
|
||||
'application:open-your-keymap': -> ipc.send('command', 'application:open-your-keymap')
|
||||
'application:open-your-snippets': -> ipc.send('command', 'application:open-your-snippets')
|
||||
'application:open-your-stylesheet': -> ipc.send('command', 'application:open-your-stylesheet')
|
||||
'application:open-license': -> @getModel().openLicense()
|
||||
'window:run-package-specs': -> ipc.send('run-package-specs', path.join(atom.project.getPath(), 'spec'))
|
||||
'window:focus-next-pane': -> @getModel().activateNextPane()
|
||||
'window:focus-previous-pane': -> @getModel().activatePreviousPane()
|
||||
'window:focus-pane-above': -> @focusPaneViewAbove()
|
||||
'window:focus-pane-below': -> @focusPaneViewBelow()
|
||||
'window:focus-pane-on-left': -> @focusPaneViewOnLeft()
|
||||
'window:focus-pane-on-right': -> @focusPaneViewOnRight()
|
||||
'window:save-all': -> @getModel().saveAll()
|
||||
'window:toggle-invisibles': -> atom.config.toggle("editor.showInvisibles")
|
||||
'window:log-deprecation-warnings': -> Grim.logDeprecationWarnings()
|
||||
'window:toggle-auto-indent': -> atom.config.toggle("editor.autoIndent")
|
||||
'pane:reopen-closed-item': -> @getModel().reopenItem()
|
||||
'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane()
|
||||
'core:save': -> @getModel().saveActivePaneItem()
|
||||
'core:save-as': -> @getModel().saveActivePaneItemAs()
|
||||
)
|
||||
|
||||
if process.platform is 'darwin'
|
||||
addCommands 'window:install-shell-commands': -> @getModel().installShellCommands()
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
setModel: (@model) ->
|
||||
@paneContainer = @model.getView(@model.paneContainer)
|
||||
@verticalAxis.appendChild(@paneContainer)
|
||||
|
||||
@addEventListener 'focus', @handleFocus.bind(this)
|
||||
handleWindowFocus = @handleWindowFocus.bind(this)
|
||||
window.addEventListener 'focus', handleWindowFocus
|
||||
@subscriptions.add(new Disposable -> window.removeEventListener 'focus', handleWindowFocus)
|
||||
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
setTextEditorFontSize: (fontSize) ->
|
||||
atom.themes.updateGlobalEditorStyle('font-size', fontSize + 'px')
|
||||
|
||||
setTextEditorFontFamily: (fontFamily) ->
|
||||
atom.themes.updateGlobalEditorStyle('font-family', fontFamily)
|
||||
|
||||
setTextEditorLineHeight: (lineHeight) ->
|
||||
atom.themes.updateGlobalEditorStyle('line-height', lineHeight)
|
||||
|
||||
handleFocus: (event) ->
|
||||
@model.getActivePane().activate()
|
||||
|
||||
handleWindowFocus: (event) ->
|
||||
@handleFocus(event) if document.activeElement is document.body
|
||||
|
||||
module.exports = WorkspaceElement = document.registerElement 'atom-workspace',
|
||||
prototype: WorkspaceElement.prototype
|
||||
extends: 'div'
|
||||
+14
-175
@@ -6,19 +6,12 @@ Delegator = require 'delegato'
|
||||
{deprecate, logDeprecationWarnings} = require 'grim'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{$, $$, View} = require './space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
Workspace = require './workspace'
|
||||
CommandInstaller = require './command-installer'
|
||||
PaneView = require './pane-view'
|
||||
PaneColumnView = require './pane-column-view'
|
||||
PaneRowView = require './pane-row-view'
|
||||
PaneContainerView = require './pane-container-view'
|
||||
TextEditor = require './text-editor'
|
||||
|
||||
atom.commands.add '.workspace',
|
||||
'window:increase-font-size': -> @getModel().increaseFontSize()
|
||||
'window:decrease-font-size': -> @getModel().decreaseFontSize()
|
||||
'window:reset-font-size': -> @getModel().resetFontSize()
|
||||
|
||||
# Extended: The top-level view for the entire window. An instance of this class is
|
||||
# available via the `atom.workspaceView` global.
|
||||
#
|
||||
@@ -64,100 +57,20 @@ class WorkspaceView extends View
|
||||
'saveActivePaneItem', 'saveActivePaneItemAs', 'saveAll', 'destroyActivePaneItem',
|
||||
'destroyActivePane', 'increaseFontSize', 'decreaseFontSize', toProperty: 'model'
|
||||
|
||||
@version: 4
|
||||
|
||||
@content: ->
|
||||
@div class: 'workspace', tabindex: -1, =>
|
||||
@div class: 'horizontal', outlet: 'horizontal', =>
|
||||
@div class: 'vertical', outlet: 'vertical', =>
|
||||
@div class: 'panes', outlet: 'panes'
|
||||
|
||||
initialize: (model) ->
|
||||
@model = model ? atom.workspace ? new Workspace unless @model?
|
||||
@element.getModel = -> model
|
||||
atom.commands.setRootNode(@[0])
|
||||
|
||||
panes = @model.getView(@model.paneContainer).__spacePenView
|
||||
@panes.replaceWith(panes)
|
||||
@panes = panes
|
||||
constructor: (@element) ->
|
||||
unless @element?
|
||||
return atom.workspace.getView(atom.workspace).__spacePenView
|
||||
super
|
||||
@deprecateViewEvents()
|
||||
|
||||
setModel: (@model) ->
|
||||
@horizontal = @find('.horizontal')
|
||||
@vertical = @find('.vertical')
|
||||
@panes = @find('.panes').view()
|
||||
@subscribe @model.onDidOpen => @trigger 'uri-opened'
|
||||
|
||||
@subscribe scrollbarStyle, (style) =>
|
||||
@removeClass('scrollbars-visible-always scrollbars-visible-when-scrolling')
|
||||
switch style
|
||||
when 'legacy'
|
||||
@addClass("scrollbars-visible-always")
|
||||
when 'overlay'
|
||||
@addClass("scrollbars-visible-when-scrolling")
|
||||
|
||||
|
||||
@subscribe atom.config.observe 'editor.fontSize', @setEditorFontSize
|
||||
@subscribe atom.config.observe 'editor.fontFamily', @setEditorFontFamily
|
||||
@subscribe atom.config.observe 'editor.lineHeight', @setEditorLineHeight
|
||||
|
||||
@updateTitle()
|
||||
|
||||
@on 'focus', (e) => @handleFocus(e)
|
||||
@subscribe $(window), 'focus', (e) =>
|
||||
@handleFocus(e) if document.activeElement is document.body
|
||||
|
||||
atom.project.onDidChangePaths => @updateTitle()
|
||||
@on 'pane-container:active-pane-item-changed', => @updateTitle()
|
||||
@on 'pane:active-item-title-changed', '.active.pane', => @updateTitle()
|
||||
@on 'pane:active-item-modified-status-changed', '.active.pane', => @updateDocumentEdited()
|
||||
|
||||
@command 'application:about', -> ipc.send('command', 'application:about')
|
||||
@command 'application:run-all-specs', -> ipc.send('command', 'application:run-all-specs')
|
||||
@command 'application:run-benchmarks', -> ipc.send('command', 'application:run-benchmarks')
|
||||
@command 'application:show-settings', -> ipc.send('command', 'application:show-settings')
|
||||
@command 'application:quit', -> ipc.send('command', 'application:quit')
|
||||
@command 'application:hide', -> ipc.send('command', 'application:hide')
|
||||
@command 'application:hide-other-applications', -> ipc.send('command', 'application:hide-other-applications')
|
||||
@command 'application:install-update', -> ipc.send('command', 'application:install-update')
|
||||
@command 'application:unhide-all-applications', -> ipc.send('command', 'application:unhide-all-applications')
|
||||
@command 'application:new-window', -> ipc.send('command', 'application:new-window')
|
||||
@command 'application:new-file', -> ipc.send('command', 'application:new-file')
|
||||
@command 'application:open', -> ipc.send('command', 'application:open')
|
||||
@command 'application:open-file', -> ipc.send('command', 'application:open-file')
|
||||
@command 'application:open-folder', -> ipc.send('command', 'application:open-folder')
|
||||
@command 'application:open-dev', -> ipc.send('command', 'application:open-dev')
|
||||
@command 'application:open-safe', -> ipc.send('command', 'application:open-safe')
|
||||
@command 'application:minimize', -> ipc.send('command', 'application:minimize')
|
||||
@command 'application:zoom', -> ipc.send('command', 'application:zoom')
|
||||
@command 'application:bring-all-windows-to-front', -> ipc.send('command', 'application:bring-all-windows-to-front')
|
||||
@command 'application:open-your-config', -> ipc.send('command', 'application:open-your-config')
|
||||
@command 'application:open-your-init-script', -> ipc.send('command', 'application:open-your-init-script')
|
||||
@command 'application:open-your-keymap', -> ipc.send('command', 'application:open-your-keymap')
|
||||
@command 'application:open-your-snippets', -> ipc.send('command', 'application:open-your-snippets')
|
||||
@command 'application:open-your-stylesheet', -> ipc.send('command', 'application:open-your-stylesheet')
|
||||
@command 'application:open-license', => @model.openLicense()
|
||||
|
||||
if process.platform is 'darwin'
|
||||
@command 'window:install-shell-commands', => @installShellCommands()
|
||||
|
||||
@command 'window:run-package-specs', -> ipc.send('run-package-specs', path.join(atom.project.getPaths()[0], 'spec'))
|
||||
|
||||
@command 'window:focus-next-pane', => @focusNextPaneView()
|
||||
@command 'window:focus-previous-pane', => @focusPreviousPaneView()
|
||||
@command 'window:focus-pane-above', => @focusPaneViewAbove()
|
||||
@command 'window:focus-pane-below', => @focusPaneViewBelow()
|
||||
@command 'window:focus-pane-on-left', => @focusPaneViewOnLeft()
|
||||
@command 'window:focus-pane-on-right', => @focusPaneViewOnRight()
|
||||
@command 'window:save-all', => @saveAll()
|
||||
@command 'window:toggle-invisibles', -> atom.config.set("editor.showInvisibles", not atom.config.get("editor.showInvisibles"))
|
||||
@command 'window:log-deprecation-warnings', -> logDeprecationWarnings()
|
||||
|
||||
@command 'window:toggle-auto-indent', ->
|
||||
atom.config.set("editor.autoIndent", not atom.config.get("editor.autoIndent"))
|
||||
|
||||
@command 'pane:reopen-closed-item', => @getModel().reopenItem()
|
||||
|
||||
@command 'core:close', => if @getModel().getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane()
|
||||
@command 'core:save', => @saveActivePaneItem()
|
||||
@command 'core:save-as', => @saveActivePaneItemAs()
|
||||
|
||||
@deprecatedViewEvents()
|
||||
beforeRemove: ->
|
||||
@model?.destroy()
|
||||
|
||||
###
|
||||
Section: Accessing the Workspace Model
|
||||
@@ -309,83 +222,9 @@ class WorkspaceView extends View
|
||||
Section: Private
|
||||
###
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
@focus() if onDom
|
||||
|
||||
# Called by SpacePen
|
||||
beforeRemove: ->
|
||||
@model.destroy()
|
||||
|
||||
setEditorFontSize: (fontSize) ->
|
||||
atom.themes.updateGlobalEditorStyle('font-size', fontSize + 'px')
|
||||
|
||||
setEditorFontFamily: (fontFamily) ->
|
||||
atom.themes.updateGlobalEditorStyle('font-family', fontFamily)
|
||||
|
||||
setEditorLineHeight: (lineHeight) ->
|
||||
atom.themes.updateGlobalEditorStyle('line-height', lineHeight)
|
||||
|
||||
# Install the Atom shell commands on the user's system.
|
||||
installShellCommands: ->
|
||||
showErrorDialog = (error) ->
|
||||
installDirectory = CommandInstaller.getInstallDirectory()
|
||||
atom.confirm
|
||||
message: "Failed to install shell commands"
|
||||
detailedMessage: error.message
|
||||
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
CommandInstaller.installAtomCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
CommandInstaller.installApmCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
atom.confirm
|
||||
message: "Commands installed."
|
||||
detailedMessage: "The shell commands `atom` and `apm` are installed."
|
||||
|
||||
handleFocus: ->
|
||||
if @getActivePaneView()
|
||||
@getActivePaneView().focus()
|
||||
false
|
||||
else
|
||||
@updateTitle()
|
||||
focusableChild = @find("[tabindex=-1]:visible:first")
|
||||
if focusableChild.length
|
||||
focusableChild.focus()
|
||||
false
|
||||
else
|
||||
$(document.body).focus()
|
||||
true
|
||||
|
||||
# Prompts to save all unsaved items
|
||||
confirmClose: ->
|
||||
@panes.confirmClose()
|
||||
|
||||
# Updates the application's title and proxy icon based on whichever file is
|
||||
# open.
|
||||
updateTitle: ->
|
||||
if projectPath = atom.project.getPaths()[0]
|
||||
if item = @getModel().getActivePaneItem()
|
||||
title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}"
|
||||
@setTitle(title, item.getPath?())
|
||||
else
|
||||
@setTitle(projectPath, projectPath)
|
||||
else
|
||||
@setTitle('untitled')
|
||||
|
||||
# Sets the application's title (and the proxy icon on OS X)
|
||||
setTitle: (title, proxyIconPath='') ->
|
||||
document.title = title
|
||||
atom.setRepresentedFilename(proxyIconPath)
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: ->
|
||||
modified = @model.getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
@model.confirmClose()
|
||||
|
||||
# Get all editor views.
|
||||
#
|
||||
@@ -403,7 +242,7 @@ class WorkspaceView extends View
|
||||
Section: Deprecated
|
||||
###
|
||||
|
||||
deprecatedViewEvents: ->
|
||||
deprecateViewEvents: ->
|
||||
originalWorkspaceViewOn = @on
|
||||
|
||||
@on = (eventName) =>
|
||||
|
||||
+81
-8
@@ -5,13 +5,13 @@ _ = require 'underscore-plus'
|
||||
Q = require 'q'
|
||||
Serializable = require 'serializable'
|
||||
Delegator = require 'delegato'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
TextEditor = require './text-editor'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
ViewRegistry = require './view-registry'
|
||||
WorkspaceView = null
|
||||
WorkspaceElement = require './workspace-element'
|
||||
|
||||
# Essential: Represents the state of the user interface for the entire window.
|
||||
# An instance of this class is available via the `atom.workspace` global.
|
||||
@@ -30,11 +30,12 @@ class Workspace extends Model
|
||||
@delegatesProperty 'activePane', 'activePaneItem', toProperty: 'paneContainer'
|
||||
|
||||
@properties
|
||||
viewRegistry: null
|
||||
paneContainer: null
|
||||
fullScreen: false
|
||||
destroyedItemUris: -> []
|
||||
|
||||
constructor: ->
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@emitter = new Emitter
|
||||
@@ -44,6 +45,8 @@ class Workspace extends Model
|
||||
@paneContainer ?= new PaneContainer({@viewRegistry})
|
||||
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
|
||||
|
||||
@subscribeToActiveItem()
|
||||
|
||||
@addOpener (filePath) =>
|
||||
switch filePath
|
||||
when 'atom://.atom/stylesheet'
|
||||
@@ -55,6 +58,10 @@ class Workspace extends Model
|
||||
when 'atom://.atom/init-script'
|
||||
@open(atom.getUserInitScriptPath())
|
||||
|
||||
@addViewProvider
|
||||
modelConstructor: Workspace
|
||||
viewConstructor: WorkspaceElement
|
||||
|
||||
# Called by the Serializable mixin during deserialization
|
||||
deserializeParams: (params) ->
|
||||
for packageName in params.packagesWithActiveGrammars ? []
|
||||
@@ -71,9 +78,6 @@ class Workspace extends Model
|
||||
fullScreen: atom.isFullScreen()
|
||||
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
|
||||
|
||||
getViewClass: ->
|
||||
WorkspaceView ?= require './workspace-view'
|
||||
|
||||
getPackageNamesWithActiveGrammars: ->
|
||||
packageNames = []
|
||||
addGrammar = ({includedGrammarScopes, packageName}={}) ->
|
||||
@@ -97,6 +101,58 @@ class Workspace extends Model
|
||||
editorAdded: (editor) ->
|
||||
@emit 'editor-created', editor
|
||||
|
||||
installShellCommands: ->
|
||||
require('./command-installer').installShellCommandsInteractively()
|
||||
|
||||
subscribeToActiveItem: ->
|
||||
@updateWindowTitle()
|
||||
@updateDocumentEdited()
|
||||
atom.project.onDidChangePaths @updateWindowTitle
|
||||
|
||||
@observeActivePaneItem (item) =>
|
||||
@updateWindowTitle()
|
||||
@updateDocumentEdited()
|
||||
|
||||
@activeItemSubscriptions?.dispose()
|
||||
@activeItemSubscriptions = new CompositeDisposable
|
||||
|
||||
if typeof item?.onDidChangeTitle is 'function'
|
||||
titleSubscription = item.onDidChangeTitle(@updateWindowTitle)
|
||||
else if typeof item?.on is 'function'
|
||||
titleSubscription = item.on('title-changed', @updateWindowTitle)
|
||||
unless typeof titleSubscription?.dispose is 'function'
|
||||
titleSubscription = new Disposable => item.off('title-changed', @updateWindowTitle)
|
||||
|
||||
if typeof item?.onDidChangeModified is 'function'
|
||||
modifiedSubscription = item.onDidChangeModified(@updateDocumentEdited)
|
||||
else if typeof item?.on? is 'function'
|
||||
modifiedSubscription = item.on('modified-status-changed', @updateDocumentEdited)
|
||||
unless typeof modifiedSubscription?.dispose is 'function'
|
||||
modifiedSubscription = new Disposable => item.off('modified-status-changed', @updateDocumentEdited)
|
||||
|
||||
@activeItemSubscriptions.add(titleSubscription) if titleSubscription?
|
||||
@activeItemSubscriptions.add(modifiedSubscription) if modifiedSubscription?
|
||||
|
||||
# Updates the application's title and proxy icon based on whichever file is
|
||||
# open.
|
||||
updateWindowTitle: =>
|
||||
if projectPath = atom.project?.getPaths()[0]
|
||||
if item = @getActivePaneItem()
|
||||
document.title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}"
|
||||
atom.setRepresentedFilename(item.getPath?() ? projectPath)
|
||||
else
|
||||
document.title = projectPath
|
||||
atom.setRepresentedFilename(projectPath)
|
||||
else
|
||||
document.title = 'untitled'
|
||||
atom.setRepresentedFilename('')
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: =>
|
||||
modified = @getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
@@ -113,8 +169,8 @@ class Workspace extends Model
|
||||
callback(textEditor) for textEditor in @getTextEditors()
|
||||
@onDidAddTextEditor ({textEditor}) -> callback(textEditor)
|
||||
|
||||
# Essential: Invoke the given callback with all current and future panes items in
|
||||
# the workspace.
|
||||
# Essential: Invoke the given callback with all current and future panes items
|
||||
# in the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future pane items.
|
||||
# * `item` An item that is present in {::getPaneItems} at the time of
|
||||
@@ -132,6 +188,15 @@ class Workspace extends Model
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidChangeActivePaneItem: (callback) -> @paneContainer.onDidChangeActivePaneItem(callback)
|
||||
|
||||
# Essential: Invoke the given callback with the current active pane item and
|
||||
# with all future active pane items in the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called when the active pane item changes.
|
||||
# * `item` The current active pane item.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observeActivePaneItem: (callback) -> @paneContainer.observeActivePaneItem(callback)
|
||||
|
||||
# Essential: Invoke the given callback whenever an item is opened. Unlike
|
||||
# {::onDidAddPaneItem}, observers will be notified for items that are already
|
||||
# present in the workspace when they are reopened.
|
||||
@@ -417,6 +482,9 @@ class Workspace extends Model
|
||||
saveAll: ->
|
||||
@paneContainer.saveAll()
|
||||
|
||||
confirmClose: ->
|
||||
@paneContainer.confirmClose()
|
||||
|
||||
# Save the active pane item.
|
||||
#
|
||||
# If the active pane item currently has a URI according to the item's
|
||||
@@ -477,6 +545,10 @@ class Workspace extends Model
|
||||
destroyActivePane: ->
|
||||
@activePane?.destroy()
|
||||
|
||||
# Destroy the active pane item or the active pane if it is empty.
|
||||
destroyActivePaneItemOrEmptyPane: ->
|
||||
if @getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane()
|
||||
|
||||
# Increase the editor font size by 1px.
|
||||
increaseFontSize: ->
|
||||
atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
|
||||
@@ -503,6 +575,7 @@ class Workspace extends Model
|
||||
# Called by Model superclass when destroyed
|
||||
destroyed: ->
|
||||
@paneContainer.destroy()
|
||||
@activeItemSubscriptions?.dispose()
|
||||
|
||||
###
|
||||
Section: View Management
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário