Comparar commits
201 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 52b5fff537 | |||
| 6fbd9fb8f8 | |||
| 5996fcbc83 | |||
| e34eb151ca | |||
| 4ee1987af4 | |||
| 91652e1174 | |||
| cbf22201e6 | |||
| 040b99b2ff | |||
| c4eecbb380 | |||
| d235180547 | |||
| a42b560c24 | |||
| 2894d87ff8 | |||
| b15e101b20 | |||
| 6cf52a7fb7 | |||
| 8cf20a6996 | |||
| 24432018ec | |||
| 5ec38f84c5 | |||
| 40ffe2a306 | |||
| b1eceb03dc | |||
| dde69f8da4 | |||
| a525d5267b | |||
| f7951aa57c | |||
| a63e058fa5 | |||
| 09327eae75 | |||
| edd48d71ae | |||
| 2faf8bc57b | |||
| aac3d7a559 | |||
| d914ae2a62 | |||
| 2710d40403 | |||
| d327d4923f | |||
| dd0bed9bff | |||
| ff78a5b075 | |||
| 856370f522 | |||
| 041d3f5c4c | |||
| 3969c71932 | |||
| 133bf0cedb | |||
| f168aafc33 | |||
| d237b3448c | |||
| bbaf908bb2 | |||
| 9d947d994e | |||
| e2ecff5e23 | |||
| decae9e34c | |||
| 4896741f0c | |||
| c360ccc62b | |||
| 913c002ee4 | |||
| 59c405d846 | |||
| a9826653e1 | |||
| b47d52d919 | |||
| 7422f0ab1b | |||
| 18c6c84d35 | |||
| 7bcf92e55a | |||
| ee7d4003de | |||
| 79e50084a9 | |||
| 73a70d430f | |||
| 503b4ce2a4 | |||
| 094ccbc1f2 | |||
| 434ab5174b | |||
| 1b85810735 | |||
| 0c75a4fd9c | |||
| c88c18c042 | |||
| cb7d4c8638 | |||
| 4a9d0ab4d3 | |||
| ac029d300a | |||
| 8fe0b7fb7b | |||
| c6c58ebc3e | |||
| 32ac99fd3e | |||
| 175a8b6968 | |||
| 6708388c29 | |||
| 958b19bd83 | |||
| e40dc5c4a6 | |||
| 12ff54c0bd | |||
| 83040d13c7 | |||
| ebc9a6bf51 | |||
| c8ad232c31 | |||
| cfd918977b | |||
| e7efaeaf17 | |||
| e849fc45ff | |||
| 9054c7a120 | |||
| 60c042bd81 | |||
| 495ba3571e | |||
| b8776425fd | |||
| 693fd43449 | |||
| 71f80809c0 | |||
| db13a40f0a | |||
| edf7e06b8d | |||
| 442abece14 | |||
| 5c143bfc6e | |||
| 51354f2326 | |||
| 1177508a45 | |||
| 4bbffd3589 | |||
| 2266c794b4 | |||
| 562ee58506 | |||
| fa96adc2ce | |||
| c46088e89a | |||
| 131ae0f9f7 | |||
| 49828b9681 | |||
| 141430ab0a | |||
| 807b4b223b | |||
| 89246f213a | |||
| a6fa2ff30a | |||
| 7f32c9a3f7 | |||
| 18b2433a99 | |||
| 51b9964f7e | |||
| 9084122a5c | |||
| 9ff07e0fc2 | |||
| 7ba47840d8 | |||
| 327e8476dd | |||
| 18eaec374c | |||
| 430a36ac42 | |||
| 508ca12be9 | |||
| adf7e17fce | |||
| 9c675f387a | |||
| 5770366c00 | |||
| f2581e8d96 | |||
| d7d678c082 | |||
| 44181457c5 | |||
| f9b27aecf5 | |||
| ddbb0ae1db | |||
| fec2567283 | |||
| ad8a020c29 | |||
| 06c04779bf | |||
| 1a047a8e14 | |||
| 0cf8666286 | |||
| 7c02b7e431 | |||
| 6c55cff603 | |||
| c64895a621 | |||
| 9dc3f2c909 | |||
| 1dc2ee743e | |||
| 1f7967d17f | |||
| 916729fbd5 | |||
| 1922536927 | |||
| de89f90700 | |||
| 09f1dff502 | |||
| 9a0414da6f | |||
| 119fc7f4f2 | |||
| 481e0b8b6c | |||
| 1b69f2db46 | |||
| 1b877c76b9 | |||
| 1fa791fc7a | |||
| e8a4867ff7 | |||
| 629717caea | |||
| 0d6253555b | |||
| 63d9edcc40 | |||
| bc2f217e7c | |||
| 7381bd09b1 | |||
| 379bd852d2 | |||
| a9ee6e5d43 | |||
| 2bef377e99 | |||
| 7f326421d7 | |||
| 3546f21af7 | |||
| 441dcfb56a | |||
| 42d9ef397d | |||
| 10eb89f078 | |||
| 8b2482af22 | |||
| a2ca59bf05 | |||
| 91f11868ea | |||
| 2c19e6a6a4 | |||
| e7ebe0a5c4 | |||
| 95ec0d8162 | |||
| 0a4f5a365a | |||
| b6b6b6d12b | |||
| 9f194ff4df | |||
| ed6ca9cd06 | |||
| 08971562cd | |||
| 263ff21cc1 | |||
| 99b08826dd | |||
| 417e00b938 | |||
| f8bb40c48f | |||
| 01b75c4393 | |||
| 9f1ffeee25 | |||
| c55faac0a9 | |||
| aaa50bae90 | |||
| b0c4910815 | |||
| 654f84a26c | |||
| ff10ea601c | |||
| 88bfba9fb2 | |||
| f11168df8e | |||
| 4ce056180c | |||
| 8718828869 | |||
| edfcc134ec | |||
| 6a34b88f79 | |||
| e596bf6ef9 | |||
| b369a1085c | |||
| 2e7e90a8aa | |||
| eae80ca46d | |||
| fe7505745d | |||
| 12b9f232c2 | |||
| 97a671cb49 | |||
| 9acea88101 | |||
| b29c0ca2f7 | |||
| a4a3577163 | |||
| 9dfaa8a4e5 | |||
| 661b09ab1c | |||
| 9399e00033 | |||
| 67d5d997c9 | |||
| 40c11410f0 | |||
| 307108ec6c | |||
| 0bb173b646 | |||
| 6538da22a6 | |||
| c79db992d9 | |||
| 89ab0becc2 |
@@ -6,7 +6,6 @@ os = require 'os'
|
||||
# modules work under node v0.11.x.
|
||||
require 'vm-compatibility-layer'
|
||||
|
||||
fm = require 'json-front-matter'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
packageJson = require '../package.json'
|
||||
@@ -22,9 +21,9 @@ module.exports = (grunt) ->
|
||||
grunt.loadNpmTasks('grunt-contrib-csslint')
|
||||
grunt.loadNpmTasks('grunt-contrib-coffee')
|
||||
grunt.loadNpmTasks('grunt-contrib-less')
|
||||
grunt.loadNpmTasks('grunt-markdown')
|
||||
grunt.loadNpmTasks('grunt-shell')
|
||||
grunt.loadNpmTasks('grunt-download-atom-shell')
|
||||
grunt.loadNpmTasks('grunt-atom-shell-installer')
|
||||
grunt.loadNpmTasks('grunt-peg')
|
||||
grunt.loadTasks('tasks')
|
||||
|
||||
@@ -194,32 +193,19 @@ module.exports = (grunt) ->
|
||||
'static/**/*.less'
|
||||
]
|
||||
|
||||
markdown:
|
||||
guides:
|
||||
files: [
|
||||
expand: true
|
||||
cwd: 'docs'
|
||||
src: '**/*.md'
|
||||
dest: 'docs/output/'
|
||||
ext: '.html'
|
||||
]
|
||||
options:
|
||||
template: 'docs/template.jst'
|
||||
templateContext:
|
||||
tag: "v#{major}.#{minor}"
|
||||
markdownOptions:
|
||||
gfm: true
|
||||
preCompile: (src, context) ->
|
||||
parsed = fm.parse(src)
|
||||
_.extend(context, parsed.attributes)
|
||||
parsed.body
|
||||
|
||||
'download-atom-shell':
|
||||
version: packageJson.atomShellVersion
|
||||
outputDir: 'atom-shell'
|
||||
downloadDir: atomShellDownloadDir
|
||||
rebuild: true # rebuild native modules after atom-shell is updated
|
||||
|
||||
'create-windows-installer':
|
||||
appDirectory: shellAppDir
|
||||
outputDirectory: path.join(buildDir, 'installer')
|
||||
authors: 'The Atom Team & Community'
|
||||
loadingGif: path.resolve(__dirname, '..', 'resources', 'win', 'loading.gif')
|
||||
iconUrl: 'https://raw.githubusercontent.com/atom/atom/master/resources/atom.png'
|
||||
|
||||
shell:
|
||||
'kill-atom':
|
||||
command: killCommand
|
||||
@@ -237,6 +223,7 @@ module.exports = (grunt) ->
|
||||
ciTasks.push('dump-symbols') if process.platform isnt 'win32'
|
||||
ciTasks.push('set-version', 'check-licenses', 'lint')
|
||||
ciTasks.push('mkdeb') if process.platform is 'linux'
|
||||
ciTasks.push('create-windows-installer') if process.platform is 'win32'
|
||||
ciTasks.push('test') if process.platform is 'darwin'
|
||||
ciTasks.push('codesign')
|
||||
ciTasks.push('publish-build')
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.2.9",
|
||||
"donna": "1.0.6",
|
||||
"donna": "1.0.7",
|
||||
"formidable": "~1.0.14",
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-atom-shell-installer": "^0.7.0",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe",
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
@@ -20,17 +21,13 @@
|
||||
"grunt-cson": "0.10.0",
|
||||
"grunt-download-atom-shell": "~0.10.0",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"harmony-collections": "~0.3.8",
|
||||
"json-front-matter": "~0.1.3",
|
||||
"legal-eagle": "~0.4.0",
|
||||
"legal-eagle": "~0.6.0",
|
||||
"minidump": "~0.8",
|
||||
"normalize-package-data": "0.2.12",
|
||||
"npm": "~1.4.5",
|
||||
"rcedit": "~0.1.2",
|
||||
"read-package-json": "1.1.8",
|
||||
"rcedit": "~0.3.0",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "~1.0.1",
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = (grunt) ->
|
||||
appDir = grunt.config.get('atom.appDir')
|
||||
|
||||
rm shellAppDir
|
||||
rm path.join(buildDir, 'installer')
|
||||
mkdir path.dirname(buildDir)
|
||||
|
||||
if process.platform is 'darwin'
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'check-licenses', 'Report the licenses of all dependencies', ->
|
||||
legalEagle = require 'legal-eagle'
|
||||
@@ -13,7 +12,7 @@ module.exports = (grunt) ->
|
||||
legalEagle options, (err, summary) ->
|
||||
if err?
|
||||
console.error(err)
|
||||
exit 1
|
||||
process.exit 1
|
||||
|
||||
for key of summary
|
||||
delete summary[key] if key.match /^atom@/
|
||||
|
||||
@@ -36,7 +36,7 @@ module.exports = (grunt) ->
|
||||
spawn {cmd, args}, (error) ->
|
||||
return callback(error) if error?
|
||||
|
||||
setupExePath = path.join(grunt.config.get('atom.shellAppDir'), '..', 'Releases', 'setup.exe')
|
||||
setupExePath = path.resolve(grunt.config.get('atom.buildDir'), 'installer', 'AtomSetup.exe')
|
||||
if fs.isFileSync(setupExePath)
|
||||
args = [setupExePath]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'create-installer', 'Create the Windows installer', ->
|
||||
return unless process.platform is 'win32'
|
||||
|
||||
done = @async()
|
||||
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
atomDir = path.join(buildDir, 'Atom')
|
||||
releasesDir = path.join(buildDir, 'Releases')
|
||||
atomGitHubToken = process.env.ATOM_ACCESS_TOKEN
|
||||
|
||||
packageInfo = grunt.file.readJSON(path.join(atomDir, 'resources', 'app', 'package.json'))
|
||||
inputTemplate = grunt.file.read(path.join('build', 'windows', 'atom.nuspec.erb'))
|
||||
|
||||
# NB: Build server has some sort of stamp on the version number
|
||||
packageInfo.version = packageInfo.version.replace(/-.*$/, '')
|
||||
|
||||
targetNuspecPath = path.join(buildDir, 'atom.nuspec')
|
||||
grunt.file.write(targetNuspecPath, _.template(inputTemplate, packageInfo))
|
||||
|
||||
# We use the previous releases to build deltas for the current release,
|
||||
# sync down the existing releases directory by rolling through GitHub releases
|
||||
cmd = 'build/windows/SyncGitHubReleases.exe'
|
||||
args = ['-r', releasesDir, '-u', 'https://github.com/atom/atom', '-t', atomGitHubToken]
|
||||
|
||||
spawn {cmd, args}, (error, result, code) ->
|
||||
if error?
|
||||
grunt.log.error "ATOM_ACCESS_TOKEN environment variable not set or invalid, can't download old releases; continuing anyways"
|
||||
|
||||
cmd = 'build/windows/nuget.exe'
|
||||
args = ['pack', targetNuspecPath, '-BasePath', atomDir, '-OutputDirectory', buildDir]
|
||||
|
||||
spawn {cmd, args}, (error, result, code) ->
|
||||
return done(error) if error?
|
||||
|
||||
pkgs = pkg for pkg in fs.readdirSync(buildDir) when path.extname(pkg) is '.nupkg'
|
||||
|
||||
cmd = 'build/windows/update.com'
|
||||
args = ['--releasify', path.join(buildDir, pkgs), '-r', releasesDir, '-g', 'build/windows/install-spinner.gif']
|
||||
spawn {cmd, args}, (error, result, code) -> done(error)
|
||||
@@ -54,6 +54,11 @@ module.exports = (gruntObject) ->
|
||||
uploadAssets(release, buildDir, assets, done)
|
||||
|
||||
getAssets = ->
|
||||
{cp} = require('./task-helpers')(grunt)
|
||||
|
||||
{version} = grunt.file.readJSON('package.json')
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
switch process.platform
|
||||
when 'darwin'
|
||||
[
|
||||
@@ -62,16 +67,16 @@ getAssets = ->
|
||||
{assetName: 'atom-api.json', sourcePath: 'atom-api.json'}
|
||||
]
|
||||
when 'win32'
|
||||
[
|
||||
{assetName: 'atom-windows.zip', sourcePath: 'Atom'}
|
||||
]
|
||||
assets = [{assetName: 'atom-windows.zip', sourcePath: 'Atom'}]
|
||||
for squirrelAsset in ['AtomSetup.exe', 'RELEASES', "atom-#{version}-full.nupkg"]
|
||||
cp path.join(buildDir, 'installer', squirrelAsset), path.join(buildDir, squirrelAsset)
|
||||
assets.push({assetName: squirrelAsset, sourcePath: assetName})
|
||||
assets
|
||||
when 'linux'
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
if process.arch is 'ia32'
|
||||
arch = 'i386'
|
||||
else
|
||||
arch = 'amd64'
|
||||
{version} = grunt.file.readJSON('package.json')
|
||||
|
||||
# Check for a Debian build
|
||||
sourcePath = "#{buildDir}/atom-#{version}-#{arch}.deb"
|
||||
@@ -87,7 +92,6 @@ getAssets = ->
|
||||
arch = 'x86_64'
|
||||
assetName = "atom.#{arch}.rpm"
|
||||
|
||||
{cp} = require('./task-helpers')(grunt)
|
||||
cp sourcePath, path.join(buildDir, assetName)
|
||||
|
||||
[
|
||||
|
||||
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id><%= name %></id>
|
||||
<version><%= version %></version>
|
||||
<authors>The Atom Community</authors>
|
||||
<owners>The Atom Community</owners>
|
||||
<iconUrl>https://raw.githubusercontent.com/atom/atom/master/resources/win/atom.ico</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description><%= description %></description>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="locales\**" target="lib\net45\locales" />
|
||||
<file src="resources\**" target="lib\net45\resources" />
|
||||
<file src="*.pak" target="lib\net45" />
|
||||
<file src="atom.exe" target="lib\net45\atom.exe" />
|
||||
<file src="atom.exe.gui" target="lib\net45\atom.exe.gui" />
|
||||
<file src="chromiumcontent.dll" target="lib\net45\chromiumcontent.dll" />
|
||||
<file src="d3dcompiler_43.dll" target="lib\net45\d3dcompiler_43.dll" />
|
||||
<file src="ffmpegsumo.dll" target="lib\net45\ffmpegsumo.dll" />
|
||||
<file src="icudtl.dat" target="lib\net45\icudtl.dat" />
|
||||
<file src="libEGL.dll" target="lib\net45\libEGL.dll" />
|
||||
<file src="libGLESv2.dll" target="lib\net45\libGLESv2.dll" />
|
||||
<file src="LICENSE" target="lib\net45\LICENSE" />
|
||||
<file src="msvcp120.dll" target="lib\net45\msvcp120.dll" />
|
||||
<file src="msvcr120.dll" target="lib\net45\msvcr120.dll" />
|
||||
<file src="vccorlib120.dll" target="lib\net45\vccorlib120.dll" />
|
||||
<file src="version" target="lib\net45\version" />
|
||||
<file src="xinput1_3.dll" target="lib\net45\xinput1_3.dll" />
|
||||
</files>
|
||||
</package>
|
||||
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 43 KiB |
+2
-57
@@ -1,60 +1,5 @@
|
||||
# Welcome to the Atom API Documentation
|
||||
# Welcome to the Atom Docs
|
||||
|
||||

|
||||
|
||||
## FAQ
|
||||
|
||||
### Where do I start?
|
||||
|
||||
Check out [EditorView][EditorView] and [Editor][Editor] classes for a good
|
||||
overview of the main editor API.
|
||||
|
||||
### How do I access these classes?
|
||||
|
||||
Check out the [Atom][Atom] class docs to see what globals are available and
|
||||
what they provide.
|
||||
|
||||
You can also require many of these classes in your package via:
|
||||
|
||||
```coffee
|
||||
{EditorView} = require 'atom'
|
||||
```
|
||||
|
||||
The classes available from `require 'atom'` are:
|
||||
* [BufferedProcess][BufferedProcess]
|
||||
* [BufferedNodeProcess][BufferedNodeProcess]
|
||||
* [EditorView][EditorView]
|
||||
* [Git][Git]
|
||||
* [Point][Point]
|
||||
* [Range][Range]
|
||||
* [ScrollView][ScrollView]
|
||||
* [SelectListView][SelectListView]
|
||||
* [View][View]
|
||||
* [WorkspaceView][WorkspaceView]
|
||||
* [Workspace][Workspace]
|
||||
|
||||
### How do I create a package?
|
||||
|
||||
You probably want to read the [creating a package][creating-a-package]
|
||||
doc first and come back here when you are done.
|
||||
|
||||
### Where are the node docs?
|
||||
|
||||
Atom ships with node 0.11.10 and the comprehensive node API docs are available
|
||||
[here][node-docs].
|
||||
|
||||
[Atom]: ../classes/Atom.html
|
||||
[BufferedProcess]: ../classes/BufferedProcess.html
|
||||
[BufferedNodeProcess]: ../classes/BufferedNodeProcess.html
|
||||
[Editor]: ../classes/Editor.html
|
||||
[EditorView]: ../classes/EditorView.html
|
||||
[Git]: ../classes/Git.html
|
||||
[Point]: ../classes/Point.html
|
||||
[Range]: ../classes/Range.html
|
||||
[ScrollView]: ../classes/ScrollView.html
|
||||
[SelectListView]: ../classes/SelectListView.html
|
||||
[View]: ../classes/View.html
|
||||
[WorkspaceView]: ../classes/WorkspaceView.html
|
||||
[Workspace]: ../classes/Workspace.html
|
||||
[creating-a-package]: https://atom.io/docs/latest/creating-a-package
|
||||
[node-docs]: http://nodejs.org/docs/v0.11.10/api
|
||||
TODO: Write when docs move to a dedicated repo.
|
||||
|
||||
@@ -16,7 +16,7 @@ keystrokes pass through `atom-text-editor` elements:
|
||||
'ctrl-shift-e': 'editor:select-to-end-of-line'
|
||||
'cmd-left': 'editor:move-to-first-character-of-line'
|
||||
|
||||
'atom-text-editor:not(.mini)'
|
||||
'atom-text-editor:not([mini])'
|
||||
'cmd-alt-[': 'editor:fold-current-row'
|
||||
'cmd-alt-]': 'editor:unfold-current-row'
|
||||
```
|
||||
@@ -27,8 +27,8 @@ patterns* to *commands*. When an element with the `atom-text-editor` class is fo
|
||||
`editor:delete-to-beginning-of-line` is emitted on the `atom-text-editor` element.
|
||||
|
||||
The second selector group also targets editors, but only if they don't have the
|
||||
`.mini` class. In this example, the commands for code folding don't really make
|
||||
sense on mini-editors, so the selector restricts them to regular editors.
|
||||
`mini` attribute. In this example, the commands for code folding don't really
|
||||
make sense on mini-editors, so the selector restricts them to regular editors.
|
||||
|
||||
### Keystroke Patterns
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ If you have problems with permissions don't forget to prefix with `sudo`
|
||||
2. Checkout the latest Atom release:
|
||||
|
||||
```sh
|
||||
git fetch
|
||||
git fetch -p
|
||||
git checkout $(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
```
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ built-in keymaps:
|
||||
'atom-text-editor':
|
||||
'enter': 'editor:newline'
|
||||
|
||||
'atom-text-editor.mini input':
|
||||
'atom-text-editor[mini] input':
|
||||
'enter': 'core:confirm'
|
||||
```
|
||||
|
||||
|
||||
@@ -20,3 +20,8 @@
|
||||
* [Serialization](advanced/serialization.md)
|
||||
* [View System](advanced/view-system.md)
|
||||
* [Scopes and Scope Descriptors](advanced/scopes-and-scope-descriptors.md)
|
||||
|
||||
### Upgrading to 1.0 APIs
|
||||
|
||||
* [Upgrading Your UI Theme Or Package Selectors](upgrading/upgrading-your-ui-theme.md)
|
||||
* [Upgrading Your Syntax Theme](upgrading/upgrading-your-syntax-theme.md)
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
|
||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="../../assets/js/html5shiv.js"></script>
|
||||
<script src="../../assets/js/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<title>Atom - <%= title %></title>
|
||||
<style>
|
||||
/*github.com style (c) Vasily Polovnyov <vast@whiteants.net>*/
|
||||
pre code {
|
||||
display: block; padding: 0.5em;
|
||||
color: #333;
|
||||
background: #f8f8ff
|
||||
}
|
||||
pre .comment,
|
||||
pre .template_comment,
|
||||
pre .diff .header,
|
||||
pre .javadoc {
|
||||
color: #998;
|
||||
font-style: italic
|
||||
}
|
||||
pre .keyword,
|
||||
pre .css .rule .keyword,
|
||||
pre .winutils,
|
||||
pre .javascript .title,
|
||||
pre .nginx .title,
|
||||
pre .subst,
|
||||
pre .request,
|
||||
pre .status {
|
||||
color: #333;
|
||||
font-weight: bold
|
||||
}
|
||||
pre .number,
|
||||
pre .hexcolor,
|
||||
pre .ruby .constant {
|
||||
color: #099;
|
||||
}
|
||||
pre .string,
|
||||
pre .tag .value,
|
||||
pre .phpdoc,
|
||||
pre .tex .formula {
|
||||
color: #d14
|
||||
}
|
||||
pre .title,
|
||||
pre .id {
|
||||
color: #900;
|
||||
font-weight: bold
|
||||
}
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .clojure .title,
|
||||
pre .subst {
|
||||
font-weight: normal
|
||||
}
|
||||
pre .class .title,
|
||||
pre .haskell .type,
|
||||
pre .vhdl .literal,
|
||||
pre .tex .command {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
pre .tag,
|
||||
pre .tag .title,
|
||||
pre .rules .property,
|
||||
pre .django .tag .keyword {
|
||||
color: #000080;
|
||||
font-weight: normal
|
||||
}
|
||||
pre .attribute,
|
||||
pre .variable,
|
||||
pre .lisp .body {
|
||||
color: #008080
|
||||
}
|
||||
pre .regexp {
|
||||
color: #009926
|
||||
}
|
||||
pre .class {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
pre .symbol,
|
||||
pre .ruby .symbol .string,
|
||||
pre .lisp .keyword,
|
||||
pre .tex .special,
|
||||
pre .prompt {
|
||||
color: #990073
|
||||
}
|
||||
pre .built_in,
|
||||
pre .lisp .title,
|
||||
pre .clojure .built_in {
|
||||
color: #0086b3
|
||||
}
|
||||
pre .preprocessor,
|
||||
pre .pi,
|
||||
pre .doctype,
|
||||
pre .shebang,
|
||||
pre .cdata {
|
||||
color: #999;
|
||||
font-weight: bold
|
||||
}
|
||||
pre .deletion {
|
||||
background: #fdd
|
||||
}
|
||||
pre .addition {
|
||||
background: #dfd
|
||||
}
|
||||
pre .diff .change {
|
||||
background: #0086b3
|
||||
}
|
||||
pre .chunk {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/<%= tag %>/index.html">Atom Documentation</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/docs/api/<%= tag %>/api/index.html">API</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<%= content %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,27 @@
|
||||
# Upgrading Your Syntax Theme
|
||||
|
||||
Text editor content is now rendered in the shadow DOM, which shields it from being styled by global style sheets to protect against accidental style pollution. For more background on the shadow DOM, check out the [Shadow DOM 101][shadow-dom-101] on HTML 5 Rocks.
|
||||
|
||||
Syntax themes are specifically intended to style only text editor content, so they are automatically loaded directly into the text editor's shadow DOM when it is enabled. This happens automatically when the the theme's `package.json` contains a `theme: "syntax"` declaration, so you don't need to change anything to target the appropriate context.
|
||||
|
||||
When theme style sheets are loaded into the text editor's shadow DOM, selectors intended to target the editor from the *outside* no longer make sense. Styles targeting the `.editor` and `.editor-colors` classes instead need to target the `:host` pseudo-element, which matches against the containing `atom-text-editor` node. Check out the [Shadow DOM 201][host-pseudo-element] article for more information about the `:host` pseudo-element.
|
||||
|
||||
Here's an example from Atom's light syntax theme. Note that the previous selectors intended to target the editor from the outside have been retained to allow the theme to keep working during the transition phase when it is possible to disable the shadow DOM.
|
||||
|
||||
```css
|
||||
.editor-colors, :host { /* :host added */
|
||||
background-color: @syntax-background-color;
|
||||
color: @syntax-text-color;
|
||||
}
|
||||
|
||||
.editor, :host { /* :host added */
|
||||
.invisible-character {
|
||||
color: @syntax-invisible-character-color;
|
||||
}
|
||||
|
||||
/* more nested selectors... */
|
||||
}
|
||||
```
|
||||
|
||||
[shadow-dom-101]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom
|
||||
[host-pseudo-element]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201#toc-style-host
|
||||
@@ -0,0 +1,137 @@
|
||||
# Upgrading Your UI Theme Or Package Selectors
|
||||
|
||||
In addition to changes in Atom's scripting API, we'll also be making some breaking changes to Atom's DOM structure, requiring stylesheets and keymaps in both packages and themes to be updated.
|
||||
|
||||
## Deprecation Cop
|
||||
|
||||
Deprecation cop will list usages of deprecated selector patterns to guide you. You can access it via the command palette (`cmd-shift-p`, then search for `Deprecation`). It breaks the deprecations down by package:
|
||||
|
||||

|
||||
|
||||
## Custom Tags
|
||||
|
||||
Rather than adding classes to standard HTML elements to indicate their role, Atom now uses custom element names. For example, `<div class="workspace">` has now been replaced with `<atom-workspace>`. Selectors should be updated accordingly. Note that tag names have lower specificity than classes in CSS, so you'll need to take care in converting things.
|
||||
|
||||
Old Selector | New Selector
|
||||
--------------------|--------------------------------
|
||||
`.editor` | `atom-text-editor`
|
||||
`.editor.mini` | `atom-text-editor[mini]`
|
||||
`.workspace` | `atom-workspace`
|
||||
`.horizontal` | `atom-workspace-axis.horizontal`
|
||||
`.vertical` | `atom-workspace-axis.vertical`
|
||||
`.pane-container` | `atom-pane-conatiner`
|
||||
`.pane` | `atom-pane`
|
||||
`.tool-panel` | `atom-panel`
|
||||
`.panel-top` | `atom-panel.top`
|
||||
`.panel-bottom` | `atom-panel.bottom`
|
||||
`.panel-left` | `atom-panel.left`
|
||||
`.panel-right` | `atom-panel.right`
|
||||
`.overlay` | `atom-panel.modal`
|
||||
|
||||
## Supporting the Shadow DOM
|
||||
|
||||
Text editor content is now rendered in the shadow DOM, which shields it from being styled by global style sheets to protect against accidental style pollution. For more background on the shadow DOM, check out the [Shadow DOM 101][shadow-dom-101] on HTML 5 Rocks. If you need to style text editor content in a UI theme, you'll need to circumvent this protection for any rules that target the text editor's content. Some examples of the kinds of UI theme styles needing to be updated:
|
||||
|
||||
* Highlight decorations
|
||||
* Gutter decorations
|
||||
* Line decorations
|
||||
* Scrollbar styling
|
||||
* Anything targeting a child selector of `.editor`
|
||||
|
||||
During a transition phase, it will be possible to enable or disable the text editor's shadow DOM in the settings, so themes will need to be compatible with both approaches.
|
||||
|
||||
### Shadow DOM Selectors
|
||||
|
||||
Chromium provides two tools for bypassing shadow boundaries, the `::shadow` pseudo-element and the `/deep/` combinator. For an in-depth explanation of styling the shadow DOM, see the [Shadow DOM 201][shadow-dom-201] article on HTML 5 Rocks.
|
||||
|
||||
#### ::shadow
|
||||
|
||||
The `::shadow` pseudo-element allows you to bypass a single shadow root. For example, say you want to update a highlight decoration for a linter package. Initially, the style looks as follows:
|
||||
|
||||
```css
|
||||
// Without shadow DOM support
|
||||
atom-text-editor .highlight.my-linter {
|
||||
background: hotpink;
|
||||
}
|
||||
```
|
||||
|
||||
In order for this style to apply with the shadow DOM enabled, you will need to add a second selector with the `::shadow` pseudo-element. You should leave the original selector in place so your theme continues to work with the shadow DOM disabled during the transition period.
|
||||
|
||||
```css
|
||||
// With shadow DOM support
|
||||
atom-text-editor .highlight.my-linter,
|
||||
atom-text-editor::shadow .highlight.my-linter {
|
||||
background: hotpink;
|
||||
}
|
||||
```
|
||||
|
||||
Check out the [find-and-replace][find-and-replace] package for another example of using `::shadow` to pierce the shadow DOM.
|
||||
|
||||
#### /deep/
|
||||
|
||||
The `/deep/` combinator overrides *all* shadow boundaries, making it useful for rules you want to apply globally such as scrollbar styling. Here's a snippet containing scrollbar styling for the Atom Dark UI theme before shadow DOM support:
|
||||
|
||||
```css
|
||||
// Without shadow DOM support
|
||||
.scrollbars-visible-always {
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track,
|
||||
::-webkit-scrollbar-corner {
|
||||
background: @scrollbar-background-color;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: @scrollbar-color;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 1px black inset;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To style scrollbars even inside of the shadow DOM, each rule needs to be prefixed with `/deep/`. We use `/deep/` instead of `::shadow` because we don't care about the selector of the host element in this case. We just want our styling to apply everywhere.
|
||||
|
||||
```css
|
||||
// With shadow DOM support using /deep/
|
||||
.scrollbars-visible-always {
|
||||
/deep/ ::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
/deep/ ::-webkit-scrollbar-track,
|
||||
/deep/ ::-webkit-scrollbar-corner {
|
||||
background: @scrollbar-background-color;
|
||||
}
|
||||
|
||||
/deep/ ::-webkit-scrollbar-thumb {
|
||||
background: @scrollbar-color;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 1px black inset;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Context-Targeted Style Sheets
|
||||
|
||||
The selector features discussed above allow you to target shadow DOM content with specific selectors, but Atom also allows you to target a specific shadow DOM context with an entire style sheet. The context into which a style sheet is loaded is based on the file name. If you want to load a style sheet into the editor, name it with the `.atom-text-editor.less` or `.atom-text-editor.css` extensions.
|
||||
|
||||
```
|
||||
my-ui-theme/
|
||||
stylesheets/
|
||||
index.less # loaded globally
|
||||
index.atom-text-editor.less # loaded in the text editor shadow DOM
|
||||
```
|
||||
|
||||
Check out this [style sheet](https://github.com/atom/decoration-example/blob/master/stylesheets/decoration-example.atom-text-editor.less) from the decoration-example package for an example of context-targeting.
|
||||
|
||||
Inside a context-targeted style sheet, there's no need to use the `::shadow` or `/deep/` expressions. If you want to refer to the element containing the shadow root, you can use the `::host` pseudo-element.
|
||||
|
||||
During the transition phase, style sheets targeting the `atom-text-editor` context will *also* be loaded globally. Make sure you update your selectors in a way that maintains compatibility with the shadow DOM being disabled. That means if you use a `::host` pseudo element, you should also include the same style rule matches against `atom-text-editor`.
|
||||
|
||||
[shadow-dom-101]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom
|
||||
[shadow-dom-201]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201#toc-style-cat-hat
|
||||
[find-and-replace]: https://github.com/atom/find-and-replace/blob/95351f261bc384960a69b66bf12eae8002da63f9/stylesheets/find-and-replace.less#L10
|
||||
+107
-16
@@ -1,4 +1,5 @@
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
module.exports =
|
||||
@@ -7,29 +8,119 @@ module.exports =
|
||||
GitRepository: require '../src/git-repository'
|
||||
Point: Point
|
||||
Range: Range
|
||||
Emitter: Emitter
|
||||
Disposable: Disposable
|
||||
CompositeDisposable: CompositeDisposable
|
||||
|
||||
# The following classes can't be used from a Task handler and should therefore
|
||||
# only be exported when not running as a child node process
|
||||
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.TextEditor = require '../src/text-editor'
|
||||
|
||||
{$, $$, $$$, View} = require '../src/space-pen-extensions'
|
||||
|
||||
module.exports.$ = $
|
||||
module.exports.$$ = $$
|
||||
module.exports.$$$ = $$$
|
||||
module.exports.TextEditorView = require '../src/text-editor-view'
|
||||
module.exports.ScrollView = require '../src/scroll-view'
|
||||
module.exports.SelectListView = require '../src/select-list-view'
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.View = View
|
||||
module.exports.WorkspaceView = require '../src/workspace-view'
|
||||
module.exports.Workspace = require '../src/workspace'
|
||||
module.exports.React = require 'react-atom-fork'
|
||||
module.exports.Reactionary = require 'reactionary-atom-fork'
|
||||
Object.defineProperty module.exports, 'Workspace', get: ->
|
||||
deprecate """
|
||||
Requiring `Workspace` from `atom` is no longer supported.
|
||||
If you need this, please open an issue on
|
||||
https://github.com/atom/atom/issues/new
|
||||
And let us know what you are using it for.
|
||||
"""
|
||||
require '../src/workspace'
|
||||
|
||||
Object.defineProperty module.exports, 'WorkspaceView', get: ->
|
||||
deprecate """
|
||||
Requiring `WorkspaceView` from `atom` is no longer supported.
|
||||
Use `atom.view.getView(atom.workspace)` instead.
|
||||
"""
|
||||
require '../src/workspace-view'
|
||||
|
||||
Object.defineProperty module.exports, '$', get: ->
|
||||
deprecate """
|
||||
Requiring `$` from `atom` is no longer supported.
|
||||
If you are using `space-pen`, please require `$` from `space-pen`. Otherwise require `jquery` instead:
|
||||
`{$} = require 'space-pen'`
|
||||
or
|
||||
`$ = require 'jquery'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
Or add `"jquery": "^2"` to your package dependencies.
|
||||
"""
|
||||
$
|
||||
|
||||
Object.defineProperty module.exports, '$$', get: ->
|
||||
deprecate """
|
||||
Requiring `$$` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{$$} = require 'space-pen'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
"""
|
||||
$$
|
||||
|
||||
Object.defineProperty module.exports, '$$$', get: ->
|
||||
deprecate """
|
||||
Requiring `$$$` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{$$$} = require 'space-pen'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
"""
|
||||
$$$
|
||||
|
||||
Object.defineProperty module.exports, 'View', get: ->
|
||||
deprecate """
|
||||
Requiring `View` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{View} = require 'space-pen'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
"""
|
||||
View
|
||||
|
||||
Object.defineProperty module.exports, 'EditorView', get: ->
|
||||
deprecate """
|
||||
Requiring `EditorView` from `atom` is no longer supported.
|
||||
Please require `TextEditorView` from `atom-space-pen-view` instead:
|
||||
`{TextEditorView} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
"""
|
||||
require '../src/text-editor-view'
|
||||
|
||||
Object.defineProperty module.exports, 'TextEditorView', get: ->
|
||||
deprecate """
|
||||
Requiring `TextEditorView` from `atom` is no longer supported.
|
||||
Please require `TextEditorView` from `atom-space-pen-view` instead:
|
||||
`{TextEditorView} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
"""
|
||||
require '../src/text-editor-view'
|
||||
|
||||
Object.defineProperty module.exports, 'ScrollView', get: ->
|
||||
deprecate """
|
||||
Requiring `ScrollView` from `atom` is no longer supported.
|
||||
Please require `ScrollView` from `atom-space-pen-view` instead:
|
||||
`{ScrollView} = require 'atom-space-pen-views'`
|
||||
Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
"""
|
||||
require '../src/scroll-view'
|
||||
|
||||
Object.defineProperty module.exports, 'SelectListView', get: ->
|
||||
deprecate """
|
||||
Requiring `SelectListView` from `atom` is no longer supported.
|
||||
Please require `SelectListView` from `atom-space-pen-view` instead:
|
||||
`{SelectListView} = require 'atom-space-pen-views'`
|
||||
Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
"""
|
||||
require '../src/select-list-view'
|
||||
|
||||
Object.defineProperty module.exports, 'React', get: ->
|
||||
deprecate "Please require `react-atom-fork` instead: `React = require 'react-atom-fork'`. Add `\"react-atom-fork\": \"^0.11\"` to your package dependencies."
|
||||
require 'react-atom-fork'
|
||||
|
||||
Object.defineProperty module.exports, 'Reactionary', get: ->
|
||||
deprecate "Please require `reactionary` instead: `Reactionary = require 'reactionary'`. Add `\"reactionary\": \"^0.9\"` to your package dependencies."
|
||||
require 'reactionary'
|
||||
|
||||
Object.defineProperty module.exports, 'Git', get: ->
|
||||
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
|
||||
module.exports.GitRepository
|
||||
|
||||
Object.defineProperty module.exports, 'EditorView', get: ->
|
||||
deprecate "Please require `TextEditorView` instead of `EditorView`: `{TextEditorView} = require 'atom'`"
|
||||
module.exports.TextEditorView
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@
|
||||
'shift-home': 'editor:select-to-first-character-of-line'
|
||||
'shift-end': 'editor:select-to-end-of-line'
|
||||
|
||||
'atom-text-editor:not(.mini)':
|
||||
'atom-text-editor:not([mini])':
|
||||
# Atom Specific
|
||||
'ctrl-C': 'editor:copy-path'
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
'shift-tab': 'editor:outdent-selected-rows'
|
||||
'ctrl-K': 'editor:delete-line'
|
||||
|
||||
'.select-list atom-text-editor.mini':
|
||||
'.select-list atom-text-editor[mini]':
|
||||
'enter': 'core:confirm'
|
||||
|
||||
'.tool-panel.panel-left, .tool-panel.panel-right':
|
||||
'escape': 'tool-panel:unfocus'
|
||||
|
||||
'atom-text-editor !important, atom-text-editor.mini !important':
|
||||
'atom-text-editor !important, atom-text-editor[mini] !important':
|
||||
'escape': 'editor:consolidate-selections'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
'cmd-l': 'editor:select-line'
|
||||
'ctrl-t': 'editor:transpose'
|
||||
|
||||
'atom-workspace atom-text-editor:not(.mini)':
|
||||
'atom-workspace atom-text-editor:not([mini])':
|
||||
# Atom specific
|
||||
'alt-cmd-z': 'editor:checkout-head-revision'
|
||||
'cmd-<': 'editor:scroll-to-cursor'
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
'ctrl-l': 'editor:select-line'
|
||||
|
||||
'atom-workspace atom-text-editor:not(.mini)':
|
||||
'atom-workspace atom-text-editor:not([mini])':
|
||||
# Atom specific
|
||||
'alt-ctrl-z': 'editor:checkout-head-revision'
|
||||
'ctrl-<': 'editor:scroll-to-cursor'
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
'ctrl-l': 'editor:select-line'
|
||||
|
||||
'atom-workspace atom-text-editor:not(.mini)':
|
||||
'atom-workspace atom-text-editor:not([mini])':
|
||||
# Atom specific
|
||||
'alt-ctrl-z': 'editor:checkout-head-revision'
|
||||
'ctrl-<': 'editor:scroll-to-cursor'
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
submenu: [
|
||||
{ label: '&Reload', command: 'window:reload' }
|
||||
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
|
||||
{ label: 'Toggle Menu Bar', command: 'window:toggle-menu-bar' }
|
||||
{
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
|
||||
+2
-1
@@ -93,6 +93,7 @@
|
||||
submenu: [
|
||||
{ label: '&Reload', command: 'window:reload' }
|
||||
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
|
||||
{ label: 'Toggle Menu Bar', command: 'window:toggle-menu-bar' }
|
||||
{
|
||||
label: 'Panes'
|
||||
submenu: [
|
||||
@@ -162,7 +163,7 @@
|
||||
submenu: [
|
||||
{ label: 'View &Terms of Use', command: 'application:open-terms-of-use' }
|
||||
{ label: 'View &License', command: 'application:open-license' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: 'VERSION', enabled: false }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Documentation', command: 'application:open-documentation' }
|
||||
{ label: 'Roadmap', command: 'application:open-roadmap' }
|
||||
|
||||
+19
-18
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.146.0",
|
||||
"version": "0.147.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.19.1",
|
||||
"atomShellVersion": "0.19.2",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^2.2.2",
|
||||
@@ -37,7 +37,8 @@
|
||||
"guid": "0.0.10",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
"less-cache": "0.17.0",
|
||||
"jquery": "^2.1.1",
|
||||
"less-cache": "0.19.0",
|
||||
"mixto": "^1",
|
||||
"mkdirp": "0.3.5",
|
||||
"nslog": "^1.0.1",
|
||||
@@ -58,20 +59,20 @@
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.8.1",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.6.0",
|
||||
"text-buffer": "^3.6.1",
|
||||
"theorist": "^1.0.2",
|
||||
"underscore-plus": "^1.6.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.21.0",
|
||||
"atom-dark-ui": "0.35.0",
|
||||
"atom-light-syntax": "0.21.0",
|
||||
"atom-light-ui": "0.30.0",
|
||||
"base16-tomorrow-dark-theme": "0.21.0",
|
||||
"base16-tomorrow-light-theme": "0.4.0",
|
||||
"solarized-dark-syntax": "0.22.0",
|
||||
"solarized-light-syntax": "0.12.0",
|
||||
"atom-dark-syntax": "0.22.0",
|
||||
"atom-dark-ui": "0.39.0",
|
||||
"atom-light-syntax": "0.22.0",
|
||||
"atom-light-ui": "0.33.0",
|
||||
"base16-tomorrow-dark-theme": "0.22.0",
|
||||
"base16-tomorrow-light-theme": "0.5.0",
|
||||
"solarized-dark-syntax": "0.23.0",
|
||||
"solarized-light-syntax": "0.13.0",
|
||||
"archive-view": "0.37.0",
|
||||
"autocomplete": "0.33.0",
|
||||
"autoflow": "0.18.0",
|
||||
@@ -80,11 +81,11 @@
|
||||
"bookmarks": "0.30.0",
|
||||
"bracket-matcher": "0.62.0",
|
||||
"command-palette": "0.27.0",
|
||||
"deprecation-cop": "0.11.0",
|
||||
"deprecation-cop": "0.13.0",
|
||||
"dev-live-reload": "0.35.0",
|
||||
"encoding-selector": "0.7.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
"find-and-replace": "0.146.0",
|
||||
"find-and-replace": "0.147.0",
|
||||
"fuzzy-finder": "0.60.0",
|
||||
"git-diff": "0.43.0",
|
||||
"go-to-line": "0.26.0",
|
||||
@@ -98,20 +99,20 @@
|
||||
"open-on-github": "0.30.0",
|
||||
"package-generator": "0.32.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.159.0",
|
||||
"settings-view": "0.160.0",
|
||||
"snippets": "0.56.0",
|
||||
"spell-check": "0.43.0",
|
||||
"status-bar": "0.46.0",
|
||||
"styleguide": "0.30.0",
|
||||
"symbols-view": "0.68.0",
|
||||
"tabs": "0.55.0",
|
||||
"tabs": "0.56.0",
|
||||
"timecop": "0.23.0",
|
||||
"tree-view": "0.132.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.19.0",
|
||||
"whitespace": "0.26.0",
|
||||
"wrap-guide": "0.23.0",
|
||||
"language-c": "0.30.0",
|
||||
"wrap-guide": "0.24.0",
|
||||
"language-c": "0.31.0",
|
||||
"language-coffee-script": "0.37.0",
|
||||
"language-css": "0.23.0",
|
||||
"language-gfm": "0.53.0",
|
||||
|
||||
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 274 KiB |
@@ -34,6 +34,9 @@ exports.safeSpawn = function(command, args, options, callback) {
|
||||
var child = childProcess.spawn(command, args, options);
|
||||
child.stderr.pipe(process.stderr);
|
||||
child.stdout.pipe(process.stdout);
|
||||
child.on('error', function(error) {
|
||||
console.error('Command \'' + command + '\' failed: ' + error.message);
|
||||
});
|
||||
child.on('exit', function(code) {
|
||||
if (code != 0)
|
||||
process.exit(code);
|
||||
|
||||
@@ -195,6 +195,52 @@ describe "Config", ->
|
||||
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
|
||||
expect(atom.config.save.callCount).toBe 1
|
||||
|
||||
it "does not call ::save or add a scoped property when no value has been set", ->
|
||||
# see https://github.com/atom/atom/issues/4175
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
|
||||
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10
|
||||
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
|
||||
scopedProperties = atom.config.scopedSettingsStore.propertiesForSource('user-config')
|
||||
expect(scopedProperties['.coffee.source']).toBeUndefined()
|
||||
|
||||
it "removes the scoped value when it was the only set value on the object", ->
|
||||
spyOn(CSON, 'writeFileSync')
|
||||
jasmine.unspy atom.config, 'save'
|
||||
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
|
||||
atom.config.set('.source.coffee', 'foo.bar.zfoo', 20)
|
||||
CSON.writeFileSync.reset()
|
||||
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55
|
||||
|
||||
atom.config.restoreDefault('.source.coffee', 'foo.bar.baz')
|
||||
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 10
|
||||
expect(atom.config.get(['.source.coffee'], 'foo.bar.zfoo')).toBe 20
|
||||
expect(CSON.writeFileSync).toHaveBeenCalled()
|
||||
properties = CSON.writeFileSync.mostRecentCall.args[1]
|
||||
expect(properties['.coffee.source']).toEqual
|
||||
foo:
|
||||
bar:
|
||||
zfoo: 20
|
||||
|
||||
CSON.writeFileSync.reset()
|
||||
atom.config.restoreDefault('.source.coffee', 'foo.bar.zfoo')
|
||||
expect(CSON.writeFileSync).toHaveBeenCalled()
|
||||
properties = CSON.writeFileSync.mostRecentCall.args[1]
|
||||
expect(properties['.coffee.source']).toBeUndefined()
|
||||
|
||||
it "does not call ::save when the value is already at the default", ->
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
atom.config.set('.source.coffee', 'foo.bar.baz', 55)
|
||||
atom.config.save.reset()
|
||||
|
||||
atom.config.restoreDefault('.source.coffee', 'foo.bar.ok')
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
expect(atom.config.get(['.source.coffee'], 'foo.bar.baz')).toBe 55
|
||||
|
||||
describe ".getSettings()", ->
|
||||
it "returns all settings including defaults", ->
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
|
||||
@@ -96,12 +96,13 @@ describe "LanguageMode", ->
|
||||
buffer.setText("//this is a single line comment")
|
||||
expect(languageMode.rowRangeForCommentAtBufferRow(0)).toBeUndefined()
|
||||
|
||||
describe "suggestedIndentForBufferRow", ->
|
||||
it "returns the suggested indentation based on auto-indent/outdent rules", ->
|
||||
describe ".suggestedIndentForBufferRow", ->
|
||||
it "bases indentation off of the previous non-blank line", ->
|
||||
expect(languageMode.suggestedIndentForBufferRow(0)).toBe 0
|
||||
expect(languageMode.suggestedIndentForBufferRow(1)).toBe 1
|
||||
expect(languageMode.suggestedIndentForBufferRow(2)).toBe 2
|
||||
expect(languageMode.suggestedIndentForBufferRow(9)).toBe 1
|
||||
expect(languageMode.suggestedIndentForBufferRow(11)).toBe 1
|
||||
|
||||
describe "rowRangeForParagraphAtBufferRow", ->
|
||||
describe "with code and comments", ->
|
||||
|
||||
@@ -34,8 +34,8 @@ describe "PanelContainerElement", ->
|
||||
element = container.getView()
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
it 'has a location attribute with value from the model', ->
|
||||
expect(element.getAttribute('location')).toBe 'left'
|
||||
it 'has a location class with value from the model', ->
|
||||
expect(element).toHaveClass 'left'
|
||||
|
||||
it 'removes the element when the container is destroyed', ->
|
||||
expect(element.parentNode).toBe jasmineContent
|
||||
@@ -50,7 +50,7 @@ describe "PanelContainerElement", ->
|
||||
panel1 = new Panel({viewRegistry, item: new TestPanelContainerItem()})
|
||||
container.addPanel(panel1)
|
||||
expect(element.childNodes.length).toBe 1
|
||||
expect(element.childNodes[0].getAttribute('location')).toBe 'left'
|
||||
expect(element.childNodes[0]).toHaveClass 'left'
|
||||
|
||||
expect(element.childNodes[0].tagName).toBe 'ATOM-PANEL'
|
||||
|
||||
@@ -79,7 +79,7 @@ describe "PanelContainerElement", ->
|
||||
panel1 = new Panel({viewRegistry, item: new TestPanelContainerItem(), className: 'one'})
|
||||
container.addPanel(panel1)
|
||||
expect(element.childNodes.length).toBe 1
|
||||
expect(element.childNodes[0].getAttribute('location')).toBe 'bottom'
|
||||
expect(element.childNodes[0]).toHaveClass 'bottom'
|
||||
expect(element.childNodes[0].tagName).toBe 'ATOM-PANEL'
|
||||
expect(panel1.getView()).toHaveClass 'one'
|
||||
|
||||
|
||||
@@ -74,3 +74,34 @@ describe "StylesElement", ->
|
||||
expect(element.children.length).toBe 2
|
||||
expect(element.children[0].textContent).toBe "a {color: red;}"
|
||||
expect(element.children[1].textContent).toBe "a {color: blue;}"
|
||||
|
||||
describe "atom-text-editor shadow DOM selector upgrades", ->
|
||||
beforeEach ->
|
||||
element.setAttribute('context', 'atom-text-editor')
|
||||
spyOn(console, 'warn')
|
||||
|
||||
it "upgrades selectors containing .editor-colors", ->
|
||||
atom.styles.addStyleSheet(".editor-colors {background: black;}", context: 'atom-text-editor')
|
||||
expect(element.firstChild.sheet.cssRules[0].selectorText).toBe ':host'
|
||||
|
||||
it "upgrades selectors containing .editor", ->
|
||||
atom.styles.addStyleSheet """
|
||||
.editor {background: black;}
|
||||
.editor.mini {background: black;}
|
||||
.editor:focus {background: black;}
|
||||
""", context: 'atom-text-editor'
|
||||
|
||||
expect(element.firstChild.sheet.cssRules[0].selectorText).toBe ':host'
|
||||
expect(element.firstChild.sheet.cssRules[1].selectorText).toBe ':host(.mini)'
|
||||
expect(element.firstChild.sheet.cssRules[2].selectorText).toBe ':host(:focus)'
|
||||
|
||||
it "defers selector upgrade until the element is attached", ->
|
||||
element = new StylesElement
|
||||
element.setAttribute('context', 'atom-text-editor')
|
||||
element.initialize()
|
||||
|
||||
atom.styles.addStyleSheet ".editor {background: black;}", context: 'atom-text-editor'
|
||||
expect(element.firstChild.sheet).toBeNull()
|
||||
|
||||
document.querySelector('#jasmine-content').appendChild(element)
|
||||
expect(element.firstChild.sheet.cssRules[0].selectorText).toBe ':host'
|
||||
|
||||
@@ -1203,6 +1203,221 @@ describe "TextEditorComponent", ->
|
||||
expect(componentNode.querySelector('.test-highlight')).toBeFalsy()
|
||||
expect(componentNode.querySelector('.new-test-highlight')).toBeTruthy()
|
||||
|
||||
describe "overlay decoration rendering", ->
|
||||
[item] = []
|
||||
beforeEach ->
|
||||
item = document.createElement('div')
|
||||
item.classList.add 'overlay-test'
|
||||
|
||||
describe "when the marker is empty", ->
|
||||
it "renders an overlay decoration when added and removes the overlay when the decoration is destroyed", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 13], [2, 13]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay .overlay-test')
|
||||
expect(overlay).toBe item
|
||||
|
||||
decoration.destroy()
|
||||
nextAnimationFrame()
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay .overlay-test')
|
||||
expect(overlay).toBe null
|
||||
|
||||
it "renders in the correct position on initial display and when the marker moves", ->
|
||||
editor.setCursorBufferPosition([2, 5])
|
||||
|
||||
marker = editor.getLastCursor().getMarker()
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([2, 5])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.moveRight()
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([2, 7])
|
||||
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
describe "when the marker is not empty", ->
|
||||
it "renders at the head of the marker", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([2, 10])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
it "renders at the head of the marker when the marker is reversed", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never', reversed: true)
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([2, 5])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
describe "positioning the overlay when near the edge of the editor", ->
|
||||
[itemWidth, itemHeight] = []
|
||||
beforeEach ->
|
||||
itemWidth = 4 * editor.getDefaultCharWidth()
|
||||
itemHeight = 4 * editor.getLineHeightInPixels()
|
||||
|
||||
gutterWidth = componentNode.querySelector('.gutter').offsetWidth
|
||||
windowWidth = gutterWidth + 30 * editor.getDefaultCharWidth()
|
||||
windowHeight = 9 * editor.getLineHeightInPixels()
|
||||
|
||||
item.style.width = itemWidth + 'px'
|
||||
item.style.height = itemHeight + 'px'
|
||||
|
||||
wrapperNode.style.width = windowWidth + 'px'
|
||||
wrapperNode.style.height = windowHeight + 'px'
|
||||
|
||||
component.measureHeightAndWidth()
|
||||
nextAnimationFrame()
|
||||
|
||||
it "flips horizontally when near the right edge", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[0, 26], [0, 26]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([0, 26])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertText('a')
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([0, 27])
|
||||
|
||||
expect(overlay.style.left).toBe position.left - itemWidth + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
it "flips vertically when near the bottom edge", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[4, 0], [4, 0]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([4, 0])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertNewline()
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([5, 0])
|
||||
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top - itemHeight + 'px'
|
||||
|
||||
describe "when the editor is very small", ->
|
||||
beforeEach ->
|
||||
gutterWidth = componentNode.querySelector('.gutter').offsetWidth
|
||||
windowWidth = gutterWidth + 6 * editor.getDefaultCharWidth()
|
||||
windowHeight = 6 * editor.getLineHeightInPixels()
|
||||
|
||||
wrapperNode.style.width = windowWidth + 'px'
|
||||
wrapperNode.style.height = windowHeight + 'px'
|
||||
|
||||
component.measureHeightAndWidth()
|
||||
nextAnimationFrame()
|
||||
|
||||
it "does not flip horizontally and force the overlay to have a negative left", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[0, 2], [0, 2]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([0, 2])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertText('a')
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([0, 3])
|
||||
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
it "does not flip vertically and force the overlay to have a negative top", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[1, 0], [1, 0]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([1, 0])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertNewline()
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([2, 0])
|
||||
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
|
||||
describe "when editor scroll position is not 0", ->
|
||||
it "flips horizontally when near the right edge", ->
|
||||
editor.setScrollLeft(2 * editor.getDefaultCharWidth())
|
||||
marker = editor.displayBuffer.markBufferRange([[0, 28], [0, 28]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([0, 28])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertText('a')
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([0, 29])
|
||||
|
||||
expect(overlay.style.left).toBe position.left - itemWidth + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
it "flips vertically when near the bottom edge", ->
|
||||
editor.setScrollTop(2 * editor.getLineHeightInPixels())
|
||||
marker = editor.displayBuffer.markBufferRange([[6, 0], [6, 0]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([6, 0])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertNewline()
|
||||
nextAnimationFrame()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([7, 0])
|
||||
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top - itemHeight + 'px'
|
||||
|
||||
describe "hidden input field", ->
|
||||
it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", ->
|
||||
editor.setVerticalScrollMargin(0)
|
||||
@@ -2469,6 +2684,24 @@ describe "TextEditorComponent", ->
|
||||
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe false
|
||||
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
|
||||
|
||||
describe "middle mouse paste on Linux", ->
|
||||
it "pastes the previously selected text", ->
|
||||
atom.clipboard.write('')
|
||||
component.listenForMiddleMousePaste()
|
||||
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', which: 2))
|
||||
|
||||
expect(atom.clipboard.read()).toBe ''
|
||||
expect(editor.lineTextForBufferRow(10)).toBe ''
|
||||
|
||||
editor.setSelectedBufferRange([[1, 6], [1, 10]])
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', which: 2))
|
||||
|
||||
expect(atom.clipboard.read()).toBe 'sort'
|
||||
expect(editor.lineTextForBufferRow(10)).toBe 'sort'
|
||||
|
||||
buildMouseEvent = (type, properties...) ->
|
||||
properties = extend({bubbles: true, cancelable: true}, properties...)
|
||||
properties.detail ?= 1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
TextEditor = require '../src/text-editor'
|
||||
|
||||
# The rest of text-editor-component-spec will be moved to this file when React
|
||||
# is eliminated. This covers only concerns related to the wrapper element for now
|
||||
@@ -19,6 +20,13 @@ describe "TextEditorElement", ->
|
||||
element = jasmineContent.firstChild
|
||||
expect(element.getModel().getPlaceholderText()).toBe 'testing'
|
||||
|
||||
describe "when the model is assigned", ->
|
||||
it "adds the 'mini' attribute if .isMini() returns true on the model", ->
|
||||
element = new TextEditorElement
|
||||
model = new TextEditor(mini: true)
|
||||
element.setModel(model)
|
||||
expect(element.hasAttribute('mini')).toBe true
|
||||
|
||||
describe "focus and blur handling", ->
|
||||
describe "when the editor.useShadowDOM config option is true", ->
|
||||
it "proxies focus/blur events to/from the hidden input inside the shadow root", ->
|
||||
|
||||
+316
-251
@@ -2477,32 +2477,32 @@ describe "TextEditor", ->
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0, editor.getTabLength() * 2]
|
||||
|
||||
describe "clipboard operations", ->
|
||||
beforeEach ->
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]])
|
||||
|
||||
describe ".cutSelectedText()", ->
|
||||
it "removes the selected text from the buffer and places it on the clipboard", ->
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]])
|
||||
editor.cutSelectedText()
|
||||
expect(buffer.lineForRow(0)).toBe "var = function () {"
|
||||
expect(buffer.lineForRow(1)).toBe " var = function(items) {"
|
||||
|
||||
expect(clipboard.readText()).toBe 'quicksort\nsort'
|
||||
|
||||
describe "when no text is selected", ->
|
||||
beforeEach ->
|
||||
editor.setSelectedBufferRanges([[1, 0], [1, 0]])
|
||||
editor.addCursorAtBufferPosition([5, 0])
|
||||
editor.setSelectedBufferRanges([
|
||||
[[0, 0], [0, 0]],
|
||||
[[5, 0], [5, 0]],
|
||||
])
|
||||
|
||||
it "cuts the lines on which there are cursors", ->
|
||||
editor.cutSelectedText()
|
||||
|
||||
expect(buffer.getLineCount()).toBe(11)
|
||||
expect(buffer.lineForRow(1)).toBe(" if (items.length <= 1) return items;")
|
||||
expect(buffer.lineForRow(4)).toBe(" current < pivot ? left.push(current) : right.push(current);")
|
||||
expect(atom.clipboard.readWithMetadata().metadata.selections).toEqual([
|
||||
"var quicksort = function () {\n"
|
||||
" current = items.shift();\n"
|
||||
])
|
||||
expect(atom.clipboard.read()).toEqual """
|
||||
var quicksort = function () {
|
||||
|
||||
current = items.shift();
|
||||
|
||||
"""
|
||||
|
||||
describe ".cutToEndOfLine()", ->
|
||||
describe "when soft wrap is on", ->
|
||||
@@ -2542,11 +2542,11 @@ describe "TextEditor", ->
|
||||
expect(buffer.lineForRow(1)).toBe " var sort = function(items) {"
|
||||
expect(buffer.lineForRow(2)).toBe " if (items.length <= 1) return items;"
|
||||
expect(clipboard.readText()).toBe 'quicksort\nsort\nitems'
|
||||
expect(atom.clipboard.readWithMetadata().metadata.selections).toEqual([
|
||||
'quicksort'
|
||||
'sort'
|
||||
'items'
|
||||
])
|
||||
expect(atom.clipboard.read()).toEqual """
|
||||
quicksort
|
||||
sort
|
||||
items
|
||||
"""
|
||||
|
||||
describe "when no text is selected", ->
|
||||
beforeEach ->
|
||||
@@ -2557,40 +2557,195 @@ describe "TextEditor", ->
|
||||
|
||||
it "copies the lines on which there are cursors", ->
|
||||
editor.copySelectedText()
|
||||
expect(atom.clipboard.readWithMetadata().metadata.selections).toEqual([
|
||||
expect(atom.clipboard.read()).toEqual([
|
||||
" var sort = function(items) {\n"
|
||||
" current = items.shift();\n"
|
||||
])
|
||||
].join("\n"))
|
||||
expect(editor.getSelectedBufferRanges()).toEqual([
|
||||
[[1, 5], [1, 5]],
|
||||
[[5, 8], [5, 8]]
|
||||
])
|
||||
|
||||
describe ".pasteText()", ->
|
||||
copyText = (text, {startColumn, textEditor}={}) ->
|
||||
startColumn ?= 0
|
||||
textEditor ?= editor
|
||||
textEditor.setCursorBufferPosition([0, 0])
|
||||
textEditor.insertText(text)
|
||||
numberOfNewlines = text.match(/\n/g)?.length
|
||||
endColumn = text.match(/[^\n]*$/)[0]?.length
|
||||
textEditor.getLastSelection().setBufferRange([[0,startColumn], [numberOfNewlines,endColumn]])
|
||||
textEditor.cutSelectedText()
|
||||
|
||||
it "pastes text into the buffer", ->
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]])
|
||||
atom.clipboard.write('first')
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var first = function () {"
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " var first = function(items) {"
|
||||
|
||||
describe 'when the clipboard has many selections', ->
|
||||
it "pastes each selection separately into the buffer", ->
|
||||
atom.clipboard.write('first\nsecond', {selections: ['first', 'second'] })
|
||||
describe "when `autoIndentOnPaste` is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.autoIndentOnPaste", true)
|
||||
|
||||
describe "when only whitespace precedes the cursor", ->
|
||||
it "auto-indents the lines spanned by the pasted text", ->
|
||||
atom.clipboard.write("console.log(x);\nconsole.log(y);\n")
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(5)).toBe(" console.log(x);")
|
||||
expect(editor.lineTextForBufferRow(6)).toBe(" console.log(y);")
|
||||
|
||||
describe "when non-whitespace characters precede the cursor", ->
|
||||
it "does not auto-indent the first line being pasted", ->
|
||||
editor.setText """
|
||||
if (x) {
|
||||
y();
|
||||
}
|
||||
"""
|
||||
|
||||
atom.clipboard.write(" z();")
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.pasteText()
|
||||
|
||||
console.log JSON.stringify(editor.lineTextForBufferRow(1))
|
||||
expect(editor.lineTextForBufferRow(1)).toBe(" y(); z();")
|
||||
|
||||
describe "when `autoIndentOnPaste` is false and `normalizeIndentOnPaste` is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set('editor.autoIndentOnPaste', false)
|
||||
atom.config.set('editor.normalizeIndentOnPaste', true)
|
||||
|
||||
describe "when the inserted text contains no newlines", ->
|
||||
it "does not adjust the indentation level of the text", ->
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
editor.insertText("foo", indentBasis: 5)
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " foo current = items.shift();"
|
||||
|
||||
it "does not adjust the whitespace if there are preceding characters", ->
|
||||
copyText(" foo")
|
||||
editor.setCursorBufferPosition([5, 30])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " current = items.shift(); foo"
|
||||
|
||||
describe "when the inserted text contains newlines", ->
|
||||
describe "when the cursor is preceded only by whitespace characters", ->
|
||||
it "normalizes indented lines to each cursor's current indentation level", ->
|
||||
editor.setSelectedBufferRanges([
|
||||
[[1,2], [3,0]],
|
||||
[[4,4], [6,0]]
|
||||
])
|
||||
editor.copySelectedText()
|
||||
expect(atom.clipboard.read()).toEqual """
|
||||
var sort = function(items) {
|
||||
if (items.length <= 1) return items;
|
||||
|
||||
while(items.length > 0) {
|
||||
current = items.shift();
|
||||
|
||||
"""
|
||||
|
||||
editor.setCursorBufferPosition([0,0])
|
||||
editor.insertNewlineAbove()
|
||||
editor.setSelectedBufferRanges([
|
||||
[[0,0], [0,0]],
|
||||
[[1,0], [1,0]]
|
||||
])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var sort = function(items) {"
|
||||
console.log JSON.stringify(editor.lineTextForBufferRow(1))
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " if (items.length <= 1) return items;"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe ""
|
||||
expect(editor.lineTextForBufferRow(3)).toBe "while(items.length > 0) {"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " current = items.shift();"
|
||||
|
||||
describe "when the cursor is preceded by non-whitespace characters", ->
|
||||
it "normalizes the indentation level of all lines based on the level of the existing first line", ->
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 0})
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " var sort = function(items) {while (true) {"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " foo();"
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " }"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe ""
|
||||
|
||||
describe 'when scoped settings are used', ->
|
||||
coffeeEditor = null
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) ->
|
||||
coffeeEditor = o
|
||||
|
||||
runs ->
|
||||
atom.config.set('.source.js', 'editor.normalizeIndentOnPaste', true)
|
||||
atom.config.set('.source.coffee', 'editor.normalizeIndentOnPaste', false)
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
it "normalizes the indentation level based on scoped settings", ->
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2, textEditor: coffeeEditor})
|
||||
coffeeEditor.setCursorBufferPosition([4, 4])
|
||||
coffeeEditor.pasteText()
|
||||
expect(coffeeEditor.lineTextForBufferRow(4)).toBe " while (true) {"
|
||||
expect(coffeeEditor.lineTextForBufferRow(5)).toBe " foo();"
|
||||
expect(coffeeEditor.lineTextForBufferRow(6)).toBe " }"
|
||||
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2})
|
||||
editor.setCursorBufferPosition([3, 4])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " while (true) {"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " foo();"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " }"
|
||||
|
||||
describe "when `autoIndentOnPaste` and `normalizeIndentOnPaste` are both false", ->
|
||||
beforeEach ->
|
||||
atom.config.set('editor.normalizeIndentOnPaste', false)
|
||||
atom.config.set("editor.autoIndentOnPaste", false)
|
||||
|
||||
it "does not auto-indent the pasted text", ->
|
||||
atom.clipboard.write("console.log(x);\nconsole.log(y);\n")
|
||||
editor.setCursorBufferPosition([5, 0])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var first = function () {"
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " var second = function(items) {"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe("console.log(x);")
|
||||
expect(editor.lineTextForBufferRow(6)).toBe("console.log(y);")
|
||||
|
||||
it "does not normalize the indentation level of the text", ->
|
||||
copyText(" function() {\nvar cool = 1;\n }\n")
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " function() {"
|
||||
expect(editor.lineTextForBufferRow(6)).toBe "var cool = 1;"
|
||||
expect(editor.lineTextForBufferRow(7)).toBe " }"
|
||||
|
||||
describe 'when the clipboard has many selections', ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.autoIndentOnPaste", false)
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]])
|
||||
editor.copySelectedText()
|
||||
|
||||
it "pastes each selection separately into the buffer", ->
|
||||
editor.copySelectedText()
|
||||
editor.moveRight()
|
||||
editor.insertText("_")
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var quicksort_quicksort = function () {"
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " var sort_sort = function(items) {"
|
||||
|
||||
describe 'and the selections count does not match', ->
|
||||
it "pastes the whole text into the buffer", ->
|
||||
atom.clipboard.write('first\nsecond\nthird', {selections: ['first', 'second', 'third'] })
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var first"
|
||||
expect(editor.lineTextForBufferRow(1)).toBe "second"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe "third = function () {"
|
||||
beforeEach ->
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]]])
|
||||
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " var first"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe "second"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe "third = function(items) {"
|
||||
it "pastes the whole text into the buffer", ->
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var quicksort"
|
||||
expect(editor.lineTextForBufferRow(1)).toBe "sort = function () {"
|
||||
|
||||
describe ".indentSelectedRows()", ->
|
||||
describe "when nothing is selected", ->
|
||||
@@ -2721,6 +2876,18 @@ describe "TextEditor", ->
|
||||
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 1], [3, 0]]
|
||||
|
||||
describe ".autoIndentSelectedRows", ->
|
||||
it "auto-indents the selection", ->
|
||||
editor.setCursorBufferPosition([2, 0])
|
||||
editor.insertText("function() {\ninside=true\n}\n i=1\n")
|
||||
editor.getLastSelection().setBufferRange([[2,0], [6,0]])
|
||||
editor.autoIndentSelectedRows()
|
||||
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " function() {"
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " inside=true"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " }"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " i=1"
|
||||
|
||||
describe ".toggleLineCommentsInSelection()", ->
|
||||
it "toggles comments on the selected lines", ->
|
||||
editor.setSelectedBufferRange([[4, 5], [7, 5]])
|
||||
@@ -3224,237 +3391,135 @@ describe "TextEditor", ->
|
||||
expect(editor.getGrammar()).toBe jsGrammar
|
||||
expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBeGreaterThan 1
|
||||
|
||||
describe "auto-indent", ->
|
||||
copyText = (text, {startColumn, textEditor}={}) ->
|
||||
startColumn ?= 0
|
||||
textEditor ?= editor
|
||||
textEditor.setCursorBufferPosition([0, 0])
|
||||
textEditor.insertText(text)
|
||||
numberOfNewlines = text.match(/\n/g)?.length
|
||||
endColumn = text.match(/[^\n]*$/)[0]?.length
|
||||
textEditor.getLastSelection().setBufferRange([[0,startColumn], [numberOfNewlines,endColumn]])
|
||||
textEditor.cutSelectedText()
|
||||
|
||||
describe "editor.autoIndent", ->
|
||||
describe "when editor.autoIndent is false (default)", ->
|
||||
describe "when `indent` is triggered", ->
|
||||
it "does not auto-indent the line", ->
|
||||
editor.setCursorBufferPosition([1, 30])
|
||||
editor.insertText("\n ")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
atom.config.set("editor.autoIndent", false)
|
||||
editor.indent()
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
describe "when editor.autoIndent is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.autoIndent", true)
|
||||
|
||||
describe "when `indent` is triggered", ->
|
||||
it "auto-indents the line", ->
|
||||
editor.setCursorBufferPosition([1, 30])
|
||||
editor.insertText("\n ")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
atom.config.set("editor.autoIndent", true)
|
||||
editor.indent()
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
describe "when a newline is added", ->
|
||||
describe "when the line preceding the newline adds a new level of indentation", ->
|
||||
it "indents the newline to one additional level of indentation beyond the preceding line", ->
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
|
||||
describe "when the line preceding the newline does't add a level of indentation", ->
|
||||
it "indents the new line to the same level a as the preceding line", ->
|
||||
editor.setCursorBufferPosition([5, 14])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(6)).toBe editor.indentationForBufferRow(5)
|
||||
|
||||
describe "when the line preceding the newline is a comment", ->
|
||||
it "maintains the indent of the commented line", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText(' //')
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(1)).toBe 2
|
||||
|
||||
it "does not indent the line preceding the newline", ->
|
||||
editor.setCursorBufferPosition([2, 0])
|
||||
editor.insertText(' var this-line-should-be-indented-more\n')
|
||||
expect(editor.indentationForBufferRow(1)).toBe 1
|
||||
|
||||
atom.config.set("editor.autoIndent", true)
|
||||
editor.setCursorBufferPosition([2, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(1)).toBe 1
|
||||
expect(editor.indentationForBufferRow(2)).toBe 1
|
||||
|
||||
describe "when the cursor is before whitespace", ->
|
||||
it "retains the whitespace following the cursor on the new line", ->
|
||||
editor.setText(" var sort = function() {}")
|
||||
editor.setCursorScreenPosition([0, 23])
|
||||
editor.insertNewline()
|
||||
|
||||
expect(buffer.lineForRow(0)).toBe ' var sort = function()'
|
||||
expect(buffer.lineForRow(1)).toBe ' {}'
|
||||
expect(editor.getCursorScreenPosition()).toEqual [1, 2]
|
||||
|
||||
describe "when inserted text matches a decrease indent pattern", ->
|
||||
describe "when the preceding line matches an increase indent pattern", ->
|
||||
it "decreases the indentation to match that of the preceding line", ->
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
editor.insertText('}')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1)
|
||||
|
||||
describe "when the preceding line doesn't match an increase indent pattern", ->
|
||||
it "decreases the indentation to be one level below that of the preceding line", ->
|
||||
editor.setCursorBufferPosition([3, Infinity])
|
||||
editor.insertText('\n ')
|
||||
expect(editor.indentationForBufferRow(4)).toBe editor.indentationForBufferRow(3)
|
||||
editor.insertText('}')
|
||||
expect(editor.indentationForBufferRow(4)).toBe editor.indentationForBufferRow(3) - 1
|
||||
|
||||
it "doesn't break when decreasing the indentation on a row that has no indentation", ->
|
||||
editor.setCursorBufferPosition([12, Infinity])
|
||||
editor.insertText("\n}; # too many closing brackets!")
|
||||
expect(editor.lineTextForBufferRow(13)).toBe "}; # too many closing brackets!"
|
||||
|
||||
describe "when inserted text does not match a decrease indent pattern", ->
|
||||
it "does not decrease the indentation", ->
|
||||
editor.setCursorBufferPosition([12, 0])
|
||||
editor.insertText(' ')
|
||||
expect(editor.lineTextForBufferRow(12)).toBe ' };'
|
||||
editor.insertText('\t\t')
|
||||
expect(editor.lineTextForBufferRow(12)).toBe ' \t\t};'
|
||||
|
||||
describe "when the current line does not match a decrease indent pattern", ->
|
||||
it "leaves the line unchanged", ->
|
||||
editor.setCursorBufferPosition([2, 4])
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
editor.insertText('foo')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
|
||||
describe 'when scoped settings are used', ->
|
||||
coffeeEditor = null
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
runs ->
|
||||
atom.config.set('.source.js', 'editor.autoIndent', true)
|
||||
atom.config.set('.source.coffee', 'editor.autoIndent', false)
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
it "does not auto-indent the line for javascript files", ->
|
||||
describe "editor.autoIndent", ->
|
||||
describe "when editor.autoIndent is false (default)", ->
|
||||
describe "when `indent` is triggered", ->
|
||||
it "does not auto-indent the line", ->
|
||||
editor.setCursorBufferPosition([1, 30])
|
||||
editor.insertText("\n")
|
||||
editor.insertText("\n ")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
atom.config.set("editor.autoIndent", false)
|
||||
editor.indent()
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
describe "when editor.autoIndent is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.autoIndent", true)
|
||||
|
||||
describe "when `indent` is triggered", ->
|
||||
it "auto-indents the line", ->
|
||||
editor.setCursorBufferPosition([1, 30])
|
||||
editor.insertText("\n ")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
atom.config.set("editor.autoIndent", true)
|
||||
editor.indent()
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
coffeeEditor.setCursorBufferPosition([1, 18])
|
||||
coffeeEditor.insertText("\n")
|
||||
expect(coffeeEditor.lineTextForBufferRow(2)).toBe ""
|
||||
|
||||
describe "editor.normalizeIndentOnPaste", ->
|
||||
beforeEach ->
|
||||
atom.config.set('editor.normalizeIndentOnPaste', true)
|
||||
|
||||
it "does not normalize the indentation level of the text when editor.normalizeIndentOnPaste is false", ->
|
||||
copyText(" function() {\nvar cool = 1;\n }\n")
|
||||
atom.config.set('editor.normalizeIndentOnPaste', false)
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " function() {"
|
||||
expect(editor.lineTextForBufferRow(6)).toBe "var cool = 1;"
|
||||
expect(editor.lineTextForBufferRow(7)).toBe " }"
|
||||
|
||||
describe "when the inserted text contains no newlines", ->
|
||||
it "does not adjust the indentation level of the text", ->
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
editor.insertText("foo", indentBasis: 5)
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " foo current = items.shift();"
|
||||
|
||||
it "does not adjust the whitespace if there are preceding characters", ->
|
||||
copyText(" foo")
|
||||
editor.setCursorBufferPosition([5, 30])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " current = items.shift(); foo"
|
||||
|
||||
describe "when the inserted text contains newlines", ->
|
||||
describe "when the cursor is preceded only by whitespace characters", ->
|
||||
it "normalizes indented lines to the cursor's current indentation level", ->
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2})
|
||||
editor.setCursorBufferPosition([3, 4])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " while (true) {"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " foo();"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " }"
|
||||
expect(editor.lineTextForBufferRow(6)).toBe "var pivot = items.shift(), current, left = [], right = [];"
|
||||
|
||||
describe "when the cursor is preceded by non-whitespace characters", ->
|
||||
it "normalizes the indentation level of all lines based on the level of the existing first line", ->
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 0})
|
||||
describe "when a newline is added", ->
|
||||
describe "when the line preceding the newline adds a new level of indentation", ->
|
||||
it "indents the newline to one additional level of indentation beyond the preceding line", ->
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.pasteText()
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " var sort = function(items) {while (true) {"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " foo();"
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " }"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe ""
|
||||
describe "when the line preceding the newline does't add a level of indentation", ->
|
||||
it "indents the new line to the same level a as the preceding line", ->
|
||||
editor.setCursorBufferPosition([5, 14])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(6)).toBe editor.indentationForBufferRow(5)
|
||||
|
||||
describe 'when scoped settings are used', ->
|
||||
coffeeEditor = null
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
describe "when the line preceding the newline is a comment", ->
|
||||
it "maintains the indent of the commented line", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText(' //')
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(1)).toBe 2
|
||||
|
||||
runs ->
|
||||
atom.config.set('.source.js', 'editor.normalizeIndentOnPaste', true)
|
||||
atom.config.set('.source.coffee', 'editor.normalizeIndentOnPaste', false)
|
||||
it "does not indent the line preceding the newline", ->
|
||||
editor.setCursorBufferPosition([2, 0])
|
||||
editor.insertText(' var this-line-should-be-indented-more\n')
|
||||
expect(editor.indentationForBufferRow(1)).toBe 1
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
atom.config.set("editor.autoIndent", true)
|
||||
editor.setCursorBufferPosition([2, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(1)).toBe 1
|
||||
expect(editor.indentationForBufferRow(2)).toBe 1
|
||||
|
||||
it "normalizes the indentation level based on scoped settings", ->
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2, textEditor: coffeeEditor})
|
||||
coffeeEditor.setCursorBufferPosition([4, 4])
|
||||
coffeeEditor.pasteText()
|
||||
expect(coffeeEditor.lineTextForBufferRow(4)).toBe " while (true) {"
|
||||
expect(coffeeEditor.lineTextForBufferRow(5)).toBe " foo();"
|
||||
expect(coffeeEditor.lineTextForBufferRow(6)).toBe " }"
|
||||
describe "when the cursor is before whitespace", ->
|
||||
it "retains the whitespace following the cursor on the new line", ->
|
||||
editor.setText(" var sort = function() {}")
|
||||
editor.setCursorScreenPosition([0, 23])
|
||||
editor.insertNewline()
|
||||
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2})
|
||||
editor.setCursorBufferPosition([3, 4])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " while (true) {"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " foo();"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " }"
|
||||
expect(buffer.lineForRow(0)).toBe ' var sort = function()'
|
||||
expect(buffer.lineForRow(1)).toBe ' {}'
|
||||
expect(editor.getCursorScreenPosition()).toEqual [1, 2]
|
||||
|
||||
it "autoIndentSelectedRows auto-indents the selection", ->
|
||||
editor.setCursorBufferPosition([2, 0])
|
||||
editor.insertText("function() {\ninside=true\n}\n i=1\n")
|
||||
editor.getLastSelection().setBufferRange([[2,0], [6,0]])
|
||||
editor.autoIndentSelectedRows()
|
||||
describe "when inserted text matches a decrease indent pattern", ->
|
||||
describe "when the preceding line matches an increase indent pattern", ->
|
||||
it "decreases the indentation to match that of the preceding line", ->
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.insertText('\n')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
editor.insertText('}')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1)
|
||||
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " function() {"
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " inside=true"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " }"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " i=1"
|
||||
describe "when the preceding line doesn't match an increase indent pattern", ->
|
||||
it "decreases the indentation to be one level below that of the preceding line", ->
|
||||
editor.setCursorBufferPosition([3, Infinity])
|
||||
editor.insertText('\n ')
|
||||
expect(editor.indentationForBufferRow(4)).toBe editor.indentationForBufferRow(3)
|
||||
editor.insertText('}')
|
||||
expect(editor.indentationForBufferRow(4)).toBe editor.indentationForBufferRow(3) - 1
|
||||
|
||||
it "doesn't break when decreasing the indentation on a row that has no indentation", ->
|
||||
editor.setCursorBufferPosition([12, Infinity])
|
||||
editor.insertText("\n}; # too many closing brackets!")
|
||||
expect(editor.lineTextForBufferRow(13)).toBe "}; # too many closing brackets!"
|
||||
|
||||
describe "when inserted text does not match a decrease indent pattern", ->
|
||||
it "does not decrease the indentation", ->
|
||||
editor.setCursorBufferPosition([12, 0])
|
||||
editor.insertText(' ')
|
||||
expect(editor.lineTextForBufferRow(12)).toBe ' };'
|
||||
editor.insertText('\t\t')
|
||||
expect(editor.lineTextForBufferRow(12)).toBe ' \t\t};'
|
||||
|
||||
describe "when the current line does not match a decrease indent pattern", ->
|
||||
it "leaves the line unchanged", ->
|
||||
editor.setCursorBufferPosition([2, 4])
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
editor.insertText('foo')
|
||||
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
|
||||
|
||||
describe 'when scoped settings are used', ->
|
||||
coffeeEditor = null
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
runs ->
|
||||
atom.config.set('.source.js', 'editor.autoIndent', true)
|
||||
atom.config.set('.source.coffee', 'editor.autoIndent', false)
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
it "does not auto-indent the line for javascript files", ->
|
||||
editor.setCursorBufferPosition([1, 30])
|
||||
editor.insertText("\n")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " "
|
||||
|
||||
coffeeEditor.setCursorBufferPosition([1, 18])
|
||||
coffeeEditor.insertText("\n")
|
||||
expect(coffeeEditor.lineTextForBufferRow(2)).toBe ""
|
||||
|
||||
describe "soft and hard tabs", ->
|
||||
afterEach ->
|
||||
|
||||
@@ -277,15 +277,15 @@ describe "WorkspaceView", ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
it 'inserts panel container elements in the correct places in the DOM', ->
|
||||
leftContainer = workspaceElement.querySelector('atom-panel-container[location="left"]')
|
||||
rightContainer = workspaceElement.querySelector('atom-panel-container[location="right"]')
|
||||
leftContainer = workspaceElement.querySelector('atom-panel-container.left')
|
||||
rightContainer = workspaceElement.querySelector('atom-panel-container.right')
|
||||
expect(leftContainer.nextSibling).toBe workspaceElement.verticalAxis
|
||||
expect(rightContainer.previousSibling).toBe workspaceElement.verticalAxis
|
||||
|
||||
topContainer = workspaceElement.querySelector('atom-panel-container[location="top"]')
|
||||
bottomContainer = workspaceElement.querySelector('atom-panel-container[location="bottom"]')
|
||||
topContainer = workspaceElement.querySelector('atom-panel-container.top')
|
||||
bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom')
|
||||
expect(topContainer.nextSibling).toBe workspaceElement.paneContainer
|
||||
expect(bottomContainer.previousSibling).toBe workspaceElement.paneContainer
|
||||
|
||||
modalContainer = workspaceElement.querySelector('atom-panel-container[location="modal"]')
|
||||
modalContainer = workspaceElement.querySelector('atom-panel-container.modal')
|
||||
expect(modalContainer.parentNode).toBe workspaceElement
|
||||
|
||||
@@ -503,7 +503,11 @@ class Atom extends Model
|
||||
@packages.activate()
|
||||
@keymaps.loadUserKeymap()
|
||||
@requireUserInitScript() unless safeMode
|
||||
|
||||
@menu.update()
|
||||
@subscribe @config.onDidChange 'core.autoHideMenuBar', ({newValue}) =>
|
||||
@setAutoHideMenuBar(newValue)
|
||||
@setAutoHideMenuBar(true) if @config.get('core.autoHideMenuBar')
|
||||
|
||||
maximize = dimensions?.maximized and process.platform isnt 'darwin'
|
||||
@displayWindow({maximize})
|
||||
@@ -723,3 +727,7 @@ class Atom extends Model
|
||||
|
||||
setBodyPlatformClass: ->
|
||||
document.body.classList.add("platform-#{process.platform}")
|
||||
|
||||
setAutoHideMenuBar: (autoHide) ->
|
||||
ipc.send('call-window-method', 'setAutoHideMenuBar', autoHide)
|
||||
ipc.send('call-window-method', 'setMenuBarVisibility', !autoHide)
|
||||
|
||||
@@ -20,10 +20,10 @@ class AutoUpdateManager
|
||||
process.nextTick => @setupAutoUpdater()
|
||||
|
||||
setupAutoUpdater: ->
|
||||
autoUpdater = require 'auto-updater'
|
||||
|
||||
if process.platform is 'win32'
|
||||
autoUpdater.checkForUpdates = => @checkForUpdatesShim()
|
||||
autoUpdater = require './auto-updater-win32'
|
||||
else
|
||||
autoUpdater = require 'auto-updater'
|
||||
|
||||
autoUpdater.setFeedUrl @feedUrl
|
||||
|
||||
@@ -48,24 +48,6 @@ class AutoUpdateManager
|
||||
unless /\w{7}/.test(@version)
|
||||
@check(hidePopups: true)
|
||||
|
||||
# Windows doesn't have an auto-updater, so use this method to shim the events.
|
||||
checkForUpdatesShim: ->
|
||||
autoUpdater.emit 'checking-for-update'
|
||||
|
||||
https = require 'https'
|
||||
request = https.get @feedUrl, (response) ->
|
||||
if response.statusCode == 200
|
||||
body = ""
|
||||
response.on 'data', (chunk) -> body += chunk
|
||||
response.on 'end', ->
|
||||
{notes, name} = JSON.parse(body)
|
||||
autoUpdater.emit 'update-downloaded', null, notes, name
|
||||
else
|
||||
autoUpdater.emit 'update-not-available'
|
||||
|
||||
request.on 'error', (error) ->
|
||||
autoUpdater.emit 'error', null, error.message
|
||||
|
||||
emitUpdateAvailableEvent: (windows...) ->
|
||||
return unless @releaseVersion? and @releaseNotes
|
||||
for atomWindow in windows
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
{EventEmitter} = require 'events'
|
||||
_ = require 'underscore-plus'
|
||||
shellAutoUpdater = require 'auto-updater'
|
||||
SquirrelUpdate = require './squirrel-update'
|
||||
|
||||
class AutoUpdater
|
||||
_.extend @prototype, EventEmitter.prototype
|
||||
|
||||
setFeedUrl: (@updateUrl) ->
|
||||
|
||||
quitAndInstall: ->
|
||||
unless SquirrelUpdate.existsSync()
|
||||
shellAutoUpdater.quitAndInstall()
|
||||
return
|
||||
|
||||
@installUpdate (error) ->
|
||||
return if error?
|
||||
|
||||
SquirrelUpdate.spawn ['--processStart', 'atom.exe'], ->
|
||||
shellAutoUpdater.quitAndInstall()
|
||||
|
||||
downloadUpdate: (callback) ->
|
||||
SquirrelUpdate.spawn ['--download', @updateUrl], (error, stdout) ->
|
||||
return callback(error) if error?
|
||||
|
||||
try
|
||||
# Last line of output is the JSON details about the releases
|
||||
json = stdout.trim().split('\n').pop()
|
||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||
catch error
|
||||
error.stdout = stdout
|
||||
return callback(error)
|
||||
|
||||
callback(null, update)
|
||||
|
||||
installUpdate: (callback) ->
|
||||
SquirrelUpdate.spawn(['--update', @updateUrl], callback)
|
||||
|
||||
checkForUpdates: ->
|
||||
throw new Error('Update URL is not set') unless @updateUrl
|
||||
|
||||
@emit 'checking-for-update'
|
||||
|
||||
unless SquirrelUpdate.existsSync()
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
|
||||
@downloadUpdate (error, update) =>
|
||||
if error?
|
||||
console.log "Failed to download: #{error.message} - #{error.code} - #{error.stdout}"
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
|
||||
unless update?
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
|
||||
@installUpdate (error) =>
|
||||
if error?
|
||||
console.log "Failed to update: #{error.message} - #{error.code} - #{error.stdout}"
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
|
||||
console.log "Updated to #{update.version}"
|
||||
|
||||
@emit 'update-available'
|
||||
@emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), 'https://atom.io', => @quitAndInstall()
|
||||
|
||||
module.exports = new AutoUpdater()
|
||||
@@ -14,6 +14,10 @@ process.on 'uncaughtException', (error={}) ->
|
||||
nslog(error.stack) if error.stack?
|
||||
|
||||
start = ->
|
||||
if process.platform is 'win32'
|
||||
SquirrelUpdate = require './squirrel-update'
|
||||
return if SquirrelUpdate.handleStartupEvent()
|
||||
|
||||
args = parseCommandLine()
|
||||
|
||||
addPathToOpen = (event, pathToOpen) ->
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
app = require 'app'
|
||||
ChildProcess = require 'child_process'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe')
|
||||
exeName = path.basename(process.execPath)
|
||||
|
||||
# Spawn the Update.exe with the given arguments and invoke the callback when
|
||||
# the command completes.
|
||||
exports.spawn = (args, callback) ->
|
||||
updateProcess = ChildProcess.spawn(updateDotExe, args)
|
||||
|
||||
stdout = ''
|
||||
updateProcess.stdout.on 'data', (data) -> stdout += data
|
||||
|
||||
error = null
|
||||
updateProcess.on 'error', (processError) -> error ?= processError
|
||||
updateProcess.on 'close', (code, signal) ->
|
||||
error ?= new Error("Command failed: #{signal}") if code isnt 0
|
||||
error?.code ?= code
|
||||
error?.stdout ?= stdout
|
||||
callback(error, stdout)
|
||||
|
||||
undefined
|
||||
|
||||
# Is the Update.exe installed with Atom?
|
||||
exports.existsSync = ->
|
||||
fs.existsSync(updateDotExe)
|
||||
|
||||
# Handle squirrel events denoted by --squirrel-* command line arguments.
|
||||
exports.handleStartupEvent = ->
|
||||
switch process.argv[1]
|
||||
when '--squirrel-install', '--squirrel-updated'
|
||||
exports.spawn ['--createShortcut', exeName], -> app.quit()
|
||||
true
|
||||
when '--squirrel-uninstall'
|
||||
exports.spawn ['--removeShortcut', exeName], -> app.quit()
|
||||
true
|
||||
when '--squirrel-obsolete'
|
||||
app.quit()
|
||||
true
|
||||
else
|
||||
false
|
||||
@@ -115,6 +115,10 @@ module.exports =
|
||||
autoIndent:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
description: 'Automatically indent the cursor when inserting a newline'
|
||||
autoIndentOnPaste:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
normalizeIndentOnPaste:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
@@ -183,3 +187,9 @@ module.exports =
|
||||
type: 'boolean'
|
||||
default: process.platform isnt 'darwin'
|
||||
description: 'Increase/decrease the editor font size when pressing the Ctrl key and scrolling the mouse up/down.'
|
||||
|
||||
if process.platform in ['win32', 'linux']
|
||||
module.exports.core.properties.autoHideMenuBar =
|
||||
type: 'boolean'
|
||||
default: false
|
||||
description: 'Automatically hide the menu bar and toggle it by pressing Alt. This is only supported on Windows & Linux.'
|
||||
|
||||
+19
-5
@@ -536,11 +536,13 @@ class Config
|
||||
|
||||
if scopeSelector?
|
||||
settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector)
|
||||
@scopedSettingsStore.removePropertiesForSourceAndSelector('user-config', scopeSelector)
|
||||
_.setValueForKeyPath(settings, keyPath, undefined)
|
||||
@addScopedSettings('user-config', scopeSelector, settings, @usersScopedSettingPriority)
|
||||
@save() unless @configFileHasErrors
|
||||
@getDefault(scopeSelector, keyPath)
|
||||
if _.valueForKeyPath(settings, keyPath)?
|
||||
@scopedSettingsStore.removePropertiesForSourceAndSelector('user-config', scopeSelector)
|
||||
_.setValueForKeyPath(settings, keyPath, undefined)
|
||||
settings = withoutEmptyObjects(settings)
|
||||
@addScopedSettings('user-config', scopeSelector, settings, @usersScopedSettingPriority) if settings?
|
||||
@save() unless @configFileHasErrors
|
||||
@getDefault(scopeSelector, keyPath)
|
||||
else
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
@get(keyPath)
|
||||
@@ -1046,3 +1048,15 @@ splitKeyPath = (keyPath) ->
|
||||
startIndex = i + 1
|
||||
keyPathArray.push keyPath.substr(startIndex, keyPath.length)
|
||||
keyPathArray
|
||||
|
||||
withoutEmptyObjects = (object) ->
|
||||
resultObject = undefined
|
||||
if isPlainObject(object)
|
||||
for key, value of object
|
||||
newValue = withoutEmptyObjects(value)
|
||||
if newValue?
|
||||
resultObject ?= {}
|
||||
resultObject[key] = newValue
|
||||
else
|
||||
resultObject = object
|
||||
resultObject
|
||||
|
||||
+5
-1
@@ -17,7 +17,7 @@ class Cursor extends Model
|
||||
visible: true
|
||||
needsAutoscroll: null
|
||||
|
||||
# Instantiated by an {TextEditor}
|
||||
# Instantiated by a {TextEditor}
|
||||
constructor: ({@editor, @marker, id}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@@ -171,6 +171,10 @@ class Cursor extends Model
|
||||
Section: Cursor Position Details
|
||||
###
|
||||
|
||||
# Public: Returns the underlying {Marker} for the cursor.
|
||||
# Useful with overlay {Decoration}s.
|
||||
getMarker: -> @marker
|
||||
|
||||
# Public: Identifies if the cursor is surrounded by whitespace.
|
||||
#
|
||||
# "Surrounded" here means that the character directly before and after the
|
||||
|
||||
@@ -250,8 +250,8 @@ class LanguageMode
|
||||
return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor)
|
||||
|
||||
currentLine = @buffer.lineForRow(bufferRow)
|
||||
precedingRow = if bufferRow > 0 then bufferRow - 1 else null
|
||||
return currentIndentLevel unless precedingRow?
|
||||
precedingRow = @buffer.previousNonBlankRow(bufferRow)
|
||||
return 0 unless precedingRow?
|
||||
|
||||
precedingLine = @buffer.lineForRow(precedingRow)
|
||||
desiredIndentLevel = @editor.indentationForBufferRow(precedingRow)
|
||||
|
||||
@@ -7,6 +7,7 @@ React = require 'react-atom-fork'
|
||||
Decoration = require './decoration'
|
||||
CursorsComponent = require './cursors-component'
|
||||
HighlightsComponent = require './highlights-component'
|
||||
OverlayManager = require './overlay-manager'
|
||||
|
||||
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
|
||||
AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT}
|
||||
@@ -20,7 +21,7 @@ LinesComponent = React.createClass
|
||||
{performedInitialMeasurement, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
|
||||
if performedInitialMeasurement
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
|
||||
{editor, overlayDecorations, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
|
||||
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
|
||||
{scrollTop, scrollLeft, cursorPixelRects, mini} = @props
|
||||
style =
|
||||
@@ -58,15 +59,22 @@ LinesComponent = React.createClass
|
||||
@renderedDecorationsByLineId = {}
|
||||
|
||||
componentDidMount: ->
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
if @props.useShadowDOM
|
||||
insertionPoint = document.createElement('content')
|
||||
insertionPoint.setAttribute('select', '.overlayer')
|
||||
@getDOMNode().appendChild(insertionPoint)
|
||||
|
||||
insertionPoint = document.createElement('content')
|
||||
insertionPoint.setAttribute('select', 'atom-overlay')
|
||||
@overlayManager = new OverlayManager(@props.hostElement)
|
||||
@getDOMNode().appendChild(insertionPoint)
|
||||
else
|
||||
@overlayManager = new OverlayManager(@getDOMNode())
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'visible',
|
||||
'overlayDecorations', 'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'visible',
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration',
|
||||
'placeholderText', 'performedInitialMeasurement', 'backgroundColor', 'cursorPixelRects'
|
||||
)
|
||||
@@ -92,6 +100,8 @@ LinesComponent = React.createClass
|
||||
@updateLines(@props.lineWidth isnt prevProps.lineWidth)
|
||||
@measureCharactersInNewLines() if visible and not scrollingVertically
|
||||
|
||||
@overlayManager?.render(@props)
|
||||
|
||||
clearScreenRowCaches: ->
|
||||
@screenRowsByLineId = {}
|
||||
@lineIdsByScreenRow = {}
|
||||
|
||||
@@ -44,7 +44,7 @@ normalizeLabel = (label) ->
|
||||
label.replace(/\&/g, '')
|
||||
|
||||
cloneMenuItem = (item) ->
|
||||
item = _.pick(item, 'type', 'label', 'enabled', 'command', 'submenu', 'commandDetail')
|
||||
item = _.pick(item, 'type', 'label', 'enabled', 'visible', 'command', 'submenu', 'commandDetail')
|
||||
if item.submenu?
|
||||
item.submenu = item.submenu.map (submenuItem) -> cloneMenuItem(submenuItem)
|
||||
item
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
module.exports =
|
||||
class OverlayManager
|
||||
constructor: (@container) ->
|
||||
@overlays = {}
|
||||
|
||||
render: (props) ->
|
||||
{editor, overlayDecorations, lineHeightInPixels} = props
|
||||
|
||||
existingDecorations = null
|
||||
for markerId, {isMarkerReversed, headPixelPosition, decorations} of overlayDecorations
|
||||
for decoration in decorations
|
||||
@renderOverlay(editor, decoration, headPixelPosition, lineHeightInPixels)
|
||||
|
||||
existingDecorations ?= {}
|
||||
existingDecorations[decoration.id] = true
|
||||
|
||||
for id, overlay of @overlays
|
||||
unless existingDecorations? and id of existingDecorations
|
||||
@container.removeChild(overlay)
|
||||
delete @overlays[id]
|
||||
|
||||
return
|
||||
|
||||
renderOverlay: (editor, decoration, pixelPosition, lineHeightInPixels) ->
|
||||
item = atom.views.getView(decoration.item)
|
||||
unless overlay = @overlays[decoration.id]
|
||||
overlay = @overlays[decoration.id] = document.createElement('atom-overlay')
|
||||
overlay.appendChild(item)
|
||||
@container.appendChild(overlay)
|
||||
|
||||
itemWidth = item.offsetWidth
|
||||
itemHeight = item.offsetHeight
|
||||
|
||||
left = pixelPosition.left
|
||||
if left + itemWidth - editor.getScrollLeft() > editor.getWidth() and left - itemWidth >= editor.getScrollLeft()
|
||||
left -= itemWidth
|
||||
|
||||
top = pixelPosition.top + lineHeightInPixels
|
||||
if top + itemHeight - editor.getScrollTop() > editor.getHeight() and top - itemHeight - lineHeightInPixels >= editor.getScrollTop()
|
||||
top -= itemHeight + lineHeightInPixels
|
||||
|
||||
overlay.style.top = top + 'px'
|
||||
overlay.style.left = left + 'px'
|
||||
@@ -10,12 +10,11 @@ class PanelContainerElement extends HTMLElement
|
||||
@subscriptions.add @model.onDidAddPanel(@panelAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemovePanel(@panelRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@destroyed.bind(this))
|
||||
|
||||
@setAttribute('location', @model.getLocation())
|
||||
@classList.add(@model.getLocation())
|
||||
|
||||
panelAdded: ({panel, index}) ->
|
||||
panelElement = panel.getView()
|
||||
panelElement.setAttribute('location', @model.getLocation())
|
||||
panelElement.classList.add(@model.getLocation())
|
||||
if index >= @childNodes.length
|
||||
@appendChild(panelElement)
|
||||
else
|
||||
|
||||
+19
-13
@@ -4,6 +4,8 @@
|
||||
{Emitter} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
NonWhitespaceRegExp = /\S/
|
||||
|
||||
# Extended: Represents a selection in the {TextEditor}.
|
||||
module.exports =
|
||||
class Selection extends Model
|
||||
@@ -368,13 +370,16 @@ class Selection extends Model
|
||||
@cursor.setBufferPosition(newBufferRange.end, skipAtomicTokens: true) if wasReversed
|
||||
|
||||
if options.autoIndent
|
||||
@editor.autoIndentBufferRow(row) for row in newBufferRange.getRows()
|
||||
precedingText = @editor.getTextInBufferRange([[newBufferRange.start.row, 0], newBufferRange.start])
|
||||
unless NonWhitespaceRegExp.test(precedingText)
|
||||
@editor.autoIndentBufferRow(newBufferRange.getRows()[0])
|
||||
@editor.autoIndentBufferRow(row) for row, i in newBufferRange.getRows() when i > 0
|
||||
else if options.autoIndentNewline and text == '\n'
|
||||
currentIndentation = @editor.indentationForBufferRow(newBufferRange.start.row)
|
||||
@editor.autoIndentBufferRow(newBufferRange.end.row, preserveLeadingWhitespace: true)
|
||||
if @editor.indentationForBufferRow(newBufferRange.end.row) < currentIndentation
|
||||
@editor.setIndentationForBufferRow(newBufferRange.end.row, currentIndentation)
|
||||
else if options.autoDecreaseIndent and /\S/.test text
|
||||
else if options.autoDecreaseIndent and NonWhitespaceRegExp.test(text)
|
||||
@editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row)
|
||||
|
||||
newBufferRange
|
||||
@@ -553,20 +558,21 @@ class Selection extends Model
|
||||
# current selection. (default: false)
|
||||
copy: (maintainClipboard=false) ->
|
||||
return if @isEmpty()
|
||||
text = @editor.buffer.getTextInRange(@getBufferRange())
|
||||
selectionText = @editor.buffer.getTextInRange(@getBufferRange())
|
||||
selectionIndentation = @editor.indentationForBufferRow(@getBufferRange().start.row)
|
||||
|
||||
if maintainClipboard
|
||||
{text: clipboardText, metadata} = atom.clipboard.readWithMetadata()
|
||||
|
||||
if metadata?.selections?
|
||||
metadata.selections.push(text)
|
||||
else
|
||||
metadata = { selections: [clipboardText, text] }
|
||||
|
||||
text = "" + (clipboardText) + "\n" + text
|
||||
metadata ?= {}
|
||||
unless metadata.selections?
|
||||
metadata.selections = [{
|
||||
text: clipboardText,
|
||||
indentBasis: metadata.indentBasis,
|
||||
}]
|
||||
metadata.selections.push(text: selectionText, indentBasis: selectionIndentation)
|
||||
atom.clipboard.write([clipboardText, selectionText].join("\n"), metadata)
|
||||
else
|
||||
metadata = { indentBasis: @editor.indentationForBufferRow(@getBufferRange().start.row) }
|
||||
|
||||
atom.clipboard.write(text, metadata)
|
||||
atom.clipboard.write(selectionText, {indentBasis: selectionIndentation})
|
||||
|
||||
# Public: Creates a fold containing the current selection.
|
||||
fold: ->
|
||||
|
||||
@@ -18,6 +18,9 @@ class StylesElement extends HTMLElement
|
||||
@styleElementClonesByOriginalElement = new WeakMap
|
||||
|
||||
attachedCallback: ->
|
||||
if @context is 'atom-text-editor'
|
||||
for styleElement in @children
|
||||
@upgradeDeprecatedSelectors(styleElement)
|
||||
@initialize()
|
||||
|
||||
detachedCallback: ->
|
||||
@@ -48,6 +51,7 @@ class StylesElement extends HTMLElement
|
||||
return unless @styleElementMatchesContext(styleElement)
|
||||
|
||||
styleElementClone = styleElement.cloneNode(true)
|
||||
styleElementClone.sourcePath = styleElement.sourcePath
|
||||
styleElementClone.context = styleElement.context
|
||||
@styleElementClonesByOriginalElement.set(styleElement, styleElementClone)
|
||||
|
||||
@@ -59,6 +63,10 @@ class StylesElement extends HTMLElement
|
||||
break
|
||||
|
||||
@insertBefore(styleElementClone, insertBefore)
|
||||
|
||||
if @context is 'atom-text-editor'
|
||||
@upgradeDeprecatedSelectors(styleElementClone)
|
||||
|
||||
@emitter.emit 'did-add-style-element', styleElementClone
|
||||
|
||||
styleElementRemoved: (styleElement) ->
|
||||
@@ -78,4 +86,30 @@ class StylesElement extends HTMLElement
|
||||
styleElementMatchesContext: (styleElement) ->
|
||||
not @context? or styleElement.context is @context
|
||||
|
||||
upgradeDeprecatedSelectors: (styleElement) ->
|
||||
return unless styleElement.sheet?
|
||||
|
||||
upgradedSelectors = []
|
||||
|
||||
for rule in styleElement.sheet.cssRules
|
||||
continue if /\:host/.test(rule.selectorText)
|
||||
|
||||
inputSelector = rule.selectorText
|
||||
outputSelector = rule.selectorText
|
||||
.replace(/\.editor-colors($|[ >])/g, ':host$1')
|
||||
.replace(/\.editor([:.][^ ,>]+)/g, ':host($1)')
|
||||
.replace(/\.editor($|[ ,>])/g, ':host$1')
|
||||
|
||||
unless inputSelector is outputSelector
|
||||
rule.selectorText = outputSelector
|
||||
upgradedSelectors.push({inputSelector, outputSelector})
|
||||
|
||||
if upgradedSelectors.length > 0
|
||||
warning = "Upgraded the following syntax theme selectors in `#{styleElement.sourcePath}` for shadow DOM compatibility:\n\n"
|
||||
for {inputSelector, outputSelector} in upgradedSelectors
|
||||
warning += "`#{inputSelector}` => `#{outputSelector}`\n"
|
||||
|
||||
warning += "\nSee the upgrade guide for information on removing this warning."
|
||||
console.warn(warning)
|
||||
|
||||
module.exports = StylesElement = document.registerElement 'atom-styles', prototype: StylesElement.prototype
|
||||
|
||||
@@ -50,7 +50,7 @@ TextEditorComponent = React.createClass
|
||||
|
||||
render: ->
|
||||
{focused, showIndentGuide, showLineNumbers, visible} = @state
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement, useShadowDOM} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty()
|
||||
style = {}
|
||||
@@ -66,6 +66,7 @@ TextEditorComponent = React.createClass
|
||||
|
||||
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
|
||||
highlightDecorations = @getHighlightDecorations(decorations)
|
||||
overlayDecorations = @getOverlayDecorations(decorations)
|
||||
lineDecorations = @getLineDecorations(decorations)
|
||||
placeholderText = editor.getPlaceholderText() if editor.isEmpty()
|
||||
visible = @isVisible()
|
||||
@@ -89,7 +90,10 @@ TextEditorComponent = React.createClass
|
||||
|
||||
style.height = scrollViewHeight if @autoHeight
|
||||
|
||||
className = 'editor-contents'
|
||||
if useShadowDOM
|
||||
className = 'editor-contents--private'
|
||||
else
|
||||
className = 'editor-contents'
|
||||
className += ' is-focused' if focused
|
||||
className += ' has-selection' if hasSelection
|
||||
|
||||
@@ -110,12 +114,13 @@ TextEditorComponent = React.createClass
|
||||
|
||||
LinesComponent {
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, tokenizedLines, lineDecorations, highlightDecorations,
|
||||
editor, lineHeightInPixels, defaultCharWidth, tokenizedLines,
|
||||
lineDecorations, highlightDecorations, overlayDecorations, hostElement,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, mini
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, mini, useShadowDOM
|
||||
}
|
||||
|
||||
ScrollbarComponent
|
||||
@@ -351,7 +356,23 @@ TextEditorComponent = React.createClass
|
||||
endPixelPosition: editor.pixelPositionForScreenPosition(screenRange.end)
|
||||
decorations: []
|
||||
filteredDecorations[markerId].decorations.push decorationParams
|
||||
filteredDecorations
|
||||
|
||||
getOverlayDecorations: (decorationsByMarkerId) ->
|
||||
{editor} = @props
|
||||
filteredDecorations = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
headBufferPosition = marker.getHeadBufferPosition()
|
||||
if marker.isValid()
|
||||
for decoration in decorations
|
||||
if decoration.isType('overlay')
|
||||
decorationParams = decoration.getProperties()
|
||||
filteredDecorations[markerId] ?=
|
||||
id: markerId
|
||||
headPixelPosition: editor.pixelPositionForScreenPosition(headBufferPosition)
|
||||
decorations: []
|
||||
filteredDecorations[markerId].decorations.push decorationParams
|
||||
filteredDecorations
|
||||
|
||||
observeEditor: ->
|
||||
@@ -384,6 +405,7 @@ TextEditorComponent = React.createClass
|
||||
window.addEventListener 'resize', @requestHeightAndWidthMeasurement
|
||||
|
||||
@listenForIMEEvents()
|
||||
@listenForMiddleMousePaste() if process.platform is 'linux'
|
||||
|
||||
listenForIMEEvents: ->
|
||||
node = @getDOMNode()
|
||||
@@ -411,6 +433,19 @@ TextEditorComponent = React.createClass
|
||||
editor.insertText(selectedText, select: true, undo: 'skip')
|
||||
event.target.value = ''
|
||||
|
||||
listenForMiddleMousePaste: ->
|
||||
clipboard = require 'clipboard'
|
||||
|
||||
@refs.scrollView.getDOMNode().addEventListener 'mouseup', ({which}) =>
|
||||
return unless which is 2
|
||||
|
||||
if selection = clipboard.readText('selection')
|
||||
@props.editor.insertText(selection)
|
||||
|
||||
@subscribe @props.editor.onDidChangeSelectionRange =>
|
||||
if selectedText = @props.editor.getSelectedText()
|
||||
clipboard.writeText(selectedText, 'selection')
|
||||
|
||||
observeConfig: ->
|
||||
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
|
||||
@subscribe atom.config.onDidChange 'editor.fontSize', @sampleFontStyling
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
{View, $, callRemoveHooks} = require 'space-pen'
|
||||
React = require 'react-atom-fork'
|
||||
Path = require 'path'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorComponent = require './text-editor-component'
|
||||
TextEditorView = null
|
||||
|
||||
ShadowStyleSheet = null
|
||||
|
||||
class TextEditorElement extends HTMLElement
|
||||
model: null
|
||||
componentDescriptor: null
|
||||
@@ -25,24 +28,31 @@ class TextEditorElement extends HTMLElement
|
||||
@setAttribute('tabindex', -1)
|
||||
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
@useShadowDOM = true
|
||||
|
||||
unless ShadowStyleSheet?
|
||||
ShadowStyleSheet = document.createElement('style')
|
||||
ShadowStyleSheet.textContent = atom.themes.loadLessStylesheet(require.resolve('../static/text-editor-shadow.less'))
|
||||
|
||||
@createShadowRoot()
|
||||
|
||||
@shadowRoot.appendChild(ShadowStyleSheet.cloneNode(true))
|
||||
@stylesElement = document.createElement('atom-styles')
|
||||
@stylesElement.setAttribute('context', 'atom-text-editor')
|
||||
@stylesElement.initialize()
|
||||
|
||||
@rootElement = document.createElement('div')
|
||||
@rootElement.classList.add('shadow')
|
||||
@rootElement.classList.add('editor--private')
|
||||
|
||||
@shadowRoot.appendChild(@stylesElement)
|
||||
@shadowRoot.appendChild(@rootElement)
|
||||
else
|
||||
@useShadowDOM = false
|
||||
|
||||
@classList.add('editor', 'editor-colors')
|
||||
@stylesElement = document.head.querySelector('atom-styles')
|
||||
@rootElement = this
|
||||
|
||||
@rootElement.classList.add('editor', 'editor-colors')
|
||||
|
||||
|
||||
createSpacePenShim: ->
|
||||
TextEditorView ?= require './text-editor-view'
|
||||
@__spacePenView = new TextEditorView(this)
|
||||
@@ -60,6 +70,7 @@ class TextEditorElement extends HTMLElement
|
||||
@model = model
|
||||
@mountComponent()
|
||||
@addGrammarScopeAttribute()
|
||||
@addMiniAttributeIfNeeded()
|
||||
@model.onDidChangeGrammar => @addGrammarScopeAttribute()
|
||||
@addEncodingAttribute()
|
||||
@model.onDidChangeEncoding => @addEncodingAttribute()
|
||||
@@ -88,10 +99,11 @@ class TextEditorElement extends HTMLElement
|
||||
editor: @model
|
||||
mini: @model.mini
|
||||
lineOverdrawMargin: @lineOverdrawMargin
|
||||
useShadowDOM: @useShadowDOM
|
||||
)
|
||||
@component = React.renderComponent(@componentDescriptor, @rootElement)
|
||||
|
||||
unless atom.config.get('editor.useShadowDOM')
|
||||
unless @useShadowDOM
|
||||
inputNode = @component.refs.input.getDOMNode()
|
||||
inputNode.addEventListener 'focus', @focused.bind(this)
|
||||
inputNode.addEventListener 'blur', => @dispatchEvent(new FocusEvent('blur', bubbles: false))
|
||||
@@ -109,7 +121,7 @@ class TextEditorElement extends HTMLElement
|
||||
@focusOnAttach = true
|
||||
|
||||
blurred: (event) ->
|
||||
unless atom.config.get('editor.useShadowDOM')
|
||||
unless @useShadowDOM
|
||||
if event.relatedTarget is @component?.refs.input?.getDOMNode()
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
@@ -120,6 +132,9 @@ class TextEditorElement extends HTMLElement
|
||||
grammarScope = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')
|
||||
@dataset.grammar = grammarScope
|
||||
|
||||
addMiniAttributeIfNeeded: ->
|
||||
@setAttributeNode(document.createAttribute("mini")) if @model.isMini()
|
||||
|
||||
addEncodingAttribute: ->
|
||||
@dataset.encoding = @model.getEncoding()
|
||||
|
||||
@@ -199,7 +214,7 @@ atom.commands.add 'atom-text-editor', stopEventPropagationAndGroupUndo(
|
||||
'editor:lower-case': -> @lowerCase()
|
||||
)
|
||||
|
||||
atom.commands.add 'atom-text-editor:not(.mini)', stopEventPropagationAndGroupUndo(
|
||||
atom.commands.add 'atom-text-editor:not([mini])', stopEventPropagationAndGroupUndo(
|
||||
'core:move-up': -> @moveUp()
|
||||
'core:move-down': -> @moveDown()
|
||||
'core:move-to-top': -> @moveToTop()
|
||||
|
||||
@@ -77,7 +77,6 @@ class TextEditorView extends View
|
||||
|
||||
@scrollView = @root.find('.scroll-view')
|
||||
|
||||
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
@underlayer = $("<div class='underlayer'></div>").appendTo(this)
|
||||
@overlayer = $("<div class='overlayer'></div>").appendTo(this)
|
||||
|
||||
+20
-14
@@ -6,7 +6,7 @@ Delegator = require 'delegato'
|
||||
{Model} = require 'theorist'
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{Point, Range} = TextBuffer = require 'text-buffer'
|
||||
LanguageMode = require './language-mode'
|
||||
DisplayBuffer = require './display-buffer'
|
||||
Cursor = require './cursor'
|
||||
@@ -84,6 +84,7 @@ class TextEditor extends Model
|
||||
@cursors = []
|
||||
@selections = []
|
||||
|
||||
buffer ?= new TextBuffer
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped})
|
||||
@buffer = @displayBuffer.buffer
|
||||
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
|
||||
@@ -2493,22 +2494,24 @@ class TextEditor extends Model
|
||||
#
|
||||
# * `options` (optional) See {Selection::insertText}.
|
||||
pasteText: (options={}) ->
|
||||
{text, metadata} = atom.clipboard.readWithMetadata()
|
||||
{text: clipboardText, metadata} = atom.clipboard.readWithMetadata()
|
||||
metadata ?= {}
|
||||
options.autoIndent = @shouldAutoIndentOnPaste()
|
||||
|
||||
containsNewlines = text.indexOf('\n') isnt -1
|
||||
@mutateSelectedText (selection, index) =>
|
||||
if metadata.selections?.length is @getSelections().length
|
||||
{text, indentBasis} = metadata.selections[index]
|
||||
else
|
||||
[text, indentBasis] = [clipboardText, metadata.indentBasis]
|
||||
|
||||
if metadata?.selections? and metadata.selections.length is @getSelections().length
|
||||
@mutateSelectedText (selection, index) ->
|
||||
text = metadata.selections[index]
|
||||
selection.insertText(text, options)
|
||||
delete options.indentBasis
|
||||
{cursor} = selection
|
||||
if indentBasis? and atom.config.get(cursor.getScopeDescriptor(), "editor.normalizeIndentOnPaste")
|
||||
containsNewlines = text.indexOf('\n') isnt -1
|
||||
if containsNewlines or !cursor.hasPrecedingCharactersOnLine()
|
||||
options.indentBasis ?= indentBasis
|
||||
|
||||
return
|
||||
|
||||
else if atom.config.get(@getLastCursor().getScopeDescriptor(), "editor.normalizeIndentOnPaste") and metadata?.indentBasis?
|
||||
if !@getLastCursor().hasPrecedingCharactersOnLine() or containsNewlines
|
||||
options.indentBasis ?= metadata.indentBasis
|
||||
|
||||
@insertText(text, options)
|
||||
selection.insertText(text, options)
|
||||
|
||||
# Public: For each selection, if the selection is empty, cut all characters
|
||||
# of the containing line following the cursor. Otherwise cut the selected
|
||||
@@ -2724,6 +2727,9 @@ class TextEditor extends Model
|
||||
shouldAutoIndent: ->
|
||||
atom.config.get(@getRootScopeDescriptor(), "editor.autoIndent")
|
||||
|
||||
shouldAutoIndentOnPaste: ->
|
||||
atom.config.get(@getRootScopeDescriptor(), "editor.autoIndentOnPaste")
|
||||
|
||||
shouldShowInvisibles: ->
|
||||
not @mini and atom.config.get(@getRootScopeDescriptor(), 'editor.showInvisibles')
|
||||
|
||||
|
||||
@@ -249,9 +249,6 @@ class ThemeManager
|
||||
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
|
||||
@requireStylesheet(nativeStylesheetPath)
|
||||
|
||||
textEditorStylesPath = path.join(@resourcePath, 'static', 'text-editor-shadow.less')
|
||||
atom.styles.addStyleSheet(@loadLessStylesheet(textEditorStylesPath), sourcePath: textEditorStylesPath, context: 'atom-text-editor')
|
||||
|
||||
stylesheetElementForId: (id) ->
|
||||
document.head.querySelector("atom-styles style[source-path=\"#{id}\"]")
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@ class WindowEventHandler
|
||||
|
||||
@subscribeToCommand $(window), 'window:toggle-dev-tools', -> atom.toggleDevTools()
|
||||
|
||||
if process.platform in ['win32', 'linux']
|
||||
@subscribeToCommand $(window), 'window:toggle-menu-bar', ->
|
||||
atom.config.set('core.autoHideMenuBar', !atom.config.get('core.autoHideMenuBar'))
|
||||
|
||||
@subscribeToCommand $(document), 'core:focus-next', @focusNext
|
||||
|
||||
@subscribeToCommand $(document), 'core:focus-previous', @focusPrevious
|
||||
|
||||
externo
+1
@@ -23,6 +23,7 @@
|
||||
@import "../node_modules/bootstrap/less/alerts.less";
|
||||
@import "../node_modules/bootstrap/less/list-group.less";
|
||||
@import "../node_modules/bootstrap/less/thumbnails.less";
|
||||
@import "../node_modules/bootstrap/less/close.less";
|
||||
|
||||
// Components w/ JavaScript
|
||||
@import "../node_modules/bootstrap/less/tooltip.less";
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
|
||||
// Tool panels
|
||||
|
||||
atom-panel-container[location="left"],
|
||||
atom-panel-container[location="right"] {
|
||||
atom-panel-container.left,
|
||||
atom-panel-container.right {
|
||||
display: -webkit-flex;
|
||||
-webkit-flex-direction: row;
|
||||
-webkit-align-items: stretch;
|
||||
@@ -59,10 +59,10 @@ atom-panel {
|
||||
display: block;
|
||||
}
|
||||
|
||||
atom-panel[location="top"],
|
||||
atom-panel[location="bottom"],
|
||||
atom-panel[location="left"],
|
||||
atom-panel[location="right"] {
|
||||
atom-panel.top,
|
||||
atom-panel.bottom,
|
||||
atom-panel.left,
|
||||
atom-panel.right {
|
||||
background-color: @tool-panel-background-color;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ atom-panel[location="right"] {
|
||||
// Modal panels
|
||||
|
||||
.overlay, // deprecated .overlay
|
||||
atom-panel[location="modal"] {
|
||||
atom-panel.modal {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: 500px;
|
||||
@@ -99,7 +99,7 @@ atom-panel[location="modal"] {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
atom-text-editor.mini {
|
||||
atom-text-editor[mini] {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ atom-panel[location="modal"] {
|
||||
|
||||
// deprecated: from-top, from-bottom
|
||||
.overlay.from-top,
|
||||
atom-panel[location="modal"] {
|
||||
atom-panel.modal {
|
||||
top: 0;
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
@import "ui-variables";
|
||||
@import "octicon-utf-codes";
|
||||
@import "octicon-mixins";
|
||||
|
||||
atom-text-editor {
|
||||
display: block;
|
||||
@@ -6,14 +8,218 @@ atom-text-editor {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
atom-text-editor.mini {
|
||||
atom-text-editor[mini] {
|
||||
font-size: @input-font-size;
|
||||
line-height: @component-line-height;
|
||||
max-height: @component-line-height + 2; // +2 for borders
|
||||
}
|
||||
|
||||
// TODO: remove this when the shadow DOM is the default
|
||||
atom-text-editor .highlight {
|
||||
background: none;
|
||||
padding: 0;
|
||||
atom-overlay {
|
||||
position: absolute;
|
||||
display: block;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
// TODO: Remove the following styles when the editor shadow DOM can no longer be disabled
|
||||
atom-text-editor {
|
||||
display: -webkit-flex;
|
||||
|
||||
.editor-contents {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
cursor: text;
|
||||
display: -webkit-flex;
|
||||
-webkit-user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
cursor: default;
|
||||
min-width: 1em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.line-numbers {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.line-number {
|
||||
white-space: nowrap;
|
||||
padding-left: .5em;
|
||||
opacity: 0.6;
|
||||
|
||||
&.cursor-line {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.icon-right {
|
||||
.octicon(chevron-down, 0.8em);
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
opacity: .6;
|
||||
padding: 0 .4em;
|
||||
|
||||
&:before {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gutter:hover {
|
||||
.line-number.foldable .icon-right {
|
||||
visibility: visible;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gutter, .gutter:hover {
|
||||
.line-number.folded .icon-right {
|
||||
.octicon(chevron-right, 0.8em);
|
||||
|
||||
visibility: visible;
|
||||
|
||||
&:before {
|
||||
position: relative;
|
||||
left: -.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
|
||||
overflow: hidden;
|
||||
-webkit-flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.underlayer {
|
||||
position: absolute;
|
||||
z-index: -2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.highlight .region {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.lines {
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.line {
|
||||
white-space: pre;
|
||||
|
||||
&.cursor-line .fold-marker:after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fold-marker {
|
||||
cursor: default;
|
||||
|
||||
&:after {
|
||||
.icon(0.8em, inline);
|
||||
|
||||
content: @ellipsis;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-text {
|
||||
position: absolute;
|
||||
color: @text-color-subtle;
|
||||
}
|
||||
|
||||
.invisible-character {
|
||||
font-weight: normal !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
|
||||
.indent-guide {
|
||||
box-shadow: inset 1px 0;
|
||||
}
|
||||
|
||||
.hidden-input {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.cursor {
|
||||
z-index: 4;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
border-left: 1px solid;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.is-focused .cursor {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cursors.blink-off .cursor {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.horizontal-scrollbar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
height: 15px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
z-index: 3;
|
||||
cursor: default;
|
||||
|
||||
.scrollbar-content {
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-scrollbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
width: 15px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
z-index: 3;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.scrollbar-corner {
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
+135
-180
@@ -2,26 +2,154 @@
|
||||
@import "octicon-utf-codes";
|
||||
@import "octicon-mixins";
|
||||
|
||||
.editor-contents {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.editor.shadow, .editor.shadow .editor-contents {
|
||||
.editor--private, .editor-contents--private {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.editor-contents--private {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
cursor: text;
|
||||
display: -webkit-flex;
|
||||
-webkit-user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
cursor: default;
|
||||
min-width: 1em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.line-numbers {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.line-number {
|
||||
white-space: nowrap;
|
||||
padding-left: .5em;
|
||||
opacity: 0.6;
|
||||
|
||||
&.cursor-line {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.icon-right {
|
||||
.octicon(chevron-down, 0.8em);
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
opacity: .6;
|
||||
padding: 0 .4em;
|
||||
|
||||
&:before {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gutter:hover {
|
||||
.line-number.foldable .icon-right {
|
||||
visibility: visible;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gutter, .gutter:hover {
|
||||
.line-number.folded .icon-right {
|
||||
.octicon(chevron-right, 0.8em);
|
||||
|
||||
visibility: visible;
|
||||
|
||||
&:before {
|
||||
position: relative;
|
||||
left: -.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
|
||||
overflow: hidden;
|
||||
-webkit-flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.underlayer {
|
||||
position: absolute;
|
||||
z-index: -2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.highlight .region {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.lines {
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.line {
|
||||
white-space: pre;
|
||||
|
||||
&.cursor-line .fold-marker:after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fold-marker {
|
||||
cursor: default;
|
||||
|
||||
&:after {
|
||||
.icon(0.8em, inline);
|
||||
|
||||
content: @ellipsis;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-text {
|
||||
position: absolute;
|
||||
color: @text-color-subtle;
|
||||
}
|
||||
|
||||
.invisible-character {
|
||||
font-weight: normal !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
|
||||
.indent-guide {
|
||||
box-shadow: inset 1px 0;
|
||||
}
|
||||
|
||||
.hidden-input {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.cursor {
|
||||
@@ -33,7 +161,7 @@
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.is-focused .cursor {
|
||||
&.is-focused .cursor {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -77,176 +205,3 @@
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
-webkit-flex: 1;
|
||||
min-width: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
.line-number {
|
||||
white-space: nowrap;
|
||||
padding-left: .5em;
|
||||
|
||||
.icon-right {
|
||||
padding: 0 .4em;
|
||||
&:before {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-text {
|
||||
position: absolute;
|
||||
color: @text-color-subtle;
|
||||
}
|
||||
|
||||
.editor {
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.editor, .editor-contents {
|
||||
overflow: hidden;
|
||||
cursor: text;
|
||||
display: -webkit-flex;
|
||||
-webkit-user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gutter .line-number.cursor-line {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
cursor: default;
|
||||
min-width: 1em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gutter .line-number {
|
||||
padding-left: .5em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.gutter .line-numbers {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gutter .line-number.folded.cursor-line {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gutter .line-number .icon-right {
|
||||
.octicon(chevron-down, 0.8em);
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
padding-left: .1em;
|
||||
padding-right: .5em;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.gutter:hover .line-number.foldable .icon-right {
|
||||
visibility: visible;
|
||||
|
||||
&:before {
|
||||
content: @chevron-down;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.gutter, .gutter:hover {
|
||||
.line-number.folded .icon-right {
|
||||
.octicon(chevron-right, 0.8em);
|
||||
visibility: visible;
|
||||
|
||||
&:before { // chevron-right renders too far right compared to chevron-down
|
||||
position: relative;
|
||||
left: -.1em;
|
||||
content: @chevron-right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fold-marker {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.fold-marker:after {
|
||||
.icon(0.8em, inline);
|
||||
content: @ellipsis;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.line.cursor-line .fold-marker:after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.editor.is-blurred .line.cursor-line {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.invisible-character {
|
||||
font-weight: normal !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
|
||||
.indent-guide {
|
||||
display: inline-block;
|
||||
box-shadow: inset 1px 0;
|
||||
}
|
||||
|
||||
.editor.soft-wrap .scroll-view {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.underlayer {
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.lines {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.overlayer {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.line {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.line span {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.hidden-input {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.highlight .region,
|
||||
.selection .region {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário