Comparar commits
106 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 4155c53bd6 | |||
| d3538502c5 | |||
| 90a17de8bd | |||
| a82ea86a05 | |||
| 22c4992788 | |||
| 2a5d034248 | |||
| ed3c37c101 | |||
| 558e5e52c5 | |||
| 92d16a9d0a | |||
| f224a6d5f0 | |||
| 16f95a1420 | |||
| 0231d02877 | |||
| 6d2b70b3d9 | |||
| 49b825aeb3 | |||
| 357299a700 | |||
| 88df674dd6 | |||
| 31afa0abd5 | |||
| b11accec6d | |||
| defa869d5c | |||
| 8d4be6ab57 | |||
| 9976166902 | |||
| 8ea277ef77 | |||
| d85b8bfaf3 | |||
| d9e15d937e | |||
| 908ff5d3cd | |||
| 35b4ba3066 | |||
| f90e47daef | |||
| 5440dd68a7 | |||
| 11205d9eaa | |||
| 34e37fce7c | |||
| 3402c8dcd1 | |||
| 3921a63f67 | |||
| 5ecaf5dfc4 | |||
| 475f92351f | |||
| 0a5b378425 | |||
| 157774f552 | |||
| 320c12134a | |||
| 280b451835 | |||
| 4ee03fe590 | |||
| db1652f1ed | |||
| 8013ff7775 | |||
| c24475c2c8 | |||
| 580c639265 | |||
| 4c33549371 | |||
| 7be5553ba1 | |||
| 43936a1faf | |||
| e3c44bf551 | |||
| 6b0636d331 | |||
| cb0ee735be | |||
| 036dc06bac | |||
| 7155ec4b73 | |||
| 86ea4d94bb | |||
| 6a2021ac98 | |||
| 6fe05064eb | |||
| dd5c9ff6d4 | |||
| 29179d0bbc | |||
| f6400a4097 | |||
| e170b9f56b | |||
| 2ea8418c66 | |||
| c20a4a3084 | |||
| 0be64f9902 | |||
| 5300fefef4 | |||
| 2602e6ec0a | |||
| 1a22fc3c68 | |||
| 6d02861f11 | |||
| 57ed190ea3 | |||
| 436d7de817 | |||
| a9feed2e4a | |||
| 8b04e94d09 | |||
| 5c5576c39d | |||
| 2b957beeda | |||
| 832aeffd4f | |||
| 5d08ecdcb2 | |||
| 997529774c | |||
| 48d20ff1ec | |||
| 0793f291d1 | |||
| 8d479328ec | |||
| 569326e76a | |||
| 8372b84e9f | |||
| eda55156e5 | |||
| c40a526302 | |||
| 540b038ced | |||
| ce1ebec253 | |||
| 44e121c997 | |||
| 3579404bed | |||
| 1e19860409 | |||
| eab4b578a3 | |||
| 2878196e0a | |||
| 1c037411e9 | |||
| 68144681b2 | |||
| 484a516bd6 | |||
| fa6e84415b | |||
| 7117634ba8 | |||
| a108c283cf | |||
| 3dc61f4a7a | |||
| 9685e3f1db | |||
| b2c70f9e69 | |||
| d7a3ffa9de | |||
| 18ed91a402 | |||
| e991b3d10c | |||
| f1b7f9ca30 | |||
| e1e510e473 | |||
| d042d15a50 | |||
| fe9fec733d | |||
| 06095e57d7 | |||
| 126d0d1b3c |
+12
@@ -6,10 +6,21 @@ Visit [atom.io](https://atom.io) to learn more.
|
||||
|
||||
## Installing
|
||||
|
||||
### Mac OS X
|
||||
|
||||
Download the latest [Atom release](https://github.com/atom/atom/releases/latest).
|
||||
|
||||
Atom will automatically update when a new release is available.
|
||||
|
||||
### Windows
|
||||
|
||||
Install the [Atom chocolatey package](https://chocolatey.org/packages/Atom).
|
||||
|
||||
1. Install [chocolatey](https://chocolatey.org).
|
||||
2. Close and reopen your command prompt or PowerShell window.
|
||||
3. Run `cinst Atom`
|
||||
4. In the future run `cup Atom` to upgrade to the latest release.
|
||||
|
||||
## Building
|
||||
|
||||
* [Linux](docs/build-instructions/linux.md)
|
||||
@@ -18,4 +29,5 @@ Atom will automatically update when a new release is available.
|
||||
* [Windows](docs/build-instructions/windows.md)
|
||||
|
||||
## Developing
|
||||
|
||||
Check out the [guides](https://atom.io/docs/latest) and the [API reference](https://atom.io/docs/api).
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.70.0"
|
||||
"atom-package-manager": "0.77.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,17 @@ module.exports = (grunt) ->
|
||||
path.join('pegjs', 'examples')
|
||||
path.join('plist', 'tests')
|
||||
path.join('xmldom', 'test')
|
||||
path.join('combined-stream', 'test')
|
||||
path.join('delayed-stream', 'test')
|
||||
path.join('domhandler', 'test')
|
||||
path.join('fstream-ignore', 'test')
|
||||
path.join('harmony-collections', 'test')
|
||||
path.join('lru-cache', 'test')
|
||||
path.join('minimatch', 'test')
|
||||
path.join('normalize-package-data', 'test')
|
||||
path.join('npm', 'test')
|
||||
path.join('jasmine-reporters', 'ext')
|
||||
path.join('jasmine-node', 'node_modules', 'gaze')
|
||||
path.join('build', 'Release', 'obj.target')
|
||||
path.join('build', 'Release', 'obj')
|
||||
path.join('build', 'Release', '.deps')
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'output-long-paths', 'Log long paths in the built application', ->
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
|
||||
longPaths = []
|
||||
grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) ->
|
||||
if relativePath
|
||||
fullPath = path.join(relativePath, fileName)
|
||||
else
|
||||
fullPath = fileName
|
||||
longPaths.push(fullPath) if fullPath.length >= 200
|
||||
|
||||
longPaths.sort (longPath1, longPath2) -> longPath2.length - longPath1.length
|
||||
|
||||
longPaths.forEach (longPath) ->
|
||||
grunt.log.error "#{longPath.length} character path: #{longPath}"
|
||||
@@ -103,4 +103,9 @@ module.exports = (grunt) ->
|
||||
failures.push "atom core" if coreSpecFailed
|
||||
|
||||
grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
|
||||
done(!coreSpecFailed and failedPackages.length == 0)
|
||||
|
||||
if process.platform is 'win32' and process.env.JANKY_SHA1
|
||||
# Package specs are still flaky on Windows CI
|
||||
done(!coreSpecFailed)
|
||||
else
|
||||
done(!coreSpecFailed and failedPackages.length == 0)
|
||||
|
||||
+37
-8
@@ -1,4 +1,4 @@
|
||||
## Atom.io package and update API
|
||||
# Atom.io package and update API
|
||||
|
||||
This guide describes the web API used by [apm](https://github.com/atom/apm) and
|
||||
Atom. The vast majority of use cases are met by the `apm` command-line tool,
|
||||
@@ -8,6 +8,8 @@ and making sure you have pushed your git tag. In fact, Atom itself shells out to
|
||||
uses `apm`, see the [PackageManager class](https://github.com/atom/settings-view/blob/master/lib/package-manager.coffee)
|
||||
in the `settings-view` package.
|
||||
|
||||
*This API should be considered pre-release and is subject to change (though significant breaking changes are unlikely).*
|
||||
|
||||
### Authorization
|
||||
|
||||
For calls to the API that require authentication, provide a valid token from your
|
||||
@@ -17,9 +19,11 @@ For calls to the API that require authentication, provide a valid token from you
|
||||
|
||||
All requests that take parameters require `application/json`.
|
||||
|
||||
## Resources
|
||||
# API Resources
|
||||
|
||||
### Packages
|
||||
## Packages
|
||||
|
||||
### Listing packages
|
||||
|
||||
#### GET /api/packages
|
||||
|
||||
@@ -40,6 +44,8 @@ Returns a list of all packages in the following format:
|
||||
]
|
||||
```
|
||||
|
||||
### Showing package details
|
||||
|
||||
#### GET /api/packages/:package_name
|
||||
|
||||
Returns package details and versions for a single package
|
||||
@@ -68,6 +74,8 @@ Returns:
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a package
|
||||
|
||||
#### POST /api/packages
|
||||
|
||||
Create a new package; requires authentication.
|
||||
@@ -92,6 +100,7 @@ Returns:
|
||||
- The package.json at owner/repo isn't valid
|
||||
- **409** - A package by that name already exists
|
||||
|
||||
### Deleting a package
|
||||
|
||||
#### DELETE /api/packages/:package_name
|
||||
|
||||
@@ -103,6 +112,13 @@ Returns:
|
||||
- **400** - Repository is inaccessible
|
||||
- **401** - Unauthorized
|
||||
|
||||
### Renaming a package
|
||||
|
||||
Packages are renamed by publishing a new version with the name changed in `package.json`
|
||||
See [Creating a new package version](#creating-a-new-package-version) for details.
|
||||
|
||||
Requests made to the previous name will forward to the new name.
|
||||
|
||||
### Package Versions
|
||||
|
||||
#### GET /api/packages/:package_name/versions/:version_name
|
||||
@@ -144,7 +160,9 @@ Returns `package.json` with `dist` key added for e.g. tarball download:
|
||||
|
||||
#### POST /api/packages/:package_name/versions
|
||||
|
||||
Creates a new package version from a git tag; requires authentication.
|
||||
Creates a new package version from a git tag; requires authentication. If `rename`
|
||||
is not `true`, the `name` field in `package.json` *must* match the current package
|
||||
name.
|
||||
|
||||
#### Parameters
|
||||
|
||||
@@ -152,14 +170,15 @@ Creates a new package version from a git tag; requires authentication.
|
||||
that the version name will not be taken from the tag, but from the `version`
|
||||
key in the `package.json` file at that ref. The authenticating user *must* have
|
||||
access to the package repository.
|
||||
- **rename** - Boolean indicating whether this version contains a new name for the package.
|
||||
|
||||
#### Returns
|
||||
|
||||
- **201** - Successfully created. Returns created version.
|
||||
- **400** - Git tag not found / Repository inaccessible
|
||||
- **400** - Git tag not found / Repository inaccessible / package.json invalid
|
||||
- **409** - Version exists
|
||||
|
||||
### Delete a version
|
||||
### Deleting a version
|
||||
|
||||
#### DELETE /api/packages/:package_name/versions/:version_name
|
||||
|
||||
@@ -172,7 +191,9 @@ you'll need to increment the version when republishing.
|
||||
Returns 204 No Content
|
||||
|
||||
|
||||
### Stars
|
||||
## Stars
|
||||
|
||||
### Listing user stars
|
||||
|
||||
#### GET /api/users/:login/stars
|
||||
|
||||
@@ -186,18 +207,24 @@ List the authenticated user's starred packages; requires authentication.
|
||||
|
||||
Return value is similar to **GET /api/packages**
|
||||
|
||||
### Starring a package
|
||||
|
||||
#### POST /api/packages/:name/star
|
||||
|
||||
Star a package; requires authentication.
|
||||
|
||||
Returns a package.
|
||||
|
||||
### Unstarring a package
|
||||
|
||||
#### DELETE /api/packages/:name/star
|
||||
|
||||
Unstar a package; requires authentication.
|
||||
|
||||
Returns 204 No Content.
|
||||
|
||||
### Listing a package's stargazers
|
||||
|
||||
#### GET /api/packages/:name/stargazers
|
||||
|
||||
List the users that have starred a package.
|
||||
@@ -211,7 +238,9 @@ Returns a list of user objects:
|
||||
]
|
||||
```
|
||||
|
||||
### Atom updates
|
||||
## Atom updates
|
||||
|
||||
### Listing Atom updates
|
||||
|
||||
#### GET /api/updates
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'shift-delete': 'core:cut'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
'ctrl-s': 'core:save'
|
||||
'ctrl-S': 'core:save-as'
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-f4': 'core:close'
|
||||
'ctrl-z': 'core:undo'
|
||||
'ctrl-y': 'core:redo'
|
||||
'ctrl-x': 'core:cut'
|
||||
@@ -40,7 +41,7 @@
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'shift-delete': 'core:cut'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
|
||||
+15
-15
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.109.0",
|
||||
"version": "0.115.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -74,27 +74,27 @@
|
||||
"autoflow": "0.17.0",
|
||||
"autosave": "0.14.0",
|
||||
"background-tips": "0.15.0",
|
||||
"bookmarks": "0.26.0",
|
||||
"bookmarks": "0.27.0",
|
||||
"bracket-matcher": "0.48.0",
|
||||
"command-palette": "0.24.0",
|
||||
"deprecation-cop": "0.7.0",
|
||||
"dev-live-reload": "0.31.0",
|
||||
"exception-reporting": "0.18.0",
|
||||
"feedback": "0.33.0",
|
||||
"find-and-replace": "0.124.0",
|
||||
"fuzzy-finder": "0.56.0",
|
||||
"git-diff": "0.34.0",
|
||||
"find-and-replace": "0.126.0",
|
||||
"fuzzy-finder": "0.57.0",
|
||||
"git-diff": "0.36.0",
|
||||
"go-to-line": "0.23.0",
|
||||
"grammar-selector": "0.27.0",
|
||||
"image-view": "0.36.0",
|
||||
"keybinding-resolver": "0.18.0",
|
||||
"link": "0.24.0",
|
||||
"markdown-preview": "0.89.0",
|
||||
"metrics": "0.32.0",
|
||||
"markdown-preview": "0.93.0",
|
||||
"metrics": "0.33.0",
|
||||
"open-on-github": "0.29.0",
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.32.0",
|
||||
"settings-view": "0.132.0",
|
||||
"release-notes": "0.35.0",
|
||||
"settings-view": "0.133.0",
|
||||
"snippets": "0.47.0",
|
||||
"spell-check": "0.38.0",
|
||||
"status-bar": "0.41.0",
|
||||
@@ -102,14 +102,14 @@
|
||||
"symbols-view": "0.59.0",
|
||||
"tabs": "0.44.0",
|
||||
"timecop": "0.21.0",
|
||||
"tree-view": "0.108.0",
|
||||
"tree-view": "0.109.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.17.0",
|
||||
"whitespace": "0.23.0",
|
||||
"whitespace": "0.24.0",
|
||||
"wrap-guide": "0.21.0",
|
||||
|
||||
"language-c": "0.21.0",
|
||||
"language-coffee-script": "0.24.0",
|
||||
"language-coffee-script": "0.25.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.42.0",
|
||||
"language-git": "0.9.0",
|
||||
@@ -117,7 +117,7 @@
|
||||
"language-html": "0.22.0",
|
||||
"language-hyperlink": "0.10.0",
|
||||
"language-java": "0.11.0",
|
||||
"language-javascript": "0.33.0",
|
||||
"language-javascript": "0.35.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.12.0",
|
||||
"language-make": "0.10.0",
|
||||
@@ -126,12 +126,12 @@
|
||||
"language-php": "0.15.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.18.0",
|
||||
"language-ruby": "0.31.0",
|
||||
"language-ruby": "0.32.0",
|
||||
"language-ruby-on-rails": "0.15.0",
|
||||
"language-sass": "0.13.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.7.0",
|
||||
"language-sql": "0.8.0",
|
||||
"language-sql": "0.9.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.10.0",
|
||||
"language-toml": "0.12.0",
|
||||
|
||||
+26
-5
@@ -44,23 +44,44 @@ function bootstrap() {
|
||||
var apmInstallCommand = npmPath + npmFlags + 'install';
|
||||
var apmInstallOptions = {cwd: apmInstallPath};
|
||||
var moduleInstallCommand = apmPath + ' install' + apmFlags;
|
||||
var dedupeCommand = apmPath + ' dedupe' + apmFlags;
|
||||
var dedupeApmCommand = apmPath + ' dedupe' + apmFlags;
|
||||
var dedupeNpmCommand = npmPath + npmFlags + 'dedupe';
|
||||
|
||||
if (process.argv.indexOf('--no-quiet') === -1) {
|
||||
buildInstallCommand += ' --quiet';
|
||||
apmInstallCommand += ' --quiet';
|
||||
moduleInstallCommand += ' --quiet';
|
||||
dedupeCommand += ' --quiet';
|
||||
dedupeApmCommand += ' --quiet';
|
||||
dedupeNpmCommand += ' --quiet';
|
||||
buildInstallOptions.ignoreStdout = true;
|
||||
apmInstallOptions.ignoreStdout = true;
|
||||
}
|
||||
|
||||
// apm ships with 32-bit node so make sure its native modules are compiled
|
||||
// for a 32-bit target architecture
|
||||
if (process.env.JANKY_SHA1 && process.platform === 'win32')
|
||||
apmInstallCommand += ' --arch=ia32';
|
||||
|
||||
var commands = [
|
||||
{command: buildInstallCommand, message: 'Installing build modules...', options: buildInstallOptions},
|
||||
{command: apmInstallCommand, message: 'Installing apm...', options: apmInstallOptions},
|
||||
{
|
||||
command: buildInstallCommand,
|
||||
message: 'Installing build modules...',
|
||||
options: buildInstallOptions
|
||||
},
|
||||
{
|
||||
command: apmInstallCommand,
|
||||
message: 'Installing apm...',
|
||||
options: apmInstallOptions
|
||||
},
|
||||
apmPath + ' clean' + apmFlags,
|
||||
moduleInstallCommand,
|
||||
dedupeCommand + ' ' + packagesToDedupe.join(' '),
|
||||
dedupeApmCommand + ' ' + packagesToDedupe.join(' '),
|
||||
{
|
||||
command: dedupeNpmCommand + ' request',
|
||||
options: {
|
||||
cwd: path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager')
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
@@ -535,3 +535,18 @@ describe "the `atom` global", ->
|
||||
expect(atom.isReleasedVersion()).toBe true
|
||||
version = '36b5518'
|
||||
expect(atom.isReleasedVersion()).toBe false
|
||||
|
||||
describe "window:update-available", ->
|
||||
it "is triggered when the auto-updater sends the update-downloaded event", ->
|
||||
updateAvailableHandler = jasmine.createSpy("update-available-handler")
|
||||
atom.workspaceView.on 'window:update-available', updateAvailableHandler
|
||||
autoUpdater = require('remote').require('auto-updater')
|
||||
autoUpdater.emit 'update-downloaded', null, "notes", "version"
|
||||
|
||||
waitsFor ->
|
||||
updateAvailableHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
[event, version, notes] = updateAvailableHandler.mostRecentCall.args
|
||||
expect(notes).toBe 'notes'
|
||||
expect(version).toBe 'version'
|
||||
|
||||
@@ -342,8 +342,6 @@ describe "DisplayBuffer", ->
|
||||
fold2 = displayBuffer.createFold(4, 9)
|
||||
fold1 = displayBuffer.createFold(0, 4)
|
||||
|
||||
displayBuffer.logLines(0, 20)
|
||||
|
||||
expect(displayBuffer.lineForRow(0).text).toMatch /^0/
|
||||
expect(displayBuffer.lineForRow(1).text).toMatch /^10/
|
||||
|
||||
@@ -1040,20 +1038,36 @@ describe "DisplayBuffer", ->
|
||||
expect(start.left).toBe (4 * 10) + (6 * 11)
|
||||
|
||||
describe "decorations", ->
|
||||
it "can add decorations associated with markers and remove them", ->
|
||||
decoration = {type: 'gutter', class: 'one'}
|
||||
[marker, decoration, decorationParams] = []
|
||||
beforeEach ->
|
||||
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
|
||||
decorationParams = {type: 'gutter', class: 'one'}
|
||||
decoration = displayBuffer.decorateMarker(marker, decorationParams)
|
||||
|
||||
decorationObject = displayBuffer.addDecorationForMarker(marker, decoration)
|
||||
expect(decorationObject).toBeDefined()
|
||||
expect(decorationObject.getParams()).toBe decoration
|
||||
expect(displayBuffer.decorationForId(decoration.id)).toBe decorationObject
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decorationObject
|
||||
it "can add decorations associated with markers and remove them", ->
|
||||
expect(decoration).toBeDefined()
|
||||
expect(decoration.getParams()).toBe decorationParams
|
||||
expect(displayBuffer.decorationForId(decoration.id)).toBe decoration
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
|
||||
|
||||
displayBuffer.removeDecorationForMarker(marker, decoration)
|
||||
decoration.destroy()
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).not.toBeDefined()
|
||||
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
|
||||
|
||||
it "will not fail if the decoration is removed twice", ->
|
||||
decoration.destroy()
|
||||
decoration.destroy()
|
||||
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
|
||||
|
||||
describe "when a decoration is updated via Decoration::update()", ->
|
||||
it "emits an 'updated' event containing the new and old params", ->
|
||||
decoration.on 'updated', updatedSpy = jasmine.createSpy()
|
||||
decoration.update type: 'gutter', class: 'two'
|
||||
|
||||
{oldParams, newParams} = updatedSpy.mostRecentCall.args[0]
|
||||
expect(oldParams).toEqual decorationParams
|
||||
expect(newParams).toEqual type: 'gutter', class: 'two', id: decoration.id
|
||||
|
||||
describe "::setScrollTop", ->
|
||||
beforeEach ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
|
||||
@@ -232,6 +232,28 @@ describe "EditorComponent", ->
|
||||
runSetImmediateCallbacks()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "a line that ends with a carriage return#{invisibles.cr}#{invisibles.eol}"
|
||||
|
||||
it "renders invisible line-ending characters on empty lines", ->
|
||||
expect(component.lineNodeForScreenRow(10).textContent).toBe invisibles.eol
|
||||
|
||||
it "interleaves invisible line-ending characters with indent guides on empty lines", ->
|
||||
component.setShowIndentGuide(true)
|
||||
editor.setTextInBufferRange([[10, 0], [11, 0]], "\r\n", false)
|
||||
runSetImmediateCallbacks()
|
||||
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span><span class="invisible-character">E</span></span>'
|
||||
|
||||
editor.setTabLength(3)
|
||||
runSetImmediateCallbacks()
|
||||
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span><span class="invisible-character">E</span> </span>'
|
||||
|
||||
editor.setTabLength(1)
|
||||
runSetImmediateCallbacks()
|
||||
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span></span><span class="indent-guide"><span class="invisible-character">E</span></span>'
|
||||
|
||||
editor.setTextInBufferRange([[9, 0], [9, Infinity]], ' ')
|
||||
editor.setTextInBufferRange([[11, 0], [11, Infinity]], ' ')
|
||||
runSetImmediateCallbacks()
|
||||
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span></span><span class="invisible-character">E</span>'
|
||||
|
||||
describe "when soft wrapping is enabled", ->
|
||||
beforeEach ->
|
||||
editor.setText "a line that wraps "
|
||||
@@ -269,13 +291,11 @@ describe "EditorComponent", ->
|
||||
|
||||
line2LeafNodes = getLeafNodes(component.lineNodeForScreenRow(2))
|
||||
|
||||
expect(line2LeafNodes.length).toBe 3
|
||||
expect(line2LeafNodes.length).toBe 2
|
||||
expect(line2LeafNodes[0].textContent).toBe ' '
|
||||
expect(line2LeafNodes[0].classList.contains('indent-guide')).toBe true
|
||||
expect(line2LeafNodes[1].textContent).toBe ' '
|
||||
expect(line2LeafNodes[1].classList.contains('indent-guide')).toBe true
|
||||
expect(line2LeafNodes[2].textContent).toBe ' '
|
||||
expect(line2LeafNodes[2].classList.contains('indent-guide')).toBe true
|
||||
|
||||
it "renders indent guides correctly on lines containing only whitespace", ->
|
||||
editor.getBuffer().insert([1, Infinity], '\n ')
|
||||
@@ -303,7 +323,7 @@ describe "EditorComponent", ->
|
||||
it "updates the indent guides on empty lines preceding an indentation change", ->
|
||||
editor.getBuffer().insert([12, 0], '\n')
|
||||
runSetImmediateCallbacks()
|
||||
editor.getBuffer().insert([13, 0], ' ')
|
||||
editor.getBuffer().insert([13, 0], ' ')
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
line12LeafNodes = getLeafNodes(component.lineNodeForScreenRow(12))
|
||||
@@ -315,7 +335,7 @@ describe "EditorComponent", ->
|
||||
it "updates the indent guides on empty lines following an indentation change", ->
|
||||
editor.getBuffer().insert([12, 2], '\n')
|
||||
runSetImmediateCallbacks()
|
||||
editor.getBuffer().insert([12, 0], ' ')
|
||||
editor.getBuffer().insert([12, 0], ' ')
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
line13LeafNodes = getLeafNodes(component.lineNodeForScreenRow(13))
|
||||
@@ -451,6 +471,7 @@ describe "EditorComponent", ->
|
||||
expect(component.refs.gutter).not.toBeDefined()
|
||||
atom.config.set("editor.showLineNumbers", true)
|
||||
expect(component.refs.gutter).toBeDefined()
|
||||
expect(component.lineNumberNodeForScreenRow(3)).toBeDefined()
|
||||
|
||||
describe "fold decorations", ->
|
||||
describe "rendering fold decorations", ->
|
||||
@@ -587,6 +608,33 @@ describe "EditorComponent", ->
|
||||
expect(cursorRect.left).toBe rangeRect.left
|
||||
expect(cursorRect.width).toBe rangeRect.width
|
||||
|
||||
it "positions cursors correctly after character widths are changed via a stylesheet change", ->
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
editor.setCursorScreenPosition([0, 16])
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
atom.themes.applyStylesheet 'test', """
|
||||
.function.js {
|
||||
font-weight: bold;
|
||||
}
|
||||
"""
|
||||
runSetImmediateCallbacks() # re-measure characters once for a synchronous set of stylesheet changes
|
||||
runSetImmediateCallbacks() # update based on new measurements
|
||||
|
||||
cursor = node.querySelector('.cursor')
|
||||
cursorRect = cursor.getBoundingClientRect()
|
||||
|
||||
cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.storage.type.function.js').firstChild
|
||||
range = document.createRange()
|
||||
range.setStart(cursorLocationTextNode, 0)
|
||||
range.setEnd(cursorLocationTextNode, 1)
|
||||
rangeRect = range.getBoundingClientRect()
|
||||
|
||||
expect(cursorRect.left).toBe rangeRect.left
|
||||
expect(cursorRect.width).toBe rangeRect.width
|
||||
|
||||
atom.themes.removeStylesheet('test')
|
||||
|
||||
it "sets the cursor to the default character width at the end of a line", ->
|
||||
editor.setCursorScreenPosition([0, Infinity])
|
||||
runSetImmediateCallbacks()
|
||||
@@ -757,12 +805,12 @@ describe "EditorComponent", ->
|
||||
expect(selectionNode.classList.contains('flash')).toBe true
|
||||
|
||||
describe "line decoration rendering", ->
|
||||
[marker, decoration] = []
|
||||
[marker, decoration, decorationParams] = []
|
||||
|
||||
beforeEach ->
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], invalidate: 'inside')
|
||||
decoration = {type: ['gutter', 'line'], class: 'a'}
|
||||
editor.addDecorationForMarker(marker, decoration)
|
||||
decorationParams = {type: ['gutter', 'line'], class: 'a'}
|
||||
decoration = editor.decorateMarker(marker, decorationParams)
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
it "applies line decoration classes to lines and line numbers", ->
|
||||
@@ -776,7 +824,7 @@ describe "EditorComponent", ->
|
||||
|
||||
# Add decorations that are out of range
|
||||
marker2 = editor.displayBuffer.markBufferRange([[9, 0], [9, 0]])
|
||||
editor.addDecorationForMarker(marker2, type: ['gutter', 'line'], class: 'b')
|
||||
editor.decorateMarker(marker2, type: ['gutter', 'line'], class: 'b')
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
# Scroll decorations into view
|
||||
@@ -799,7 +847,7 @@ describe "EditorComponent", ->
|
||||
|
||||
marker.destroy()
|
||||
marker = editor.markBufferRange([[0, 0], [0, 2]])
|
||||
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'b')
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'b')
|
||||
runSetImmediateCallbacks()
|
||||
expect(lineNumberHasClass(0, 'b')).toBe true
|
||||
expect(lineNumberHasClass(1, 'b')).toBe false
|
||||
@@ -833,7 +881,7 @@ describe "EditorComponent", ->
|
||||
|
||||
it "remove decoration classes and unsubscribes from markers decorations are removed", ->
|
||||
expect(marker.getSubscriptionCount('changed'))
|
||||
editor.removeDecorationForMarker(marker, decoration)
|
||||
decoration.destroy()
|
||||
runSetImmediateCallbacks()
|
||||
expect(lineNumberHasClass(1, 'a')).toBe false
|
||||
expect(lineNumberHasClass(2, 'a')).toBe false
|
||||
@@ -868,7 +916,7 @@ describe "EditorComponent", ->
|
||||
|
||||
describe "when the decoration's 'onlyHead' property is true", ->
|
||||
it "only applies the decoration's class to lines containing the marker's head", ->
|
||||
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'only-head', onlyHead: true)
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-head', onlyHead: true)
|
||||
runSetImmediateCallbacks()
|
||||
expect(lineAndLineNumberHaveClass(1, 'only-head')).toBe false
|
||||
expect(lineAndLineNumberHaveClass(2, 'only-head')).toBe false
|
||||
@@ -877,7 +925,7 @@ describe "EditorComponent", ->
|
||||
|
||||
describe "when the decoration's 'onlyEmpty' property is true", ->
|
||||
it "only applies the decoration when its marker is empty", ->
|
||||
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'only-empty', onlyEmpty: true)
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-empty', onlyEmpty: true)
|
||||
runSetImmediateCallbacks()
|
||||
expect(lineAndLineNumberHaveClass(2, 'only-empty')).toBe false
|
||||
expect(lineAndLineNumberHaveClass(3, 'only-empty')).toBe false
|
||||
@@ -889,7 +937,7 @@ describe "EditorComponent", ->
|
||||
|
||||
describe "when the decoration's 'onlyNonEmpty' property is true", ->
|
||||
it "only applies the decoration when its marker is non-empty", ->
|
||||
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'only-non-empty', onlyNonEmpty: true)
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-non-empty', onlyNonEmpty: true)
|
||||
runSetImmediateCallbacks()
|
||||
expect(lineAndLineNumberHaveClass(2, 'only-non-empty')).toBe true
|
||||
expect(lineAndLineNumberHaveClass(3, 'only-non-empty')).toBe true
|
||||
@@ -905,7 +953,7 @@ describe "EditorComponent", ->
|
||||
scrollViewClientLeft = node.querySelector('.scroll-view').getBoundingClientRect().left
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], invalidate: 'inside')
|
||||
decorationParams = {type: 'highlight', class: 'test-highlight'}
|
||||
decoration = editor.addDecorationForMarker(marker, decorationParams)
|
||||
decoration = editor.decorateMarker(marker, decorationParams)
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
it "does not render highlights for off-screen lines until they come on-screen", ->
|
||||
@@ -914,7 +962,7 @@ describe "EditorComponent", ->
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
marker = editor.displayBuffer.markBufferRange([[9, 2], [9, 4]], invalidate: 'inside')
|
||||
editor.addDecorationForMarker(marker, type: 'highlight', class: 'some-highlight')
|
||||
editor.decorateMarker(marker, type: 'highlight', class: 'some-highlight')
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
# Should not be rendering range containing the marker
|
||||
@@ -942,7 +990,7 @@ describe "EditorComponent", ->
|
||||
expect(regions.length).toBe 2
|
||||
|
||||
it "removes highlights when a decoration is removed", ->
|
||||
editor.removeDecorationForMarker(marker, decorationParams)
|
||||
decoration.destroy()
|
||||
runSetImmediateCallbacks()
|
||||
regions = node.querySelectorAll('.test-highlight .region')
|
||||
expect(regions.length).toBe 0
|
||||
@@ -973,7 +1021,7 @@ describe "EditorComponent", ->
|
||||
regions = node.querySelectorAll('.test-highlight .region')
|
||||
expect(regions.length).toBe 2
|
||||
|
||||
describe "flashing a decoration via the Decoration::flash()", ->
|
||||
describe "when flashing a decoration via Decoration::flash()", ->
|
||||
highlightNode = null
|
||||
beforeEach ->
|
||||
highlightNode = node.querySelector('.test-highlight')
|
||||
@@ -1029,6 +1077,16 @@ describe "EditorComponent", ->
|
||||
regionStyle = node.querySelector('.test-highlight .region').style
|
||||
expect(parseInt(regionStyle.top)).toBe 5 * lineHeightInPixels
|
||||
|
||||
describe "when a decoration is updated via Decoration::update", ->
|
||||
it "renders the decoration's new params", ->
|
||||
expect(node.querySelector('.test-highlight')).toBeTruthy()
|
||||
|
||||
decoration.update(type: 'highlight', class: 'new-test-highlight')
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
expect(node.querySelector('.test-highlight')).toBeFalsy()
|
||||
expect(node.querySelector('.new-test-highlight')).toBeTruthy()
|
||||
|
||||
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)
|
||||
@@ -1804,6 +1862,29 @@ describe "EditorComponent", ->
|
||||
line0Right = node.querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
expect(cursorLeft).toBe line0Right
|
||||
|
||||
describe "when stylesheets change while the editor is hidden", ->
|
||||
afterEach ->
|
||||
atom.themes.removeStylesheet('test')
|
||||
|
||||
it "does not re-measure character widths until the editor is shown again", ->
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
|
||||
wrapperView.hide()
|
||||
atom.themes.applyStylesheet 'test', """
|
||||
.function.js {
|
||||
font-weight: bold;
|
||||
}
|
||||
"""
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
wrapperView.show()
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
runSetImmediateCallbacks()
|
||||
|
||||
cursorLeft = node.querySelector('.cursor').getBoundingClientRect().left
|
||||
line0Right = node.querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
expect(cursorLeft).toBe line0Right
|
||||
|
||||
describe "when lines are changed while the editor is hidden", ->
|
||||
it "does not measure new characters until the editor is shown again", ->
|
||||
editor.setText('')
|
||||
|
||||
@@ -792,6 +792,12 @@ describe "Editor", ->
|
||||
editor.insertNewline()
|
||||
expect(editor.getScrollBottom()).toBe 15 * 10
|
||||
|
||||
it "autoscrolls to the cursor when it moves due to undo", ->
|
||||
editor.insertText('abc')
|
||||
editor.setScrollTop(Infinity)
|
||||
editor.undo()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
describe "selection", ->
|
||||
selection = null
|
||||
|
||||
@@ -1234,6 +1240,8 @@ describe "Editor", ->
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
|
||||
|
||||
it "autoscrolls to the added selection if needed", ->
|
||||
editor.manageScrollPosition = true
|
||||
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
|
||||
@@ -684,8 +684,8 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
|
||||
|
||||
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
|
||||
@@ -693,12 +693,12 @@ describe "TokenizedBuffer", ->
|
||||
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
|
||||
|
||||
delete changeHandler.argsForCall[0][0].bufferChange
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: 2)
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: 2)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
|
||||
|
||||
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
|
||||
@@ -711,7 +711,7 @@ describe "TokenizedBuffer", ->
|
||||
buffer.setTextInRange([[7, 0], [8, 65]], ' ok')
|
||||
|
||||
delete changeHandler.argsForCall[0][0].bufferChange
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: -1)
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: -1)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
|
||||
|
||||
+19
-7
@@ -225,9 +225,15 @@ class Atom extends Model
|
||||
else
|
||||
@center()
|
||||
|
||||
# Returns true if the dimensions are useable, false if they should be ignored.
|
||||
# Work around for https://github.com/atom/atom-shell/issues/473
|
||||
isValidDimensions: ({x, y, width, height}={}) ->
|
||||
width > 0 and height > 0 and x + width > 0 and y + height > 0
|
||||
|
||||
storeDefaultWindowDimensions: ->
|
||||
dimensions = JSON.stringify(atom.getWindowDimensions())
|
||||
localStorage.setItem("defaultWindowDimensions", dimensions)
|
||||
dimensions = @getWindowDimensions()
|
||||
if @isValidDimensions(dimensions)
|
||||
localStorage.setItem("defaultWindowDimensions", JSON.stringify(dimensions))
|
||||
|
||||
getDefaultWindowDimensions: ->
|
||||
{windowDimensions} = @getLoadSettings()
|
||||
@@ -240,15 +246,21 @@ class Atom extends Model
|
||||
console.warn "Error parsing default window dimensions", error
|
||||
localStorage.removeItem("defaultWindowDimensions")
|
||||
|
||||
{width, height} = screen.getPrimaryDisplay().workAreaSize
|
||||
dimensions ? {x: 0, y: 0, width: Math.min(1024, width), height: height}
|
||||
if @isValidDimensions(dimensions)
|
||||
dimensions
|
||||
else
|
||||
{width, height} = screen.getPrimaryDisplay().workAreaSize
|
||||
{x: 0, y: 0, width: Math.min(1024, width), height}
|
||||
|
||||
restoreWindowDimensions: ->
|
||||
windowDimensions = @state.windowDimensions ? @getDefaultWindowDimensions()
|
||||
@setWindowDimensions(windowDimensions)
|
||||
dimensions = @state.windowDimensions
|
||||
unless @isValidDimensions(dimensions)
|
||||
dimensions = @getDefaultWindowDimensions()
|
||||
@setWindowDimensions(dimensions)
|
||||
|
||||
storeWindowDimensions: ->
|
||||
@state.windowDimensions = @getWindowDimensions()
|
||||
dimensions = @getWindowDimensions()
|
||||
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
|
||||
|
||||
# Public: Get the load settings for the current window.
|
||||
#
|
||||
|
||||
@@ -138,6 +138,7 @@ class AtomWindow
|
||||
when 'window:reload' then @reload()
|
||||
when 'window:toggle-dev-tools' then @toggleDevTools()
|
||||
when 'window:close' then @close()
|
||||
when 'window:update-available' then @sendCommandToBrowserWindow(command, args...) # For spec testing
|
||||
else if @isWebViewFocused()
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
else
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
https = require 'https'
|
||||
autoUpdater = require 'auto-updater'
|
||||
dialog = require 'dialog'
|
||||
_ = require 'underscore-plus'
|
||||
@@ -16,11 +17,12 @@ class AutoUpdateManager
|
||||
|
||||
constructor: (@version) ->
|
||||
@state = IDLE_STATE
|
||||
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
|
||||
|
||||
# Only released versions should check for updates.
|
||||
return if /\w{7}/.test(@version)
|
||||
if process.platform is 'win32'
|
||||
autoUpdater.checkForUpdates = => @checkForUpdatesShim()
|
||||
|
||||
autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"
|
||||
autoUpdater.setFeedUrl @feedUrl
|
||||
|
||||
autoUpdater.on 'checking-for-update', =>
|
||||
@setState(CHECKING_STATE)
|
||||
@@ -39,7 +41,25 @@ class AutoUpdateManager
|
||||
@setState(UPDATE_AVAILABLE_STATE)
|
||||
@emitUpdateAvailableEvent(@getWindows()...)
|
||||
|
||||
@check(hidePopups: true)
|
||||
# Only released versions should check for updates.
|
||||
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'
|
||||
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
|
||||
|
||||
@@ -45,7 +45,10 @@ class BufferedProcess
|
||||
# Related to joyent/node#2318
|
||||
if process.platform is "win32"
|
||||
# Quote all arguments and escapes inner quotes
|
||||
cmdArgs = args.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
|
||||
if args?
|
||||
cmdArgs = args.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
|
||||
else
|
||||
cmdArgs = []
|
||||
cmdArgs.unshift("\"#{command}\"")
|
||||
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
|
||||
cmdOptions = _.clone(options)
|
||||
|
||||
@@ -28,6 +28,7 @@ class Cursor extends Model
|
||||
|
||||
# Supports old editor view
|
||||
@needsAutoscroll ?= @isLastCursor() and !textChanged
|
||||
@autoscroll() if @editor.manageScrollPosition and @isLastCursor() and textChanged
|
||||
|
||||
@goalColumn = null
|
||||
|
||||
|
||||
+69
-4
@@ -4,6 +4,39 @@ _ = require 'underscore-plus'
|
||||
idCounter = 0
|
||||
nextId = -> idCounter++
|
||||
|
||||
# Public: Represents a decoration that follows a {Marker}. A decoration is
|
||||
# basically a visual representation of a marker. It allows you to add CSS
|
||||
# classes to line numbers in the gutter, lines, and add selection-line regions
|
||||
# around marked ranges of text.
|
||||
#
|
||||
# {Decoration} objects are not meant to be created directly, but created with
|
||||
# {Editor::decorateMarker}. eg.
|
||||
#
|
||||
# ```coffee
|
||||
# range = editor.getSelectedBufferRange() # any range you like
|
||||
# marker = editor.markBufferRange(range)
|
||||
# decoration = editor.decorateMarker(marker, {type: 'line', class: 'my-line-class'})
|
||||
# ```
|
||||
#
|
||||
# Best practice for destorying the decoration is by destroying the {Marker}.
|
||||
#
|
||||
# ```
|
||||
# marker.destroy()
|
||||
# ```
|
||||
#
|
||||
# You should only use {Decoration::destroy} when you still need or do not own
|
||||
# the marker.
|
||||
#
|
||||
# ### IDs
|
||||
# Each {Decoration} has a unique ID available via `decoration.id`.
|
||||
#
|
||||
# ### Events
|
||||
# A couple of events are emitted:
|
||||
#
|
||||
# * `destroyed`: When the {Decoration} is destroyed
|
||||
# * `updated`: When the {Decoration} is updated via {Decoration::update}.
|
||||
# Event object has properties `oldParams` and `newParams`
|
||||
#
|
||||
module.exports =
|
||||
class Decoration
|
||||
Emitter.includeInto(this)
|
||||
@@ -14,14 +47,46 @@ class Decoration
|
||||
else
|
||||
type is decorationParams.type
|
||||
|
||||
constructor: (@marker, @params) ->
|
||||
constructor: (@marker, @displayBuffer, @params) ->
|
||||
@id = nextId()
|
||||
@params.id = @id
|
||||
@flashQueue = null
|
||||
@isDestroyed = false
|
||||
|
||||
getParams: ->
|
||||
@params
|
||||
# Public: Destroy this marker.
|
||||
#
|
||||
# If you own the marker, you should use {Marker:destroy} which will destroy
|
||||
# this decoration.
|
||||
destroy: ->
|
||||
return if @isDestroyed
|
||||
@isDestroyed = true
|
||||
@displayBuffer.removeDecoration(this)
|
||||
@emit 'destoryed'
|
||||
|
||||
# Public: Update the marker with new params. Allows you to change the decoration's class.
|
||||
#
|
||||
# ```
|
||||
# decoration.update({type: 'gutter', class: 'my-new-class'})
|
||||
# ```
|
||||
update: (newParams) ->
|
||||
return if @isDestroyed
|
||||
oldParams = @params
|
||||
@params = newParams
|
||||
@params.id = @id
|
||||
@displayBuffer.decorationUpdated(this)
|
||||
@emit 'updated', {oldParams, newParams}
|
||||
|
||||
# Public: Returns the marker associated with this {Decoration}
|
||||
getMarker: -> @marker
|
||||
|
||||
# Public: Returns the {Decoration}'s params.
|
||||
getParams: -> @params
|
||||
|
||||
# Public: Check if this decoration is of type `type`
|
||||
#
|
||||
# type - A {String} type like `'gutter'`
|
||||
#
|
||||
# Returns a {Boolean}
|
||||
isType: (type) ->
|
||||
Decoration.isType(@params, type)
|
||||
|
||||
@@ -35,7 +100,7 @@ class Decoration
|
||||
flashObject = {class: klass, duration}
|
||||
@flashQueue ?= []
|
||||
@flashQueue.push(flashObject)
|
||||
@emit('flash')
|
||||
@emit 'flash'
|
||||
|
||||
consumeNextFlash: ->
|
||||
return @flashQueue.shift() if @flashQueue?.length > 0
|
||||
|
||||
+15
-13
@@ -767,7 +767,7 @@ class DisplayBuffer extends Model
|
||||
decorationsByMarkerId[marker.id] = decorations
|
||||
decorationsByMarkerId
|
||||
|
||||
addDecorationForMarker: (marker, decorationParams) ->
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
marker = @getMarker(marker.id)
|
||||
|
||||
@decorationMarkerDestroyedSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', =>
|
||||
@@ -782,24 +782,23 @@ class DisplayBuffer extends Model
|
||||
for decoration in decorations
|
||||
@emit 'decoration-changed', marker, decoration, event
|
||||
|
||||
decoration = new Decoration(marker, decorationParams)
|
||||
decoration = new Decoration(marker, this, decorationParams)
|
||||
@decorationsByMarkerId[marker.id] ?= []
|
||||
@decorationsByMarkerId[marker.id].push(decoration)
|
||||
@decorationsById[decoration.id] = decoration
|
||||
@emit 'decoration-added', marker, decoration
|
||||
decoration
|
||||
|
||||
removeDecorationForMarker: (marker, decorationPattern) ->
|
||||
removeDecoration: (decoration) ->
|
||||
{marker} = decoration
|
||||
return unless decorations = @decorationsByMarkerId[marker.id]
|
||||
index = decorations.indexOf(decoration)
|
||||
|
||||
for i in [decorations.length - 1..0]
|
||||
decoration = decorations[i]
|
||||
if decoration.matchesPattern(decorationPattern)
|
||||
decorations.splice(i, 1)
|
||||
delete @decorationsById[decoration.id]
|
||||
@emit 'decoration-removed', marker, decoration
|
||||
|
||||
@removedAllMarkerDecorations(marker) if decorations.length is 0
|
||||
if index > -1
|
||||
decorations.splice(index, 1)
|
||||
delete @decorationsById[decoration.id]
|
||||
@emit 'decoration-removed', marker, decoration
|
||||
@removedAllMarkerDecorations(marker) if decorations.length is 0
|
||||
|
||||
removeAllDecorationsForMarker: (marker) ->
|
||||
decorations = @decorationsByMarkerId[marker.id].slice()
|
||||
@@ -815,6 +814,9 @@ class DisplayBuffer extends Model
|
||||
delete @decorationMarkerChangedSubscriptions[marker.id]
|
||||
delete @decorationMarkerDestroyedSubscriptions[marker.id]
|
||||
|
||||
decorationUpdated: (decoration) ->
|
||||
@emit 'decoration-updated', decoration
|
||||
|
||||
# Retrieves a {DisplayBufferMarker} based on its id.
|
||||
#
|
||||
# id - A {Number} representing a marker id
|
||||
@@ -968,7 +970,7 @@ class DisplayBuffer extends Model
|
||||
for marker in @getMarkers()
|
||||
marker.notifyObservers(textChanged: false)
|
||||
|
||||
destroy: ->
|
||||
destroyed: ->
|
||||
marker.unsubscribe() for marker in @getMarkers()
|
||||
@tokenizedBuffer.destroy()
|
||||
@unsubscribe()
|
||||
@@ -1092,7 +1094,7 @@ class DisplayBuffer extends Model
|
||||
@emit 'marker-created', @getMarker(marker.id)
|
||||
|
||||
createFoldForMarker: (marker) ->
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'folded')
|
||||
@decorateMarker(marker, type: 'gutter', class: 'folded')
|
||||
new Fold(this, marker)
|
||||
|
||||
foldForMarker: (marker) ->
|
||||
|
||||
@@ -42,7 +42,7 @@ EditorComponent = React.createClass
|
||||
scrollSensitivity: 0.4
|
||||
scrollViewMeasurementRequested: false
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: false
|
||||
remeasureCharacterWidthsWhenShown: false
|
||||
remeasureCharacterWidthsIfVisibleAfterNextUpdate: false
|
||||
inputEnabled: true
|
||||
scrollViewMeasurementInterval: 100
|
||||
scopedCharacterWidthsChangeCount: null
|
||||
@@ -182,6 +182,7 @@ EditorComponent = React.createClass
|
||||
@measureScrollbars()
|
||||
|
||||
componentWillUnmount: ->
|
||||
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
|
||||
@unsubscribe()
|
||||
clearInterval(@scrollViewMeasurementIntervalId)
|
||||
@scrollViewMeasurementIntervalId = null
|
||||
@@ -294,8 +295,8 @@ EditorComponent = React.createClass
|
||||
else
|
||||
continue if decorationParams.onlyEmpty
|
||||
|
||||
decorationsByScreenRow[screenRow] ?= []
|
||||
decorationsByScreenRow[screenRow].push decorationParams
|
||||
decorationsByScreenRow[screenRow] ?= {}
|
||||
decorationsByScreenRow[screenRow][decoration.id] = decorationParams
|
||||
|
||||
decorationsByScreenRow
|
||||
|
||||
@@ -332,6 +333,7 @@ EditorComponent = React.createClass
|
||||
@subscribe editor, 'decoration-added', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-removed', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-changed', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-updated', @onDecorationChanged
|
||||
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
|
||||
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
|
||||
@subscribe editor.$scrollLeft.changes, @requestUpdate
|
||||
@@ -460,7 +462,7 @@ EditorComponent = React.createClass
|
||||
'editor:unfold-all': => editor.unfoldAll()
|
||||
'editor:fold-current-row': => editor.foldCurrentRow()
|
||||
'editor:unfold-current-row': => editor.unfoldCurrentRow()
|
||||
'editor:fold-selection': => neditor.foldSelectedLines()
|
||||
'editor:fold-selection': => editor.foldSelectedLines()
|
||||
'editor:fold-at-indent-level-1': => editor.foldAllAtIndentLevel(0)
|
||||
'editor:fold-at-indent-level-2': => editor.foldAllAtIndentLevel(1)
|
||||
'editor:fold-at-indent-level-3': => editor.foldAllAtIndentLevel(2)
|
||||
@@ -653,6 +655,8 @@ EditorComponent = React.createClass
|
||||
|
||||
onStylesheetsChanged: (stylesheet) ->
|
||||
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
|
||||
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = true
|
||||
@requestUpdate() if @state.visible
|
||||
|
||||
onScreenLinesChanged: (change) ->
|
||||
{editor} = @props
|
||||
@@ -789,12 +793,12 @@ EditorComponent = React.createClass
|
||||
if @state.visible
|
||||
@remeasureCharacterWidths()
|
||||
else
|
||||
@remeasureCharacterWidthsWhenShown = true
|
||||
else if @remeasureCharacterWidthsWhenShown and @state.visible and not prevState.visible
|
||||
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = true
|
||||
else if @remeasureCharacterWidthsIfVisibleAfterNextUpdate and @state.visible
|
||||
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = false
|
||||
@remeasureCharacterWidths()
|
||||
|
||||
remeasureCharacterWidths: ->
|
||||
@remeasureCharacterWidthsWhenShown = false
|
||||
@refs.lines.remeasureCharacterWidths()
|
||||
|
||||
onGutterWidthChanged: (@gutterWidth) ->
|
||||
|
||||
+48
-58
@@ -131,6 +131,10 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
|
||||
# - {::markScreenRange}
|
||||
# - {::getMarker}
|
||||
# - {::findMarkers}
|
||||
#
|
||||
# ### Decorations
|
||||
# - {::decorateMarker}
|
||||
# - {::decorationsForScreenRowRange}
|
||||
module.exports =
|
||||
class Editor extends Model
|
||||
Serializable.includeInto(this)
|
||||
@@ -219,6 +223,7 @@ class Editor extends Model
|
||||
@subscribe @displayBuffer, "decoration-added", (args...) => @emit 'decoration-added', args...
|
||||
@subscribe @displayBuffer, "decoration-removed", (args...) => @emit 'decoration-removed', args...
|
||||
@subscribe @displayBuffer, "decoration-changed", (args...) => @emit 'decoration-changed', args...
|
||||
@subscribe @displayBuffer, "decoration-updated", (args...) => @emit 'decoration-updated', args...
|
||||
@subscribe @displayBuffer, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
|
||||
|
||||
getViewClass: ->
|
||||
@@ -1079,8 +1084,10 @@ class Editor extends Model
|
||||
# startScreenRow - the {Number} beginning screen row
|
||||
# endScreenRow - the {Number} end screen row (inclusive)
|
||||
#
|
||||
# Returns an {Object} of decorations in the form `{1: [{type: 'gutter', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are markerIds, and the values are an array of decoration objects attached to the marker.
|
||||
# Returns an {Object} of decorations in the form
|
||||
# `{1: [{id: 10, type: 'gutter', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are {Marker} IDs, and the values are an array of decoration
|
||||
# params objects attached to the marker.
|
||||
# Returns an empty object when no decorations are found
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
|
||||
@@ -1089,59 +1096,42 @@ class Editor extends Model
|
||||
# is invalidated, or is destroyed, the decoration will be updated to reflect
|
||||
# the marker's state.
|
||||
#
|
||||
# There are three types of supported decorations:
|
||||
# * `line`: Adds your CSS `class` to the line nodes within the range
|
||||
# marked by the marker
|
||||
# * `gutter`: Adds your CSS `class` to the line number nodes within the
|
||||
# range marked by the marker
|
||||
# * `highlight`: Adds a new highlight div to the editor surrounding the
|
||||
# range marked by the marker. When the user selects text, the selection is
|
||||
# visualized with a highlight decoration internally. The structure of this
|
||||
# highlight will be:
|
||||
# ```html
|
||||
# <div class="highlight <your-class>">
|
||||
# <!-- Will be one region for each row in the range. Spans 2 lines? There will be 2 regions. -->
|
||||
# <div class="region"></div>
|
||||
# </div>
|
||||
# ```
|
||||
#
|
||||
# marker - A {Marker} you want this decoration to follow.
|
||||
# decoration - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
# The decoration can contain the following keys:
|
||||
# * type: There are a few supported decoration types:
|
||||
# * `gutter`: Applies the decoration to the line numbers spanned by the
|
||||
# marker.
|
||||
# * `line`: Applies the decoration to the lines spanned by the marker.
|
||||
# * `highlight`: Applies the decoration to a "highlight" behind the
|
||||
# marked range. When the user selects text, the selection is
|
||||
# visualized with a highlight decoration internally.
|
||||
# * class: This CSS class will be applied to the decorated line number,
|
||||
# line, or highlight.
|
||||
# * onlyHead: If `true`, the decoration will only be applied to the head
|
||||
# of the marker. Only applicable to the `line` and `gutter` types.
|
||||
# * onlyEmpty: If `true`, the decoration will only be applied if the
|
||||
# associated marker is empty. Only applicable to the `line` and
|
||||
# `gutter` types.
|
||||
# * onlyNonEmpty: If `true`, the decoration will only be applied if the
|
||||
# associated marker is non-empty. Only applicable to the `line` and
|
||||
# gutter types.
|
||||
addDecorationForMarker: (marker, decoration) ->
|
||||
@displayBuffer.addDecorationForMarker(marker, decoration)
|
||||
|
||||
# Public: Removes all decorations associated with a {Marker} that match a
|
||||
# `decorationPattern` and stop tracking the {Marker}.
|
||||
# decorationParams - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
# :type - There are a few supported decoration types:
|
||||
# * `gutter`: Applies the decoration to the line numbers spanned by the marker.
|
||||
# * `line`: Applies the decoration to the lines spanned by the marker.
|
||||
# * `highlight`: Applies the decoration to a "highlight" behind the marked range.
|
||||
# :class - This CSS class will be applied to the decorated line number,
|
||||
# line, or highlight.
|
||||
# :onlyHead - If `true`, the decoration will only be applied to the head
|
||||
# of the marker. Only applicable to the `line` and `gutter` types.
|
||||
# :onlyEmpty - If `true`, the decoration will only be applied if the
|
||||
# associated marker is empty. Only applicable to the `line` and
|
||||
# `gutter` types.
|
||||
# :onlyNonEmpty - If `true`, the decoration will only be applied if the
|
||||
# associated marker is non-empty. Only applicable to the `line` and
|
||||
# gutter types.
|
||||
#
|
||||
# ```coffee
|
||||
# marker = editor.markBufferRange([[4, 13], [5, 17]])
|
||||
# editor.removeDecorationForMarker(marker, {type: 'gutter', class: 'linter-error'})
|
||||
# ```
|
||||
#
|
||||
# All decorations matching a pattern will be removed. For example, you might
|
||||
# have decorations with a namespace like this attached to a row:
|
||||
#
|
||||
# ```coffee
|
||||
# [
|
||||
# {type: 'gutter', namespace: 'myns', class: 'something'},
|
||||
# {type: 'gutter', namespace: 'myns', class: 'something-else'}
|
||||
# ]
|
||||
# ```
|
||||
#
|
||||
# You can remove both with:
|
||||
#
|
||||
# ```coffee
|
||||
# editor.removeDecorationForMarker(marker, {namespace: 'myns'})
|
||||
# ```
|
||||
#
|
||||
# marker - the {Marker} to detach from
|
||||
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
#
|
||||
# Returns nothing
|
||||
removeDecorationForMarker: (marker, decorationPattern) ->
|
||||
@displayBuffer.removeDecorationForMarker(marker, decorationPattern)
|
||||
# Returns a {Decoration} object
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
@displayBuffer.decorateMarker(marker, decorationParams)
|
||||
|
||||
decorationForId: (id) ->
|
||||
@displayBuffer.decorationForId(id)
|
||||
@@ -1251,9 +1241,9 @@ class Editor extends Model
|
||||
addCursor: (marker) ->
|
||||
cursor = new Cursor(editor: this, marker: marker)
|
||||
@cursors.push(cursor)
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'cursor-line')
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
|
||||
@addDecorationForMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
|
||||
@decorateMarker(marker, type: 'gutter', class: 'cursor-line')
|
||||
@decorateMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
|
||||
@decorateMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
|
||||
@emit 'cursor-added', cursor
|
||||
cursor
|
||||
|
||||
@@ -1294,7 +1284,7 @@ class Editor extends Model
|
||||
addSelectionForBufferRange: (bufferRange, options={}) ->
|
||||
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
selection = @getLastSelection()
|
||||
selection.autoscroll()
|
||||
selection.autoscroll() if @manageScrollPosition
|
||||
selection
|
||||
|
||||
# Public: Set the selected range in buffer coordinates. If there are multiple
|
||||
@@ -1502,7 +1492,7 @@ class Editor extends Model
|
||||
# text - A {String}
|
||||
#
|
||||
# Returns the {Range} of the newly-inserted text.
|
||||
setTextInBufferRange: (range, text) -> @getBuffer().setTextInRange(range, text)
|
||||
setTextInBufferRange: (range, text, normalizeLineEndings) -> @getBuffer().setTextInRange(range, text, normalizeLineEndings)
|
||||
|
||||
# Public: Get the {Range} of the paragraph surrounding the most recently added
|
||||
# cursor.
|
||||
|
||||
@@ -41,6 +41,7 @@ GutterComponent = React.createClass
|
||||
|
||||
componentDidMount: ->
|
||||
@appendDummyLineNumber()
|
||||
@updateLineNumbers() if @props.renderedRowRange?
|
||||
|
||||
# Only update the gutter if the visible row range has changed or if a
|
||||
# non-zero-delta change to the screen lines has occurred within the current
|
||||
@@ -154,7 +155,7 @@ GutterComponent = React.createClass
|
||||
|
||||
classes = ''
|
||||
if lineDecorations? and decorations = lineDecorations[screenRow]
|
||||
for decoration in decorations
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'gutter')
|
||||
classes += decoration.class + ' '
|
||||
|
||||
@@ -186,12 +187,13 @@ GutterComponent = React.createClass
|
||||
previousDecorations = @renderedDecorationsByLineNumberId[lineNumberId]
|
||||
|
||||
if previousDecorations?
|
||||
for decoration in previousDecorations
|
||||
node.classList.remove(decoration.class) if Decoration.isType(decoration, 'gutter') and not _.deepContains(decorations, decoration)
|
||||
for id, decoration of previousDecorations
|
||||
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(decorations, decoration)
|
||||
node.classList.remove(decoration.class)
|
||||
|
||||
if decorations?
|
||||
for decoration in decorations
|
||||
if Decoration.isType(decoration, 'gutter') and not _.deepContains(previousDecorations, decoration)
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(previousDecorations, decoration)
|
||||
node.classList.add(decoration.class)
|
||||
|
||||
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
|
||||
@@ -201,6 +203,9 @@ GutterComponent = React.createClass
|
||||
@screenRowsByLineNumberId[lineNumberId] = screenRow
|
||||
@lineNumberIdsByScreenRow[screenRow] = lineNumberId
|
||||
|
||||
hasDecoration: (decorations, decoration) ->
|
||||
decorations? and decorations[decoration.id] is decoration
|
||||
|
||||
hasLineNumberNode: (lineNumberId) ->
|
||||
@lineNumberNodesById.hasOwnProperty(lineNumberId)
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ LinesComponent = React.createClass
|
||||
|
||||
classes = ''
|
||||
if decorations = lineDecorations[screenRow]
|
||||
for decoration in decorations
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'line')
|
||||
classes += decoration.class + ' '
|
||||
classes += 'line'
|
||||
@@ -153,14 +153,31 @@ LinesComponent = React.createClass
|
||||
lineHTML
|
||||
|
||||
buildEmptyLineInnerHTML: (line) ->
|
||||
{showIndentGuide} = @props
|
||||
{showIndentGuide, invisibles} = @props
|
||||
{cr, eol} = invisibles
|
||||
{indentLevel, tabLength} = line
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
|
||||
multiplyString(indentSpan, indentLevel + 1)
|
||||
invisiblesToRender = []
|
||||
invisiblesToRender.push(cr) if cr? and line.lineEnding is '\r\n'
|
||||
invisiblesToRender.push(eol) if eol?
|
||||
|
||||
lineHTML = ''
|
||||
for i in [0...indentLevel]
|
||||
lineHTML += "<span class='indent-guide'>"
|
||||
for j in [0...tabLength]
|
||||
if invisible = invisiblesToRender.shift()
|
||||
lineHTML += "<span class='invisible-character'>#{invisible}</span>"
|
||||
else
|
||||
lineHTML += ' '
|
||||
lineHTML += "</span>"
|
||||
|
||||
while invisiblesToRender.length
|
||||
lineHTML += "<span class='invisible-character'>#{invisiblesToRender.shift()}</span>"
|
||||
|
||||
lineHTML
|
||||
else
|
||||
" "
|
||||
@buildEndOfLineHTML(line, @props.invisibles)
|
||||
|
||||
buildLineInnerHTML: (line) ->
|
||||
{invisibles, mini, showIndentGuide, invisibles} = @props
|
||||
@@ -223,12 +240,13 @@ LinesComponent = React.createClass
|
||||
previousDecorations = @renderedDecorationsByLineId[line.id]
|
||||
|
||||
if previousDecorations?
|
||||
for decoration in previousDecorations
|
||||
lineNode.classList.remove(decoration.class) if Decoration.isType(decoration, 'line') and not _.deepContains(decorations, decoration)
|
||||
for id, decoration of previousDecorations
|
||||
if Decoration.isType(decoration, 'line') and not @hasDecoration(decorations, decoration)
|
||||
lineNode.classList.remove(decoration.class)
|
||||
|
||||
if decorations?
|
||||
for decoration in decorations
|
||||
if Decoration.isType(decoration, 'line') and not _.deepContains(previousDecorations, decoration)
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'line') and not @hasDecoration(previousDecorations, decoration)
|
||||
lineNode.classList.add(decoration.class)
|
||||
|
||||
lineNode.style.width = lineWidth + 'px' if updateWidth
|
||||
@@ -239,6 +257,9 @@ LinesComponent = React.createClass
|
||||
@screenRowsByLineId[line.id] = screenRow
|
||||
@lineIdsByScreenRow[screenRow] = line.id
|
||||
|
||||
hasDecoration: (decorations, decoration) ->
|
||||
decorations? and decorations[decoration.id] is decoration
|
||||
|
||||
lineNodeForScreenRow: (screenRow) ->
|
||||
@lineNodesByLineId[@lineIdsByScreenRow[screenRow]]
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ class PaneContainer extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
@version: 1
|
||||
|
||||
@properties
|
||||
root: -> new Pane
|
||||
activePane: null
|
||||
@@ -27,10 +29,12 @@ class PaneContainer extends Model
|
||||
deserializeParams: (params) ->
|
||||
params.root = atom.deserializers.deserialize(params.root, container: this)
|
||||
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
||||
params.activePane = params.root.getPanes().find (pane) -> pane.id is params.activePaneId
|
||||
params
|
||||
|
||||
serializeParams: (params) ->
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
replaceChild: (oldChild, newChild) ->
|
||||
throw new Error("Replacing non-existent child") if oldChild isnt @root
|
||||
|
||||
+1
-3
@@ -40,14 +40,12 @@ class Pane extends Model
|
||||
@subscribe @items.onRemoval (item, index) =>
|
||||
@unsubscribe item if typeof item.on is 'function'
|
||||
|
||||
@activate() if params?.active
|
||||
|
||||
# Called by the Serializable mixin during serialization.
|
||||
serializeParams: ->
|
||||
id: @id
|
||||
items: compact(@items.map((item) -> item.serialize?()))
|
||||
activeItemUri: @activeItem?.getUri?()
|
||||
focused: @focused
|
||||
active: @active
|
||||
|
||||
# Called by the Serializable mixin during deserialization.
|
||||
deserializeParams: (params) ->
|
||||
|
||||
@@ -38,17 +38,20 @@ class ReactEditorView extends View
|
||||
@overlayer = $(node).find('.lines').addClass('overlayer')
|
||||
@hiddenInput = $(node).find('.hidden-input')
|
||||
|
||||
@gutter = $(node).find('.gutter')
|
||||
@gutter.removeClassFromAllLines = (klass) =>
|
||||
@gutter.find('.line-number').removeClass(klass)
|
||||
# FIXME: there should be a better way to deal with the gutter element
|
||||
@subscribe atom.config.observe 'editor.showLineNumbers', =>
|
||||
@gutter = $(node).find('.gutter')
|
||||
|
||||
@gutter.getLineNumberElement = (bufferRow) =>
|
||||
@gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
@gutter.removeClassFromAllLines = (klass) =>
|
||||
@gutter.find('.line-number').removeClass(klass)
|
||||
|
||||
@gutter.addClassToLine = (bufferRow, klass) =>
|
||||
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
lines.addClass(klass)
|
||||
lines.length > 0
|
||||
@gutter.getLineNumberElement = (bufferRow) =>
|
||||
@gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
|
||||
@gutter.addClassToLine = (bufferRow, klass) =>
|
||||
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
lines.addClass(klass)
|
||||
lines.length > 0
|
||||
|
||||
@focus() if @focusOnAttach
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class Selection extends Model
|
||||
constructor: ({@cursor, @marker, @editor, id}) ->
|
||||
@assignId(id)
|
||||
@cursor.selection = this
|
||||
@decoration = @editor.addDecorationForMarker(@marker, type: 'highlight', class: 'selection')
|
||||
@decoration = @editor.decorateMarker(@marker, type: 'highlight', class: 'selection')
|
||||
|
||||
@marker.on 'changed', => @screenRangeChanged()
|
||||
@marker.on 'destroyed', =>
|
||||
@@ -326,8 +326,6 @@ class Selection extends Model
|
||||
|
||||
newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo'))
|
||||
|
||||
@cursor.autoscroll() if @editor.manageScrollPosition and @cursor.isLastCursor()
|
||||
|
||||
if options.select
|
||||
@setBufferRange(newBufferRange, reversed: wasReversed)
|
||||
else
|
||||
|
||||
@@ -231,22 +231,27 @@ class TokenizedBuffer extends Model
|
||||
|
||||
indentLevelForRow: (row) ->
|
||||
line = @buffer.lineForRow(row)
|
||||
indentLevel = 0
|
||||
|
||||
if line is ''
|
||||
nextRow = row + 1
|
||||
lineCount = @getLineCount()
|
||||
while nextRow < lineCount
|
||||
nextLine = @buffer.lineForRow(nextRow)
|
||||
return @indentLevelForLine(nextLine) unless nextLine is ''
|
||||
unless nextLine is ''
|
||||
indentLevel = Math.ceil(@indentLevelForLine(nextLine))
|
||||
break
|
||||
nextRow++
|
||||
|
||||
previousRow = row - 1
|
||||
while previousRow >= 0
|
||||
previousLine = @buffer.lineForRow(previousRow)
|
||||
return @indentLevelForLine(previousLine) unless previousLine is ''
|
||||
unless previousLine is ''
|
||||
indentLevel = Math.max(Math.ceil(@indentLevelForLine(previousLine)), indentLevel)
|
||||
break
|
||||
previousRow--
|
||||
|
||||
0
|
||||
indentLevel
|
||||
else
|
||||
@indentLevelForLine(line)
|
||||
|
||||
|
||||
@@ -64,15 +64,15 @@
|
||||
}
|
||||
|
||||
.btn-toolbar {
|
||||
> .btn-group {
|
||||
> .btn-group + .btn-group, > .btn-group + .btn, > .btn + .btn {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
}
|
||||
> * {
|
||||
margin-right: 0;
|
||||
margin-left: @component-padding/2;
|
||||
}
|
||||
> *:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
> * {
|
||||
margin-right: @component-padding / 2;
|
||||
}
|
||||
> *:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +179,11 @@
|
||||
box-shadow: inset 1px 0;
|
||||
}
|
||||
|
||||
.editor .vertical-scrollbar,
|
||||
.editor .horizontal-scrollbar {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.editor .vertical-scrollbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário