Comparar commits
203 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 48f161b63a | |||
| f032dacebb | |||
| 5ba86b3dbc | |||
| 790f134d7c | |||
| 32353a31eb | |||
| 0bae432109 | |||
| dccb2c295c | |||
| 2a94e4a33c | |||
| 3371ceadf3 | |||
| 070ca1a4bb | |||
| 0849f1ea84 | |||
| c4f5a3516b | |||
| 69aa34954f | |||
| 83659272ac | |||
| abadc9805c | |||
| ad269357b7 | |||
| ae323d2083 | |||
| cef24a3979 | |||
| 7220c61e98 | |||
| 6e40f3b2f9 | |||
| c4811a8fb7 | |||
| c7242ec964 | |||
| d37bd14a62 | |||
| 3d2d8c491f | |||
| b05a83a6ce | |||
| 0d68430bb8 | |||
| d75485a2d8 | |||
| e54bc0fbaa | |||
| cf9208bc02 | |||
| 35fd19f3ef | |||
| 97bcdcc9b0 | |||
| fc441ef5e2 | |||
| 01c4fe5340 | |||
| 431fab1a43 | |||
| 0e62c98768 | |||
| f8026bb005 | |||
| ef889a50ed | |||
| c3c91ae6c3 | |||
| c073d042b8 | |||
| ecf237697b | |||
| 4b8fd222f1 | |||
| 62a1888c6b | |||
| 176d73dfcc | |||
| c0704edb0d | |||
| fb53f85573 | |||
| 6610447e09 | |||
| 9f7560bb89 | |||
| a853a27857 | |||
| 154fe4006f | |||
| 17feb91876 | |||
| 5bdf8a14a7 | |||
| 1196e5a264 | |||
| a4ae314b00 | |||
| c9390b61de | |||
| 2811663177 | |||
| 4dc89f1b1e | |||
| b0a9eefa04 | |||
| dc55d42491 | |||
| d3b06542a5 | |||
| 9c154a2f5a | |||
| 6b1868efd5 | |||
| e50887aab8 | |||
| c6ca03fa49 | |||
| a15deaef81 | |||
| 461cca2d22 | |||
| d15728321c | |||
| 9164b0ea3b | |||
| 59a80dcd60 | |||
| 72354ebf32 | |||
| a56cea2408 | |||
| cc28eaf6d2 | |||
| 283c76ad3c | |||
| a71a524ec7 | |||
| a2f7ec9d73 | |||
| 26d696a93d | |||
| 30aa47026d | |||
| ec6bfbb9e6 | |||
| d986ab0293 | |||
| c7f5321d14 | |||
| cb868bab4c | |||
| 024d7f8d88 | |||
| 1022d8ab4b | |||
| 760e6c6c29 | |||
| beae15ef7f | |||
| 5cb084d568 | |||
| f72daffdbb | |||
| 4aba8fef7e | |||
| 75853e2f9c | |||
| 3baeb3797f | |||
| 7d0452f093 | |||
| 7edcadb50a | |||
| fc198b6e17 | |||
| 86f8944aaf | |||
| dda0e7f4ce | |||
| e1ff6ab327 | |||
| 2b87f4bcb5 | |||
| 3190c0c517 | |||
| a1d8ee86f9 | |||
| ebbea64b3d | |||
| a20f04149c | |||
| b46e03437c | |||
| ccd32cd084 | |||
| 6b5d16173b | |||
| 237d71417d | |||
| 590bfa0c86 | |||
| 881c21829b | |||
| 34f96b2ea2 | |||
| c989557b5e | |||
| 0a07e862c2 | |||
| 0eaec57f7b | |||
| 5873a03145 | |||
| 3ff8f35863 | |||
| 6c52bcf20c | |||
| 5975548cec | |||
| 3742dadbb9 | |||
| 919f541685 | |||
| 8bebfdb871 | |||
| cda8382902 | |||
| dfbf0de961 | |||
| 4a9e397be0 | |||
| e10a578c04 | |||
| 2bd8456923 | |||
| c5f0126078 | |||
| 28500e189b | |||
| a62e90820d | |||
| 853e8e8f17 | |||
| 1da47dbbbd | |||
| f96ac09c36 | |||
| d6852cab15 | |||
| 75f01f87da | |||
| f901007892 | |||
| a7a6236b26 | |||
| ef47bdab3f | |||
| 8cf999f73b | |||
| 20b44500d1 | |||
| e0ebc661f2 | |||
| d38711e2bf | |||
| 753f47ef21 | |||
| e202ecd1b6 | |||
| 02557d36c2 | |||
| eabad3dcef | |||
| 6ad099260e | |||
| ebfd921807 | |||
| 83c77b6e4b | |||
| cbe5593381 | |||
| 32e59ce238 | |||
| 654a4392a4 | |||
| 8457c74f2f | |||
| 88366cb5d4 | |||
| c70c819aa2 | |||
| 4ac8aba31f | |||
| 776e431cc5 | |||
| 5a966240b9 | |||
| 27f0c525ac | |||
| 00170804e5 | |||
| d7e5f05f83 | |||
| 3ce641f53b | |||
| 27ca957629 | |||
| 84d0abc52c | |||
| 41c62e8628 | |||
| 1515690302 | |||
| 2be658b894 | |||
| d3e1c004fb | |||
| 62924dfcd1 | |||
| 770e97efff | |||
| 2704d2f15a | |||
| 957e45944a | |||
| 16fd14d295 | |||
| 20daed176b | |||
| 8c11c4a4c6 | |||
| 7cb44b69ef | |||
| d37cfb9042 | |||
| 986753981d | |||
| 970bde9361 | |||
| 7b55946abf | |||
| c74f6bb615 | |||
| 63f2ab3088 | |||
| 742ec6df0d | |||
| 864f9bc2b4 | |||
| 73896d100e | |||
| 193001d793 | |||
| 052f9580f2 | |||
| 2daf70f0e5 | |||
| fca9ed07e6 | |||
| e725a8ffeb | |||
| 23c67c53dc | |||
| c6fc0d050d | |||
| 6e913c47ef | |||
| a245624211 | |||
| 8af8caca55 | |||
| bbeb4be5b1 | |||
| 449da91216 | |||
| 521647e8ac | |||
| d863638c24 | |||
| 651df12f9b | |||
| 83706647d1 | |||
| 13f66fb2ae | |||
| d6a8217e94 | |||
| 8e649e3008 | |||
| d5e30e83f6 | |||
| d16c0e9e41 | |||
| bd8ac3bb32 | |||
| e1f4b7415a |
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.89.0"
|
||||
"atom-package-manager": "0.92.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require '../src/window'
|
||||
Atom = require '../src/atom'
|
||||
atom = new Atom()
|
||||
window.atom = Atom.loadOrCreate('spec')
|
||||
atom.show() unless atom.getLoadSettings().exitWhenDone
|
||||
window.atom = atom
|
||||
|
||||
@@ -9,5 +9,4 @@ window.atom = atom
|
||||
atom.openDevTools()
|
||||
|
||||
document.title = "Benchmark Suite"
|
||||
benchmarkSuite = require.resolve('./benchmark-suite')
|
||||
runSpecSuite(benchmarkSuite, true)
|
||||
runSpecSuite('../benchmark/benchmark-suite', atom.getLoadSettings().logFile)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
require '../spec/spec-helper'
|
||||
|
||||
path = require 'path'
|
||||
{$, _, Point, fs} = require 'atom'
|
||||
{$, Point} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Project = require '../src/project'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
|
||||
@@ -101,7 +103,7 @@ $.fn.resultOfTrigger = (type) ->
|
||||
event.result
|
||||
|
||||
$.fn.enableKeymap = ->
|
||||
@on 'keydown', (e) => window.keymap.handleKeyEvent(e)
|
||||
@on 'keydown', (e) -> window.keymap.handleKeyEvent(e)
|
||||
|
||||
$.fn.attachToDom = ->
|
||||
$('#jasmine-content').append(this)
|
||||
|
||||
+5
-5
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"indentation": {
|
||||
"level": "ignore"
|
||||
},
|
||||
"max_line_length": {
|
||||
"level": "ignore"
|
||||
},
|
||||
"no_empty_param_list": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_unnecessary_fat_arrows": {
|
||||
"level": "ignore"
|
||||
"arrow_spacing": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_interpolation_in_single_quotes": {
|
||||
"level": "error"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,17 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
* development headers for [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring)
|
||||
|
||||
### Ubuntu / Debian
|
||||
|
||||
* `sudo apt-get install build-essential git libgnome-keyring-dev`
|
||||
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
|
||||
### Fedora
|
||||
|
||||
* `sudo yum --assumeyes install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel`
|
||||
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora).
|
||||
|
||||
### Arch
|
||||
|
||||
* `sudo pacman -S base-devel git nodejs libgnome-keyring`
|
||||
* `export PYTHON=/usr/bin/python2` before building Atom.
|
||||
|
||||
@@ -51,6 +54,20 @@ From the cloned repository directory:
|
||||
|
||||
Use the newly installed atom by restarting any running atom instances.
|
||||
|
||||
## Advanced Options
|
||||
|
||||
### Custom install directory
|
||||
|
||||
```sh
|
||||
sudo script/grunt install --install-dir /install/atom/here
|
||||
```
|
||||
|
||||
### Custom build directory
|
||||
|
||||
```sh
|
||||
script/build --build-dir /build/atom/here
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Exception: "TypeError: Unable to watch path"
|
||||
|
||||
@@ -15,10 +15,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.$ = $
|
||||
module.exports.$$ = $$
|
||||
module.exports.$$$ = $$$
|
||||
if atom.config.get('core.useReactMiniEditors')
|
||||
module.exports.EditorView = require '../src/react-editor-view'
|
||||
else
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
module.exports.ScrollView = require '../src/scroll-view'
|
||||
module.exports.SelectListView = require '../src/select-list-view'
|
||||
module.exports.Task = require '../src/task'
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
'ctrl-n': 'application:new-file'
|
||||
'ctrl-s': 'core:save'
|
||||
'ctrl-S': 'core:save-as'
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-f4': 'core:close'
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-z': 'core:undo'
|
||||
'ctrl-shift-z': 'core:redo'
|
||||
'ctrl-y': 'core:redo'
|
||||
|
||||
@@ -133,16 +133,6 @@
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Window'
|
||||
submenu: [
|
||||
{ label: 'Mi&nimize', command: 'application:minimize' }
|
||||
{ label: 'Ma&ximize', command: 'application:zoom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Help'
|
||||
submenu: [
|
||||
|
||||
@@ -157,16 +157,6 @@
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Window'
|
||||
submenu: [
|
||||
{ label: 'Mi&nimize', command: 'application:minimize' }
|
||||
{ label: 'Ma&ximize', command: 'application:zoom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Help'
|
||||
submenu: [
|
||||
|
||||
+35
-34
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.121.0",
|
||||
"version": "0.124.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,10 +17,10 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.15.6",
|
||||
"atomShellVersion": "0.15.9",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^2",
|
||||
"atom-keymap": "^2.0.2",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
@@ -32,7 +32,7 @@
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^1.1",
|
||||
"git-utils": "^2.1.4",
|
||||
"grim": "0.11.0",
|
||||
"grim": "0.12.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
"less-cache": "0.13.0",
|
||||
@@ -41,7 +41,7 @@
|
||||
"nslog": "^1.0.1",
|
||||
"oniguruma": "^3.0.3",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^2.0.6",
|
||||
"pathwatcher": "^2.0.7",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
@@ -54,9 +54,9 @@
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.2.0",
|
||||
"space-pen": "3.4.1",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.0.0",
|
||||
"text-buffer": "^3.0.1",
|
||||
"theorist": "^1",
|
||||
"underscore-plus": "^1.5.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
@@ -70,37 +70,37 @@
|
||||
"base16-tomorrow-light-theme": "0.4.0",
|
||||
"solarized-dark-syntax": "0.22.0",
|
||||
"solarized-light-syntax": "0.12.0",
|
||||
"archive-view": "0.35.0",
|
||||
"archive-view": "0.36.0",
|
||||
"autocomplete": "0.31.0",
|
||||
"autoflow": "0.17.0",
|
||||
"autosave": "0.14.0",
|
||||
"background-tips": "0.15.0",
|
||||
"bookmarks": "0.27.0",
|
||||
"bracket-matcher": "0.53.0",
|
||||
"autoflow": "0.18.0",
|
||||
"autosave": "0.15.0",
|
||||
"background-tips": "0.16.0",
|
||||
"bookmarks": "0.28.0",
|
||||
"bracket-matcher": "0.54.0",
|
||||
"command-palette": "0.24.0",
|
||||
"deprecation-cop": "0.7.0",
|
||||
"deprecation-cop": "0.9.0",
|
||||
"dev-live-reload": "0.34.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
"feedback": "0.33.0",
|
||||
"find-and-replace": "0.128.0",
|
||||
"find-and-replace": "0.130.0",
|
||||
"fuzzy-finder": "0.57.0",
|
||||
"git-diff": "0.37.0",
|
||||
"git-diff": "0.39.0",
|
||||
"go-to-line": "0.24.0",
|
||||
"grammar-selector": "0.27.0",
|
||||
"grammar-selector": "0.29.0",
|
||||
"image-view": "0.36.0",
|
||||
"incompatible-packages": "0.6.0",
|
||||
"incompatible-packages": "0.9.0",
|
||||
"keybinding-resolver": "0.19.0",
|
||||
"link": "0.25.0",
|
||||
"markdown-preview": "0.99.0",
|
||||
"metrics": "0.33.0",
|
||||
"open-on-github": "0.29.0",
|
||||
"open-on-github": "0.30.0",
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.139.0",
|
||||
"settings-view": "0.140.0",
|
||||
"snippets": "0.51.0",
|
||||
"spell-check": "0.40.0",
|
||||
"status-bar": "0.42.0",
|
||||
"styleguide": "0.29.0",
|
||||
"spell-check": "0.42.0",
|
||||
"status-bar": "0.44.0",
|
||||
"styleguide": "0.30.0",
|
||||
"symbols-view": "0.63.0",
|
||||
"tabs": "0.49.0",
|
||||
"timecop": "0.22.0",
|
||||
@@ -110,27 +110,28 @@
|
||||
"whitespace": "0.25.0",
|
||||
"wrap-guide": "0.21.0",
|
||||
|
||||
"language-c": "0.27.0",
|
||||
"language-coffee-script": "0.29.0",
|
||||
"language-c": "0.28.0",
|
||||
"language-coffee-script": "0.30.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.46.0",
|
||||
"language-gfm": "0.48.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.16.0",
|
||||
"language-html": "0.24.0",
|
||||
"language-hyperlink": "0.10.0",
|
||||
"language-html": "0.25.0",
|
||||
"language-hyperlink": "0.12.0",
|
||||
"language-java": "0.11.0",
|
||||
"language-javascript": "0.39.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.13.0",
|
||||
"language-make": "0.10.0",
|
||||
"language-less": "0.14.0",
|
||||
"language-make": "0.12.0",
|
||||
"language-mustache": "0.10.0",
|
||||
"language-objective-c": "0.11.0",
|
||||
"language-perl": "0.9.0",
|
||||
"language-php": "0.15.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.18.0",
|
||||
"language-ruby": "0.34.0",
|
||||
"language-ruby-on-rails": "0.15.0",
|
||||
"language-sass": "0.15.0",
|
||||
"language-ruby": "0.35.0",
|
||||
"language-ruby-on-rails": "0.18.0",
|
||||
"language-sass": "0.19.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.8.0",
|
||||
"language-sql": "0.10.0",
|
||||
@@ -138,7 +139,7 @@
|
||||
"language-todo": "0.10.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.18.0",
|
||||
"language-yaml": "0.15.0"
|
||||
"language-yaml": "0.17.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
+5
-4
@@ -13,21 +13,22 @@ CONTROL_FILE="$3"
|
||||
DESKTOP_FILE="$4"
|
||||
ICON_FILE="$5"
|
||||
DEB_PATH="$6"
|
||||
FILE_MODE=755
|
||||
|
||||
TARGET_ROOT="`mktemp -d`"
|
||||
chmod 755 "$TARGET_ROOT"
|
||||
TARGET="$TARGET_ROOT/atom-$VERSION-$ARCH"
|
||||
|
||||
mkdir -p "$TARGET/usr"
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr"
|
||||
env INSTALL_PREFIX="$TARGET/usr" script/grunt install
|
||||
|
||||
mkdir -p "$TARGET/DEBIAN"
|
||||
mkdir -m $FILE_MODE -p "$TARGET/DEBIAN"
|
||||
cp "$CONTROL_FILE" "$TARGET/DEBIAN/control"
|
||||
|
||||
mkdir -p "$TARGET/usr/share/applications"
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr/share/applications"
|
||||
cp "$DESKTOP_FILE" "$TARGET/usr/share/applications"
|
||||
|
||||
mkdir -p "$TARGET/usr/share/pixmaps"
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr/share/pixmaps"
|
||||
cp "$ICON_FILE" "$TARGET/usr/share/pixmaps"
|
||||
|
||||
dpkg-deb -b "$TARGET"
|
||||
|
||||
@@ -119,14 +119,14 @@ class AtomReporter extends View
|
||||
grim.clearDeprecations()
|
||||
|
||||
handleEvents: ->
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) =>
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) ->
|
||||
element = $(currentTarget)
|
||||
specFailures = element.parent().find('.spec-failures')
|
||||
specFailures.toggle()
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
$(document).on "click", ".deprecation-toggle", ({currentTarget}) =>
|
||||
$(document).on "click", ".deprecation-toggle", ({currentTarget}) ->
|
||||
element = $(currentTarget)
|
||||
deprecationList = $(document).find('.deprecation-list')
|
||||
deprecationList.toggle()
|
||||
|
||||
@@ -23,6 +23,18 @@ describe "Config", ->
|
||||
retrievedValue.array[1].b = 2.1
|
||||
expect(atom.config.get('value')).toEqual(array: [1, b: 2, 3])
|
||||
|
||||
it "merges defaults into the returned value if both the assigned value and the default value are objects", ->
|
||||
atom.config.setDefaults("foo", a: 1, b: 2)
|
||||
atom.config.set("foo", a: 3)
|
||||
expect(atom.config.get("foo")).toEqual {a: 3, b: 2}
|
||||
|
||||
atom.config.set("foo", 7)
|
||||
expect(atom.config.get("foo")).toBe 7
|
||||
|
||||
atom.config.set("bar.baz", a: 3)
|
||||
atom.config.setDefaults("bar", baz: 7)
|
||||
expect(atom.config.get("bar.baz")).toEqual {a: 3}
|
||||
|
||||
describe ".set(keyPath, value)", ->
|
||||
it "allows a key path's value to be written", ->
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
|
||||
|
||||
@@ -1037,6 +1037,19 @@ describe "DisplayBuffer", ->
|
||||
expect(start.top).toBe 5 * 20
|
||||
expect(start.left).toBe (4 * 10) + (6 * 11)
|
||||
|
||||
describe 'when there are multiple DisplayBuffers for a buffer', ->
|
||||
describe 'when a marker is created', ->
|
||||
it 'the second display buffer will not emit a marker-created event when the marker has been deleted in the first marker-created event', ->
|
||||
displayBuffer2 = new DisplayBuffer({buffer, tabLength})
|
||||
displayBuffer.on 'marker-created', markerCreated1 = jasmine.createSpy().andCallFake (marker) ->
|
||||
marker.destroy()
|
||||
displayBuffer2.on 'marker-created', markerCreated2 = jasmine.createSpy()
|
||||
|
||||
displayBuffer.markBufferRange([[0, 0], [1, 5]], {})
|
||||
|
||||
expect(markerCreated1).toHaveBeenCalled()
|
||||
expect(markerCreated2).not.toHaveBeenCalled()
|
||||
|
||||
describe "decorations", ->
|
||||
[marker, decoration, decorationParams] = []
|
||||
beforeEach ->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
_ = require 'underscore-plus'
|
||||
{extend, flatten, toArray, last} = _
|
||||
|
||||
ReactEditorView = require '../src/react-editor-view'
|
||||
EditorView = require '../src/editor-view'
|
||||
EditorComponent = require '../src/editor-component'
|
||||
nbsp = String.fromCharCode(160)
|
||||
|
||||
@@ -34,7 +34,7 @@ describe "EditorComponent", ->
|
||||
contentNode = document.querySelector('#jasmine-content')
|
||||
contentNode.style.width = '1000px'
|
||||
|
||||
wrapperView = new ReactEditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView = new EditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView.attachToDom()
|
||||
wrapperNode = wrapperView.element
|
||||
|
||||
@@ -209,25 +209,32 @@ describe "EditorComponent", ->
|
||||
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
atom.config.set("editor.invisibles", invisibles)
|
||||
nextAnimationFrame()
|
||||
|
||||
it "re-renders the lines when the showInvisibles config option changes", ->
|
||||
editor.setText " a line with tabs\tand spaces "
|
||||
editor.setText " a line with tabs\tand spaces \n"
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
atom.config.set("editor.showInvisibles", false)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe " a line with tabs and spaces "
|
||||
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
it "displays spaces, tabs, and newlines as visible characters", ->
|
||||
editor.setText " a line with tabs\tand spaces "
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
it "displays leading/trailing spaces, tabs, and newlines as visible characters", ->
|
||||
editor.setText " a line with tabs\tand spaces \n"
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
|
||||
expect(leafNodes[0].classList.contains('invisible-character')).toBe true
|
||||
expect(leafNodes[leafNodes.length - 1].classList.contains('invisible-character')).toBe true
|
||||
|
||||
it "displays newlines as their own token outside of the other tokens' scopes", ->
|
||||
editor.setText "var"
|
||||
editor.setText "var\n"
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).innerHTML).toBe "<span class=\"source js\"><span class=\"storage modifier js\">var</span></span><span class=\"invisible-character\">#{invisibles.eol}</span>"
|
||||
|
||||
@@ -241,10 +248,12 @@ describe "EditorComponent", ->
|
||||
|
||||
it "renders an nbsp on empty lines when the line-ending character is an empty string", ->
|
||||
atom.config.set("editor.invisibles", eol: '')
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp
|
||||
|
||||
it "renders an nbsp on empty lines when no line-ending character is defined", ->
|
||||
atom.config.set("editor.invisibles", eol: null)
|
||||
it "renders an nbsp on empty lines when the line-ending character is false", ->
|
||||
atom.config.set("editor.invisibles", eol: false)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp
|
||||
|
||||
it "interleaves invisible line-ending characters with indent guides on empty lines", ->
|
||||
@@ -268,7 +277,7 @@ describe "EditorComponent", ->
|
||||
|
||||
describe "when soft wrapping is enabled", ->
|
||||
beforeEach ->
|
||||
editor.setText "a line that wraps "
|
||||
editor.setText "a line that wraps \n"
|
||||
editor.setSoftWrap(true)
|
||||
nextAnimationFrame()
|
||||
componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
|
||||
@@ -1309,6 +1318,12 @@ describe "EditorComponent", ->
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([4, 8]), {target}))
|
||||
expect(editor.isFoldedAtBufferRow 4).toBe false
|
||||
|
||||
describe "when the horizontal scrollbar is interacted with", ->
|
||||
it "clicking on the scrollbar does not move the cursor", ->
|
||||
target = horizontalScrollbarNode
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([4, 8]), {target}))
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
|
||||
|
||||
describe "mouse interactions on the gutter", ->
|
||||
gutterNode = null
|
||||
|
||||
@@ -1542,6 +1557,7 @@ describe "EditorComponent", ->
|
||||
height: 8px;
|
||||
}
|
||||
"""
|
||||
nextAnimationFrame()
|
||||
|
||||
scrollbarCornerNode = componentNode.querySelector('.scrollbar-corner')
|
||||
expect(verticalScrollbarNode.offsetWidth).toBe 8
|
||||
@@ -1895,7 +1911,7 @@ describe "EditorComponent", ->
|
||||
hiddenParent.style.display = 'none'
|
||||
contentNode.appendChild(hiddenParent)
|
||||
|
||||
wrapperView = new ReactEditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView = new EditorView(editor, {lineOverdrawMargin})
|
||||
wrapperNode = wrapperView.element
|
||||
wrapperView.appendTo(hiddenParent)
|
||||
|
||||
@@ -1937,6 +1953,7 @@ describe "EditorComponent", ->
|
||||
wrapperView.hide()
|
||||
|
||||
component.setFontSize(22)
|
||||
editor.getBuffer().insert([0, 0], 'a') # regression test against atom/atom#3318
|
||||
|
||||
wrapperView.show()
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
@@ -2107,8 +2124,9 @@ describe "EditorComponent", ->
|
||||
expect(component.refs.lines.getDOMNode().getAttribute('style')).not.toContain 'background-color'
|
||||
|
||||
it "does not render invisible characters", ->
|
||||
component.setInvisibles(eol: 'E')
|
||||
component.setShowInvisibles(true)
|
||||
atom.config.set('editor.invisibles', eol: 'E')
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe 'var quicksort = function () {'
|
||||
|
||||
it "does not assign an explicit line-height on the editor contents", ->
|
||||
@@ -2147,6 +2165,12 @@ describe "EditorComponent", ->
|
||||
setEditorWidthInChars(wrapperView, 10)
|
||||
expect(componentNode.querySelector('.scroll-view').offsetWidth).toBe charWidth * 10
|
||||
|
||||
describe "grammar data attributes", ->
|
||||
it "adds and updates the grammar data attribute based on the current grammar", ->
|
||||
expect(wrapperNode.dataset.grammar).toBe 'source js'
|
||||
editor.setGrammar(atom.syntax.nullGrammar)
|
||||
expect(wrapperNode.dataset.grammar).toBe 'text plain null-grammar'
|
||||
|
||||
buildMouseEvent = (type, properties...) ->
|
||||
properties = extend({bubbles: true, cancelable: true}, properties...)
|
||||
properties.detail ?= 1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
clipboard = require 'clipboard'
|
||||
Editor = require '../src/editor'
|
||||
|
||||
describe "Editor", ->
|
||||
[buffer, editor, lineLengths] = []
|
||||
@@ -33,6 +34,26 @@ describe "Editor", ->
|
||||
expect(editor2.isFoldedAtBufferRow(4)).toBeTruthy()
|
||||
editor2.destroy()
|
||||
|
||||
it "preserves the invisibles setting", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
previousInvisibles = editor.displayBuffer.invisibles
|
||||
|
||||
editor2 = editor.testSerialization()
|
||||
|
||||
expect(editor2.displayBuffer.invisibles).toEqual previousInvisibles
|
||||
expect(editor2.displayBuffer.tokenizedBuffer.invisibles).toEqual previousInvisibles
|
||||
|
||||
it "updates invisibles if the settings have changed between serialization and deserialization", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
previousInvisibles = editor.displayBuffer.invisibles
|
||||
|
||||
state = editor.serialize()
|
||||
atom.config.set('editor.invisibles', eol: '?')
|
||||
editor2 = Editor.deserialize(state)
|
||||
|
||||
expect(editor2.displayBuffer.invisibles.eol).toBe '?'
|
||||
expect(editor2.displayBuffer.tokenizedBuffer.invisibles.eol).toBe '?'
|
||||
|
||||
describe "when the editor is constructed with an initialLine option", ->
|
||||
it "positions the cursor on the specified line", ->
|
||||
editor = null
|
||||
@@ -499,6 +520,26 @@ describe "Editor", ->
|
||||
cursor = editor.getCursor()
|
||||
expect(cursor.getBufferPosition()).toEqual [1,0]
|
||||
|
||||
describe "when invisible characters are enabled with soft tabs", ->
|
||||
it "moves to the first character of the current line without being confused by the invisible characters", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
editor.setCursorScreenPosition [1,7]
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1,2]
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1,0]
|
||||
|
||||
describe "when invisible characters are enabled with hard tabs", ->
|
||||
it "moves to the first character of the current line without being confused by the invisible characters", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', false)
|
||||
|
||||
editor.setCursorScreenPosition [1,7]
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1,3]
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1,0]
|
||||
|
||||
describe ".moveCursorToBeginningOfWord()", ->
|
||||
it "moves the cursor to the beginning of the word", ->
|
||||
editor.setCursorBufferPosition [0, 8]
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -119,6 +119,38 @@ describe "Git", ->
|
||||
repo.checkoutHead(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe ".checkoutHeadForEditor(editor)", ->
|
||||
[filePath, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
workingDirPath = copyRepository()
|
||||
repo = new Git(workingDirPath)
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
|
||||
runs ->
|
||||
editor = atom.workspace.getActiveEditor()
|
||||
|
||||
it "displays a confirmation dialog by default", ->
|
||||
spyOn(atom, 'confirm').andCallFake ({buttons}) -> buttons.OK()
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', true)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
|
||||
|
||||
it "does not display a dialog when confirmation is disabled", ->
|
||||
spyOn(atom, 'confirm')
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', false)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
|
||||
expect(atom.confirm).not.toHaveBeenCalled()
|
||||
|
||||
describe ".destroy()", ->
|
||||
it "throws an exception when any method is called after it is called", ->
|
||||
repo = new Git(require.resolve('./fixtures/git/master.git/HEAD'))
|
||||
|
||||
@@ -95,7 +95,6 @@ beforeEach ->
|
||||
config.set "editor.autoIndent", false
|
||||
config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]
|
||||
config.set "core.useReactEditor", true
|
||||
config.save.reset()
|
||||
atom.config = config
|
||||
|
||||
@@ -211,6 +210,13 @@ addCustomMatchers = (spec) ->
|
||||
element = element.get(0) if element.jquery
|
||||
element.webkitMatchesSelector(":focus") or element.querySelector(":focus")
|
||||
|
||||
toShow: ->
|
||||
notText = if @isNot then " not" else ""
|
||||
element = @actual
|
||||
element = element.get(0) if element.jquery
|
||||
@message = -> return "Expected element '#{element}' or its descendants #{notText} to show."
|
||||
element.style.display in ['block', 'inline-block', 'static', 'fixed']
|
||||
|
||||
window.keyIdentifierForKey = (key) ->
|
||||
if key.length > 1 # named key
|
||||
key
|
||||
|
||||
@@ -247,6 +247,21 @@ describe "ThemeManager", ->
|
||||
# from within the theme itself
|
||||
expect($(".editor").css("background-color")).toBe "rgb(0, 152, 255)"
|
||||
|
||||
describe "theme classes on the workspace", ->
|
||||
it 'adds theme-* classes to the workspace for each active theme', ->
|
||||
expect(atom.workspaceView).toHaveClass 'theme-atom-dark-ui'
|
||||
|
||||
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables'])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
# `theme-` twice as it prefixes the name with `theme-`
|
||||
expect(atom.workspaceView).toHaveClass 'theme-theme-with-ui-variables'
|
||||
expect(atom.workspaceView).not.toHaveClass 'theme-atom-dark-ui'
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
it "reloads it", ->
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
|
||||
@@ -18,7 +18,7 @@ class TimeReporter extends jasmine.Reporter
|
||||
log ?= (line) -> console.log(line)
|
||||
log "Longest running suites:"
|
||||
suites = _.map(window.timedSuites, (key, value) -> [value, key])
|
||||
for suite in _.sortBy(suites, (suite) => -suite[1])[0...number]
|
||||
for suite in _.sortBy(suites, (suite) -> -suite[1])[0...number]
|
||||
time = Math.round(suite[1] / 100) / 10
|
||||
log " #{suite[0]} (#{time}s)"
|
||||
undefined
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
TextBuffer = require 'text-buffer'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
describe "TokenizedBuffer", ->
|
||||
@@ -12,6 +13,9 @@ describe "TokenizedBuffer", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
tokenizedBuffer?.destroy()
|
||||
|
||||
startTokenizing = (tokenizedBuffer) ->
|
||||
tokenizedBuffer.setVisible(true)
|
||||
|
||||
@@ -584,51 +588,113 @@ describe "TokenizedBuffer", ->
|
||||
atom.config.set('editor.tabLength', 0)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
describe "when the invisibles value changes", ->
|
||||
beforeEach ->
|
||||
|
||||
it "updates the tokens with the appropriate invisible characters", ->
|
||||
buffer = new TextBuffer(text: " \t a line with tabs\tand \tspaces \t ")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS"
|
||||
# Also needs to work for copies
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).copy().text).toBe "SST Sa line with tabsTand T spacesSTS"
|
||||
|
||||
it "assigns endOfLineInvisibles to tokenized lines", ->
|
||||
buffer = new TextBuffer(text: "a line that ends in a carriage-return-line-feed \r\na line that ends in just a line-feed\na line with no ending")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
tokenizedBuffer.setInvisibles(cr: 'R', eol: 'N')
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).endOfLineInvisibles).toEqual ['R', 'N']
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).endOfLineInvisibles).toEqual ['N']
|
||||
|
||||
# Lines ending in soft wraps get no invisibles
|
||||
[left, right] = tokenizedBuffer.lineForScreenRow(0).softWrapAt(20)
|
||||
expect(left.endOfLineInvisibles).toBe null
|
||||
expect(right.endOfLineInvisibles).toEqual ['R', 'N']
|
||||
|
||||
tokenizedBuffer.setInvisibles(cr: 'R', eol: false)
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).endOfLineInvisibles).toEqual ['R']
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).endOfLineInvisibles).toEqual []
|
||||
|
||||
describe "leading and trailing whitespace", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
it "sets ::hasLeadingWhitespace to true on tokens that have leading whitespace", ->
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2].hasLeadingWhitespace).toBe false
|
||||
it "assigns ::firstNonWhitespaceIndex on tokens that have leading whitespace", ->
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0].firstNonWhitespaceIndex).toBe null
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].firstNonWhitespaceIndex).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
# The 4th token *has* leading whitespace, but isn't entirely whitespace
|
||||
buffer.insert([5, 0], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[3].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[3].firstNonWhitespaceIndex).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
# Lines that are *only* whitespace are not considered to have leading whitespace
|
||||
buffer.insert([10, 0], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
it "sets ::hasTrailingWhitespace to true on tokens that have trailing whitespace", ->
|
||||
it "assigns ::firstTrailingWhitespaceIndex on tokens that have trailing whitespace", ->
|
||||
buffer.insert([0, Infinity], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[11].hasTrailingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[12].hasTrailingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[11].firstTrailingWhitespaceIndex).toBe null
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[12].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
# The last token *has* trailing whitespace, but isn't entirely whitespace
|
||||
buffer.setTextInRange([[2, 39], [2, 40]], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[14].hasTrailingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[15].hasTrailingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[14].firstTrailingWhitespaceIndex).toBe null
|
||||
console.log tokenizedBuffer.lineForScreenRow(2).tokens[15]
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[15].firstTrailingWhitespaceIndex).toBe 6
|
||||
|
||||
# Lines that are *only* whitespace are considered to have trailing whitespace
|
||||
buffer.insert([10, 0], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].hasTrailingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
it "only marks trailing whitespace on the last segment of a soft-wrapped line", ->
|
||||
buffer.insert([0, Infinity], ' ')
|
||||
tokenizedLine = tokenizedBuffer.lineForScreenRow(0)
|
||||
[segment1, segment2] = tokenizedLine.softWrapAt(16)
|
||||
expect(segment1.tokens[5].value).toBe ' '
|
||||
expect(segment1.tokens[5].hasTrailingWhitespace).toBe false
|
||||
expect(segment1.tokens[5].firstTrailingWhitespaceIndex).toBe null
|
||||
expect(segment2.tokens[6].value).toBe ' '
|
||||
expect(segment2.tokens[6].hasTrailingWhitespace).toBe true
|
||||
expect(segment2.tokens[6].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
it "sets leading and trailing whitespace correctly on a line with invisible characters that is copied", ->
|
||||
buffer.setText(" \t a line with tabs\tand \tspaces \t ")
|
||||
|
||||
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
line = tokenizedBuffer.lineForScreenRow(0).copy()
|
||||
expect(line.tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", ->
|
||||
tokenizedBuffer.setInvisibles(space: 'S')
|
||||
buffer.setText(" token ")
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
token = tokenizedBuffer.tokenizedLines[0].tokens[0]
|
||||
|
||||
[leftToken, rightToken] = token.splitAt(1)
|
||||
expect(leftToken.hasInvisibleCharacters).toBe true
|
||||
expect(leftToken.firstNonWhitespaceIndex).toBe 1
|
||||
expect(leftToken.firstTrailingWhitespaceIndex).toBe null
|
||||
|
||||
expect(leftToken.hasInvisibleCharacters).toBe true
|
||||
expect(rightToken.firstNonWhitespaceIndex).toBe null
|
||||
expect(rightToken.firstTrailingWhitespaceIndex).toBe 5
|
||||
|
||||
describe "indent level", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -195,13 +195,12 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.height(200)
|
||||
atom.workspaceView.attachToDom()
|
||||
rightEditorView = atom.workspaceView.getActiveView()
|
||||
rightEditorView.getEditor().setText("\t ")
|
||||
rightEditorView.getEditor().setText("\t \n")
|
||||
leftEditorView = rightEditorView.splitLeft()
|
||||
expect(rightEditorView.find(".line:first").text()).toBe " "
|
||||
expect(leftEditorView.find(".line:first").text()).toBe " "
|
||||
|
||||
{invisibles} = rightEditorView.component.state
|
||||
{space, tab, eol} = invisibles
|
||||
{space, tab, eol} = atom.config.get('editor.invisibles')
|
||||
withInvisiblesShowing = "#{tab} #{space}#{space}#{eol}"
|
||||
|
||||
atom.workspaceView.trigger "window:toggle-invisibles"
|
||||
|
||||
+41
-6
@@ -111,6 +111,7 @@ class Atom extends Model
|
||||
remote.getCurrentWindow()
|
||||
|
||||
workspaceViewParentSelector: 'body'
|
||||
lastUncaughtError: null
|
||||
|
||||
# Call .loadOrCreate instead
|
||||
constructor: (@state) ->
|
||||
@@ -125,6 +126,7 @@ class Atom extends Model
|
||||
window.onerror = =>
|
||||
@openDevTools()
|
||||
@executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()')
|
||||
@lastUncaughtError = Array::slice.call(arguments)
|
||||
@emit 'uncaught-error', arguments...
|
||||
|
||||
@unsubscribe()
|
||||
@@ -196,7 +198,8 @@ class Atom extends Model
|
||||
browserWindow = @getCurrentWindow()
|
||||
[x, y] = browserWindow.getPosition()
|
||||
[width, height] = browserWindow.getSize()
|
||||
{x, y, width, height}
|
||||
maximized = browserWindow.isMaximized()
|
||||
{x, y, width, height, maximized}
|
||||
|
||||
# Public: Set the dimensions of the window.
|
||||
#
|
||||
@@ -249,6 +252,7 @@ class Atom extends Model
|
||||
unless @isValidDimensions(dimensions)
|
||||
dimensions = @getDefaultWindowDimensions()
|
||||
@setWindowDimensions(dimensions)
|
||||
dimensions
|
||||
|
||||
storeWindowDimensions: ->
|
||||
dimensions = @getWindowDimensions()
|
||||
@@ -298,7 +302,7 @@ class Atom extends Model
|
||||
CommandInstaller.installApmCommand resourcePath, false, (error) ->
|
||||
console.warn error.message if error?
|
||||
|
||||
@restoreWindowDimensions()
|
||||
dimensions = @restoreWindowDimensions()
|
||||
@config.load()
|
||||
@config.setDefaults('core', require('./workspace-view').configDefaults)
|
||||
@config.setDefaults('editor', require('./editor-view').configDefaults)
|
||||
@@ -306,12 +310,16 @@ class Atom extends Model
|
||||
@themes.loadBaseStylesheets()
|
||||
@packages.loadPackages()
|
||||
@deserializeEditorWindow()
|
||||
|
||||
@watchProjectPath()
|
||||
|
||||
@packages.activate()
|
||||
@keymaps.loadUserKeymap()
|
||||
@requireUserInitScript()
|
||||
@menu.update()
|
||||
|
||||
@displayWindow()
|
||||
maximize = dimensions?.maximized and process.platform isnt 'darwin'
|
||||
@displayWindow({maximize})
|
||||
|
||||
unloadEditorWindow: ->
|
||||
return if not @project and not @workspaceView
|
||||
@@ -344,13 +352,29 @@ class Atom extends Model
|
||||
pack.reloadStylesheets?()
|
||||
null
|
||||
|
||||
# Notify the browser project of the window's current project path
|
||||
watchProjectPath: ->
|
||||
onProjectPathChanged = =>
|
||||
ipc.send('window-command', 'project-path-changed', @project.getPath())
|
||||
@subscribe @project, 'path-changed', onProjectPathChanged
|
||||
onProjectPathChanged()
|
||||
|
||||
# Public: Open a new Atom window using the given options.
|
||||
#
|
||||
# Calling this method without an options parameter will open a prompt to pick
|
||||
# a file/folder to open in the new window.
|
||||
#
|
||||
# options - An {Object} with the following keys:
|
||||
# :pathsToOpen - An {Array} of {String} paths to open.
|
||||
# :pathsToOpen - An {Array} of {String} paths to open.
|
||||
# :newWindow - A {Boolean}, true to always open a new window instead of
|
||||
# reusing existing windows depending on the paths to open.
|
||||
# :devMode - A {Boolean}, true to open the window in development mode.
|
||||
# Development mode loads the Atom source from the locally
|
||||
# cloned repository and also loads all the packages in
|
||||
# ~/.atom/dev/packages
|
||||
# :safeMode - A {Boolean}, true to open the window in safe mode. Safe
|
||||
# mode prevents all packages installed to ~/.atom/packages
|
||||
# from loading.
|
||||
open: (options) ->
|
||||
ipc.send('open', options)
|
||||
|
||||
@@ -451,15 +475,17 @@ class Atom extends Model
|
||||
center: ->
|
||||
ipc.send('call-window-method', 'center')
|
||||
|
||||
|
||||
# Schedule the window to be shown and focused on the next tick.
|
||||
#
|
||||
# This is done in a next tick to prevent a white flicker from occurring
|
||||
# if called synchronously.
|
||||
displayWindow: ->
|
||||
displayWindow: ({maximize}={}) ->
|
||||
setImmediate =>
|
||||
@show()
|
||||
@focus()
|
||||
@setFullScreen(true) if @workspaceView.fullScreen
|
||||
@setFullScreen(true) if @workspace.fullScreen
|
||||
@maximize() if maximize
|
||||
|
||||
# Public: Close the current window.
|
||||
close: ->
|
||||
@@ -470,6 +496,12 @@ class Atom extends Model
|
||||
app.emit('will-exit')
|
||||
remote.process.exit(status)
|
||||
|
||||
setDocumentEdited: (edited) ->
|
||||
ipc.send('call-window-method', 'setDocumentEdited', edited)
|
||||
|
||||
setRepresentedFilename: (filename) ->
|
||||
ipc.send('call-window-method', 'setRepresentedFilename', filename)
|
||||
|
||||
# Public: Is the current window in development mode?
|
||||
inDevMode: ->
|
||||
@getLoadSettings().devMode
|
||||
@@ -491,6 +523,9 @@ class Atom extends Model
|
||||
isFullScreen: ->
|
||||
@getCurrentWindow().isFullScreen()
|
||||
|
||||
maximize: ->
|
||||
ipc.send('call-window-method', 'maximize')
|
||||
|
||||
# Public: Get the version of the Atom application.
|
||||
#
|
||||
# Returns the version text {String}.
|
||||
|
||||
@@ -116,7 +116,7 @@ class ApplicationMenu
|
||||
item.metadata ?= {}
|
||||
if item.command
|
||||
item.accelerator = @acceleratorForCommand(item.command, keystrokesByCommand)
|
||||
item.click = => global.atomApplication.sendCommand(item.command)
|
||||
item.click = -> global.atomApplication.sendCommand(item.command)
|
||||
item.metadata['windowSpecific'] = true unless /^application:/.test(item.command)
|
||||
@translateTemplate(item.submenu, keystrokesByCommand) if item.submenu
|
||||
template
|
||||
|
||||
@@ -103,6 +103,12 @@ class AtomApplication
|
||||
window.once 'window:loaded', =>
|
||||
@autoUpdateManager.emitUpdateAvailableEvent(window)
|
||||
|
||||
focusHandler = => @lastFocusedWindow = window
|
||||
window.browserWindow.on 'focus', focusHandler
|
||||
window.browserWindow.once 'closed', =>
|
||||
@lastFocusedWindow = null if window is @lastFocusedWindow
|
||||
window.browserWindow.removeListener 'focus', focusHandler
|
||||
|
||||
# Creates server to listen for additional atom application launches.
|
||||
#
|
||||
# You can run the atom command multiple times, but after the first launch
|
||||
@@ -199,13 +205,15 @@ class AtomApplication
|
||||
|
||||
# A request from the associated render process to open a new render process.
|
||||
ipc.on 'open', (event, options) =>
|
||||
window = @windowForEvent(event)
|
||||
if options?
|
||||
if options.pathsToOpen?.length > 0
|
||||
options.window = window
|
||||
@openPaths(options)
|
||||
else
|
||||
new AtomWindow(options)
|
||||
else
|
||||
@promptForPath()
|
||||
@promptForPath({window})
|
||||
|
||||
ipc.on 'update-application-menu', (event, template, keystrokesByCommand) =>
|
||||
@applicationMenu.update(template, keystrokesByCommand)
|
||||
@@ -281,8 +289,12 @@ class AtomApplication
|
||||
|
||||
# Returns the {AtomWindow} for the given path.
|
||||
windowForPath: (pathToOpen) ->
|
||||
for atomWindow in @windows
|
||||
return atomWindow if atomWindow.containsPath(pathToOpen)
|
||||
_.find @windows, (atomWindow) -> atomWindow.containsPath(pathToOpen)
|
||||
|
||||
# Returns the {AtomWindow} for the given ipc event.
|
||||
windowForEvent: ({sender}) ->
|
||||
window = BrowserWindow.fromWebContents(sender)
|
||||
_.find @windows, ({browserWindow}) -> window is browserWindow
|
||||
|
||||
# Public: Returns the currently focused {AtomWindow} or undefined if none.
|
||||
focusedWindow: ->
|
||||
@@ -296,9 +308,10 @@ class AtomApplication
|
||||
# :newWindow - Boolean of whether this should be opened in a new window.
|
||||
# :devMode - Boolean to control the opened window's dev mode.
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode}) ->
|
||||
# :window - {AtomWindow} to open file paths in.
|
||||
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window}) ->
|
||||
for pathToOpen in pathsToOpen ? []
|
||||
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode})
|
||||
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window})
|
||||
|
||||
# Public: Opens a single path, in an existing window if possible.
|
||||
#
|
||||
@@ -309,15 +322,30 @@ class AtomApplication
|
||||
# :devMode - Boolean to control the opened window's dev mode.
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
# :windowDimensions - Object with height and width keys.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions}={}) ->
|
||||
# :window - {AtomWindow} to open file paths in.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}={}) ->
|
||||
{pathToOpen, initialLine, initialColumn} = @locationForPathToOpen(pathToOpen)
|
||||
|
||||
unless devMode
|
||||
existingWindow = @windowForPath(pathToOpen) unless pidToKillWhenClosed or newWindow
|
||||
if existingWindow
|
||||
unless pidToKillWhenClosed or newWindow
|
||||
pathToOpenStat = fs.statSyncNoException(pathToOpen)
|
||||
|
||||
# Default to using the specified window or the last focused window
|
||||
currentWindow = window ? @lastFocusedWindow
|
||||
|
||||
if pathToOpenStat.isFile?()
|
||||
# Open the file in the current window
|
||||
existingWindow = currentWindow
|
||||
else if pathToOpenStat.isDirectory?()
|
||||
# Open the folder in the current window if it doesn't have a path
|
||||
existingWindow = currentWindow unless currentWindow?.hasProjectPath()
|
||||
|
||||
# Don't reuse windows in dev mode
|
||||
existingWindow ?= @windowForPath(pathToOpen) unless devMode
|
||||
|
||||
if existingWindow?
|
||||
openedWindow = existingWindow
|
||||
openedWindow.openPath(pathToOpen, initialLine)
|
||||
openedWindow.restore()
|
||||
openedWindow.restore() if openedWindow.isMinimized()
|
||||
else
|
||||
if devMode
|
||||
try
|
||||
@@ -331,7 +359,7 @@ class AtomApplication
|
||||
if pidToKillWhenClosed?
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
|
||||
openedWindow.browserWindow.on 'closed', =>
|
||||
openedWindow.browserWindow.once 'closed', =>
|
||||
@killProcessForWindow(openedWindow)
|
||||
|
||||
# Kill all processes associated with opened windows.
|
||||
@@ -407,14 +435,17 @@ class AtomApplication
|
||||
safeMode ?= false
|
||||
new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode})
|
||||
|
||||
runBenchmarks: ->
|
||||
runBenchmarks: ({exitWhenDone, specDirectory}={}) ->
|
||||
try
|
||||
bootstrapScript = require.resolve(path.resolve(global.devResourcePath, 'benchmark', 'benchmark-bootstrap'))
|
||||
catch error
|
||||
bootstrapScript = require.resolve(path.resolve(__dirname, '..', '..', 'benchmark', 'benchmark-bootstrap'))
|
||||
|
||||
specDirectory ?= path.dirname(bootstrapScript)
|
||||
|
||||
isSpec = true
|
||||
new AtomWindow({bootstrapScript, @resourcePath, isSpec})
|
||||
devMode = true
|
||||
new AtomWindow({bootstrapScript, @resourcePath, exitWhenDone, isSpec, specDirectory, devMode})
|
||||
|
||||
locationForPathToOpen: (pathToOpen) ->
|
||||
return {pathToOpen} unless pathToOpen
|
||||
@@ -441,7 +472,8 @@ class AtomApplication
|
||||
# should be in dev mode or not.
|
||||
# :safeMode - A Boolean which controls whether any newly opened windows
|
||||
# should be in safe mode or not.
|
||||
promptForPath: ({type, devMode, safeMode}={}) ->
|
||||
# :window - An {AtomWindow} to use for opening a selected file path.
|
||||
promptForPath: ({type, devMode, safeMode, window}={}) ->
|
||||
type ?= 'all'
|
||||
properties =
|
||||
switch type
|
||||
@@ -450,4 +482,4 @@ class AtomApplication
|
||||
when 'all' then ['openFile', 'openDirectory']
|
||||
else throw new Error("#{type} is an invalid type for promptForPath")
|
||||
dialog.showOpenDialog title: 'Open', properties: properties.concat(['multiSelections', 'createDirectory']), (pathsToOpen) =>
|
||||
@openPaths({pathsToOpen, devMode, safeMode})
|
||||
@openPaths({pathsToOpen, devMode, safeMode, window})
|
||||
|
||||
@@ -25,9 +25,9 @@ class AtomWindow
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
|
||||
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
|
||||
global.atomApplication.addWindow(this)
|
||||
|
||||
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
|
||||
@handleEvents()
|
||||
|
||||
loadSettings = _.extend({}, settings)
|
||||
@@ -49,6 +49,8 @@ class AtomWindow
|
||||
@emit 'window:loaded'
|
||||
@loaded = true
|
||||
|
||||
@browserWindow.on 'project-path-changed', (@projectPath) =>
|
||||
|
||||
@browserWindow.loadUrl @getUrl(loadSettings)
|
||||
@browserWindow.focusOnWebView() if @isSpec
|
||||
|
||||
@@ -66,6 +68,8 @@ class AtomWindow
|
||||
slashes: true
|
||||
query: {loadSettings: JSON.stringify(loadSettings)}
|
||||
|
||||
hasProjectPath: -> @projectPath?.length > 0
|
||||
|
||||
getInitialPath: ->
|
||||
@browserWindow.loadSettings.initialPath
|
||||
|
||||
@@ -169,6 +173,8 @@ class AtomWindow
|
||||
|
||||
isFocused: -> @browserWindow.isFocused()
|
||||
|
||||
isMinimized: -> @browserWindow.isMinimized()
|
||||
|
||||
isWebViewFocused: -> @browserWindow.isWebViewFocused()
|
||||
|
||||
isSpecWindow: -> @isSpec
|
||||
|
||||
@@ -74,7 +74,7 @@ class AutoUpdateManager
|
||||
getState: ->
|
||||
@state
|
||||
|
||||
check: ({hidePopups}={})->
|
||||
check: ({hidePopups}={}) ->
|
||||
unless hidePopups
|
||||
autoUpdater.once 'update-not-available', @onUpdateNotAvailable
|
||||
autoUpdater.once 'error', @onUpdateError
|
||||
|
||||
@@ -63,7 +63,14 @@ parseCommandLine = ->
|
||||
options.usage """
|
||||
Atom Editor v#{version}
|
||||
|
||||
Usage: atom [options] [file ...]
|
||||
Usage: atom [options] [path ...]
|
||||
|
||||
One or more paths to files or folders to open may be specified.
|
||||
|
||||
File paths will open in the current window.
|
||||
|
||||
Folder paths will open in an existing window if that folder has already been
|
||||
opened or a new window if it hasn't.
|
||||
"""
|
||||
options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.')
|
||||
options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.')
|
||||
|
||||
@@ -41,7 +41,7 @@ module.exports =
|
||||
callback()
|
||||
return
|
||||
|
||||
symlinkCommand commandPath, destinationPath, (error) =>
|
||||
symlinkCommand commandPath, destinationPath, (error) ->
|
||||
if askForPrivilege and error?.code is 'EACCES'
|
||||
try
|
||||
error = null
|
||||
|
||||
+14
-3
@@ -39,7 +39,7 @@ class Config
|
||||
|
||||
fs.makeTreeSync(@configDirPath)
|
||||
|
||||
queue = async.queue ({sourcePath, destinationPath}, callback) =>
|
||||
queue = async.queue ({sourcePath, destinationPath}, callback) ->
|
||||
fs.copy(sourcePath, destinationPath, callback)
|
||||
queue.drain = done
|
||||
|
||||
@@ -103,8 +103,19 @@ class Config
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file, or `null` if the key doesn't exist in either.
|
||||
get: (keyPath) ->
|
||||
value = _.valueForKeyPath(@settings, keyPath) ? _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
_.deepClone(value)
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
valueIsObject = _.isObject(value) and not _.isArray(value)
|
||||
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
|
||||
if valueIsObject and defaultValueIsObject
|
||||
_.defaults(value, defaultValue)
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
|
||||
value
|
||||
|
||||
# Public: Retrieves the setting for the given key as an integer.
|
||||
#
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
{View} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
class CursorView extends View
|
||||
@content: ->
|
||||
@div class: 'cursor idle', => @raw ' '
|
||||
|
||||
@blinkPeriod: 800
|
||||
|
||||
@blinkCursors: ->
|
||||
element.classList.toggle('blink-off') for [element] in @cursorViews
|
||||
|
||||
@startBlinking: (cursorView) ->
|
||||
@cursorViews ?= []
|
||||
@cursorViews.push(cursorView)
|
||||
if @cursorViews.length is 1
|
||||
@blinkInterval = setInterval(@blinkCursors.bind(this), @blinkPeriod / 2)
|
||||
|
||||
@stopBlinking: (cursorView) ->
|
||||
cursorView[0].classList.remove('blink-off')
|
||||
_.remove(@cursorViews, cursorView)
|
||||
clearInterval(@blinkInterval) if @cursorViews.length is 0
|
||||
|
||||
blinking: false
|
||||
visible: true
|
||||
needsUpdate: true
|
||||
needsRemoval: false
|
||||
shouldPauseBlinking: false
|
||||
|
||||
initialize: (@cursor, @editorView) ->
|
||||
@subscribe @cursor, 'moved', =>
|
||||
@needsUpdate = true
|
||||
@shouldPauseBlinking = true
|
||||
|
||||
@subscribe @cursor, 'visibility-changed', =>
|
||||
@needsUpdate = true
|
||||
|
||||
@subscribe @cursor, 'autoscrolled', =>
|
||||
@editorView.requestDisplayUpdate()
|
||||
|
||||
@subscribe @cursor, 'destroyed', =>
|
||||
@needsRemoval = true
|
||||
|
||||
beforeRemove: ->
|
||||
@editorView.removeCursorView(this)
|
||||
@stopBlinking()
|
||||
|
||||
updateDisplay: ->
|
||||
screenPosition = @getScreenPosition()
|
||||
pixelPosition = @getPixelPosition()
|
||||
|
||||
unless _.isEqual(@lastPixelPosition, pixelPosition)
|
||||
@lastPixelPosition = pixelPosition
|
||||
@css(pixelPosition)
|
||||
@trigger 'cursor:moved'
|
||||
|
||||
if @shouldPauseBlinking
|
||||
@resetBlinking()
|
||||
else if !@startBlinkingTimeout
|
||||
@startBlinking()
|
||||
|
||||
@setVisible(@cursor.isVisible() and not @editorView.getEditor().isFoldedAtScreenRow(screenPosition.row))
|
||||
|
||||
# Override for speed. The base function checks the computedStyle
|
||||
isHidden: ->
|
||||
this[0].style.display is 'none' or not @isOnDom()
|
||||
|
||||
needsAutoscroll: ->
|
||||
@cursor.needsAutoscroll
|
||||
|
||||
clearAutoscroll: ->
|
||||
@cursor.clearAutoscroll()
|
||||
|
||||
getPixelPosition: ->
|
||||
@editorView.pixelPositionForScreenPosition(@getScreenPosition())
|
||||
|
||||
setVisible: (visible) ->
|
||||
unless @visible is visible
|
||||
@visible = visible
|
||||
hiddenCursor = 'hidden-cursor'
|
||||
if visible
|
||||
@removeClass hiddenCursor
|
||||
else
|
||||
@addClass hiddenCursor
|
||||
|
||||
stopBlinking: ->
|
||||
@constructor.stopBlinking(this) if @blinking
|
||||
@blinking = false
|
||||
|
||||
startBlinking: ->
|
||||
@constructor.startBlinking(this) unless @blinking
|
||||
@blinking = true
|
||||
|
||||
resetBlinking: ->
|
||||
@stopBlinking()
|
||||
@startBlinking()
|
||||
|
||||
getBufferPosition: ->
|
||||
@cursor.getBufferPosition()
|
||||
|
||||
getScreenPosition: ->
|
||||
@cursor.getScreenPosition()
|
||||
|
||||
removeIdleClassTemporarily: ->
|
||||
@removeClass 'idle'
|
||||
window.clearTimeout(@idleTimeout) if @idleTimeout
|
||||
@idleTimeout = window.setTimeout (=> @addClass 'idle'), 200
|
||||
|
||||
resetCursorAnimation: ->
|
||||
window.clearTimeout(@idleTimeout) if @idleTimeout
|
||||
@removeClass 'idle'
|
||||
_.defer => @addClass 'idle'
|
||||
+22
-14
@@ -120,7 +120,7 @@ class Cursor extends Model
|
||||
# (default: true)
|
||||
#
|
||||
# Returns a {RegExp}.
|
||||
wordRegExp: ({includeNonWordCharacters}={})->
|
||||
wordRegExp: ({includeNonWordCharacters}={}) ->
|
||||
includeNonWordCharacters ?= true
|
||||
nonWordCharacters = atom.config.get('editor.nonWordCharacters')
|
||||
segments = ["^[\t ]*$"]
|
||||
@@ -272,12 +272,20 @@ class Cursor extends Model
|
||||
# Public: Moves the cursor to the beginning of the first character in the
|
||||
# line.
|
||||
moveToFirstCharacterOfLine: ->
|
||||
{row, column} = @getScreenPosition()
|
||||
screenline = @editor.lineForScreenRow(row)
|
||||
screenRow = @getScreenRow()
|
||||
lineBufferRange = @editor.bufferRangeForScreenRange([[screenRow, 0], [screenRow, Infinity]])
|
||||
|
||||
goalColumn = screenline.text.search(/\S/)
|
||||
goalColumn = 0 if goalColumn == column or goalColumn == -1
|
||||
@setScreenPosition([row, goalColumn])
|
||||
firstCharacterColumn = null
|
||||
@editor.scanInBufferRange /\S/, lineBufferRange, ({range, stop}) ->
|
||||
firstCharacterColumn = range.start.column
|
||||
stop()
|
||||
|
||||
if firstCharacterColumn? and firstCharacterColumn isnt @getBufferColumn()
|
||||
targetBufferColumn = firstCharacterColumn
|
||||
else
|
||||
targetBufferColumn = lineBufferRange.start.column
|
||||
|
||||
@setBufferPosition([lineBufferRange.start.row, targetBufferColumn])
|
||||
|
||||
# Public: Moves the cursor to the beginning of the buffer line, skipping all
|
||||
# whitespace.
|
||||
@@ -285,7 +293,7 @@ class Cursor extends Model
|
||||
position = @getBufferPosition()
|
||||
scanRange = @getCurrentLineBufferRange()
|
||||
endOfLeadingWhitespace = null
|
||||
@editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) =>
|
||||
@editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) ->
|
||||
endOfLeadingWhitespace = range.end
|
||||
|
||||
@setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
|
||||
@@ -341,7 +349,7 @@ class Cursor extends Model
|
||||
scanRange = [[previousNonBlankRow, 0], currentBufferPosition]
|
||||
|
||||
beginningOfWordPosition = null
|
||||
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) =>
|
||||
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) ->
|
||||
if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious
|
||||
beginningOfWordPosition = range.start
|
||||
if not beginningOfWordPosition?.isEqual(currentBufferPosition)
|
||||
@@ -362,7 +370,7 @@ class Cursor extends Model
|
||||
scanRange = [[previousNonBlankRow, 0], currentBufferPosition]
|
||||
|
||||
beginningOfWordPosition = null
|
||||
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) =>
|
||||
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
|
||||
if range.start.row < currentBufferPosition.row and currentBufferPosition.column > 0
|
||||
# force it to stop at the beginning of each line
|
||||
beginningOfWordPosition = new Point(currentBufferPosition.row, 0)
|
||||
@@ -383,7 +391,7 @@ class Cursor extends Model
|
||||
scanRange = [currentBufferPosition, @editor.getEofBufferPosition()]
|
||||
|
||||
endOfWordPosition = null
|
||||
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) =>
|
||||
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
|
||||
if range.start.row > currentBufferPosition.row
|
||||
# force it to stop at the beginning of each line
|
||||
endOfWordPosition = new Point(range.start.row, 0)
|
||||
@@ -413,7 +421,7 @@ class Cursor extends Model
|
||||
scanRange = [currentBufferPosition, @editor.getEofBufferPosition()]
|
||||
|
||||
endOfWordPosition = null
|
||||
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) =>
|
||||
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) ->
|
||||
if range.start.isLessThanOrEqual(currentBufferPosition) or allowNext
|
||||
endOfWordPosition = range.end
|
||||
if not endOfWordPosition?.isEqual(currentBufferPosition)
|
||||
@@ -434,7 +442,7 @@ class Cursor extends Model
|
||||
scanRange = [start, @editor.getEofBufferPosition()]
|
||||
|
||||
beginningOfNextWordPosition = null
|
||||
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) =>
|
||||
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
|
||||
beginningOfNextWordPosition = range.start
|
||||
stop()
|
||||
|
||||
@@ -476,7 +484,7 @@ class Cursor extends Model
|
||||
{row, column} = eof
|
||||
position = new Point(row, column - 1)
|
||||
|
||||
@editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) =>
|
||||
@editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) ->
|
||||
if !range.start.isEqual(start)
|
||||
position = range.start
|
||||
stop()
|
||||
@@ -489,7 +497,7 @@ class Cursor extends Model
|
||||
scanRange = [[row-1, column], [0,0]]
|
||||
position = new Point(0, 0)
|
||||
zero = new Point(0,0)
|
||||
@editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) =>
|
||||
@editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) ->
|
||||
if !range.start.isEqual(zero)
|
||||
position = range.start
|
||||
stop()
|
||||
|
||||
@@ -31,17 +31,17 @@ class DisplayBuffer extends Model
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
scrollWidth: 0
|
||||
verticalScrollbarWidth: 15
|
||||
horizontalScrollbarHeight: 15
|
||||
|
||||
verticalScrollMargin: 2
|
||||
horizontalScrollMargin: 6
|
||||
horizontalScrollbarHeight: 15
|
||||
verticalScrollbarWidth: 15
|
||||
scopedCharacterWidthsChangeCount: 0
|
||||
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) ->
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, @invisibles}={}) ->
|
||||
super
|
||||
@softWrap ?= atom.config.get('editor.softWrap') ? false
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer})
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles})
|
||||
@buffer = @tokenizedBuffer.buffer
|
||||
@charWidthsByScope = {}
|
||||
@markers = {}
|
||||
@@ -75,13 +75,14 @@ class DisplayBuffer extends Model
|
||||
scrollTop: @scrollTop
|
||||
scrollLeft: @scrollLeft
|
||||
tokenizedBuffer: @tokenizedBuffer.serialize()
|
||||
invisibles: _.clone(@invisibles)
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer)
|
||||
params
|
||||
|
||||
copy: ->
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()})
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @invisibles})
|
||||
newDisplayBuffer.setScrollTop(@getScrollTop())
|
||||
newDisplayBuffer.setScrollLeft(@getScrollLeft())
|
||||
|
||||
@@ -340,6 +341,9 @@ class DisplayBuffer extends Model
|
||||
setTabLength: (tabLength) ->
|
||||
@tokenizedBuffer.setTabLength(tabLength)
|
||||
|
||||
setInvisibles: (@invisibles) ->
|
||||
@tokenizedBuffer.setInvisibles(@invisibles)
|
||||
|
||||
# Deprecated: Use the softWrap property directly
|
||||
setSoftWrap: (@softWrap) -> @softWrap
|
||||
|
||||
@@ -977,7 +981,7 @@ class DisplayBuffer extends Model
|
||||
@tokenizedBuffer.destroy()
|
||||
@unsubscribe()
|
||||
|
||||
logLines: (start=0, end=@getLastRow())->
|
||||
logLines: (start=0, end=@getLastRow()) ->
|
||||
for row in [start..end]
|
||||
line = @lineForRow(row).text
|
||||
console.log row, @bufferRowForScreenRow(row), line, line.length
|
||||
@@ -1093,7 +1097,10 @@ class DisplayBuffer extends Model
|
||||
|
||||
handleBufferMarkerCreated: (marker) =>
|
||||
@createFoldForMarker(marker) if marker.matchesAttributes(@getFoldMarkerAttributes())
|
||||
@emit 'marker-created', @getMarker(marker.id)
|
||||
if displayBufferMarker = @getMarker(marker.id)
|
||||
# The marker might have been removed in some other handler called before
|
||||
# this one. Only emit when the marker still exists.
|
||||
@emit 'marker-created', displayBufferMarker
|
||||
|
||||
createFoldForMarker: (marker) ->
|
||||
@decorateMarker(marker, type: 'gutter', class: 'folded')
|
||||
|
||||
+187
-172
@@ -3,6 +3,7 @@ React = require 'react-atom-fork'
|
||||
{debounce, defaults, isEqualForProperties} = require 'underscore-plus'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{Range, Point} = require 'text-buffer'
|
||||
grim = require 'grim'
|
||||
|
||||
GutterComponent = require './gutter-component'
|
||||
InputComponent = require './input-component'
|
||||
@@ -33,25 +34,23 @@ EditorComponent = React.createClass
|
||||
selectionChanged: false
|
||||
selectionAdded: false
|
||||
scrollingVertically: false
|
||||
refreshingScrollbars: false
|
||||
measuringScrollbars: true
|
||||
mouseWheelScreenRow: null
|
||||
mouseWheelScreenRowClearDelay: 150
|
||||
scrollSensitivity: 0.4
|
||||
heightAndWidthMeasurementRequested: false
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: false
|
||||
remeasureCharacterWidthsWhenShown: false
|
||||
inputEnabled: true
|
||||
scopedCharacterWidthsChangeCount: null
|
||||
domPollingInterval: 100
|
||||
domPollingIntervalId: null
|
||||
domPollingPaused: false
|
||||
measureScrollbarsWhenShown: true
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: true
|
||||
remeasureCharacterWidthsWhenShown: false
|
||||
|
||||
render: ->
|
||||
{focused, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
|
||||
{focused, showIndentGuide, showLineNumbers, visible} = @state
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
invisibles = if showInvisibles and not mini then @state.invisibles else {}
|
||||
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
|
||||
style = {}
|
||||
|
||||
@@ -60,10 +59,13 @@ EditorComponent = React.createClass
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
|
||||
|
||||
tokenizedLines = editor.linesForScreenRows(renderedStartRow, renderedEndRow - 1)
|
||||
|
||||
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
|
||||
highlightDecorations = @getHighlightDecorations(decorations)
|
||||
lineDecorations = @getLineDecorations(decorations)
|
||||
placeholderText = @props.placeholderText if @props.placeholderText? and editor.isEmpty()
|
||||
visible = @isVisible()
|
||||
|
||||
scrollHeight = editor.getScrollHeight()
|
||||
scrollWidth = editor.getScrollWidth()
|
||||
@@ -107,10 +109,10 @@ EditorComponent = React.createClass
|
||||
|
||||
LinesComponent {
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
|
||||
editor, lineHeightInPixels, defaultCharWidth, tokenizedLines, lineDecorations, highlightDecorations,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
|
||||
@visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, mini
|
||||
}
|
||||
@@ -122,7 +124,7 @@ EditorComponent = React.createClass
|
||||
onScroll: @onHorizontalScroll
|
||||
scrollLeft: scrollLeft
|
||||
scrollWidth: scrollWidth
|
||||
visible: horizontallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
|
||||
visible: horizontallyScrollable
|
||||
scrollableInOppositeDirection: verticallyScrollable
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
@@ -134,7 +136,7 @@ EditorComponent = React.createClass
|
||||
onScroll: @onVerticalScroll
|
||||
scrollTop: scrollTop
|
||||
scrollHeight: scrollHeight
|
||||
visible: verticallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
|
||||
visible: verticallyScrollable
|
||||
scrollableInOppositeDirection: horizontallyScrollable
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
@@ -142,7 +144,7 @@ EditorComponent = React.createClass
|
||||
# Also used to measure the height/width of scrollbars after the initial render
|
||||
ScrollbarCornerComponent
|
||||
ref: 'scrollbarCorner'
|
||||
visible: not @refreshingScrollbars and (@measuringScrollbars or horizontallyScrollable and verticallyScrollable)
|
||||
visible: horizontallyScrollable and verticallyScrollable
|
||||
measuringScrollbars: @measuringScrollbars
|
||||
height: horizontalScrollbarHeight
|
||||
width: verticalScrollbarWidth
|
||||
@@ -170,8 +172,6 @@ EditorComponent = React.createClass
|
||||
componentDidMount: ->
|
||||
{editor} = @props
|
||||
|
||||
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
|
||||
|
||||
@observeEditor()
|
||||
@listenForDOMEvents()
|
||||
@listenForCommands()
|
||||
@@ -179,9 +179,8 @@ EditorComponent = React.createClass
|
||||
@subscribe atom.themes, 'stylesheet-added stylesheet-removed stylesheet-updated', @onStylesheetsChanged
|
||||
@subscribe scrollbarStyle.changes, @refreshScrollbars
|
||||
|
||||
if @visible = @isVisible()
|
||||
@performInitialMeasurement()
|
||||
@forceUpdate()
|
||||
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
|
||||
@checkForVisibilityChange()
|
||||
|
||||
componentWillUnmount: ->
|
||||
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
|
||||
@@ -191,10 +190,8 @@ EditorComponent = React.createClass
|
||||
@domPollingIntervalId = null
|
||||
@props.editor.destroy()
|
||||
|
||||
componentWillUpdate: ->
|
||||
wasVisible = @visible
|
||||
@visible = @isVisible()
|
||||
@performInitialMeasurement() if @visible and not wasVisible
|
||||
componentWillReceiveProps: (newProps) ->
|
||||
@props.editor.setMini(newProps.mini)
|
||||
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
cursorsMoved = @cursorsMoved
|
||||
@@ -202,7 +199,6 @@ EditorComponent = React.createClass
|
||||
@pendingChanges.length = 0
|
||||
@cursorsMoved = false
|
||||
@selectionChanged = false
|
||||
@refreshingScrollbars = false
|
||||
|
||||
if @props.editor.isAlive()
|
||||
@updateParentViewFocusedClassIfNeeded(prevState)
|
||||
@@ -211,20 +207,18 @@ EditorComponent = React.createClass
|
||||
@props.parentView.trigger 'selection:changed' if selectionChanged
|
||||
@props.parentView.trigger 'editor:display-updated'
|
||||
|
||||
if @performedInitialMeasurement
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
|
||||
performInitialMeasurement: ->
|
||||
becameVisible: ->
|
||||
@updatesPaused = true
|
||||
@measureHeightAndWidth()
|
||||
@sampleFontStyling()
|
||||
@sampleBackgroundColors()
|
||||
@measureScrollbars()
|
||||
@measureHeightAndWidth()
|
||||
@measureScrollbars() if @measureScrollbarsWhenShown
|
||||
@measureLineHeightAndDefaultCharWidth() if @measureLineHeightAndDefaultCharWidthWhenShown
|
||||
@remeasureCharacterWidths() if @remeasureCharacterWidthsWhenShown
|
||||
@props.editor.setVisible(true)
|
||||
@updatesPaused = false
|
||||
@performedInitialMeasurement = true
|
||||
@updatesPaused = false
|
||||
@forceUpdate() if @updateRequestedWhilePaused
|
||||
|
||||
requestUpdate: ->
|
||||
return unless @isMounted()
|
||||
@@ -360,6 +354,8 @@ EditorComponent = React.createClass
|
||||
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
|
||||
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
|
||||
@subscribe editor.$scrollLeft.changes, @requestUpdate
|
||||
@subscribe editor.$verticalScrollbarWidth.changes, @requestUpdate
|
||||
@subscribe editor.$horizontalScrollbarHeight.changes, @requestUpdate
|
||||
@subscribe editor.$height.changes, @requestUpdate
|
||||
@subscribe editor.$width.changes, @requestUpdate
|
||||
@subscribe editor.$defaultCharWidth.changes, @requestUpdate
|
||||
@@ -407,105 +403,105 @@ EditorComponent = React.createClass
|
||||
{parentView, editor, mini} = @props
|
||||
|
||||
@addCommandListeners
|
||||
'core:move-left': => editor.moveCursorLeft()
|
||||
'core:move-right': => editor.moveCursorRight()
|
||||
'core:select-left': => editor.selectLeft()
|
||||
'core:select-right': => editor.selectRight()
|
||||
'core:select-all': => editor.selectAll()
|
||||
'core:backspace': => editor.backspace()
|
||||
'core:delete': => editor.delete()
|
||||
'core:undo': => editor.undo()
|
||||
'core:redo': => editor.redo()
|
||||
'core:cut': => editor.cutSelectedText()
|
||||
'core:copy': => editor.copySelectedText()
|
||||
'core:paste': => editor.pasteText()
|
||||
'editor:move-to-previous-word': => editor.moveCursorToPreviousWord()
|
||||
'editor:select-word': => editor.selectWord()
|
||||
'core:move-left': -> editor.moveCursorLeft()
|
||||
'core:move-right': -> editor.moveCursorRight()
|
||||
'core:select-left': -> editor.selectLeft()
|
||||
'core:select-right': -> editor.selectRight()
|
||||
'core:select-all': -> editor.selectAll()
|
||||
'core:backspace': -> editor.backspace()
|
||||
'core:delete': -> editor.delete()
|
||||
'core:undo': -> editor.undo()
|
||||
'core:redo': -> editor.redo()
|
||||
'core:cut': -> editor.cutSelectedText()
|
||||
'core:copy': -> editor.copySelectedText()
|
||||
'core:paste': -> editor.pasteText()
|
||||
'editor:move-to-previous-word': -> editor.moveCursorToPreviousWord()
|
||||
'editor:select-word': -> editor.selectWord()
|
||||
'editor:consolidate-selections': @consolidateSelections
|
||||
'editor:delete-to-beginning-of-word': => editor.deleteToBeginningOfWord()
|
||||
'editor:delete-to-beginning-of-line': => editor.deleteToBeginningOfLine()
|
||||
'editor:delete-to-end-of-line': => editor.deleteToEndOfLine()
|
||||
'editor:delete-to-end-of-word': => editor.deleteToEndOfWord()
|
||||
'editor:delete-line': => editor.deleteLine()
|
||||
'editor:cut-to-end-of-line': => editor.cutToEndOfLine()
|
||||
'editor:move-to-beginning-of-next-paragraph': => editor.moveCursorToBeginningOfNextParagraph()
|
||||
'editor:move-to-beginning-of-previous-paragraph': => editor.moveCursorToBeginningOfPreviousParagraph()
|
||||
'editor:move-to-beginning-of-screen-line': => editor.moveCursorToBeginningOfScreenLine()
|
||||
'editor:move-to-beginning-of-line': => editor.moveCursorToBeginningOfLine()
|
||||
'editor:move-to-end-of-screen-line': => editor.moveCursorToEndOfScreenLine()
|
||||
'editor:move-to-end-of-line': => editor.moveCursorToEndOfLine()
|
||||
'editor:move-to-first-character-of-line': => editor.moveCursorToFirstCharacterOfLine()
|
||||
'editor:move-to-beginning-of-word': => editor.moveCursorToBeginningOfWord()
|
||||
'editor:move-to-end-of-word': => editor.moveCursorToEndOfWord()
|
||||
'editor:move-to-beginning-of-next-word': => editor.moveCursorToBeginningOfNextWord()
|
||||
'editor:move-to-previous-word-boundary': => editor.moveCursorToPreviousWordBoundary()
|
||||
'editor:move-to-next-word-boundary': => editor.moveCursorToNextWordBoundary()
|
||||
'editor:select-to-beginning-of-next-paragraph': => editor.selectToBeginningOfNextParagraph()
|
||||
'editor:select-to-beginning-of-previous-paragraph': => editor.selectToBeginningOfPreviousParagraph()
|
||||
'editor:select-to-end-of-line': => editor.selectToEndOfLine()
|
||||
'editor:select-to-beginning-of-line': => editor.selectToBeginningOfLine()
|
||||
'editor:select-to-end-of-word': => editor.selectToEndOfWord()
|
||||
'editor:select-to-beginning-of-word': => editor.selectToBeginningOfWord()
|
||||
'editor:select-to-beginning-of-next-word': => editor.selectToBeginningOfNextWord()
|
||||
'editor:select-to-next-word-boundary': => editor.selectToNextWordBoundary()
|
||||
'editor:select-to-previous-word-boundary': => editor.selectToPreviousWordBoundary()
|
||||
'editor:select-to-first-character-of-line': => editor.selectToFirstCharacterOfLine()
|
||||
'editor:select-line': => editor.selectLine()
|
||||
'editor:transpose': => editor.transpose()
|
||||
'editor:upper-case': => editor.upperCase()
|
||||
'editor:lower-case': => editor.lowerCase()
|
||||
'editor:delete-to-beginning-of-word': -> editor.deleteToBeginningOfWord()
|
||||
'editor:delete-to-beginning-of-line': -> editor.deleteToBeginningOfLine()
|
||||
'editor:delete-to-end-of-line': -> editor.deleteToEndOfLine()
|
||||
'editor:delete-to-end-of-word': -> editor.deleteToEndOfWord()
|
||||
'editor:delete-line': -> editor.deleteLine()
|
||||
'editor:cut-to-end-of-line': -> editor.cutToEndOfLine()
|
||||
'editor:move-to-beginning-of-next-paragraph': -> editor.moveCursorToBeginningOfNextParagraph()
|
||||
'editor:move-to-beginning-of-previous-paragraph': -> editor.moveCursorToBeginningOfPreviousParagraph()
|
||||
'editor:move-to-beginning-of-screen-line': -> editor.moveCursorToBeginningOfScreenLine()
|
||||
'editor:move-to-beginning-of-line': -> editor.moveCursorToBeginningOfLine()
|
||||
'editor:move-to-end-of-screen-line': -> editor.moveCursorToEndOfScreenLine()
|
||||
'editor:move-to-end-of-line': -> editor.moveCursorToEndOfLine()
|
||||
'editor:move-to-first-character-of-line': -> editor.moveCursorToFirstCharacterOfLine()
|
||||
'editor:move-to-beginning-of-word': -> editor.moveCursorToBeginningOfWord()
|
||||
'editor:move-to-end-of-word': -> editor.moveCursorToEndOfWord()
|
||||
'editor:move-to-beginning-of-next-word': -> editor.moveCursorToBeginningOfNextWord()
|
||||
'editor:move-to-previous-word-boundary': -> editor.moveCursorToPreviousWordBoundary()
|
||||
'editor:move-to-next-word-boundary': -> editor.moveCursorToNextWordBoundary()
|
||||
'editor:select-to-beginning-of-next-paragraph': -> editor.selectToBeginningOfNextParagraph()
|
||||
'editor:select-to-beginning-of-previous-paragraph': -> editor.selectToBeginningOfPreviousParagraph()
|
||||
'editor:select-to-end-of-line': -> editor.selectToEndOfLine()
|
||||
'editor:select-to-beginning-of-line': -> editor.selectToBeginningOfLine()
|
||||
'editor:select-to-end-of-word': -> editor.selectToEndOfWord()
|
||||
'editor:select-to-beginning-of-word': -> editor.selectToBeginningOfWord()
|
||||
'editor:select-to-beginning-of-next-word': -> editor.selectToBeginningOfNextWord()
|
||||
'editor:select-to-next-word-boundary': -> editor.selectToNextWordBoundary()
|
||||
'editor:select-to-previous-word-boundary': -> editor.selectToPreviousWordBoundary()
|
||||
'editor:select-to-first-character-of-line': -> editor.selectToFirstCharacterOfLine()
|
||||
'editor:select-line': -> editor.selectLine()
|
||||
'editor:transpose': -> editor.transpose()
|
||||
'editor:upper-case': -> editor.upperCase()
|
||||
'editor:lower-case': -> editor.lowerCase()
|
||||
|
||||
unless mini
|
||||
@addCommandListeners
|
||||
'core:move-up': => editor.moveCursorUp()
|
||||
'core:move-down': => editor.moveCursorDown()
|
||||
'core:move-to-top': => editor.moveCursorToTop()
|
||||
'core:move-to-bottom': => editor.moveCursorToBottom()
|
||||
'core:page-up': => editor.pageUp()
|
||||
'core:page-down': => editor.pageDown()
|
||||
'core:select-up': => editor.selectUp()
|
||||
'core:select-down': => editor.selectDown()
|
||||
'core:select-to-top': => editor.selectToTop()
|
||||
'core:select-to-bottom': => editor.selectToBottom()
|
||||
'core:select-page-up': => editor.selectPageUp()
|
||||
'core:select-page-down': => editor.selectPageDown()
|
||||
'editor:indent': => editor.indent()
|
||||
'editor:auto-indent': => editor.autoIndentSelectedRows()
|
||||
'editor:indent-selected-rows': => editor.indentSelectedRows()
|
||||
'editor:outdent-selected-rows': => editor.outdentSelectedRows()
|
||||
'editor:newline': => editor.insertNewline()
|
||||
'editor:newline-below': => editor.insertNewlineBelow()
|
||||
'editor:newline-above': => editor.insertNewlineAbove()
|
||||
'editor:add-selection-below': => editor.addSelectionBelow()
|
||||
'editor:add-selection-above': => editor.addSelectionAbove()
|
||||
'editor:split-selections-into-lines': => editor.splitSelectionsIntoLines()
|
||||
'editor:toggle-soft-tabs': => editor.toggleSoftTabs()
|
||||
'editor:toggle-soft-wrap': => editor.toggleSoftWrap()
|
||||
'editor:fold-all': => editor.foldAll()
|
||||
'editor:unfold-all': => editor.unfoldAll()
|
||||
'editor:fold-current-row': => editor.foldCurrentRow()
|
||||
'editor:unfold-current-row': => editor.unfoldCurrentRow()
|
||||
'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)
|
||||
'editor:fold-at-indent-level-4': => editor.foldAllAtIndentLevel(3)
|
||||
'editor:fold-at-indent-level-5': => editor.foldAllAtIndentLevel(4)
|
||||
'editor:fold-at-indent-level-6': => editor.foldAllAtIndentLevel(5)
|
||||
'editor:fold-at-indent-level-7': => editor.foldAllAtIndentLevel(6)
|
||||
'editor:fold-at-indent-level-8': => editor.foldAllAtIndentLevel(7)
|
||||
'editor:fold-at-indent-level-9': => editor.foldAllAtIndentLevel(8)
|
||||
'editor:toggle-line-comments': => editor.toggleLineCommentsInSelection()
|
||||
'editor:log-cursor-scope': => editor.logCursorScope()
|
||||
'editor:checkout-head-revision': => editor.checkoutHead()
|
||||
'editor:copy-path': => editor.copyPathToClipboard()
|
||||
'editor:move-line-up': => editor.moveLineUp()
|
||||
'editor:move-line-down': => editor.moveLineDown()
|
||||
'editor:duplicate-lines': => editor.duplicateLines()
|
||||
'editor:join-lines': => editor.joinLines()
|
||||
'editor:toggle-indent-guide': => atom.config.toggle('editor.showIndentGuide')
|
||||
'editor:toggle-line-numbers': => atom.config.toggle('editor.showLineNumbers')
|
||||
'editor:scroll-to-cursor': => editor.scrollToCursorPosition()
|
||||
'core:move-up': -> editor.moveCursorUp()
|
||||
'core:move-down': -> editor.moveCursorDown()
|
||||
'core:move-to-top': -> editor.moveCursorToTop()
|
||||
'core:move-to-bottom': -> editor.moveCursorToBottom()
|
||||
'core:page-up': -> editor.pageUp()
|
||||
'core:page-down': -> editor.pageDown()
|
||||
'core:select-up': -> editor.selectUp()
|
||||
'core:select-down': -> editor.selectDown()
|
||||
'core:select-to-top': -> editor.selectToTop()
|
||||
'core:select-to-bottom': -> editor.selectToBottom()
|
||||
'core:select-page-up': -> editor.selectPageUp()
|
||||
'core:select-page-down': -> editor.selectPageDown()
|
||||
'editor:indent': -> editor.indent()
|
||||
'editor:auto-indent': -> editor.autoIndentSelectedRows()
|
||||
'editor:indent-selected-rows': -> editor.indentSelectedRows()
|
||||
'editor:outdent-selected-rows': -> editor.outdentSelectedRows()
|
||||
'editor:newline': -> editor.insertNewline()
|
||||
'editor:newline-below': -> editor.insertNewlineBelow()
|
||||
'editor:newline-above': -> editor.insertNewlineAbove()
|
||||
'editor:add-selection-below': -> editor.addSelectionBelow()
|
||||
'editor:add-selection-above': -> editor.addSelectionAbove()
|
||||
'editor:split-selections-into-lines': -> editor.splitSelectionsIntoLines()
|
||||
'editor:toggle-soft-tabs': -> editor.toggleSoftTabs()
|
||||
'editor:toggle-soft-wrap': -> editor.toggleSoftWrap()
|
||||
'editor:fold-all': -> editor.foldAll()
|
||||
'editor:unfold-all': -> editor.unfoldAll()
|
||||
'editor:fold-current-row': -> editor.foldCurrentRow()
|
||||
'editor:unfold-current-row': -> editor.unfoldCurrentRow()
|
||||
'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)
|
||||
'editor:fold-at-indent-level-4': -> editor.foldAllAtIndentLevel(3)
|
||||
'editor:fold-at-indent-level-5': -> editor.foldAllAtIndentLevel(4)
|
||||
'editor:fold-at-indent-level-6': -> editor.foldAllAtIndentLevel(5)
|
||||
'editor:fold-at-indent-level-7': -> editor.foldAllAtIndentLevel(6)
|
||||
'editor:fold-at-indent-level-8': -> editor.foldAllAtIndentLevel(7)
|
||||
'editor:fold-at-indent-level-9': -> editor.foldAllAtIndentLevel(8)
|
||||
'editor:toggle-line-comments': -> editor.toggleLineCommentsInSelection()
|
||||
'editor:log-cursor-scope': -> editor.logCursorScope()
|
||||
'editor:checkout-head-revision': -> atom.project.getRepo()?.checkoutHeadForEditor(editor)
|
||||
'editor:copy-path': -> editor.copyPathToClipboard()
|
||||
'editor:move-line-up': -> editor.moveLineUp()
|
||||
'editor:move-line-down': -> editor.moveLineDown()
|
||||
'editor:duplicate-lines': -> editor.duplicateLines()
|
||||
'editor:join-lines': -> editor.joinLines()
|
||||
'editor:toggle-indent-guide': -> atom.config.toggle('editor.showIndentGuide')
|
||||
'editor:toggle-line-numbers': -> atom.config.toggle('editor.showLineNumbers')
|
||||
'editor:scroll-to-cursor': -> editor.scrollToCursorPosition()
|
||||
'benchmark:scroll': @runScrollBenchmark
|
||||
|
||||
addCommandListeners: (listenersByCommandName) ->
|
||||
@@ -522,8 +518,6 @@ EditorComponent = React.createClass
|
||||
|
||||
observeConfig: ->
|
||||
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
|
||||
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
|
||||
@subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers
|
||||
@subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity
|
||||
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
|
||||
@@ -612,9 +606,14 @@ EditorComponent = React.createClass
|
||||
|
||||
onMouseDown: (event) ->
|
||||
return unless event.button is 0 # only handle the left mouse button
|
||||
return if event.target?.classList.contains('horizontal-scrollbar')
|
||||
|
||||
{editor} = @props
|
||||
{detail, shiftKey, metaKey, ctrlKey} = event
|
||||
|
||||
# CTRL+click brings up the context menu on OSX, so don't handle those either
|
||||
return if ctrlKey and process.platform is 'darwin'
|
||||
|
||||
screenPosition = @screenPositionForMouseEvent(event)
|
||||
|
||||
if event.target?.classList.contains('fold-marker')
|
||||
@@ -776,15 +775,20 @@ EditorComponent = React.createClass
|
||||
pollDOM: ->
|
||||
return if @domPollingPaused or @updateRequested or not @isMounted()
|
||||
|
||||
wasVisible = @visible
|
||||
if @visible = @isVisible()
|
||||
if wasVisible
|
||||
@measureHeightAndWidth()
|
||||
@sampleFontStyling()
|
||||
@sampleBackgroundColors()
|
||||
unless @checkForVisibilityChange()
|
||||
@sampleBackgroundColors()
|
||||
@measureHeightAndWidth()
|
||||
@sampleFontStyling()
|
||||
|
||||
checkForVisibilityChange: ->
|
||||
if @isVisible()
|
||||
if @wasVisible
|
||||
false
|
||||
else
|
||||
@performInitialMeasurement()
|
||||
@forceUpdate()
|
||||
@becameVisible()
|
||||
@wasVisible = true
|
||||
else
|
||||
@wasVisible = false
|
||||
|
||||
requestHeightAndWidthMeasurement: ->
|
||||
return if @heightAndWidthMeasurementRequested
|
||||
@@ -810,7 +814,7 @@ EditorComponent = React.createClass
|
||||
if position is 'absolute' or height
|
||||
if @autoHeight
|
||||
@autoHeight = false
|
||||
@forceUpdate()
|
||||
@forceUpdate() unless @updatesPaused
|
||||
|
||||
clientHeight = scrollViewNode.clientHeight
|
||||
editor.setHeight(clientHeight) if clientHeight > 0
|
||||
@@ -852,30 +856,36 @@ EditorComponent = React.createClass
|
||||
@requestUpdate() unless suppressUpdate
|
||||
|
||||
measureLineHeightAndDefaultCharWidth: ->
|
||||
if @visible
|
||||
if @isVisible()
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = false
|
||||
@refs.lines.measureLineHeightAndDefaultCharWidth()
|
||||
else
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = true
|
||||
|
||||
remeasureCharacterWidths: ->
|
||||
if @visible
|
||||
if @isVisible()
|
||||
@remeasureCharacterWidthsWhenShown = false
|
||||
@refs.lines.remeasureCharacterWidths()
|
||||
else
|
||||
@remeasureCharacterWidthsWhenShown = true
|
||||
|
||||
measureScrollbars: ->
|
||||
return unless @visible
|
||||
@measuringScrollbars = false
|
||||
@measureScrollbarsWhenShown = false
|
||||
|
||||
{editor} = @props
|
||||
scrollbarCornerNode = @refs.scrollbarCorner.getDOMNode()
|
||||
width = (scrollbarCornerNode.offsetWidth - scrollbarCornerNode.clientWidth) or 15
|
||||
height = (scrollbarCornerNode.offsetHeight - scrollbarCornerNode.clientHeight) or 15
|
||||
cornerNode = @refs.scrollbarCorner.getDOMNode()
|
||||
originalDisplayValue = cornerNode.style.display
|
||||
|
||||
cornerNode.style.display = 'block'
|
||||
|
||||
width = (cornerNode.offsetWidth - cornerNode.clientWidth) or 15
|
||||
height = (cornerNode.offsetHeight - cornerNode.clientHeight) or 15
|
||||
|
||||
editor.setVerticalScrollbarWidth(width)
|
||||
editor.setHorizontalScrollbarHeight(height)
|
||||
|
||||
cornerNode.style.display = originalDisplayValue
|
||||
|
||||
containsScrollbarSelector: (stylesheet) ->
|
||||
for rule in stylesheet.cssRules
|
||||
if rule.selectorText?.indexOf('scrollbar') > -1
|
||||
@@ -883,24 +893,39 @@ EditorComponent = React.createClass
|
||||
false
|
||||
|
||||
refreshScrollbars: ->
|
||||
# Believe it or not, proper handling of changes to scrollbar styles requires
|
||||
# three DOM updates.
|
||||
if @isVisible()
|
||||
@measureScrollbarsWhenShown = false
|
||||
else
|
||||
@measureScrollbarsWhenShown = true
|
||||
return
|
||||
|
||||
# Scrollbar style changes won't apply to scrollbars that are already
|
||||
# visible, so first we need to hide scrollbars so we can redisplay them and
|
||||
# force Chromium to apply updates.
|
||||
@refreshingScrollbars = true
|
||||
@forceUpdate()
|
||||
{verticalScrollbar, horizontalScrollbar, scrollbarCorner} = @refs
|
||||
|
||||
# Next, we display only the scrollbar corner so we can measure the new
|
||||
# scrollbar dimensions. The ::measuringScrollbars property will be set back
|
||||
# to false after the scrollbars are measured.
|
||||
@measuringScrollbars = true
|
||||
@forceUpdate()
|
||||
verticalNode = verticalScrollbar.getDOMNode()
|
||||
horizontalNode = verticalScrollbar.getDOMNode()
|
||||
cornerNode = scrollbarCorner.getDOMNode()
|
||||
|
||||
# Finally, we restore the scrollbars based on the newly-measured dimensions
|
||||
# if the editor's content and dimensions require them to be visible.
|
||||
@forceUpdate()
|
||||
originalVerticalDisplayValue = verticalNode.style.display
|
||||
originalHorizontalDisplayValue = horizontalNode.style.display
|
||||
originalCornerDisplayValue = cornerNode.style.display
|
||||
|
||||
# First, hide all scrollbars in case they are visible so they take on new
|
||||
# styles when they are shown again.
|
||||
verticalNode.style.display = 'none'
|
||||
horizontalNode.style.display = 'none'
|
||||
cornerNode.style.display = 'none'
|
||||
|
||||
# Force a reflow
|
||||
cornerNode.offsetWidth
|
||||
|
||||
# Now measure the new scrollbar dimensions
|
||||
@measureScrollbars()
|
||||
|
||||
# Now restore the display value for all scrollbars, since they were
|
||||
# previously hidden
|
||||
verticalNode.style.display = originalVerticalDisplayValue
|
||||
horizontalNode.style.display = originalHorizontalDisplayValue
|
||||
cornerNode.style.display = originalCornerDisplayValue
|
||||
|
||||
clearMouseWheelScreenRow: ->
|
||||
if @mouseWheelScreenRow?
|
||||
@@ -944,24 +969,14 @@ EditorComponent = React.createClass
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
@setState({showIndentGuide})
|
||||
|
||||
# Public: Defines which characters are invisible.
|
||||
#
|
||||
# invisibles - An {Object} defining the invisible characters:
|
||||
# :eol - The end of line invisible {String} (default: `\u00ac`).
|
||||
# :space - The space invisible {String} (default: `\u00b7`).
|
||||
# :tab - The tab invisible {String} (default: `\u00bb`).
|
||||
# :cr - The carriage return invisible {String} (default: `\u00a4`).
|
||||
# Deprecated
|
||||
setInvisibles: (invisibles={}) ->
|
||||
defaults invisibles,
|
||||
eol: '\u00ac'
|
||||
space: '\u00b7'
|
||||
tab: '\u00bb'
|
||||
cr: '\u00a4'
|
||||
|
||||
@setState({invisibles})
|
||||
grim.deprecate "Use config.set('editor.invisibles', invisibles) instead"
|
||||
atom.config.set('editor.invisibles', invisibles)
|
||||
|
||||
# Deprecated
|
||||
setShowInvisibles: (showInvisibles) ->
|
||||
@setState({showInvisibles})
|
||||
atom.config.set('editor.showInvisibles', showInvisibles)
|
||||
|
||||
setShowLineNumbers: (showLineNumbers) ->
|
||||
@setState({showLineNumbers})
|
||||
|
||||
+231
-1443
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+53
-37
@@ -157,15 +157,20 @@ class Editor extends Model
|
||||
toProperty: 'languageMode'
|
||||
|
||||
@delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
|
||||
'$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer'
|
||||
'$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft',
|
||||
'manageScrollPosition', toProperty: 'displayBuffer'
|
||||
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini}) ->
|
||||
super
|
||||
|
||||
@cursors = []
|
||||
@selections = []
|
||||
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrap})
|
||||
if @shouldShowInvisibles()
|
||||
invisibles = atom.config.get('editor.invisibles')
|
||||
|
||||
@displayBuffer?.setInvisibles(invisibles)
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrap, invisibles})
|
||||
@buffer = @displayBuffer.buffer
|
||||
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
|
||||
|
||||
@@ -186,6 +191,9 @@ class Editor extends Model
|
||||
@subscribe @$scrollTop, (scrollTop) => @emit 'scroll-top-changed', scrollTop
|
||||
@subscribe @$scrollLeft, (scrollLeft) => @emit 'scroll-left-changed', scrollLeft
|
||||
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', callNow: false, (show) => @updateInvisibles()
|
||||
@subscribe atom.config.observe 'editor.invisibles', callNow: false, => @updateInvisibles()
|
||||
|
||||
atom.workspace?.editorAdded(this) if registerEditor
|
||||
|
||||
serializeParams: ->
|
||||
@@ -227,10 +235,7 @@ class Editor extends Model
|
||||
@subscribe @displayBuffer, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
|
||||
|
||||
getViewClass: ->
|
||||
if atom.config.get('core.useReactEditor')
|
||||
require './react-editor-view'
|
||||
else
|
||||
require './editor-view'
|
||||
require './editor-view'
|
||||
|
||||
destroyed: ->
|
||||
@unsubscribe()
|
||||
@@ -281,6 +286,11 @@ class Editor extends Model
|
||||
# Controls visibility based on the given {Boolean}.
|
||||
setVisible: (visible) -> @displayBuffer.setVisible(visible)
|
||||
|
||||
setMini: (mini) ->
|
||||
if mini isnt @mini
|
||||
@mini = mini
|
||||
@updateInvisibles()
|
||||
|
||||
# Set the number of characters that can be displayed horizontally in the
|
||||
# editor.
|
||||
#
|
||||
@@ -435,10 +445,6 @@ class Editor extends Model
|
||||
# filePath - A {String} path.
|
||||
saveAs: (filePath) -> @buffer.saveAs(filePath)
|
||||
|
||||
checkoutHead: ->
|
||||
if filePath = @getPath()
|
||||
atom.project.getRepo()?.checkoutHead(filePath)
|
||||
|
||||
# Copies the current file path to the native clipboard.
|
||||
copyPathToClipboard: ->
|
||||
if filePath = @getPath()
|
||||
@@ -637,7 +643,8 @@ class Editor extends Model
|
||||
# text - A {String} representing the text to insert.
|
||||
# options - See {Selection::insertText}.
|
||||
#
|
||||
# Returns a {Bool} indicating whether or not the text was inserted.
|
||||
# Returns a {Range} when the text has been inserted
|
||||
# Returns a {Bool} false when the text has not been inserted
|
||||
insertText: (text, options={}) ->
|
||||
willInsert = true
|
||||
cancel = -> willInsert = false
|
||||
@@ -683,7 +690,7 @@ class Editor extends Model
|
||||
|
||||
# Indent all lines intersecting selections. See {Selection::indent} for more
|
||||
# information.
|
||||
indent: (options={})->
|
||||
indent: (options={}) ->
|
||||
options.autoIndent ?= @shouldAutoIndent()
|
||||
@mutateSelectedText (selection) -> selection.indent(options)
|
||||
|
||||
@@ -1661,55 +1668,55 @@ class Editor extends Model
|
||||
#
|
||||
# This method may merge selections that end up intesecting.
|
||||
selectRight: ->
|
||||
@expandSelectionsForward (selection) => selection.selectRight()
|
||||
@expandSelectionsForward (selection) -> selection.selectRight()
|
||||
|
||||
# Public: Move the cursor of each selection one character leftward while
|
||||
# preserving the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intesecting.
|
||||
selectLeft: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectLeft()
|
||||
@expandSelectionsBackward (selection) -> selection.selectLeft()
|
||||
|
||||
# Public: Move the cursor of each selection one character upward while
|
||||
# preserving the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intesecting.
|
||||
selectUp: (rowCount) ->
|
||||
@expandSelectionsBackward (selection) => selection.selectUp(rowCount)
|
||||
@expandSelectionsBackward (selection) -> selection.selectUp(rowCount)
|
||||
|
||||
# Public: Move the cursor of each selection one character downward while
|
||||
# preserving the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intesecting.
|
||||
selectDown: (rowCount) ->
|
||||
@expandSelectionsForward (selection) => selection.selectDown(rowCount)
|
||||
@expandSelectionsForward (selection) -> selection.selectDown(rowCount)
|
||||
|
||||
# Public: Select from the top of the buffer to the end of the last selection
|
||||
# in the buffer.
|
||||
#
|
||||
# This method merges multiple selections into a single selection.
|
||||
selectToTop: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToTop()
|
||||
@expandSelectionsBackward (selection) -> selection.selectToTop()
|
||||
|
||||
# Public: Select all text in the buffer.
|
||||
#
|
||||
# This method merges multiple selections into a single selection.
|
||||
selectAll: ->
|
||||
@expandSelectionsForward (selection) => selection.selectAll()
|
||||
@expandSelectionsForward (selection) -> selection.selectAll()
|
||||
|
||||
# Public: Selects from the top of the first selection in the buffer to the end
|
||||
# of the buffer.
|
||||
#
|
||||
# This method merges multiple selections into a single selection.
|
||||
selectToBottom: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToBottom()
|
||||
@expandSelectionsForward (selection) -> selection.selectToBottom()
|
||||
|
||||
# Public: Move the cursor of each selection to the beginning of its line
|
||||
# while preserving the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intesecting.
|
||||
selectToBeginningOfLine: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToBeginningOfLine()
|
||||
@expandSelectionsBackward (selection) -> selection.selectToBeginningOfLine()
|
||||
|
||||
# Public: Move the cursor of each selection to the first non-whitespace
|
||||
# character of its line while preserving the selection's tail position. If the
|
||||
@@ -1718,34 +1725,34 @@ class Editor extends Model
|
||||
#
|
||||
# This method may merge selections that end up intersecting.
|
||||
selectToFirstCharacterOfLine: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToFirstCharacterOfLine()
|
||||
@expandSelectionsBackward (selection) -> selection.selectToFirstCharacterOfLine()
|
||||
|
||||
# Public: Move the cursor of each selection to the end of its line while
|
||||
# preserving the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intersecting.
|
||||
selectToEndOfLine: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToEndOfLine()
|
||||
@expandSelectionsForward (selection) -> selection.selectToEndOfLine()
|
||||
|
||||
# Public: For each selection, move its cursor to the preceding word boundary
|
||||
# while maintaining the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intersecting.
|
||||
selectToPreviousWordBoundary: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToPreviousWordBoundary()
|
||||
@expandSelectionsBackward (selection) -> selection.selectToPreviousWordBoundary()
|
||||
|
||||
# Public: For each selection, move its cursor to the next word boundary while
|
||||
# maintaining the selection's tail position.
|
||||
#
|
||||
# This method may merge selections that end up intersecting.
|
||||
selectToNextWordBoundary: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToNextWordBoundary()
|
||||
@expandSelectionsForward (selection) -> selection.selectToNextWordBoundary()
|
||||
|
||||
# Public: For each cursor, select the containing line.
|
||||
#
|
||||
# This method merges selections on successive lines.
|
||||
selectLine: ->
|
||||
@expandSelectionsForward (selection) => selection.selectLine()
|
||||
@expandSelectionsForward (selection) -> selection.selectLine()
|
||||
|
||||
# Public: Add a similarly-shaped selection to the next eligible line below
|
||||
# each selection.
|
||||
@@ -1756,7 +1763,7 @@ class Editor extends Model
|
||||
# selection to the next line that is long enough for a non-empty selection
|
||||
# starting at the same column as the current selection to be added to it.
|
||||
addSelectionBelow: ->
|
||||
@expandSelectionsForward (selection) => selection.addSelectionBelow()
|
||||
@expandSelectionsForward (selection) -> selection.addSelectionBelow()
|
||||
|
||||
# Public: Add a similarly-shaped selection to the next eligible line above
|
||||
# each selection.
|
||||
@@ -1767,7 +1774,7 @@ class Editor extends Model
|
||||
# selection to the next line that is long enough for a non-empty selection
|
||||
# starting at the same column as the current selection to be added to it.
|
||||
addSelectionAbove: ->
|
||||
@expandSelectionsBackward (selection) => selection.addSelectionAbove()
|
||||
@expandSelectionsBackward (selection) -> selection.addSelectionAbove()
|
||||
|
||||
# Public: Split multi-line selections into one selection per line.
|
||||
#
|
||||
@@ -1792,7 +1799,7 @@ class Editor extends Model
|
||||
# If the selection is empty, the characters preceding and following the cursor
|
||||
# are swapped. Otherwise, the selected characters are reversed.
|
||||
transpose: ->
|
||||
@mutateSelectedText (selection) =>
|
||||
@mutateSelectedText (selection) ->
|
||||
if selection.isEmpty()
|
||||
selection.selectRight()
|
||||
text = selection.getText()
|
||||
@@ -1807,14 +1814,14 @@ class Editor extends Model
|
||||
# For each selection, if the selection is empty, converts the containing word
|
||||
# to upper case. Otherwise convert the selected text to upper case.
|
||||
upperCase: ->
|
||||
@replaceSelectedText selectWordIfEmpty:true, (text) => text.toUpperCase()
|
||||
@replaceSelectedText selectWordIfEmpty:true, (text) -> text.toUpperCase()
|
||||
|
||||
# Public: Convert the selected text to lower case.
|
||||
#
|
||||
# For each selection, if the selection is empty, converts the containing word
|
||||
# to upper case. Otherwise convert the selected text to upper case.
|
||||
lowerCase: ->
|
||||
@replaceSelectedText selectWordIfEmpty:true, (text) => text.toLowerCase()
|
||||
@replaceSelectedText selectWordIfEmpty:true, (text) -> text.toLowerCase()
|
||||
|
||||
# Convert multiple lines to a single line.
|
||||
#
|
||||
@@ -1832,39 +1839,39 @@ class Editor extends Model
|
||||
# Operates on all selections. Moves the cursor to the beginning of the
|
||||
# containing word while preserving the selection's tail position.
|
||||
selectToBeginningOfWord: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToBeginningOfWord()
|
||||
@expandSelectionsBackward (selection) -> selection.selectToBeginningOfWord()
|
||||
|
||||
# Public: Expand selections to the end of their containing word.
|
||||
#
|
||||
# Operates on all selections. Moves the cursor to the end of the containing
|
||||
# word while preserving the selection's tail position.
|
||||
selectToEndOfWord: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToEndOfWord()
|
||||
@expandSelectionsForward (selection) -> selection.selectToEndOfWord()
|
||||
|
||||
# Public: Expand selections to the beginning of the next word.
|
||||
#
|
||||
# Operates on all selections. Moves the cursor to the beginning of the next
|
||||
# word while preserving the selection's tail position.
|
||||
selectToBeginningOfNextWord: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToBeginningOfNextWord()
|
||||
@expandSelectionsForward (selection) -> selection.selectToBeginningOfNextWord()
|
||||
|
||||
# Public: Select the word containing each cursor.
|
||||
selectWord: ->
|
||||
@expandSelectionsForward (selection) => selection.selectWord()
|
||||
@expandSelectionsForward (selection) -> selection.selectWord()
|
||||
|
||||
# Public: Expand selections to the beginning of the next paragraph.
|
||||
#
|
||||
# Operates on all selections. Moves the cursor to the beginning of the next
|
||||
# paragraph while preserving the selection's tail position.
|
||||
selectToBeginningOfNextParagraph: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToBeginningOfNextParagraph()
|
||||
@expandSelectionsForward (selection) -> selection.selectToBeginningOfNextParagraph()
|
||||
|
||||
# Public: Expand selections to the beginning of the next paragraph.
|
||||
#
|
||||
# Operates on all selections. Moves the cursor to the beginning of the next
|
||||
# paragraph while preserving the selection's tail position.
|
||||
selectToBeginningOfPreviousParagraph: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToBeginningOfPreviousParagraph()
|
||||
@expandSelectionsBackward (selection) -> selection.selectToBeginningOfPreviousParagraph()
|
||||
|
||||
# Public: Select the range of the given marker if it is valid.
|
||||
#
|
||||
@@ -1951,6 +1958,15 @@ class Editor extends Model
|
||||
shouldAutoIndent: ->
|
||||
atom.config.get("editor.autoIndent")
|
||||
|
||||
shouldShowInvisibles: ->
|
||||
not @mini and atom.config.get('editor.showInvisibles')
|
||||
|
||||
updateInvisibles: ->
|
||||
if @shouldShowInvisibles()
|
||||
@displayBuffer.setInvisibles(atom.config.get('editor.invisibles'))
|
||||
else
|
||||
@displayBuffer.setInvisibles(null)
|
||||
|
||||
# Public: Batch multiple operations as a single undo/redo step.
|
||||
#
|
||||
# Any group of operations that are logically grouped from the perspective of
|
||||
|
||||
+22
-1
@@ -1,4 +1,4 @@
|
||||
{join} = require 'path'
|
||||
{basename, join} = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{Emitter, Subscriber} = require 'emissary'
|
||||
@@ -93,6 +93,27 @@ class Git
|
||||
@getPathStatus(path)
|
||||
@subscribe buffer, 'destroyed', => @unsubscribe(buffer)
|
||||
|
||||
# Subscribes to editor view event.
|
||||
checkoutHeadForEditor: (editor) ->
|
||||
filePath = editor.getPath()
|
||||
return unless filePath
|
||||
|
||||
fileName = basename(filePath)
|
||||
|
||||
checkoutHead = =>
|
||||
editor.buffer.reload() if editor.buffer.isModified()
|
||||
@checkoutHead(filePath)
|
||||
|
||||
if atom.config.get('editor.confirmCheckoutHeadRevision')
|
||||
atom.confirm
|
||||
message: 'Confirm Checkout HEAD Revision'
|
||||
detailedMessage: "Are you sure you want to discard all changes to \"#{fileName}\" since the last Git commit?"
|
||||
buttons:
|
||||
OK: checkoutHead
|
||||
Cancel: null
|
||||
else
|
||||
checkoutHead()
|
||||
|
||||
# Public: Destroy this `Git` object. This destroys any tasks and subscriptions
|
||||
# and releases the underlying libgit2 repository handle.
|
||||
destroy: ->
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
{View, $, $$, $$$} = require './space-pen-extensions'
|
||||
{Range} = require 'text-buffer'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
# Represents the portion of the {EditorView} containing row numbers.
|
||||
#
|
||||
# The gutter also indicates if rows are folded.
|
||||
module.exports =
|
||||
class GutterView extends View
|
||||
@content: ->
|
||||
@div class: 'gutter', =>
|
||||
@div outlet: 'lineNumbers', class: 'line-numbers'
|
||||
|
||||
firstScreenRow: null
|
||||
lastScreenRow: null
|
||||
|
||||
initialize: ->
|
||||
@elementBuilder = document.createElement('div')
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return if @attached or not onDom
|
||||
@attached = true
|
||||
|
||||
highlightLines = => @highlightLines()
|
||||
@getEditorView().on 'cursor:moved', highlightLines
|
||||
@getEditorView().on 'selection:changed', highlightLines
|
||||
@on 'mousedown', (e) => @handleMouseEvents(e)
|
||||
|
||||
beforeRemove: ->
|
||||
$(document).off(".gutter-#{@getEditorView().id}")
|
||||
|
||||
handleMouseEvents: (e) ->
|
||||
editorView = @getEditorView()
|
||||
editor = @getEditor()
|
||||
startRow = editorView.screenPositionFromMouseEvent(e).row
|
||||
if e.shiftKey
|
||||
editor.selectToScreenPosition([startRow + 1, 0])
|
||||
return
|
||||
else
|
||||
editor.getSelection().setScreenRange([[startRow, 0], [startRow, 0]])
|
||||
|
||||
moveHandler = (e) =>
|
||||
start = startRow
|
||||
end = editorView.screenPositionFromMouseEvent(e).row
|
||||
if end > start then end++ else start++
|
||||
editor.getSelection().setScreenRange([[start, 0], [end, 0]])
|
||||
|
||||
$(document).on "mousemove.gutter-#{editorView.id}", moveHandler
|
||||
$(document).one "mouseup.gutter-#{editorView.id}", => $(document).off 'mousemove', moveHandler
|
||||
|
||||
# Retrieves the containing {EditorView}.
|
||||
#
|
||||
# Returns an {EditorView}.
|
||||
getEditorView: ->
|
||||
@parentView
|
||||
|
||||
getEditor: ->
|
||||
@getEditorView().getEditor()
|
||||
|
||||
# Defines whether to show the gutter or not.
|
||||
#
|
||||
# showLineNumbers - A {Boolean} which, if `false`, hides the gutter
|
||||
setShowLineNumbers: (showLineNumbers) ->
|
||||
if showLineNumbers then @lineNumbers.show() else @lineNumbers.hide()
|
||||
|
||||
# Get all the line-number divs.
|
||||
#
|
||||
# Returns a list of {HTMLElement}s.
|
||||
getLineNumberElements: ->
|
||||
@lineNumbers[0].children
|
||||
|
||||
# Get all the line-number divs.
|
||||
#
|
||||
# Returns a list of {HTMLElement}s.
|
||||
getLineNumberElementsForClass: (klass) ->
|
||||
@lineNumbers[0].getElementsByClassName(klass)
|
||||
|
||||
# Get a single line-number div.
|
||||
#
|
||||
# * bufferRow: 0 based line number
|
||||
#
|
||||
# Returns a list of {HTMLElement}s that correspond to the bufferRow. More than
|
||||
# one in the list indicates a wrapped line.
|
||||
getLineNumberElement: (bufferRow) ->
|
||||
@getLineNumberElementsForClass("line-number-#{bufferRow}")
|
||||
|
||||
# Add a class to all line-number divs.
|
||||
#
|
||||
# * klass: string class name
|
||||
#
|
||||
# Returns true if the class was added to any lines
|
||||
addClassToAllLines: (klass)->
|
||||
elements = @getLineNumberElements()
|
||||
el.classList.add(klass) for el in elements
|
||||
!!elements.length
|
||||
|
||||
# Remove a class from all line-number divs.
|
||||
#
|
||||
# * klass: string class name. Can only be one class name. i.e. 'my-class'
|
||||
#
|
||||
# Returns true if the class was removed from any lines
|
||||
removeClassFromAllLines: (klass)->
|
||||
# This is faster than calling $.removeClass on all lines, and faster than
|
||||
# making a new array and iterating through it.
|
||||
elements = @getLineNumberElementsForClass(klass)
|
||||
willRemoveClasses = !!elements.length
|
||||
elements[0].classList.remove(klass) while elements.length > 0
|
||||
willRemoveClasses
|
||||
|
||||
# Add a class to a single line-number div
|
||||
#
|
||||
# * bufferRow: 0 based line number
|
||||
# * klass: string class name
|
||||
#
|
||||
# Returns true if there were lines the class was added to
|
||||
addClassToLine: (bufferRow, klass)->
|
||||
elements = @getLineNumberElement(bufferRow)
|
||||
el.classList.add(klass) for el in elements
|
||||
!!elements.length
|
||||
|
||||
# Remove a class from a single line-number div
|
||||
#
|
||||
# * bufferRow: 0 based line number
|
||||
# * klass: string class name
|
||||
#
|
||||
# Returns true if there were lines the class was removed from
|
||||
removeClassFromLine: (bufferRow, klass)->
|
||||
classesRemoved = false
|
||||
elements = @getLineNumberElement(bufferRow)
|
||||
for el in elements
|
||||
hasClass = el.classList.contains(klass)
|
||||
classesRemoved |= hasClass
|
||||
el.classList.remove(klass) if hasClass
|
||||
classesRemoved
|
||||
|
||||
updateLineNumbers: (changes, startScreenRow, endScreenRow) ->
|
||||
# Check if we have something already rendered that overlaps the requested range
|
||||
updateAllLines = not (startScreenRow? and endScreenRow?)
|
||||
updateAllLines |= endScreenRow <= @firstScreenRow or startScreenRow >= @lastScreenRow
|
||||
|
||||
unless updateAllLines
|
||||
for change in changes
|
||||
if change.screenDelta or change.bufferDelta
|
||||
updateAllLines = true
|
||||
break
|
||||
|
||||
# Rebuild the entire gutter if a change added or removed lines
|
||||
if updateAllLines
|
||||
@lineNumbers[0].innerHTML = @buildLineElementsHtml(startScreenRow, endScreenRow)
|
||||
|
||||
# Handle changes that didn't add/remove lines more optimally
|
||||
else
|
||||
if startScreenRow < @firstScreenRow
|
||||
@prependLineElements(@buildLineElements(startScreenRow, @firstScreenRow-1))
|
||||
else if startScreenRow != @firstScreenRow
|
||||
@removeLineElements(startScreenRow - @firstScreenRow)
|
||||
|
||||
if endScreenRow > @lastScreenRow
|
||||
@appendLineElements(@buildLineElements(@lastScreenRow+1, endScreenRow))
|
||||
else if endScreenRow != @lastScreenRow
|
||||
@removeLineElements(endScreenRow - @lastScreenRow)
|
||||
|
||||
@updateFoldableClasses(changes)
|
||||
|
||||
@firstScreenRow = startScreenRow
|
||||
@lastScreenRow = endScreenRow
|
||||
@highlightedRows = null
|
||||
@highlightLines()
|
||||
|
||||
prependLineElements: (lineElements) ->
|
||||
anchor = @lineNumbers[0].children[0]
|
||||
return appendLineElements(lineElements) unless anchor?
|
||||
@lineNumbers[0].insertBefore(lineElements[0], anchor) while lineElements.length > 0
|
||||
null # defeat coffeescript array return
|
||||
|
||||
appendLineElements: (lineElements) ->
|
||||
@lineNumbers[0].appendChild(lineElements[0]) while lineElements.length > 0
|
||||
null # defeat coffeescript array return
|
||||
|
||||
removeLineElements: (numberOfElements) ->
|
||||
children = @getLineNumberElements()
|
||||
|
||||
# children is a live NodeList, so remove from the desired end {numberOfElements} times
|
||||
if numberOfElements < 0
|
||||
@lineNumbers[0].removeChild(children[children.length-1]) while numberOfElements++
|
||||
else if numberOfElements > 0
|
||||
@lineNumbers[0].removeChild(children[0]) while numberOfElements--
|
||||
|
||||
null # defeat coffeescript array return
|
||||
|
||||
buildLineElements: (startScreenRow, endScreenRow) ->
|
||||
@elementBuilder.innerHTML = @buildLineElementsHtml(startScreenRow, endScreenRow)
|
||||
@elementBuilder.children
|
||||
|
||||
buildLineElementsHtml: (startScreenRow, endScreenRow) =>
|
||||
editor = @getEditor()
|
||||
maxDigits = editor.getLineCount().toString().length
|
||||
rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow)
|
||||
|
||||
html = ''
|
||||
for row in rows
|
||||
if row is lastRow
|
||||
rowValue = '•'
|
||||
else
|
||||
rowValue = (row + 1).toString()
|
||||
|
||||
classes = "line-number line-number-#{row}"
|
||||
classes += ' foldable' if row isnt lastRow and editor.isFoldableAtBufferRow(row)
|
||||
classes += ' folded' if editor.isFoldedAtBufferRow(row)
|
||||
|
||||
rowValuePadding = _.multiplyString(' ', maxDigits - rowValue.length)
|
||||
|
||||
html += """<div class="#{classes}" data-buffer-row=#{row}>#{rowValuePadding}#{rowValue}<div class="icon-right"></div></div>"""
|
||||
|
||||
lastRow = row
|
||||
|
||||
html
|
||||
|
||||
# Called to update the 'foldable' class of line numbers when there's
|
||||
# a change to the display buffer that doesn't regenerate all the line numbers
|
||||
# anyway.
|
||||
updateFoldableClasses: (changes) ->
|
||||
editor = @getEditor()
|
||||
for {start, end} in changes when start <= @lastScreenRow and end >= @firstScreenRow
|
||||
startScreenRow = Math.max(start - 1, @firstScreenRow)
|
||||
endScreenRow = Math.min(end + 1, @lastScreenRow)
|
||||
lastBufferRow = null
|
||||
for bufferRow in editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) when bufferRow isnt lastBufferRow
|
||||
lastBufferRow = bufferRow
|
||||
if lineNumberElement = @getLineNumberElement(bufferRow)[0]
|
||||
if editor.isFoldableAtBufferRow(bufferRow)
|
||||
lineNumberElement.classList.add('foldable')
|
||||
else
|
||||
lineNumberElement.classList.remove('foldable')
|
||||
|
||||
removeLineHighlights: ->
|
||||
return unless @highlightedLineNumbers
|
||||
for line in @highlightedLineNumbers
|
||||
line.classList.remove('cursor-line')
|
||||
line.classList.remove('cursor-line-no-selection')
|
||||
@highlightedLineNumbers = null
|
||||
|
||||
addLineHighlight: (row, emptySelection) ->
|
||||
return if row < @firstScreenRow or row > @lastScreenRow
|
||||
@highlightedLineNumbers ?= []
|
||||
if highlightedLineNumber = @lineNumbers[0].children[row - @firstScreenRow]
|
||||
highlightedLineNumber.classList.add('cursor-line')
|
||||
highlightedLineNumber.classList.add('cursor-line-no-selection') if emptySelection
|
||||
@highlightedLineNumbers.push(highlightedLineNumber)
|
||||
|
||||
highlightLines: ->
|
||||
editor = @getEditor()
|
||||
return unless editor?.isAlive()
|
||||
|
||||
if editor.getSelection().isEmpty()
|
||||
row = editor.getCursorScreenPosition().row
|
||||
rowRange = new Range([row, 0], [row, 0])
|
||||
return if @selectionEmpty and @highlightedRows?.isEqual(rowRange)
|
||||
|
||||
@removeLineHighlights()
|
||||
@addLineHighlight(row, true)
|
||||
@highlightedRows = rowRange
|
||||
@selectionEmpty = true
|
||||
else
|
||||
selectedRows = editor.getSelection().getScreenRange()
|
||||
endRow = selectedRows.end.row
|
||||
endRow-- if selectedRows.end.column is 0
|
||||
selectedRows = new Range([selectedRows.start.row, 0], [endRow, 0])
|
||||
return if not @selectionEmpty and @highlightedRows?.isEqual(selectedRows)
|
||||
|
||||
@removeLineHighlights()
|
||||
for row in [selectedRows.start.row..selectedRows.end.row]
|
||||
@addLineHighlight(row, false)
|
||||
@highlightedRows = selectedRows
|
||||
@selectionEmpty = false
|
||||
@@ -60,7 +60,7 @@ LinesComponent = React.createClass
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'visible',
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration',
|
||||
'placeholderText', 'performedInitialMeasurement', 'backgroundColor', 'cursorPixelRects'
|
||||
)
|
||||
@@ -82,7 +82,7 @@ LinesComponent = React.createClass
|
||||
return unless performedInitialMeasurement
|
||||
|
||||
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
|
||||
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
|
||||
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide')
|
||||
@updateLines(@props.lineWidth isnt prevProps.lineWidth)
|
||||
@measureCharactersInNewLines() if visible and not scrollingVertically
|
||||
|
||||
@@ -91,12 +91,11 @@ LinesComponent = React.createClass
|
||||
@lineIdsByScreenRow = {}
|
||||
|
||||
updateLines: (updateWidth) ->
|
||||
{editor, renderedRowRange, showIndentGuide, selectionChanged, lineDecorations} = @props
|
||||
[startRow, endRow] = renderedRowRange
|
||||
{tokenizedLines, renderedRowRange, showIndentGuide, selectionChanged, lineDecorations} = @props
|
||||
[startRow] = renderedRowRange
|
||||
|
||||
visibleLines = editor.linesForScreenRows(startRow, endRow - 1)
|
||||
@removeLineNodes(visibleLines)
|
||||
@appendOrUpdateVisibleLineNodes(visibleLines, startRow, updateWidth)
|
||||
@removeLineNodes(tokenizedLines)
|
||||
@appendOrUpdateVisibleLineNodes(tokenizedLines, startRow, updateWidth)
|
||||
|
||||
removeLineNodes: (visibleLines=[]) ->
|
||||
{mouseWheelScreenRow} = @props
|
||||
@@ -147,7 +146,7 @@ LinesComponent = React.createClass
|
||||
@lineNodesByLineId.hasOwnProperty(lineId)
|
||||
|
||||
buildLineHTML: (line, screenRow) ->
|
||||
{editor, mini, showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props
|
||||
{mini, showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props
|
||||
{tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line
|
||||
|
||||
classes = ''
|
||||
@@ -170,34 +169,30 @@ LinesComponent = React.createClass
|
||||
lineHTML
|
||||
|
||||
buildEmptyLineInnerHTML: (line) ->
|
||||
{showIndentGuide, invisibles} = @props
|
||||
{cr, eol} = invisibles
|
||||
{indentLevel, tabLength} = line
|
||||
{showIndentGuide} = @props
|
||||
{indentLevel, tabLength, endOfLineInvisibles} = line
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
invisiblesToRender = []
|
||||
invisiblesToRender.push(cr) if cr? and line.lineEnding is '\r\n'
|
||||
invisiblesToRender.push(eol) if eol?
|
||||
|
||||
invisibleIndex = 0
|
||||
lineHTML = ''
|
||||
for i in [0...indentLevel]
|
||||
lineHTML += "<span class='indent-guide'>"
|
||||
for j in [0...tabLength]
|
||||
if invisible = invisiblesToRender.shift()
|
||||
if invisible = endOfLineInvisibles?[invisibleIndex++]
|
||||
lineHTML += "<span class='invisible-character'>#{invisible}</span>"
|
||||
else
|
||||
lineHTML += ' '
|
||||
lineHTML += "</span>"
|
||||
|
||||
while invisiblesToRender.length
|
||||
lineHTML += "<span class='invisible-character'>#{invisiblesToRender.shift()}</span>"
|
||||
while invisibleIndex < endOfLineInvisibles?.length
|
||||
lineHTML += "<span class='invisible-character'>#{line.endOfLineInvisibles[invisibleIndex++]}</span>"
|
||||
|
||||
lineHTML
|
||||
else
|
||||
@buildEndOfLineHTML(line, @props.invisibles) or ' '
|
||||
@buildEndOfLineHTML(line) or ' '
|
||||
|
||||
buildLineInnerHTML: (line) ->
|
||||
{invisibles, mini, showIndentGuide, invisibles} = @props
|
||||
{mini, showIndentGuide} = @props
|
||||
{tokens, text} = line
|
||||
innerHTML = ""
|
||||
|
||||
@@ -206,24 +201,20 @@ LinesComponent = React.createClass
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
for token in tokens
|
||||
innerHTML += @updateScopeStack(scopeStack, token.scopes)
|
||||
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly))
|
||||
innerHTML += token.getValueAsHtml({invisibles, hasIndentGuide})
|
||||
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and lineIsWhitespaceOnly))
|
||||
innerHTML += token.getValueAsHtml({hasIndentGuide})
|
||||
|
||||
innerHTML += @popScope(scopeStack) while scopeStack.length > 0
|
||||
innerHTML += @buildEndOfLineHTML(line, invisibles)
|
||||
innerHTML += @buildEndOfLineHTML(line)
|
||||
innerHTML
|
||||
|
||||
buildEndOfLineHTML: (line, invisibles) ->
|
||||
return '' if @props.mini or line.isSoftWrapped()
|
||||
buildEndOfLineHTML: (line) ->
|
||||
{endOfLineInvisibles} = line
|
||||
|
||||
html = ''
|
||||
# Note the lack of '?' in the character checks. A user can set the chars
|
||||
# to an empty string which we will interpret as not-set
|
||||
if invisibles.cr and line.lineEnding is '\r\n'
|
||||
html += "<span class='invisible-character'>#{invisibles.cr}</span>"
|
||||
if invisibles.eol
|
||||
html += "<span class='invisible-character'>#{invisibles.eol}</span>"
|
||||
|
||||
if endOfLineInvisibles?
|
||||
for invisible in endOfLineInvisibles
|
||||
html += "<span class='invisible-character'>#{invisible}</span>"
|
||||
html
|
||||
|
||||
updateScopeStack: (scopeStack, desiredScopes) ->
|
||||
@@ -252,7 +243,7 @@ LinesComponent = React.createClass
|
||||
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
|
||||
|
||||
updateLineNode: (line, screenRow, updateWidth) ->
|
||||
{editor, lineHeightInPixels, lineDecorations, lineWidth} = @props
|
||||
{lineHeightInPixels, lineDecorations, lineWidth} = @props
|
||||
lineNode = @lineNodesByLineId[line.id]
|
||||
|
||||
decorations = lineDecorations[screenRow]
|
||||
@@ -294,16 +285,18 @@ LinesComponent = React.createClass
|
||||
editor.setDefaultCharWidth(charWidth)
|
||||
|
||||
remeasureCharacterWidths: ->
|
||||
return unless @props.performedInitialMeasurement
|
||||
|
||||
@clearScopedCharWidths()
|
||||
@measureCharactersInNewLines()
|
||||
|
||||
measureCharactersInNewLines: ->
|
||||
{editor} = @props
|
||||
[visibleStartRow, visibleEndRow] = @props.renderedRowRange
|
||||
{editor, tokenizedLines, renderedRowRange} = @props
|
||||
[visibleStartRow] = renderedRowRange
|
||||
node = @getDOMNode()
|
||||
|
||||
editor.batchCharacterMeasurement =>
|
||||
for tokenizedLine in editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
|
||||
for tokenizedLine in tokenizedLines
|
||||
unless @measuredLines.has(tokenizedLine)
|
||||
lineNode = @lineNodesByLineId[tokenizedLine.id]
|
||||
@measureCharactersInLine(tokenizedLine, lineNode)
|
||||
|
||||
@@ -141,13 +141,17 @@ class PaneView extends View
|
||||
@activeItem
|
||||
|
||||
onActiveItemChanged: (item) =>
|
||||
@previousActiveItem?.off? 'title-changed', @activeItemTitleChanged
|
||||
if @previousActiveItem?.off?
|
||||
@previousActiveItem.off 'title-changed', @activeItemTitleChanged
|
||||
@previousActiveItem.off 'modified-status-changed', @activeItemModifiedChanged
|
||||
@previousActiveItem = item
|
||||
|
||||
return unless item?
|
||||
|
||||
hasFocus = @hasFocus()
|
||||
item.on? 'title-changed', @activeItemTitleChanged
|
||||
if item.on?
|
||||
item.on 'title-changed', @activeItemTitleChanged
|
||||
item.on 'modified-status-changed', @activeItemModifiedChanged
|
||||
view = @viewForItem(item)
|
||||
otherView.hide() for otherView in @itemViews.children().not(view).views()
|
||||
@itemViews.append(view) unless view.parent().is(@itemViews)
|
||||
@@ -183,6 +187,9 @@ class PaneView extends View
|
||||
activeItemTitleChanged: =>
|
||||
@trigger 'pane:active-item-title-changed'
|
||||
|
||||
activeItemModifiedChanged: =>
|
||||
@trigger 'pane:active-item-modified-status-changed'
|
||||
|
||||
viewForItem: (item) ->
|
||||
return unless item?
|
||||
if item instanceof $
|
||||
|
||||
@@ -100,9 +100,9 @@ class Project extends Model
|
||||
uri
|
||||
else
|
||||
if fs.isAbsolute(uri)
|
||||
fs.absolute(uri)
|
||||
path.normalize(fs.absolute(uri))
|
||||
else if projectPath = @getPath()
|
||||
fs.absolute(path.join(projectPath, uri))
|
||||
path.normalize(fs.absolute(path.join(projectPath, uri)))
|
||||
else
|
||||
undefined
|
||||
|
||||
@@ -184,7 +184,7 @@ class Project extends Model
|
||||
# Returns a promise that resolves to the {TextBuffer}.
|
||||
buildBuffer: (absoluteFilePath) ->
|
||||
if fs.getSizeSync(absoluteFilePath) >= 2 * 1048576 # 2MB
|
||||
throw new Error("Atom can only handle files < 2MB, for now.")
|
||||
throw new Error("Atom can only handle files < 2MB for now.")
|
||||
|
||||
buffer = new TextBuffer({filePath: absoluteFilePath})
|
||||
@addBuffer(buffer)
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
{View, $} = require 'space-pen'
|
||||
React = require 'react-atom-fork'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Editor = require './editor'
|
||||
EditorComponent = require './editor-component'
|
||||
|
||||
module.exports =
|
||||
class ReactEditorView extends View
|
||||
@content: (params) ->
|
||||
attributes = params.attributes ? {}
|
||||
attributes.class = 'editor react editor-colors'
|
||||
attributes.tabIndex = -1
|
||||
@div attributes
|
||||
|
||||
focusOnAttach: false
|
||||
|
||||
constructor: (editorOrParams, props) ->
|
||||
super
|
||||
|
||||
if editorOrParams instanceof Editor
|
||||
@editor = editorOrParams
|
||||
else
|
||||
{@editor, mini, placeholderText} = editorOrParams
|
||||
props ?= {}
|
||||
props.mini = mini
|
||||
props.placeholderText = placeholderText
|
||||
@editor ?= new Editor
|
||||
buffer: new TextBuffer
|
||||
softWrap: false
|
||||
tabLength: 2
|
||||
softTabs: true
|
||||
|
||||
props = defaults({@editor, parentView: this}, props)
|
||||
@component = React.renderComponent(EditorComponent(props), @element)
|
||||
|
||||
node = @component.getDOMNode()
|
||||
|
||||
@scrollView = $(node).find('.scroll-view')
|
||||
@underlayer = $(node).find('.highlights').addClass('underlayer')
|
||||
@overlayer = $(node).find('.lines').addClass('overlayer')
|
||||
@hiddenInput = $(node).find('.hidden-input')
|
||||
|
||||
# FIXME: there should be a better way to deal with the gutter element
|
||||
@subscribe atom.config.observe 'editor.showLineNumbers', =>
|
||||
@gutter = $(node).find('.gutter')
|
||||
|
||||
@gutter.removeClassFromAllLines = (klass) =>
|
||||
@gutter.find('.line-number').removeClass(klass)
|
||||
|
||||
@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
|
||||
|
||||
@on 'focus', =>
|
||||
if @component?
|
||||
@component.onFocus()
|
||||
else
|
||||
@focusOnAttach = true
|
||||
|
||||
getEditor: -> @editor
|
||||
|
||||
getModel: -> @editor
|
||||
|
||||
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeightInPixels()
|
||||
Object.defineProperty @::, 'charWidth', get: -> @editor.getDefaultCharWidth()
|
||||
Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0]
|
||||
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
|
||||
Object.defineProperty @::, 'active', get: -> @is(@getPane()?.activeView)
|
||||
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
|
||||
Object.defineProperty @::, 'mini', get: -> @component?.props.mini
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return unless onDom
|
||||
return if @attached
|
||||
@attached = true
|
||||
@component.pollDOM()
|
||||
@focus() if @focusOnAttach
|
||||
@trigger 'editor:attached', [this]
|
||||
|
||||
scrollTop: (scrollTop) ->
|
||||
if scrollTop?
|
||||
@editor.setScrollTop(scrollTop)
|
||||
else
|
||||
@editor.getScrollTop()
|
||||
|
||||
scrollLeft: (scrollLeft) ->
|
||||
if scrollLeft?
|
||||
@editor.setScrollLeft(scrollLeft)
|
||||
else
|
||||
@editor.getScrollLeft()
|
||||
|
||||
scrollToBottom: ->
|
||||
@editor.setScrollBottom(Infinity)
|
||||
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
@editor.scrollToScreenPosition(screenPosition, options)
|
||||
|
||||
scrollToBufferPosition: (bufferPosition, options) ->
|
||||
@editor.scrollToBufferPosition(bufferPosition, options)
|
||||
|
||||
scrollToCursorPosition: ->
|
||||
@editor.scrollToCursorPosition()
|
||||
|
||||
scrollToPixelPosition: (pixelPosition) ->
|
||||
screenPosition = screenPositionForPixelPosition(pixelPosition)
|
||||
@editor.scrollToScreenPosition(screenPosition)
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@editor.pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
@editor.pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
appendToLinesView: (view) ->
|
||||
view.css('position', 'absolute')
|
||||
view.css('z-index', 1)
|
||||
@find('.lines').prepend(view)
|
||||
|
||||
beforeRemove: ->
|
||||
return unless @attached
|
||||
@attached = false
|
||||
React.unmountComponentAtNode(@element) if @component.isMounted()
|
||||
@trigger 'editor:detached', this
|
||||
|
||||
# Public: Split the editor view left.
|
||||
splitLeft: ->
|
||||
pane = @getPane()
|
||||
pane?.splitLeft(pane?.copyActiveItem()).activeView
|
||||
|
||||
# Public: Split the editor view right.
|
||||
splitRight: ->
|
||||
pane = @getPane()
|
||||
pane?.splitRight(pane?.copyActiveItem()).activeView
|
||||
|
||||
# Public: Split the editor view up.
|
||||
splitUp: ->
|
||||
pane = @getPane()
|
||||
pane?.splitUp(pane?.copyActiveItem()).activeView
|
||||
|
||||
# Public: Split the editor view down.
|
||||
splitDown: ->
|
||||
pane = @getPane()
|
||||
pane?.splitDown(pane?.copyActiveItem()).activeView
|
||||
|
||||
getPane: ->
|
||||
@parent('.item-views').parents('.pane').view()
|
||||
|
||||
hide: ->
|
||||
super
|
||||
@pollComponentDOM()
|
||||
|
||||
show: ->
|
||||
super
|
||||
@pollComponentDOM()
|
||||
|
||||
pollComponentDOM: ->
|
||||
return unless @component?
|
||||
valueToRestore = @component.performSyncUpdates
|
||||
@component.performSyncUpdates = true
|
||||
@component.pollDOM()
|
||||
@component.performSyncUpdates = valueToRestore
|
||||
|
||||
pageDown: ->
|
||||
@editor.pageDown()
|
||||
|
||||
pageUp: ->
|
||||
@editor.pageUp()
|
||||
|
||||
getFirstVisibleScreenRow: ->
|
||||
@editor.getVisibleRowRange()[0]
|
||||
|
||||
getLastVisibleScreenRow: ->
|
||||
@editor.getVisibleRowRange()[1]
|
||||
|
||||
getFontFamily: ->
|
||||
@component?.getFontFamily()
|
||||
|
||||
setFontFamily: (fontFamily)->
|
||||
@component?.setFontFamily(fontFamily)
|
||||
|
||||
getFontSize: ->
|
||||
@component?.getFontSize()
|
||||
|
||||
setFontSize: (fontSize)->
|
||||
@component?.setFontSize(fontSize)
|
||||
|
||||
setWidthInChars: (widthInChars) ->
|
||||
@component.getDOMNode().style.width = (@editor.getDefaultCharWidth() * widthInChars) + 'px'
|
||||
|
||||
setLineHeight: (lineHeight) ->
|
||||
@component.setLineHeight(lineHeight)
|
||||
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
@component.setShowIndentGuide(showIndentGuide)
|
||||
|
||||
setSoftWrap: (softWrap) ->
|
||||
@editor.setSoftWrap(softWrap)
|
||||
|
||||
setShowInvisibles: (showInvisibles) ->
|
||||
@component.setShowInvisibles(showInvisibles)
|
||||
|
||||
toggleSoftWrap: ->
|
||||
@editor.toggleSoftWrap()
|
||||
|
||||
toggleSoftTabs: ->
|
||||
@editor.toggleSoftTabs()
|
||||
|
||||
getText: ->
|
||||
@editor.getText()
|
||||
|
||||
setText: (text) ->
|
||||
@editor.setText(text)
|
||||
|
||||
insertText: (text) ->
|
||||
@editor.insertText(text)
|
||||
|
||||
isInputEnabled: ->
|
||||
@component.isInputEnabled()
|
||||
|
||||
setInputEnabled: (inputEnabled) ->
|
||||
@component.setInputEnabled(inputEnabled)
|
||||
|
||||
requestDisplayUpdate: -> # No-op shim for find-and-replace
|
||||
|
||||
updateDisplay: -> # No-op shim for package specs
|
||||
|
||||
resetDisplay: -> # No-op shim for package specs
|
||||
|
||||
redraw: -> # No-op shim
|
||||
|
||||
setPlaceholderText: (placeholderText) ->
|
||||
if @component?
|
||||
@component.setProps({placeholderText})
|
||||
else
|
||||
@props.placeholderText = placeholderText
|
||||
|
||||
lineElementForScreenRow: (screenRow) ->
|
||||
$(@component.lineNodeForScreenRow(screenRow))
|
||||
@@ -39,9 +39,9 @@ ScrollbarComponent = React.createClass
|
||||
|
||||
switch @props.orientation
|
||||
when 'vertical'
|
||||
not isEqualForProperties(newProps, @props, 'scrollHeight', 'scrollTop', 'scrollableInOppositeDirection')
|
||||
not isEqualForProperties(newProps, @props, 'scrollHeight', 'scrollTop', 'scrollableInOppositeDirection', 'verticalScrollbarWidth')
|
||||
when 'horizontal'
|
||||
not isEqualForProperties(newProps, @props, 'scrollWidth', 'scrollLeft', 'scrollableInOppositeDirection')
|
||||
not isEqualForProperties(newProps, @props, 'scrollWidth', 'scrollLeft', 'scrollableInOppositeDirection', 'horizontalScrollbarHeight')
|
||||
|
||||
componentDidUpdate: ->
|
||||
{orientation, scrollTop, scrollLeft} = @props
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{$, View} = require './space-pen-extensions'
|
||||
if atom.config.get('core.useReactMiniEditors')
|
||||
EditorView = require './react-editor-view'
|
||||
else
|
||||
EditorView = require './editor-view'
|
||||
EditorView = require './editor-view'
|
||||
fuzzyFilter = require('fuzzaldrin').filter
|
||||
|
||||
# Public: Provides a view that renders a list of items with an editor that
|
||||
@@ -275,7 +272,6 @@ class SelectListView extends View
|
||||
|
||||
cancelled: ->
|
||||
@filterEditorView.getEditor().setText('')
|
||||
@filterEditorView.updateDisplay()
|
||||
|
||||
# Public: Cancel and close this select list view.
|
||||
#
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{View, $$} = require './space-pen-extensions'
|
||||
|
||||
module.exports =
|
||||
class SelectionView extends View
|
||||
|
||||
@content: ->
|
||||
@div class: 'selection'
|
||||
|
||||
regions: null
|
||||
needsRemoval: false
|
||||
|
||||
initialize: ({@editorView, @selection} = {}) ->
|
||||
@regions = []
|
||||
@selection.on 'screen-range-changed', => @editorView.requestDisplayUpdate()
|
||||
@selection.on 'destroyed', =>
|
||||
@needsRemoval = true
|
||||
@editorView.requestDisplayUpdate()
|
||||
|
||||
updateDisplay: ->
|
||||
@clearRegions()
|
||||
range = @getScreenRange()
|
||||
|
||||
@trigger 'selection:changed'
|
||||
@editorView.highlightFoldsContainingBufferRange(@getBufferRange())
|
||||
return if range.isEmpty()
|
||||
|
||||
rowSpan = range.end.row - range.start.row
|
||||
|
||||
if rowSpan == 0
|
||||
@appendRegion(1, range.start, range.end)
|
||||
else
|
||||
@appendRegion(1, range.start, null)
|
||||
if rowSpan > 1
|
||||
@appendRegion(rowSpan - 1, { row: range.start.row + 1, column: 0}, null)
|
||||
@appendRegion(1, { row: range.end.row, column: 0 }, range.end)
|
||||
|
||||
appendRegion: (rows, start, end) ->
|
||||
{ lineHeight, charWidth } = @editorView
|
||||
css = @editorView.pixelPositionForScreenPosition(start)
|
||||
css.height = lineHeight * rows
|
||||
if end
|
||||
css.width = @editorView.pixelPositionForScreenPosition(end).left - css.left
|
||||
else
|
||||
css.right = 0
|
||||
|
||||
region = ($$ -> @div class: 'region').css(css)
|
||||
@append(region)
|
||||
@regions.push(region)
|
||||
|
||||
getCenterPixelPosition: ->
|
||||
{ start, end } = @getScreenRange()
|
||||
startRow = start.row
|
||||
endRow = end.row
|
||||
endRow-- if end.column == 0
|
||||
@editorView.pixelPositionForScreenPosition([((startRow + endRow + 1) / 2), start.column])
|
||||
|
||||
clearRegions: ->
|
||||
region.remove() for region in @regions
|
||||
@regions = []
|
||||
|
||||
getScreenRange: ->
|
||||
@selection.getScreenRange()
|
||||
|
||||
getBufferRange: ->
|
||||
@selection.getBufferRange()
|
||||
|
||||
needsAutoscroll: ->
|
||||
@selection.needsAutoscroll
|
||||
|
||||
clearAutoscroll: ->
|
||||
@selection.clearAutoscroll()
|
||||
|
||||
highlight: ->
|
||||
@unhighlight()
|
||||
@addClass('highlighted')
|
||||
clearTimeout(@unhighlightTimeout)
|
||||
@unhighlightTimeout = setTimeout((=> @unhighlight()), 1000)
|
||||
|
||||
unhighlight: ->
|
||||
@removeClass('highlighted')
|
||||
|
||||
remove: ->
|
||||
@editorView.removeSelectionView(this)
|
||||
super
|
||||
@@ -381,7 +381,7 @@ class Selection extends Model
|
||||
# options - A {Object} with the keys:
|
||||
# :autoIndent - If `true`, the line is indented to an automatically-inferred
|
||||
# level. Otherwise, {Editor::getTabText} is inserted.
|
||||
indent: ({ autoIndent }={})->
|
||||
indent: ({ autoIndent }={}) ->
|
||||
{ row, column } = @cursor.getBufferPosition()
|
||||
|
||||
if @isEmpty()
|
||||
|
||||
@@ -78,6 +78,9 @@ class Task
|
||||
|
||||
# Public: Starts the task.
|
||||
#
|
||||
# Throws an error if this task has already been terminated or if sending a
|
||||
# message to the child process fails.
|
||||
#
|
||||
# args - The arguments to pass to the function exported by this task's script.
|
||||
# callback - An optional {Function} to call when the task completes.
|
||||
start: (args..., callback) ->
|
||||
@@ -92,6 +95,9 @@ class Task
|
||||
|
||||
# Public: Send message to the task.
|
||||
#
|
||||
# Throws an error if this task has already been terminated or if sending a
|
||||
# message to the child process fails.
|
||||
#
|
||||
# message - The message to send to the task.
|
||||
send: (message) ->
|
||||
throw new Error("Cannot send message to terminated process") unless @childProcess?
|
||||
|
||||
@@ -94,6 +94,7 @@ class ThemeManager
|
||||
console.warn("Failed to activate theme '#{themeName}' because it isn't installed.")
|
||||
|
||||
Q.all(promises).then =>
|
||||
@addActiveThemeClasses()
|
||||
@refreshLessCache() # Update cache again now that @getActiveThemes() is populated
|
||||
@loadUserStylesheet()
|
||||
@reloadBaseStylesheets()
|
||||
@@ -103,10 +104,21 @@ class ThemeManager
|
||||
deferred.promise
|
||||
|
||||
deactivateThemes: ->
|
||||
@removeActiveThemeClasses()
|
||||
@unwatchUserStylesheet()
|
||||
@packageManager.deactivatePackage(pack.name) for pack in @getActiveThemes()
|
||||
null
|
||||
|
||||
addActiveThemeClasses: ->
|
||||
for pack in @getActiveThemes()
|
||||
atom.workspaceView?[0]?.classList.add("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
removeActiveThemeClasses: ->
|
||||
for pack in @getActiveThemes()
|
||||
atom.workspaceView?[0]?.classList.remove("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
refreshLessCache: ->
|
||||
@lessCache?.setImportPaths(@getImportPaths())
|
||||
|
||||
|
||||
+45
-26
@@ -2,11 +2,7 @@ _ = require 'underscore-plus'
|
||||
textUtils = require './text-utils'
|
||||
|
||||
WhitespaceRegexesByTabLength = {}
|
||||
LeadingSpaceRegex = /^[ ]+/
|
||||
TrailingSpaceRegex = /[ ]+$/
|
||||
EscapeRegex = /[&"'<>]/g
|
||||
CharacterRegex = /./g
|
||||
StartCharacterRegex = /^./
|
||||
StartDotRegex = /^\.?/
|
||||
WhitespaceRegex = /\S/
|
||||
|
||||
@@ -20,8 +16,9 @@ class Token
|
||||
scopes: null
|
||||
isAtomic: null
|
||||
isHardTab: null
|
||||
hasLeadingWhitespace: false
|
||||
hasTrailingWhitespace: false
|
||||
firstNonWhitespaceIndex: null
|
||||
firstTrailingWhitespaceIndex: null
|
||||
hasInvisibleCharacters: false
|
||||
|
||||
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab}) ->
|
||||
@screenDelta = @value.length
|
||||
@@ -35,9 +32,26 @@ class Token
|
||||
/^meta\.brace\b/.test(_.last(@scopes))
|
||||
|
||||
splitAt: (splitIndex) ->
|
||||
value1 = @value.substring(0, splitIndex)
|
||||
value2 = @value.substring(splitIndex)
|
||||
[new Token(value: value1, scopes: @scopes), new Token(value: value2, scopes: @scopes)]
|
||||
leftToken = new Token(value: @value.substring(0, splitIndex), scopes: @scopes)
|
||||
rightToken = new Token(value: @value.substring(splitIndex), scopes: @scopes)
|
||||
|
||||
if @firstNonWhitespaceIndex?
|
||||
leftToken.firstNonWhitespaceIndex = Math.min(splitIndex, @firstNonWhitespaceIndex)
|
||||
leftToken.hasInvisibleCharacters = @hasInvisibleCharacters
|
||||
|
||||
if @firstNonWhitespaceIndex > splitIndex
|
||||
rightToken.firstNonWhitespaceIndex = @firstNonWhitespaceIndex - splitIndex
|
||||
rightToken.hasInvisibleCharacters = @hasInvisibleCharacters
|
||||
|
||||
if @firstTrailingWhitespaceIndex?
|
||||
rightToken.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - splitIndex)
|
||||
rightToken.hasInvisibleCharacters = @hasInvisibleCharacters
|
||||
|
||||
if @firstTrailingWhitespaceIndex < splitIndex
|
||||
leftToken.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex
|
||||
leftToken.hasInvisibleCharacters = @hasInvisibleCharacters
|
||||
|
||||
[leftToken, rightToken]
|
||||
|
||||
whitespaceRegexForTabLength: (tabLength) ->
|
||||
WhitespaceRegexesByTabLength[tabLength] ?= new RegExp("([ ]{#{tabLength}})|(\t)|([^\t]+)", "g")
|
||||
@@ -136,14 +150,12 @@ class Token
|
||||
scopeClasses = scope.split('.')
|
||||
_.isSubset(targetClasses, scopeClasses)
|
||||
|
||||
getValueAsHtml: ({invisibles, hasIndentGuide})->
|
||||
invisibles ?= {}
|
||||
getValueAsHtml: ({hasIndentGuide}) ->
|
||||
if @isHardTab
|
||||
classes = 'hard-tab'
|
||||
classes += ' indent-guide' if hasIndentGuide
|
||||
classes += ' invisible-character' if invisibles.tab
|
||||
value = if invisibles.tab then @value.replace(StartCharacterRegex, invisibles.tab) else @value
|
||||
html = "<span class='#{classes}'>#{@escapeString(value)}</span>"
|
||||
classes += ' invisible-character' if @hasInvisibleCharacters
|
||||
html = "<span class='#{classes}'>#{@escapeString(@value)}</span>"
|
||||
else
|
||||
startIndex = 0
|
||||
endIndex = @value.length
|
||||
@@ -151,26 +163,27 @@ class Token
|
||||
leadingHtml = ''
|
||||
trailingHtml = ''
|
||||
|
||||
if @hasLeadingWhitespace and match = LeadingSpaceRegex.exec(@value)
|
||||
if @hasLeadingWhitespace()
|
||||
leadingWhitespace = @value.substring(0, @firstNonWhitespaceIndex)
|
||||
|
||||
classes = 'leading-whitespace'
|
||||
classes += ' indent-guide' if hasIndentGuide
|
||||
classes += ' invisible-character' if invisibles.space
|
||||
classes += ' invisible-character' if @hasInvisibleCharacters
|
||||
|
||||
match[0] = match[0].replace(CharacterRegex, invisibles.space) if invisibles.space
|
||||
leadingHtml = "<span class='#{classes}'>#{match[0]}</span>"
|
||||
leadingHtml = "<span class='#{classes}'>#{leadingWhitespace}</span>"
|
||||
startIndex = @firstNonWhitespaceIndex
|
||||
|
||||
startIndex = match[0].length
|
||||
if @hasTrailingWhitespace()
|
||||
tokenIsOnlyWhitespace = @firstTrailingWhitespaceIndex is 0
|
||||
trailingWhitespace = @value.substring(@firstTrailingWhitespaceIndex)
|
||||
|
||||
if @hasTrailingWhitespace and match = TrailingSpaceRegex.exec(@value)
|
||||
tokenIsOnlyWhitespace = match[0].length is @value.length
|
||||
classes = 'trailing-whitespace'
|
||||
classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace and tokenIsOnlyWhitespace
|
||||
classes += ' invisible-character' if invisibles.space
|
||||
classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace() and tokenIsOnlyWhitespace
|
||||
classes += ' invisible-character' if @hasInvisibleCharacters
|
||||
|
||||
match[0] = match[0].replace(CharacterRegex, invisibles.space) if invisibles.space
|
||||
trailingHtml = "<span class='#{classes}'>#{match[0]}</span>"
|
||||
trailingHtml = "<span class='#{classes}'>#{trailingWhitespace}</span>"
|
||||
|
||||
endIndex = match.index
|
||||
endIndex = @firstTrailingWhitespaceIndex
|
||||
|
||||
html = leadingHtml
|
||||
if @value.length > MaxTokenLength
|
||||
@@ -200,3 +213,9 @@ class Token
|
||||
when '<' then '<'
|
||||
when '>' then '>'
|
||||
else match
|
||||
|
||||
hasLeadingWhitespace: ->
|
||||
@firstNonWhitespaceIndex? and @firstNonWhitespaceIndex > 0
|
||||
|
||||
hasTrailingWhitespace: ->
|
||||
@firstTrailingWhitespaceIndex? and @firstTrailingWhitespaceIndex < @value.length
|
||||
|
||||
@@ -19,27 +19,23 @@ class TokenizedBuffer extends Model
|
||||
invalidRows: null
|
||||
visible: false
|
||||
|
||||
constructor: ({@buffer, @tabLength}) ->
|
||||
constructor: ({@buffer, @tabLength, @invisibles}) ->
|
||||
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
|
||||
|
||||
@subscribe atom.syntax, 'grammar-added grammar-updated', (grammar) =>
|
||||
if grammar.injectionSelector?
|
||||
@resetTokenizedLines() if @hasTokenForSelector(grammar.injectionSelector)
|
||||
@retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector)
|
||||
else
|
||||
newScore = grammar.getScore(@buffer.getPath(), @buffer.getText())
|
||||
@setGrammar(grammar, newScore) if newScore > @currentGrammarScore
|
||||
|
||||
@on 'grammar-changed grammar-updated', => @resetTokenizedLines()
|
||||
@on 'grammar-changed grammar-updated', => @retokenizeLines()
|
||||
@subscribe @buffer, "changed", (e) => @handleBufferChange(e)
|
||||
@subscribe @buffer, "path-changed", =>
|
||||
@bufferPath = @buffer.getPath()
|
||||
@reloadGrammar()
|
||||
|
||||
@subscribe @$tabLength.changes, (tabLength) =>
|
||||
lastRow = @buffer.getLastRow()
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow)
|
||||
@invalidateRow(0)
|
||||
@emit "changed", { start: 0, end: lastRow, delta: 0 }
|
||||
@subscribe @$tabLength.changes, (tabLength) => @retokenizeLines()
|
||||
|
||||
@subscribe atom.config.observe 'editor.tabLength', callNow: false, =>
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength', 2))
|
||||
@@ -49,6 +45,7 @@ class TokenizedBuffer extends Model
|
||||
serializeParams: ->
|
||||
bufferPath: @buffer.getPath()
|
||||
tabLength: @tabLength
|
||||
invisibles: _.clone(@invisibles)
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.buffer = atom.project.bufferForPathSync(params.bufferPath)
|
||||
@@ -59,7 +56,7 @@ class TokenizedBuffer extends Model
|
||||
@unsubscribe(@grammar) if @grammar
|
||||
@grammar = grammar
|
||||
@currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText())
|
||||
@subscribe @grammar, 'grammar-updated', => @resetTokenizedLines()
|
||||
@subscribe @grammar, 'grammar-updated', => @retokenizeLines()
|
||||
@emit 'grammar-changed', grammar
|
||||
|
||||
reloadGrammar: ->
|
||||
@@ -74,11 +71,13 @@ class TokenizedBuffer extends Model
|
||||
return true if selector.matches(token.scopes)
|
||||
false
|
||||
|
||||
resetTokenizedLines: ->
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, @buffer.getLastRow())
|
||||
retokenizeLines: ->
|
||||
lastRow = @buffer.getLastRow()
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow)
|
||||
@invalidRows = []
|
||||
@invalidateRow(0)
|
||||
@fullyTokenized = false
|
||||
@emit "changed", {start: 0, end: lastRow, delta: 0}
|
||||
|
||||
setVisible: (@visible) ->
|
||||
@tokenizeInBackground() if @visible
|
||||
@@ -94,6 +93,11 @@ class TokenizedBuffer extends Model
|
||||
# tabLength - A {Number} that defines the new tab length.
|
||||
setTabLength: (@tabLength) ->
|
||||
|
||||
setInvisibles: (invisibles) ->
|
||||
unless _.isEqual(invisibles, @invisibles)
|
||||
@invisibles = invisibles
|
||||
@retokenizeLines()
|
||||
|
||||
tokenizeInBackground: ->
|
||||
return if not @visible or @pendingChunk or not @isAlive()
|
||||
@pendingChunk = true
|
||||
@@ -206,15 +210,16 @@ class TokenizedBuffer extends Model
|
||||
tokens = [new Token(value: line, scopes: [@grammar.scopeName])]
|
||||
tabLength = @getTabLength()
|
||||
indentLevel = @indentLevelForRow(row)
|
||||
new TokenizedLine({tokens, tabLength, indentLevel})
|
||||
lineEnding = @buffer.lineEndingForRow(row)
|
||||
new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding})
|
||||
|
||||
buildTokenizedTokenizedLineForRow: (row, ruleStack) ->
|
||||
line = @buffer.lineForRow(row)
|
||||
lineEnding = @buffer.lineEndingForRow(row)
|
||||
tabLength = @getTabLength()
|
||||
indentLevel = @indentLevelForRow(row)
|
||||
{ tokens, ruleStack } = @grammar.tokenizeLine(line, ruleStack, row is 0)
|
||||
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel})
|
||||
{tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0)
|
||||
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles})
|
||||
|
||||
# FIXME: benogle says: These are actually buffer rows as all buffer rows are
|
||||
# accounted for in @tokenizedLines
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
NonWhitespaceRegex = /\S/
|
||||
LeadingWhitespaceRegex = /^\s*/
|
||||
TrailingWhitespaceRegex = /\s*$/
|
||||
RepeatedSpaceRegex = /[ ]/g
|
||||
idCounter = 1
|
||||
|
||||
module.exports =
|
||||
class TokenizedLine
|
||||
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel}) ->
|
||||
endOfLineInvisibles: null
|
||||
|
||||
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) ->
|
||||
@startBufferColumn ?= 0
|
||||
@tokens = @breakOutAtomicTokens(tokens)
|
||||
@text = @buildText()
|
||||
@@ -12,6 +18,9 @@ class TokenizedLine
|
||||
|
||||
@id = idCounter++
|
||||
@markLeadingAndTrailingWhitespaceTokens()
|
||||
if @invisibles
|
||||
@substituteInvisibleCharacters()
|
||||
@buildEndOfLineInvisibles() if @lineEnding?
|
||||
|
||||
buildText: ->
|
||||
text = ""
|
||||
@@ -90,12 +99,14 @@ class TokenizedLine
|
||||
tokens: leftTokens
|
||||
startBufferColumn: @startBufferColumn
|
||||
ruleStack: @ruleStack
|
||||
invisibles: @invisibles
|
||||
lineEnding: null
|
||||
)
|
||||
rightFragment = new TokenizedLine(
|
||||
tokens: rightTokens
|
||||
startBufferColumn: @bufferColumnForScreenColumn(column)
|
||||
ruleStack: @ruleStack
|
||||
invisibles: @invisibles
|
||||
lineEnding: @lineEnding
|
||||
)
|
||||
[leftFragment, rightFragment]
|
||||
@@ -133,15 +144,53 @@ class TokenizedLine
|
||||
outputTokens
|
||||
|
||||
markLeadingAndTrailingWhitespaceTokens: ->
|
||||
firstNonWhitespacePosition = @text.search(/\S/)
|
||||
firstTrailingWhitespacePosition = @text.search(/\s*$/)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
position = 0
|
||||
for token, i in @tokens
|
||||
token.hasLeadingWhitespace = position < firstNonWhitespacePosition
|
||||
firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex)
|
||||
firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0
|
||||
index = 0
|
||||
for token in @tokens
|
||||
if index < firstNonWhitespaceIndex
|
||||
token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index)
|
||||
# Only the *last* segment of a soft-wrapped line can have trailing whitespace
|
||||
token.hasTrailingWhitespace = @lineEnding? and (position + token.value.length > firstTrailingWhitespacePosition)
|
||||
position += token.value.length
|
||||
if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex)
|
||||
token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index)
|
||||
index += token.value.length
|
||||
|
||||
substituteInvisibleCharacters: ->
|
||||
invisibles = @invisibles
|
||||
changedText = false
|
||||
|
||||
for token, i in @tokens
|
||||
if token.isHardTab
|
||||
if invisibles.tab
|
||||
token.value = invisibles.tab + token.value.substring(invisibles.tab.length)
|
||||
token.hasInvisibleCharacters = true
|
||||
changedText = true
|
||||
else
|
||||
if invisibles.space
|
||||
if token.hasLeadingWhitespace()
|
||||
token.value = token.value.replace LeadingWhitespaceRegex, (leadingWhitespace) ->
|
||||
leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space
|
||||
token.hasInvisibleCharacters = true
|
||||
changedText = true
|
||||
if token.hasTrailingWhitespace()
|
||||
token.value = token.value.replace TrailingWhitespaceRegex, (leadingWhitespace) ->
|
||||
leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space
|
||||
token.hasInvisibleCharacters = true
|
||||
changedText = true
|
||||
|
||||
@text = @buildText() if changedText
|
||||
|
||||
buildEndOfLineInvisibles: ->
|
||||
@endOfLineInvisibles = []
|
||||
{cr, eol} = @invisibles
|
||||
|
||||
switch @lineEnding
|
||||
when '\r\n'
|
||||
@endOfLineInvisibles.push(cr) if cr
|
||||
@endOfLineInvisibles.push(eol) if eol
|
||||
when '\n'
|
||||
@endOfLineInvisibles.push(eol) if eol
|
||||
|
||||
isComment: ->
|
||||
for token in @tokens
|
||||
|
||||
@@ -28,7 +28,9 @@ class WindowEventHandler
|
||||
@subscribe $(window), 'blur', -> document.body.classList.add('is-blurred')
|
||||
|
||||
@subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine, initialColumn}) ->
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
if fs.isDirectorySync(pathToOpen)
|
||||
atom.project.setPath(pathToOpen) unless atom.project.getPath()
|
||||
else
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
@subscribe $(window), 'beforeunload', =>
|
||||
|
||||
@@ -9,7 +9,6 @@ scrollbarStyle = require 'scrollbar-style'
|
||||
fs = require 'fs-plus'
|
||||
Workspace = require './workspace'
|
||||
CommandInstaller = require './command-installer'
|
||||
EditorView = require './editor-view'
|
||||
PaneView = require './pane-view'
|
||||
PaneColumnView = require './pane-column-view'
|
||||
PaneRowView = require './pane-row-view'
|
||||
@@ -71,7 +70,6 @@ class WorkspaceView extends View
|
||||
projectHome: path.join(fs.getHomeDirectory(), 'github')
|
||||
audioBeep: true
|
||||
destroyEmptyPanes: true
|
||||
useReactEditor: true
|
||||
|
||||
@content: ->
|
||||
@div class: 'workspace', tabindex: -1, =>
|
||||
@@ -110,6 +108,7 @@ class WorkspaceView extends View
|
||||
atom.project.on 'path-changed', => @updateTitle()
|
||||
@on 'pane-container:active-pane-item-changed', => @updateTitle()
|
||||
@on 'pane:active-item-title-changed', '.active.pane', => @updateTitle()
|
||||
@on 'pane:active-item-modified-status-changed', '.active.pane', => @updateDocumentEdited()
|
||||
|
||||
@command 'application:about', -> ipc.send('command', 'application:about')
|
||||
@command 'application:run-all-specs', -> ipc.send('command', 'application:run-all-specs')
|
||||
@@ -210,19 +209,28 @@ class WorkspaceView extends View
|
||||
confirmClose: ->
|
||||
@panes.confirmClose()
|
||||
|
||||
# Updates the application's title, based on whichever file is open.
|
||||
# Updates the application's title and proxy icon based on whichever file is
|
||||
# open.
|
||||
updateTitle: ->
|
||||
if projectPath = atom.project.getPath()
|
||||
if item = @getModel().getActivePaneItem()
|
||||
@setTitle("#{item.getTitle?() ? 'untitled'} - #{projectPath}")
|
||||
title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}"
|
||||
@setTitle(title, item.getPath?())
|
||||
else
|
||||
@setTitle(projectPath)
|
||||
@setTitle(projectPath, projectPath)
|
||||
else
|
||||
@setTitle('untitled')
|
||||
|
||||
# Sets the application's title.
|
||||
setTitle: (title) ->
|
||||
# Sets the application's title (and the proxy icon on OS X)
|
||||
setTitle: (title, proxyIconPath='') ->
|
||||
document.title = title
|
||||
atom.setRepresentedFilename(proxyIconPath)
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: ->
|
||||
modified = @model.getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
|
||||
# Get all editor views.
|
||||
#
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
.cursors.blink-off .cursor {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.horizontal-scrollbar {
|
||||
|
||||
@@ -43,6 +43,10 @@ div > .inline-block-tight:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.inline-block .inline-block {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
// Use left margin when it's in a float: right element.
|
||||
// Sets the margin correctly when inline blocks are hidden and shown.
|
||||
.pull-right {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário