mirror of
https://github.com/atom/atom.git
synced 2026-01-24 22:38:20 -05:00
Merge branch 'master' into as-double-reflow-measurements
# Conflicts: # src/text-editor-presenter.coffee
This commit is contained in:
@@ -8,17 +8,19 @@ branches:
|
||||
env:
|
||||
global:
|
||||
- ATOM_ACCESS_TOKEN=da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4
|
||||
- NODE_VERSION=0.12
|
||||
|
||||
compiler: clang
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: NODE_VERSION=0.12
|
||||
- os: linux
|
||||
env: NODE_VERSION=4
|
||||
- os: osx
|
||||
env: ATOM_SPECS_TASK=core
|
||||
env: ATOM_SPECS_TASK=core NODE_VERSION=0.12
|
||||
- os: osx
|
||||
env: ATOM_SPECS_TASK=packages
|
||||
env: ATOM_SPECS_TASK=packages NODE_VERSION=0.12
|
||||
|
||||
sudo: false
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "1.0.5"
|
||||
"atom-package-manager": "1.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
21
atom.sh
21
atom.sh
@@ -11,6 +11,12 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(basename $0)" == 'atom-beta' ]; then
|
||||
BETA_VERSION=true
|
||||
else
|
||||
BETA_VERSION=
|
||||
fi
|
||||
|
||||
while getopts ":wtfvh-:" opt; do
|
||||
case "$opt" in
|
||||
-)
|
||||
@@ -45,7 +51,11 @@ if [ $REDIRECT_STDERR ]; then
|
||||
fi
|
||||
|
||||
if [ $OS == 'Mac' ]; then
|
||||
ATOM_APP_NAME=Atom.app
|
||||
if [ -n "$BETA_VERSION" ]; then
|
||||
ATOM_APP_NAME="Atom Beta.app"
|
||||
else
|
||||
ATOM_APP_NAME="Atom.app"
|
||||
fi
|
||||
|
||||
if [ -z "${ATOM_PATH}" ]; then
|
||||
# If ATOM_PATH isnt set, check /Applications and then ~/Applications for Atom.app
|
||||
@@ -74,9 +84,14 @@ if [ $OS == 'Mac' ]; then
|
||||
elif [ $OS == 'Linux' ]; then
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
USR_DIRECTORY=$(readlink -f $(dirname $SCRIPT)/..)
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
ATOM_HOME="${ATOM_HOME:-$HOME/.atom}"
|
||||
|
||||
if [ -n "$BETA_VERSION" ]; then
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom-beta/atom"
|
||||
else
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
fi
|
||||
|
||||
ATOM_HOME="${ATOM_HOME:-$HOME/.atom}"
|
||||
mkdir -p "$ATOM_HOME"
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
@@ -31,38 +31,52 @@ module.exports = (grunt) ->
|
||||
# This allows all subsequent paths to the relative to the root of the repo
|
||||
grunt.file.setBase(path.resolve('..'))
|
||||
|
||||
tmpDir = os.tmpdir()
|
||||
appName = if process.platform is 'darwin' then 'Atom.app' else 'Atom'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
buildDir = path.resolve(buildDir)
|
||||
# Options
|
||||
installDir = grunt.option('install-dir')
|
||||
buildDir = grunt.option('build-dir')
|
||||
buildDir ?= path.join(os.tmpdir(), 'atom-build')
|
||||
buildDir = path.resolve(buildDir)
|
||||
disableAutoUpdate = grunt.option('no-auto-update') ? false
|
||||
|
||||
channel = grunt.option('channel')
|
||||
channel ?= process.env.JANKY_BRANCH if process.env.JANKY_BRANCH in ['stable', 'beta']
|
||||
channel ?= 'dev'
|
||||
|
||||
home = if process.platform is 'win32' then process.env.USERPROFILE else process.env.HOME
|
||||
electronDownloadDir = path.join(home, '.atom', 'electron')
|
||||
metadata = packageJson
|
||||
appName = packageJson.productName
|
||||
appFileName = packageJson.name
|
||||
apmFileName = 'apm'
|
||||
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
if channel is 'beta'
|
||||
appName += ' Beta'
|
||||
appFileName += '-beta'
|
||||
apmFileName += '-beta'
|
||||
|
||||
appName += '.app' if process.platform is 'darwin'
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
|
||||
if process.platform is 'win32'
|
||||
homeDir = process.env.USERPROFILE
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
installDir ?= path.join(process.env.ProgramFiles, appName)
|
||||
killCommand = 'taskkill /F /IM atom.exe'
|
||||
else if process.platform is 'darwin'
|
||||
homeDir = process.env.HOME
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
installDir ?= path.join('/Applications', appName)
|
||||
killCommand = 'pkill -9 Atom'
|
||||
else
|
||||
homeDir = process.env.HOME
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
installDir ?= process.env.INSTALL_PREFIX ? '/usr/local'
|
||||
killCommand ='pkill -9 atom'
|
||||
|
||||
installDir = path.resolve(installDir)
|
||||
electronDownloadDir = path.join(homeDir, '.atom', 'electron')
|
||||
|
||||
coffeeConfig =
|
||||
glob_to_multiple:
|
||||
@@ -104,7 +118,7 @@ module.exports = (grunt) ->
|
||||
csonConfig =
|
||||
options:
|
||||
rootObject: true
|
||||
cachePath: path.join(home, '.atom', 'compile-cache', 'grunt-cson')
|
||||
cachePath: path.join(homeDir, '.atom', 'compile-cache', 'grunt-cson')
|
||||
|
||||
glob_to_multiple:
|
||||
expand: true
|
||||
@@ -155,7 +169,11 @@ module.exports = (grunt) ->
|
||||
grunt.initConfig
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
|
||||
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir, channel}
|
||||
atom: {
|
||||
appName, channel, metadata, disableAutoUpdate,
|
||||
appFileName, apmFileName,
|
||||
appDir, buildDir, contentsDir, installDir, shellAppDir, symbolsDir,
|
||||
}
|
||||
|
||||
docsOutputDir: 'docs/output'
|
||||
|
||||
@@ -236,8 +254,8 @@ module.exports = (grunt) ->
|
||||
outputDirectory: path.join(buildDir, 'installer')
|
||||
authors: 'GitHub Inc.'
|
||||
loadingGif: path.resolve(__dirname, '..', 'resources', 'win', 'loading.gif')
|
||||
iconUrl: 'https://raw.githubusercontent.com/atom/atom/master/resources/app-icons/stable/atom.ico'
|
||||
setupIcon: path.resolve(__dirname, '..', 'resources', 'app-icons', 'stable', 'atom.ico')
|
||||
iconUrl: "https://raw.githubusercontent.com/atom/atom/master/resources/app-icons/#{channel}/atom.ico"
|
||||
setupIcon: path.resolve(__dirname, '..', 'resources', 'app-icons', channel, 'atom.ico')
|
||||
remoteReleases: 'https://atom.io/api/updates'
|
||||
|
||||
shell:
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
"grunt-contrib-coffee": "~0.12.0",
|
||||
"grunt-contrib-csslint": "~0.2.0",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.15.0",
|
||||
"grunt-cson": "0.16.0",
|
||||
"grunt-download-electron": "^2.1.1",
|
||||
"grunt-electron-installer": "1.0.3-0",
|
||||
"grunt-electron-installer": "1.0.3",
|
||||
"grunt-lesslint": "0.17.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
@@ -33,7 +33,7 @@
|
||||
"rcedit": "~0.3.0",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "^2",
|
||||
"runas": "^3.1",
|
||||
"tello": "1.0.5",
|
||||
"temp": "~0.8.1",
|
||||
"underscore-plus": "1.x",
|
||||
|
||||
@@ -90,10 +90,6 @@ module.exports = (grunt) ->
|
||||
path.join('snippets', 'node_modules', 'pegjs')
|
||||
path.join('snippets', 'node_modules', '.bin', 'pegjs')
|
||||
|
||||
# These aren't needed since WeakMap is built-in
|
||||
path.join('emissary', 'node_modules', 'es6-weak-map')
|
||||
path.join('property-accessors', 'node_modules', 'es6-weak-map')
|
||||
|
||||
'.DS_Store'
|
||||
'.jshintrc'
|
||||
'.npmignore'
|
||||
@@ -190,4 +186,5 @@ module.exports = (grunt) ->
|
||||
dependencies = ['compile', 'generate-license:save', 'generate-module-cache', 'compile-packages-slug']
|
||||
dependencies.push('copy-info-plist') if process.platform is 'darwin'
|
||||
dependencies.push('set-exe-icon') if process.platform is 'win32'
|
||||
dependencies.push('disable-autoupdate') if grunt.config.get('atom.disableAutoUpdate')
|
||||
grunt.task.run(dependencies...)
|
||||
|
||||
12
build/tasks/disable-autoupdate-task.coffee
Normal file
12
build/tasks/disable-autoupdate-task.coffee
Normal file
@@ -0,0 +1,12 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
|
||||
grunt.registerTask 'disable-autoupdate', 'Set up disableAutoUpdate field in package.json file', ->
|
||||
appDir = fs.realpathSync(grunt.config.get('atom.appDir'))
|
||||
|
||||
metadata = grunt.file.readJSON(path.join(appDir, 'package.json'))
|
||||
metadata._disableAutoUpdate = grunt.config.get('atom.disableAutoUpdate')
|
||||
|
||||
grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata))
|
||||
@@ -1,15 +1,19 @@
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
runas = null
|
||||
temp = require 'temp'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
{cp, fillTemplate, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'install', 'Install the built application', ->
|
||||
appName = grunt.config.get('atom.appName')
|
||||
appFileName = grunt.config.get('atom.appFileName')
|
||||
apmFileName = grunt.config.get('atom.apmFileName')
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
installDir = grunt.config.get('atom.installDir')
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
{description} = grunt.config.get('atom.metadata')
|
||||
|
||||
if process.platform is 'win32'
|
||||
runas ?= require 'runas'
|
||||
@@ -18,7 +22,7 @@ module.exports = (grunt) ->
|
||||
grunt.log.error("Failed to copy #{shellAppDir} to #{installDir}")
|
||||
|
||||
createShortcut = path.resolve 'script', 'create-shortcut.cmd'
|
||||
runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom'])
|
||||
runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), appName])
|
||||
else if process.platform is 'darwin'
|
||||
rm installDir
|
||||
mkdir path.dirname(installDir)
|
||||
@@ -28,32 +32,29 @@ module.exports = (grunt) ->
|
||||
cp shellAppDir, tempFolder
|
||||
fs.renameSync(tempFolder, installDir)
|
||||
else
|
||||
binDir = path.join(installDir, 'bin')
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
|
||||
mkdir binDir
|
||||
cp 'atom.sh', path.join(binDir, 'atom')
|
||||
shareDir = path.join(installDir, 'share', appFileName)
|
||||
rm shareDir
|
||||
mkdir path.dirname(shareDir)
|
||||
cp shellAppDir, shareDir
|
||||
|
||||
# Create atom.desktop if installation not in temporary folder
|
||||
tmpDir = if process.env.TMPDIR? then process.env.TMPDIR else '/tmp'
|
||||
if installDir.indexOf(tmpDir) isnt 0
|
||||
desktopFile = path.join('resources', 'linux', 'atom.desktop.in')
|
||||
desktopInstallFile = path.join(installDir, 'share', 'applications', 'atom.desktop')
|
||||
unless installDir.indexOf(process.env.TMPDIR ? '/tmp') is 0
|
||||
iconPath = path.join(shareDir, 'resources', 'app.asar.unpacked', 'resources', 'atom.png')
|
||||
|
||||
{description} = grunt.file.readJSON('package.json')
|
||||
iconName = path.join(shareDir, 'resources', 'app.asar.unpacked', 'resources', 'atom.png')
|
||||
executable = path.join(shareDir, 'atom')
|
||||
template = _.template(String(fs.readFileSync(desktopFile)))
|
||||
filled = template({description, iconName, executable})
|
||||
mkdir path.join(installDir, 'share', 'applications')
|
||||
fillTemplate(
|
||||
path.join('resources', 'linux', 'atom.desktop.in'),
|
||||
path.join(installDir, 'share', 'applications', appFileName + '.desktop'),
|
||||
{appName, appFileName, description, iconPath, installDir}
|
||||
)
|
||||
|
||||
grunt.file.write(desktopInstallFile, filled)
|
||||
binDir = path.join(installDir, 'bin')
|
||||
mkdir binDir
|
||||
cp 'atom.sh', path.join(binDir, appFileName)
|
||||
|
||||
# Create relative symbol link for apm.
|
||||
process.chdir(binDir)
|
||||
rm('apm')
|
||||
fs.symlinkSync(path.join('..', 'share', 'atom', 'resources', 'app', 'apm', 'node_modules', '.bin', 'apm'), 'apm')
|
||||
rm(path.join(binDir, apmFileName))
|
||||
fs.symlinkSync(
|
||||
path.join('..', 'share', appFileName, 'resources', 'app', 'apm', 'node_modules', '.bin', 'apm'),
|
||||
path.join(binDir, apmFileName)
|
||||
)
|
||||
|
||||
fs.chmodSync(path.join(shareDir, 'atom'), "755")
|
||||
fs.chmodSync(path.join(shareDir, 'atom'), '755')
|
||||
|
||||
@@ -1,28 +1,18 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
|
||||
fillTemplate = (filePath, data) ->
|
||||
template = _.template(String(fs.readFileSync("#{filePath}.in")))
|
||||
filled = template(data)
|
||||
|
||||
outputPath = path.join(grunt.config.get('atom.buildDir'), path.basename(filePath))
|
||||
grunt.file.write(outputPath, filled)
|
||||
outputPath
|
||||
|
||||
getInstalledSize = (buildDir, callback) ->
|
||||
cmd = 'du'
|
||||
args = ['-sk', path.join(buildDir, 'Atom')]
|
||||
spawn {cmd, args}, (error, {stdout}) ->
|
||||
installedSize = stdout.split(/\s+/)?[0] or '200000' # default to 200MB
|
||||
callback(null, installedSize)
|
||||
{spawn, fillTemplate} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'mkdeb', 'Create debian package', ->
|
||||
done = @async()
|
||||
|
||||
appName = grunt.config.get('atom.appName')
|
||||
appFileName = grunt.config.get('atom.appFileName')
|
||||
apmFileName = grunt.config.get('atom.apmFileName')
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
installDir = '/usr'
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
{version, description} = grunt.config.get('atom.metadata')
|
||||
channel = grunt.config.get('atom.channel')
|
||||
|
||||
if process.arch is 'ia32'
|
||||
@@ -32,23 +22,38 @@ module.exports = (grunt) ->
|
||||
else
|
||||
return done("Unsupported arch #{process.arch}")
|
||||
|
||||
{name, version, description} = grunt.file.readJSON('package.json')
|
||||
section = 'devel'
|
||||
maintainer = 'GitHub <atom@github.com>'
|
||||
installDir = '/usr'
|
||||
iconName = 'atom'
|
||||
executable = path.join(installDir, 'share', 'atom', 'atom')
|
||||
getInstalledSize buildDir, (error, installedSize) ->
|
||||
data = {name, version, description, section, arch, maintainer, installDir, iconName, installedSize, executable}
|
||||
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
|
||||
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'atom.desktop'), data)
|
||||
iconPath = path.join('resources', 'app-icons', channel, 'png', '1024.png')
|
||||
desktopFilePath = path.join(buildDir, appFileName + '.desktop')
|
||||
fillTemplate(
|
||||
path.join('resources', 'linux', 'atom.desktop.in'),
|
||||
desktopFilePath,
|
||||
{appName, appFileName, description, installDir, iconPath: appFileName}
|
||||
)
|
||||
|
||||
getInstalledSize shellAppDir, (error, installedSize) ->
|
||||
if error?
|
||||
return done(error)
|
||||
|
||||
controlFilePath = path.join(buildDir, 'control')
|
||||
fillTemplate(
|
||||
path.join('resources', 'linux', 'debian', 'control.in'),
|
||||
controlFilePath,
|
||||
{appFileName, version, arch, installedSize, description}
|
||||
)
|
||||
|
||||
iconPath = path.join(shellAppDir, 'resources', 'app.asar.unpacked', 'resources', 'atom.png')
|
||||
|
||||
cmd = path.join('script', 'mkdeb')
|
||||
args = [version, arch, controlFilePath, desktopFilePath, iconPath, buildDir]
|
||||
args = [appFileName, version, channel, arch, controlFilePath, desktopFilePath, iconPath, buildDir]
|
||||
spawn {cmd, args}, (error) ->
|
||||
if error?
|
||||
done(error)
|
||||
else
|
||||
grunt.log.ok "Created #{buildDir}/atom-#{version}-#{arch}.deb"
|
||||
grunt.log.ok "Created #{buildDir}/#{appFileName}-#{version}-#{arch}.deb"
|
||||
done()
|
||||
|
||||
getInstalledSize = (directory, callback) ->
|
||||
cmd = 'du'
|
||||
args = ['-sk', directory]
|
||||
spawn {cmd, args}, (error, {stdout}) ->
|
||||
installedSize = stdout.split(/\s+/)?[0] or '200000' # default to 200MB
|
||||
callback(null, installedSize)
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn, rm, mkdir} = require('./task-helpers')(grunt)
|
||||
|
||||
fillTemplate = (filePath, data) ->
|
||||
template = _.template(String(fs.readFileSync("#{filePath}.in")))
|
||||
filled = template(data)
|
||||
|
||||
outputPath = path.join(grunt.config.get('atom.buildDir'), path.basename(filePath))
|
||||
grunt.file.write(outputPath, filled)
|
||||
outputPath
|
||||
{spawn, fillTemplate, rm, mkdir} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'mkrpm', 'Create rpm package', ->
|
||||
done = @async()
|
||||
|
||||
appName = grunt.config.get('atom.appName')
|
||||
appFileName = grunt.config.get('atom.appFileName')
|
||||
apmFileName = grunt.config.get('atom.apmFileName')
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
installDir = '/usr'
|
||||
{version, description} = grunt.config.get('atom.metadata')
|
||||
|
||||
if process.arch is 'ia32'
|
||||
arch = 'i386'
|
||||
else if process.arch is 'x64'
|
||||
@@ -23,7 +20,12 @@ module.exports = (grunt) ->
|
||||
else
|
||||
return done("Unsupported arch #{process.arch}")
|
||||
|
||||
{name, version, description} = grunt.file.readJSON('package.json')
|
||||
desktopFilePath = path.join(buildDir, appFileName + '.desktop')
|
||||
fillTemplate(
|
||||
path.join('resources', 'linux', 'atom.desktop.in'),
|
||||
desktopFilePath,
|
||||
{appName, appFileName, description, installDir, iconPath: appFileName}
|
||||
)
|
||||
|
||||
# RPM versions can't have dashes in them.
|
||||
# * http://www.rpm.org/max-rpm/ch-rpm-file-format.html
|
||||
@@ -31,23 +33,19 @@ module.exports = (grunt) ->
|
||||
version = version.replace(/-beta/, "~beta")
|
||||
version = version.replace(/-dev/, "~dev")
|
||||
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
specFilePath = path.join(buildDir, appFileName + '.spec')
|
||||
fillTemplate(
|
||||
path.join('resources', 'linux', 'redhat', 'atom.spec.in'),
|
||||
specFilePath,
|
||||
{appName, appFileName, apmFileName, installDir, version, description}
|
||||
)
|
||||
|
||||
rpmDir = path.join(buildDir, 'rpm')
|
||||
rm rpmDir
|
||||
mkdir rpmDir
|
||||
|
||||
installDir = grunt.config.get('atom.installDir')
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
iconName = 'atom'
|
||||
executable = path.join(shareDir, 'atom')
|
||||
|
||||
data = {name, version, description, installDir, iconName, executable}
|
||||
specFilePath = fillTemplate(path.join('resources', 'linux', 'redhat', 'atom.spec'), data)
|
||||
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'atom.desktop'), data)
|
||||
|
||||
cmd = path.join('script', 'mkrpm')
|
||||
args = [specFilePath, desktopFilePath, buildDir]
|
||||
args = [appName, appFileName, specFilePath, desktopFilePath, buildDir]
|
||||
spawn {cmd, args}, (error) ->
|
||||
if error?
|
||||
done(error)
|
||||
|
||||
@@ -31,7 +31,8 @@ module.exports = (gruntObject) ->
|
||||
cp path.join(docsOutputDir, 'api.json'), path.join(buildDir, 'atom-api.json')
|
||||
|
||||
grunt.registerTask 'upload-assets', 'Upload the assets to a GitHub release', ->
|
||||
switch process.env.JANKY_BRANCH
|
||||
branchName = process.env.JANKY_BRANCH
|
||||
switch branchName
|
||||
when 'stable'
|
||||
isPrerelease = false
|
||||
when 'beta'
|
||||
@@ -54,7 +55,7 @@ module.exports = (gruntObject) ->
|
||||
|
||||
zipAssets buildDir, assets, (error) ->
|
||||
return done(error) if error?
|
||||
getAtomDraftRelease isPrerelease, (error, release) ->
|
||||
getAtomDraftRelease isPrerelease, branchName, (error, release) ->
|
||||
return done(error) if error?
|
||||
assetNames = (asset.assetName for asset in assets)
|
||||
deleteExistingAssets release, assetNames, (error) ->
|
||||
@@ -76,7 +77,12 @@ getAssets = ->
|
||||
]
|
||||
when 'win32'
|
||||
assets = [{assetName: 'atom-windows.zip', sourcePath: 'Atom'}]
|
||||
for squirrelAsset in ['AtomSetup.exe', 'RELEASES', "atom-#{version}-full.nupkg", "atom-#{version}-delta.nupkg"]
|
||||
|
||||
# NuGet packages can't have dots in their pre-release name, so we remove
|
||||
# those dots in `grunt-electron-installer` when generating the package.
|
||||
nupkgVersion = version.replace(/\.(\d+)$/, '$1')
|
||||
|
||||
for squirrelAsset in ['AtomSetup.exe', 'RELEASES', "atom-#{nupkgVersion}-full.nupkg", "atom-#{nupkgVersion}-delta.nupkg"]
|
||||
cp path.join(buildDir, 'installer', squirrelAsset), path.join(buildDir, squirrelAsset)
|
||||
assets.push({assetName: squirrelAsset, sourcePath: assetName})
|
||||
assets
|
||||
@@ -128,7 +134,7 @@ zipAssets = (buildDir, assets, callback) ->
|
||||
tasks.push(zip.bind(this, buildDir, sourcePath, assetName))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
getAtomDraftRelease = (isPrerelease, callback) ->
|
||||
getAtomDraftRelease = (isPrerelease, branchName, callback) ->
|
||||
atomRepo = new GitHub({repo: 'atom/atom', token})
|
||||
atomRepo.getReleases {prerelease: isPrerelease}, (error, releases=[]) ->
|
||||
if error?
|
||||
@@ -150,9 +156,9 @@ getAtomDraftRelease = (isPrerelease, callback) ->
|
||||
firstDraft.assets = assets
|
||||
callback(null, firstDraft)
|
||||
else
|
||||
createAtomDraftRelease(isPrerelease, callback)
|
||||
createAtomDraftRelease(isPrerelease, branchName, callback)
|
||||
|
||||
createAtomDraftRelease = (isPrerelease, callback) ->
|
||||
createAtomDraftRelease = (isPrerelease, branchName, callback) ->
|
||||
{version} = require('../../package.json')
|
||||
options =
|
||||
uri: 'https://api.github.com/repos/atom/atom/releases'
|
||||
@@ -161,6 +167,7 @@ createAtomDraftRelease = (isPrerelease, callback) ->
|
||||
json:
|
||||
tag_name: "v#{version}"
|
||||
prerelease: isPrerelease
|
||||
target_commitish: branchName
|
||||
name: version
|
||||
draft: true
|
||||
body: """
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
cp: (source, destination, {filter}={}) ->
|
||||
@@ -66,3 +67,7 @@ module.exports = (grunt) ->
|
||||
engines?.atom?
|
||||
catch error
|
||||
false
|
||||
|
||||
fillTemplate: (templatePath, outputPath, data) ->
|
||||
content = _.template(String(fs.readFileSync(templatePath)))(data)
|
||||
grunt.file.write(outputPath, content)
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
### On Windows 8 or 10
|
||||
* [Visual Studio Express 2013 or 2015 for Windows Desktop](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_2)
|
||||
* For VS 2015, be sure to customize the installation to include Visual C++. It's not installed by default.
|
||||
* Some have experienced issues with Node locating C++ on VS 2015. If so, try VS 2013.
|
||||
* [node.js](http://nodejs.org/download/) (0.10.x or 0.12.x) or [io.js](https://iojs.org) (1.x or 2.x)
|
||||
* [Python](https://www.python.org/downloads/) v2.7.x (required by [node-gyp](https://github.com/TooTallNate/node-gyp))
|
||||
* [GitHub Desktop](http://desktop.github.com/)
|
||||
|
||||
@@ -2,7 +2,6 @@ TextBuffer = require 'text-buffer'
|
||||
{Point, Range} = TextBuffer
|
||||
{File, Directory} = require 'pathwatcher'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
|
||||
module.exports =
|
||||
BufferedNodeProcess: require '../src/buffered-node-process'
|
||||
@@ -23,8 +22,3 @@ module.exports =
|
||||
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.TextEditor = require '../src/text-editor'
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
Object.defineProperty module.exports, 'Git', get: ->
|
||||
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
|
||||
module.exports.GitRepository
|
||||
|
||||
67
package.json
67
package.json
@@ -12,49 +12,44 @@
|
||||
"url": "https://github.com/atom/atom/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"electronVersion": "0.30.6",
|
||||
"electronVersion": "0.30.7",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^5.1.11",
|
||||
"atom-keymap": "^6.0.0",
|
||||
"babel-core": "^5.8.21",
|
||||
"bootstrap": "^3.3.4",
|
||||
"clear-cut": "^2.0.1",
|
||||
"coffee-script": "1.8.0",
|
||||
"color": "^0.7.3",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.3.3",
|
||||
"event-kit": "^1.3.0",
|
||||
"first-mate": "^5.0.0",
|
||||
"fs-plus": "^2.8.0",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^2.1",
|
||||
"git-utils": "^3.0.0",
|
||||
"git-utils": "^4",
|
||||
"grim": "1.4.2",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-tagged": "^1.1.4",
|
||||
"jquery": "^2.1.1",
|
||||
"less-cache": "0.22",
|
||||
"marked": "^0.3.4",
|
||||
"mixto": "^1",
|
||||
"normalize-package-data": "^2.0.0",
|
||||
"nslog": "^2.0.0",
|
||||
"oniguruma": "^4.2.2",
|
||||
"pathwatcher": "^5.0.0",
|
||||
"nslog": "^3",
|
||||
"oniguruma": "^5",
|
||||
"pathwatcher": "^6.2",
|
||||
"property-accessors": "^1.1.3",
|
||||
"random-words": "0.0.1",
|
||||
"runas": "2.0.0",
|
||||
"scandal": "2.1.2",
|
||||
"runas": "^3.1",
|
||||
"scandal": "^2.2",
|
||||
"scoped-property-store": "^0.17.0",
|
||||
"scrollbar-style": "^3.1",
|
||||
"scrollbar-style": "^3.2",
|
||||
"season": "^5.3",
|
||||
"semver": "^4.3.3",
|
||||
"serializable": "^1",
|
||||
"service-hub": "^0.6.2",
|
||||
"source-map-support": "^0.3.2",
|
||||
"stacktrace-parser": "0.1.1",
|
||||
"temp": "0.8.1",
|
||||
"text-buffer": "7.0.3",
|
||||
"theorist": "^1.0.2",
|
||||
"text-buffer": "7.1.2",
|
||||
"typescript-simple": "1.0.0",
|
||||
"underscore-plus": "^1.6.6",
|
||||
"yargs": "^3.23.0"
|
||||
@@ -66,10 +61,10 @@
|
||||
"atom-light-ui": "0.43.0",
|
||||
"base16-tomorrow-dark-theme": "0.27.0",
|
||||
"base16-tomorrow-light-theme": "0.9.0",
|
||||
"one-dark-ui": "1.1.3",
|
||||
"one-dark-syntax": "1.1.0",
|
||||
"one-light-syntax": "1.1.0",
|
||||
"one-light-ui": "1.1.3",
|
||||
"one-dark-ui": "1.1.4",
|
||||
"one-dark-syntax": "1.1.1",
|
||||
"one-light-syntax": "1.1.1",
|
||||
"one-light-ui": "1.1.4",
|
||||
"solarized-dark-syntax": "0.38.1",
|
||||
"solarized-light-syntax": "0.22.1",
|
||||
"about": "1.1.0",
|
||||
@@ -77,20 +72,20 @@
|
||||
"autocomplete-atom-api": "0.9.2",
|
||||
"autocomplete-css": "0.11.0",
|
||||
"autocomplete-html": "0.7.2",
|
||||
"autocomplete-plus": "2.19.1",
|
||||
"autocomplete-plus": "2.20.0",
|
||||
"autocomplete-snippets": "1.7.1",
|
||||
"autoflow": "0.25.0",
|
||||
"autosave": "0.22.0",
|
||||
"background-tips": "0.26.0",
|
||||
"bookmarks": "0.38.0",
|
||||
"bracket-matcher": "0.76.0",
|
||||
"bracket-matcher": "0.78.0",
|
||||
"command-palette": "0.36.0",
|
||||
"deprecation-cop": "0.54.0",
|
||||
"dev-live-reload": "0.47.0",
|
||||
"encoding-selector": "0.21.0",
|
||||
"exception-reporting": "0.37.0",
|
||||
"find-and-replace": "0.181.0",
|
||||
"fuzzy-finder": "0.89.0",
|
||||
"find-and-replace": "0.182.0",
|
||||
"fuzzy-finder": "0.90.0",
|
||||
"git-diff": "0.56.0",
|
||||
"go-to-line": "0.30.0",
|
||||
"grammar-selector": "0.47.0",
|
||||
@@ -98,49 +93,49 @@
|
||||
"incompatible-packages": "0.25.0",
|
||||
"keybinding-resolver": "0.33.0",
|
||||
"line-ending-selector": "0.0.5",
|
||||
"link": "0.30.0",
|
||||
"markdown-preview": "0.152.0",
|
||||
"link": "0.31.0",
|
||||
"markdown-preview": "0.154.0",
|
||||
"metrics": "0.51.0",
|
||||
"notifications": "0.59.0",
|
||||
"open-on-github": "0.38.0",
|
||||
"package-generator": "0.40.0",
|
||||
"release-notes": "0.53.0",
|
||||
"settings-view": "0.219.0",
|
||||
"snippets": "0.99.0",
|
||||
"spell-check": "0.59.0",
|
||||
"settings-view": "0.222.0",
|
||||
"snippets": "0.100.0",
|
||||
"spell-check": "0.60.0",
|
||||
"status-bar": "0.79.0",
|
||||
"styleguide": "0.44.0",
|
||||
"symbols-view": "0.107.0",
|
||||
"symbols-view": "0.108.0",
|
||||
"tabs": "0.84.0",
|
||||
"timecop": "0.33.0",
|
||||
"tree-view": "0.188.0",
|
||||
"tree-view": "0.189.0",
|
||||
"update-package-dependencies": "0.10.0",
|
||||
"welcome": "0.30.0",
|
||||
"whitespace": "0.31.0",
|
||||
"wrap-guide": "0.36.0",
|
||||
"language-c": "0.48.0",
|
||||
"language-clojure": "0.17.0",
|
||||
"language-coffee-script": "0.41.0",
|
||||
"language-coffee-script": "0.42.0",
|
||||
"language-csharp": "0.10.0",
|
||||
"language-css": "0.34.0",
|
||||
"language-gfm": "0.81.0",
|
||||
"language-git": "0.10.0",
|
||||
"language-go": "0.39.0",
|
||||
"language-html": "0.41.2",
|
||||
"language-html": "0.41.3",
|
||||
"language-hyperlink": "0.14.0",
|
||||
"language-java": "0.16.0",
|
||||
"language-javascript": "0.95.0",
|
||||
"language-javascript": "0.96.0",
|
||||
"language-json": "0.16.0",
|
||||
"language-less": "0.28.2",
|
||||
"language-make": "0.17.0",
|
||||
"language-make": "0.18.0",
|
||||
"language-mustache": "0.12.0",
|
||||
"language-objective-c": "0.15.0",
|
||||
"language-perl": "0.29.0",
|
||||
"language-php": "0.30.0",
|
||||
"language-property-list": "0.8.0",
|
||||
"language-python": "0.40.0",
|
||||
"language-ruby": "0.59.0",
|
||||
"language-ruby-on-rails": "0.22.0",
|
||||
"language-ruby": "0.60.0",
|
||||
"language-ruby-on-rails": "0.23.0",
|
||||
"language-sass": "0.41.0",
|
||||
"language-shellscript": "0.17.0",
|
||||
"language-source": "0.9.0",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Name=Atom
|
||||
Name=<%= appName %>
|
||||
Comment=<%= description %>
|
||||
GenericName=Text Editor
|
||||
Exec=<%= executable %> %U
|
||||
Icon=<%= iconName %>
|
||||
Exec=<%= installDir %>/share/<%= appFileName %>/atom %U
|
||||
Icon=<%= iconPath %>
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Utility;TextEditor;Development;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Package: <%= name %>
|
||||
Package: <%= appFileName %>
|
||||
Version: <%= version %>
|
||||
Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils, libcap2
|
||||
Recommends: lsb-release
|
||||
Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0
|
||||
Section: <%= section %>
|
||||
Section: devel
|
||||
Priority: optional
|
||||
Architecture: <%= arch %>
|
||||
Installed-Size: <%= installedSize %>
|
||||
Maintainer: <%= maintainer %>
|
||||
Maintainer: GitHub <atom@github.com>
|
||||
Description: <%= description %>
|
||||
Atom is a free and open source text editor that is modern, approachable, and hackable to the core.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name: <%= name %>
|
||||
Name: <%= appFileName %>
|
||||
Version: <%= version %>
|
||||
Release: 0.1%{?dist}
|
||||
Summary: <%= description %>
|
||||
@@ -13,25 +13,23 @@ Requires: lsb-core-noarch
|
||||
<%= description %>
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}/<%= installDir %>/share/atom/
|
||||
cp -r Atom/* %{buildroot}/<%= installDir %>/share/atom/
|
||||
mkdir -p %{buildroot}/<%= installDir %>/bin/
|
||||
ln -sf ../share/atom/resources/app/apm/node_modules/.bin/apm %{buildroot}/<%= installDir %>/bin/apm
|
||||
cp atom.sh %{buildroot}/<%= installDir %>/bin/atom
|
||||
chmod 755 %{buildroot}/<%= installDir %>/bin/atom
|
||||
mkdir -p %{buildroot}/<%= installDir %>/share/applications/
|
||||
cp atom.desktop %{buildroot}/<%= installDir %>/share/applications/
|
||||
mkdir -p "%{buildroot}/<%= installDir %>/share/<%= appFileName %>/"
|
||||
cp -r "<%= appName %>"/* "%{buildroot}/<%= installDir %>/share/<%= appFileName %>/"
|
||||
mkdir -p "%{buildroot}/<%= installDir %>/bin/"
|
||||
ln -sf "../share/<%= appFileName %>/resources/app/apm/node_modules/.bin/apm" "%{buildroot}/<%= installDir %>/bin/<%= apmFileName %>"
|
||||
cp atom.sh "%{buildroot}/<%= installDir %>/bin/<%= appFileName %>"
|
||||
chmod 755 "%{buildroot}/<%= installDir %>/bin/<%= appFileName %>"
|
||||
mkdir -p "%{buildroot}/<%= installDir %>/share/applications/"
|
||||
cp "<%= appFileName %>.desktop" "%{buildroot}/<%= installDir %>/share/applications/"
|
||||
|
||||
# copy over icons in sizes that most desktop environments like
|
||||
for i in 1024 512 256 128 64 48 32 24 16
|
||||
do
|
||||
mkdir -p %{buildroot}/<%= installDir %>/share/icons/hicolor/${i}x${i}/apps
|
||||
cp icons/${i}.png %{buildroot}/<%= installDir %>/share/icons/hicolor/${i}x${i}/apps/atom.png
|
||||
for i in 1024 512 256 128 64 48 32 24 16; do
|
||||
mkdir -p "%{buildroot}/<%= installDir %>/share/icons/hicolor/${i}x${i}/apps"
|
||||
cp "icons/${i}.png" "%{buildroot}/<%= installDir %>/share/icons/hicolor/${i}x${i}/apps/<%= appFileName %>.png"
|
||||
done
|
||||
|
||||
%files
|
||||
<%= installDir %>/bin/atom
|
||||
<%= installDir %>/bin/apm
|
||||
<%= installDir %>/share/atom/
|
||||
<%= installDir %>/share/applications/atom.desktop
|
||||
<%= installDir %>/bin/<%= appFileName %>
|
||||
<%= installDir %>/bin/<%= apmFileName %>
|
||||
<%= installDir %>/share/<%= appFileName %>/
|
||||
<%= installDir %>/share/applications/<%= appFileName %>.desktop
|
||||
<%= installDir %>/share/icons/hicolor/
|
||||
|
||||
@@ -20,6 +20,7 @@ var commands = [
|
||||
[__dirname, '..', 'build', 'node_modules'],
|
||||
[__dirname, '..', 'apm', 'node_modules'],
|
||||
[__dirname, '..', 'atom-shell'],
|
||||
[__dirname, '..', 'electron'],
|
||||
[home, '.atom', '.node-gyp'],
|
||||
[home, '.atom', 'storage'],
|
||||
[home, '.atom', '.apm'],
|
||||
|
||||
30
script/mkdeb
30
script/mkdeb
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# mkdeb version control-file-path deb-file-path
|
||||
# mkdeb name version channel arch control-file-path desktop-file-path icon-path deb-file-path
|
||||
|
||||
set -e
|
||||
|
||||
@@ -7,20 +7,22 @@ SCRIPT=`readlink -f "$0"`
|
||||
ROOT=`readlink -f $(dirname $SCRIPT)/..`
|
||||
cd $ROOT
|
||||
|
||||
VERSION="$1"
|
||||
ARCH="$2"
|
||||
CONTROL_FILE="$3"
|
||||
DESKTOP_FILE="$4"
|
||||
ICON_FILE="$5"
|
||||
DEB_PATH="$6"
|
||||
NAME="$1"
|
||||
VERSION="$2"
|
||||
CHANNEL="$3"
|
||||
ARCH="$4"
|
||||
CONTROL_FILE="$5"
|
||||
DESKTOP_FILE="$6"
|
||||
ICON_FILE="$7"
|
||||
DEB_PATH="$8"
|
||||
FILE_MODE=755
|
||||
|
||||
TARGET_ROOT="`mktemp -d`"
|
||||
chmod $FILE_MODE "$TARGET_ROOT"
|
||||
TARGET="$TARGET_ROOT/atom-$VERSION-$ARCH"
|
||||
TARGET="$TARGET_ROOT/$NAME-$VERSION-$ARCH"
|
||||
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr"
|
||||
env INSTALL_PREFIX="$TARGET/usr" script/grunt install
|
||||
env INSTALL_PREFIX="$TARGET/usr" script/grunt install --channel $CHANNEL
|
||||
|
||||
mkdir -m $FILE_MODE -p "$TARGET/DEBIAN"
|
||||
cp "$CONTROL_FILE" "$TARGET/DEBIAN/control"
|
||||
@@ -29,19 +31,19 @@ mkdir -m $FILE_MODE -p "$TARGET/usr/share/applications"
|
||||
cp "$DESKTOP_FILE" "$TARGET/usr/share/applications"
|
||||
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr/share/pixmaps"
|
||||
cp "$ICON_FILE" "$TARGET/usr/share/pixmaps"
|
||||
cp "$ICON_FILE" "$TARGET/usr/share/pixmaps/$NAME.png"
|
||||
|
||||
# Copy generated LICENSE.md to /usr/share/doc/atom/copyright
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr/share/doc/atom"
|
||||
cp "$TARGET/usr/share/atom/resources/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright"
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr/share/doc/$NAME"
|
||||
cp "$TARGET/usr/share/$NAME/resources/LICENSE.md" "$TARGET/usr/share/doc/$NAME/copyright"
|
||||
|
||||
# Add lintian overrides
|
||||
mkdir -m $FILE_MODE -p "$TARGET/usr/share/lintian/overrides"
|
||||
cp "$ROOT/resources/linux/debian/lintian-overrides" "$TARGET/usr/share/lintian/overrides/atom"
|
||||
cp "$ROOT/resources/linux/debian/lintian-overrides" "$TARGET/usr/share/lintian/overrides/$NAME"
|
||||
|
||||
# Remove executable bit from .node files
|
||||
find "$TARGET" -type f -name "*.node" -exec chmod a-x {} \;
|
||||
|
||||
fakeroot dpkg-deb -b "$TARGET"
|
||||
mv "$TARGET_ROOT/atom-$VERSION-$ARCH.deb" "$DEB_PATH"
|
||||
mv "$TARGET_ROOT/$NAME-$VERSION-$ARCH.deb" "$DEB_PATH"
|
||||
rm -rf "$TARGET_ROOT"
|
||||
|
||||
24
script/mkrpm
24
script/mkrpm
@@ -2,22 +2,24 @@
|
||||
|
||||
set -e
|
||||
|
||||
SPEC_FILE="$1"
|
||||
DESKTOP_FILE="$2"
|
||||
BUILD_DIRECTORY="$3"
|
||||
APP_NAME="$1"
|
||||
APP_FILE_NAME="$2"
|
||||
SPEC_FILE="$3"
|
||||
DESKTOP_FILE="$4"
|
||||
BUILD_DIRECTORY="$5"
|
||||
|
||||
RPM_BUILD_ROOT=~/rpmbuild
|
||||
ARCH=`uname -m`
|
||||
|
||||
rpmdev-setuptree
|
||||
|
||||
cp -r $BUILD_DIRECTORY/Atom $RPM_BUILD_ROOT/BUILD
|
||||
cp -r $BUILD_DIRECTORY/icons $RPM_BUILD_ROOT/BUILD
|
||||
cp $SPEC_FILE $RPM_BUILD_ROOT/SPECS
|
||||
cp ./atom.sh $RPM_BUILD_ROOT/BUILD
|
||||
cp $DESKTOP_FILE $RPM_BUILD_ROOT/BUILD
|
||||
cp -r "$BUILD_DIRECTORY/$APP_NAME" "$RPM_BUILD_ROOT/BUILD"
|
||||
cp -r "$BUILD_DIRECTORY/icons" "$RPM_BUILD_ROOT/BUILD"
|
||||
cp "$SPEC_FILE" "$RPM_BUILD_ROOT/SPECS"
|
||||
cp ./atom.sh "$RPM_BUILD_ROOT/BUILD"
|
||||
cp "$DESKTOP_FILE" "$RPM_BUILD_ROOT/BUILD"
|
||||
|
||||
rpmbuild -ba $SPEC_FILE
|
||||
cp $RPM_BUILD_ROOT/RPMS/$ARCH/atom-*.rpm $BUILD_DIRECTORY/rpm
|
||||
rpmbuild -ba "$SPEC_FILE"
|
||||
cp $RPM_BUILD_ROOT/RPMS/$ARCH/$APP_FILE_NAME-*.rpm "$BUILD_DIRECTORY/rpm"
|
||||
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
rm -rf "$RPM_BUILD_ROOT"
|
||||
|
||||
@@ -1,34 +1,81 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
installer = require '../src/command-installer'
|
||||
CommandInstaller = require '../src/command-installer'
|
||||
|
||||
describe "install(commandPath, callback)", ->
|
||||
commandFilePath = temp.openSync("atom-command").path
|
||||
commandName = path.basename(commandFilePath)
|
||||
installationPath = temp.mkdirSync("atom-bin")
|
||||
installationFilePath = path.join(installationPath, commandName)
|
||||
describe "CommandInstaller on #darwin", ->
|
||||
[installer, resourcesPath, installationPath, atomBinPath, apmBinPath] = []
|
||||
|
||||
beforeEach ->
|
||||
fs.chmodSync(commandFilePath, '755')
|
||||
spyOn(installer, 'getInstallDirectory').andReturn installationPath
|
||||
installationPath = temp.mkdirSync("atom-bin")
|
||||
|
||||
describe "on #darwin", ->
|
||||
it "symlinks the command and makes it executable", ->
|
||||
expect(fs.isFileSync(commandFilePath)).toBeTruthy()
|
||||
expect(fs.isFileSync(installationFilePath)).toBeFalsy()
|
||||
resourcesPath = temp.mkdirSync('atom-app')
|
||||
atomBinPath = path.join(resourcesPath, 'app', 'atom.sh')
|
||||
apmBinPath = path.join(resourcesPath, 'app', 'apm', 'node_modules', '.bin', 'apm')
|
||||
fs.writeFileSync(atomBinPath, "")
|
||||
fs.writeFileSync(apmBinPath, "")
|
||||
fs.chmodSync(atomBinPath, '755')
|
||||
fs.chmodSync(apmBinPath, '755')
|
||||
|
||||
installDone = false
|
||||
installError = null
|
||||
installer.createSymlink commandFilePath, false, (error) ->
|
||||
installDone = true
|
||||
installError = error
|
||||
spyOn(CommandInstaller::, 'getResourcesDirectory').andReturn(resourcesPath)
|
||||
spyOn(CommandInstaller::, 'getInstallDirectory').andReturn(installationPath)
|
||||
|
||||
waitsFor ->
|
||||
installDone
|
||||
describe "when using a stable version of atom", ->
|
||||
beforeEach ->
|
||||
installer = new CommandInstaller("2.0.2")
|
||||
|
||||
it "symlinks the atom command as 'atom'", ->
|
||||
installedAtomPath = path.join(installationPath, 'atom')
|
||||
|
||||
expect(fs.isFileSync(installedAtomPath)).toBeFalsy()
|
||||
|
||||
waitsFor (done) ->
|
||||
installer.installAtomCommand(false, done)
|
||||
|
||||
runs ->
|
||||
expect(installError).toBeNull()
|
||||
expect(fs.isFileSync(installationFilePath)).toBeTruthy()
|
||||
expect(fs.realpathSync(installationFilePath)).toBe fs.realpathSync(commandFilePath)
|
||||
expect(fs.isExecutableSync(installationFilePath)).toBeTruthy()
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe fs.realpathSync(atomBinPath)
|
||||
expect(fs.isExecutableSync(installedAtomPath)).toBe true
|
||||
expect(fs.isFileSync(path.join(installationPath, 'atom-beta'))).toBe false
|
||||
|
||||
it "symlinks the apm command as 'apm'", ->
|
||||
installedApmPath = path.join(installationPath, 'apm')
|
||||
|
||||
expect(fs.isFileSync(installedApmPath)).toBeFalsy()
|
||||
|
||||
waitsFor (done) ->
|
||||
installer.installApmCommand(false, done)
|
||||
|
||||
runs ->
|
||||
expect(fs.realpathSync(installedApmPath)).toBe fs.realpathSync(apmBinPath)
|
||||
expect(fs.isExecutableSync(installedApmPath)).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(installationPath, 'apm-beta'))).toBe false
|
||||
|
||||
describe "when using a beta version of atom", ->
|
||||
beforeEach ->
|
||||
installer = new CommandInstaller("2.2.0-beta.0")
|
||||
|
||||
it "symlinks the atom command as 'atom-beta'", ->
|
||||
installedAtomPath = path.join(installationPath, 'atom-beta')
|
||||
|
||||
expect(fs.isFileSync(installedAtomPath)).toBeFalsy()
|
||||
|
||||
waitsFor (done) ->
|
||||
installer.installAtomCommand(false, done)
|
||||
|
||||
runs ->
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe fs.realpathSync(atomBinPath)
|
||||
expect(fs.isExecutableSync(installedAtomPath)).toBe true
|
||||
expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe false
|
||||
|
||||
it "symlinks the apm command as 'apm-beta'", ->
|
||||
installedApmPath = path.join(installationPath, 'apm-beta')
|
||||
|
||||
expect(fs.isFileSync(installedApmPath)).toBeFalsy()
|
||||
|
||||
waitsFor (done) ->
|
||||
installer.installApmCommand(false, done)
|
||||
|
||||
runs ->
|
||||
expect(fs.realpathSync(installedApmPath)).toBe fs.realpathSync(apmBinPath)
|
||||
expect(fs.isExecutableSync(installedApmPath)).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(installationPath, 'apm'))).toBe false
|
||||
|
||||
@@ -2,7 +2,6 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
|
||||
describe "Config", ->
|
||||
dotAtomPath = null
|
||||
@@ -364,16 +363,6 @@ describe "Config", ->
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 55
|
||||
|
||||
it "deprecates passing a scope selector as the first argument", ->
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
|
||||
|
||||
spyOn(Grim, 'deprecate')
|
||||
atom.config.unset('.source.coffee', 'foo.bar.baz')
|
||||
expect(Grim.deprecate).toHaveBeenCalled()
|
||||
|
||||
expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10
|
||||
|
||||
describe ".onDidChange(keyPath, {scope})", ->
|
||||
[observeHandler, observeSubscription] = []
|
||||
|
||||
@@ -458,15 +447,6 @@ describe "Config", ->
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined})
|
||||
changeSpy.reset()
|
||||
|
||||
it 'deprecates using a scope descriptor as an optional first argument', ->
|
||||
keyPath = "foo.bar.baz"
|
||||
spyOn(Grim, 'deprecate')
|
||||
atom.config.onDidChange [".source.coffee", ".string.quoted.double.coffee"], keyPath, changeSpy = jasmine.createSpy()
|
||||
expect(Grim.deprecate).toHaveBeenCalled()
|
||||
|
||||
atom.config.set("foo.bar.baz", 12)
|
||||
expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12})
|
||||
|
||||
describe ".observe(keyPath, {scope})", ->
|
||||
[observeHandler, observeSubscription] = []
|
||||
|
||||
@@ -535,16 +515,6 @@ describe "Config", ->
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 2")
|
||||
expect(otherHandler).not.toHaveBeenCalledWith("value 2")
|
||||
|
||||
it "deprecates using a scope descriptor as the first argument", ->
|
||||
spyOn(Grim, 'deprecate')
|
||||
atom.config.observe([".some.scope"], "foo.bar.baz", observeHandler)
|
||||
atom.config.observe([".another.scope"], "foo.bar.baz", otherHandler)
|
||||
expect(Grim.deprecate).toHaveBeenCalled()
|
||||
|
||||
atom.config.set('foo.bar.baz', "value 2", scopeSelector: ".some")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 2")
|
||||
expect(otherHandler).not.toHaveBeenCalledWith("value 2")
|
||||
|
||||
it 'calls the callback when properties with more specific selectors are removed', ->
|
||||
changeSpy = jasmine.createSpy()
|
||||
atom.config.observe("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"], changeSpy)
|
||||
@@ -1629,135 +1599,3 @@ describe "Config", ->
|
||||
|
||||
expect(atom.config.set('foo.bar.arr', ['two', 'three'])).toBe true
|
||||
expect(atom.config.get('foo.bar.arr')).toEqual ['two', 'three']
|
||||
|
||||
describe "Deprecated Methods", ->
|
||||
describe ".getDefault(keyPath)", ->
|
||||
it "returns a clone of the default value", ->
|
||||
atom.config.setDefaults("foo", same: 1, changes: 1)
|
||||
|
||||
spyOn(Grim, 'deprecate')
|
||||
expect(atom.config.getDefault('foo.same')).toBe 1
|
||||
expect(atom.config.getDefault('foo.changes')).toBe 1
|
||||
expect(Grim.deprecate.callCount).toBe 2
|
||||
|
||||
atom.config.set('foo.same', 2)
|
||||
atom.config.set('foo.changes', 3)
|
||||
|
||||
expect(atom.config.getDefault('foo.same')).toBe 1
|
||||
expect(atom.config.getDefault('foo.changes')).toBe 1
|
||||
expect(Grim.deprecate.callCount).toBe 4
|
||||
|
||||
initialDefaultValue = [1, 2, 3]
|
||||
atom.config.setDefaults("foo", bar: initialDefaultValue)
|
||||
expect(atom.config.getDefault('foo.bar')).toEqual initialDefaultValue
|
||||
expect(atom.config.getDefault('foo.bar')).not.toBe initialDefaultValue
|
||||
expect(Grim.deprecate.callCount).toBe 6
|
||||
|
||||
describe "when scoped settings are used", ->
|
||||
it "returns the global default when no scoped default set", ->
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
|
||||
spyOn(Grim, 'deprecate')
|
||||
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 10
|
||||
expect(Grim.deprecate).toHaveBeenCalled()
|
||||
|
||||
it "returns the scoped settings not including the user's config file", ->
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
atom.config.set("foo.bar.baz", 42, scopeSelector: ".source.coffee", source: "some-source")
|
||||
|
||||
spyOn(Grim, 'deprecate')
|
||||
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42
|
||||
expect(Grim.deprecate.callCount).toBe 1
|
||||
|
||||
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
|
||||
expect(atom.config.getDefault('.source.coffee', 'foo.bar.baz')).toBe 42
|
||||
expect(Grim.deprecate.callCount).toBe 2
|
||||
|
||||
describe ".isDefault(keyPath)", ->
|
||||
it "returns true when the value of the key path is its default value", ->
|
||||
atom.config.setDefaults("foo", same: 1, changes: 1)
|
||||
|
||||
spyOn(Grim, 'deprecate')
|
||||
expect(atom.config.isDefault('foo.same')).toBe true
|
||||
expect(atom.config.isDefault('foo.changes')).toBe true
|
||||
expect(Grim.deprecate.callCount).toBe 2
|
||||
|
||||
atom.config.set('foo.same', 2)
|
||||
atom.config.set('foo.changes', 3)
|
||||
|
||||
expect(atom.config.isDefault('foo.same')).toBe false
|
||||
expect(atom.config.isDefault('foo.changes')).toBe false
|
||||
expect(Grim.deprecate.callCount).toBe 4
|
||||
|
||||
describe "when scoped settings are used", ->
|
||||
it "returns false when a scoped setting was set by the user", ->
|
||||
spyOn(Grim, 'deprecate')
|
||||
expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe true
|
||||
expect(Grim.deprecate.callCount).toBe 1
|
||||
|
||||
atom.config.set("foo.bar.baz", 42, scopeSelector: ".source.coffee", source: "something-else")
|
||||
expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe true
|
||||
expect(Grim.deprecate.callCount).toBe 2
|
||||
|
||||
atom.config.set('foo.bar.baz', 55, scopeSelector: '.source.coffee')
|
||||
expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe false
|
||||
expect(Grim.deprecate.callCount).toBe 3
|
||||
|
||||
describe ".toggle(keyPath)", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "negates the boolean value of the current key path value", ->
|
||||
atom.config.set('foo.a', 1)
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe false
|
||||
|
||||
atom.config.set('foo.a', '')
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe true
|
||||
|
||||
atom.config.set('foo.a', null)
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe true
|
||||
|
||||
atom.config.set('foo.a', true)
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe false
|
||||
|
||||
describe ".getSettings()", ->
|
||||
it "returns all settings including defaults", ->
|
||||
atom.config.setDefaults("foo", bar: baz: 10)
|
||||
atom.config.set("foo.ok", 12)
|
||||
|
||||
jasmine.snapshotDeprecations()
|
||||
expect(atom.config.getSettings().foo).toEqual
|
||||
ok: 12
|
||||
bar:
|
||||
baz: 10
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe ".getPositiveInt(keyPath, defaultValue)", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "returns the proper coerced value", ->
|
||||
atom.config.set('editor.preferredLineLength', 0)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
|
||||
|
||||
it "returns the proper coerced value", ->
|
||||
atom.config.set('editor.preferredLineLength', -1234)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
|
||||
|
||||
it "returns the default value when a string is passed in", ->
|
||||
atom.config.set('editor.preferredLineLength', 'abcd')
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
|
||||
it "returns the default value when null is passed in", ->
|
||||
atom.config.set('editor.preferredLineLength', null)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
|
||||
@@ -156,32 +156,3 @@ describe "ContextMenuManager", ->
|
||||
catch error
|
||||
addError = error
|
||||
expect(addError.message).toContain('<>')
|
||||
|
||||
describe "when the menus are specified in a legacy format", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "allows items to be specified in the legacy format for now", ->
|
||||
contextMenu.add '.parent':
|
||||
'A': 'a'
|
||||
'Separator 1': '-'
|
||||
'B':
|
||||
'C': 'c'
|
||||
'Separator 2': '-'
|
||||
'D': 'd'
|
||||
|
||||
expect(contextMenu.templateForElement(parent)).toEqual [
|
||||
{label: 'A', command: 'a'}
|
||||
{type: 'separator'}
|
||||
{
|
||||
label: 'B'
|
||||
submenu: [
|
||||
{label: 'C', command: 'c'}
|
||||
{type: 'separator'}
|
||||
{label: 'D', command: 'd'}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -47,14 +47,6 @@ describe "DisplayBuffer", ->
|
||||
buffer.insert([0, 0], oneHundredLines)
|
||||
expect(displayBuffer.getLineCount()).toBe 100 + originalLineCount
|
||||
|
||||
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
|
||||
displayBuffer.setHeight(50)
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
displayBuffer.setScrollTop(80)
|
||||
|
||||
buffer.delete([[8, 0], [10, 0]])
|
||||
expect(displayBuffer.getScrollTop()).toBe 60
|
||||
|
||||
it "updates the display buffer prior to invoking change handlers registered on the buffer", ->
|
||||
buffer.onDidChange -> expect(displayBuffer2.tokenizedLineForScreenRow(0).text).toBe "testing"
|
||||
displayBuffer2 = new DisplayBuffer({buffer, tabLength})
|
||||
@@ -240,7 +232,8 @@ describe "DisplayBuffer", ->
|
||||
describe "when a newline is inserted, deleted, and re-inserted at the end of a wrapped line (regression)", ->
|
||||
it "correctly renders the original wrapped line", ->
|
||||
buffer = atom.project.buildBufferSync(null, '')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30, softWrapped: true})
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30})
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
|
||||
buffer.insert([0, 0], "the quick brown fox jumps over the lazy dog.")
|
||||
buffer.insert([0, Infinity], '\n')
|
||||
@@ -296,18 +289,6 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.setEditorWidthInChars(-1)
|
||||
expect(displayBuffer.editorWidthInChars).not.toBe -1
|
||||
|
||||
it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", ->
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
displayBuffer.setWidth(85)
|
||||
|
||||
displayBuffer.setSoftWrapped(false)
|
||||
displayBuffer.setScrollLeft(Infinity)
|
||||
expect(displayBuffer.getScrollLeft()).toBeGreaterThan 0
|
||||
displayBuffer.setSoftWrapped(true)
|
||||
expect(displayBuffer.getScrollLeft()).toBe 0
|
||||
displayBuffer.setScrollLeft(10)
|
||||
expect(displayBuffer.getScrollLeft()).toBe 0
|
||||
|
||||
describe "primitive folding", ->
|
||||
beforeEach ->
|
||||
displayBuffer.destroy()
|
||||
@@ -737,21 +718,6 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.clipScreenPosition([0, 1], clip: 'forward')).toEqual [0, tabLength]
|
||||
expect(displayBuffer.clipScreenPosition([0, tabLength], clip: 'forward')).toEqual [0, tabLength]
|
||||
|
||||
describe "::screenPositionForPixelPosition(pixelPosition)", ->
|
||||
it "clips pixel positions above buffer start", ->
|
||||
displayBuffer.setLineHeightInPixels(20)
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: -Infinity, left: -Infinity)).toEqual [0, 0]
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: -Infinity, left: Infinity)).toEqual [0, 0]
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: -1, left: Infinity)).toEqual [0, 0]
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: 0, left: Infinity)).toEqual [0, 29]
|
||||
|
||||
it "clips pixel positions below buffer end", ->
|
||||
displayBuffer.setLineHeightInPixels(20)
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: Infinity, left: -Infinity)).toEqual [12, 2]
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: Infinity, left: Infinity)).toEqual [12, 2]
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: displayBuffer.getHeight() + 1, left: 0)).toEqual [12, 2]
|
||||
expect(displayBuffer.screenPositionForPixelPosition(top: displayBuffer.getHeight() - 1, left: 0)).toEqual [12, 0]
|
||||
|
||||
describe "::screenPositionForBufferPosition(bufferPosition, options)", ->
|
||||
it "clips the specified buffer position", ->
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 2])).toEqual [0, 2]
|
||||
@@ -1185,20 +1151,6 @@ describe "DisplayBuffer", ->
|
||||
expect(marker1.getProperties()).toEqual a: 1, b: 2
|
||||
expect(marker2.getProperties()).toEqual a: 1, b: 3
|
||||
|
||||
describe "Marker::getPixelRange()", ->
|
||||
it "returns the start and end positions of the marker based on the line height and character widths assigned to the DisplayBuffer", ->
|
||||
marker = displayBuffer.markScreenRange([[5, 10], [6, 4]])
|
||||
|
||||
displayBuffer.setLineHeightInPixels(20)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
|
||||
for char in ['r', 'e', 't', 'u', 'r', 'n']
|
||||
displayBuffer.setScopedCharWidth(["source.js", "keyword.control.js"], char, 11)
|
||||
|
||||
{start, end} = marker.getPixelRange()
|
||||
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', ->
|
||||
@@ -1253,157 +1205,18 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.getDecorations(class: 'two').length).toEqual 0
|
||||
expect(displayBuffer.getDecorations(class: 'one').length).toEqual 1
|
||||
|
||||
describe "::setScrollTop", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
|
||||
it "disallows negative values", ->
|
||||
displayBuffer.setHeight(displayBuffer.getScrollHeight() + 100)
|
||||
expect(displayBuffer.setScrollTop(-10)).toBe 0
|
||||
expect(displayBuffer.getScrollTop()).toBe 0
|
||||
|
||||
it "disallows values that would make ::getScrollBottom() exceed ::getScrollHeight()", ->
|
||||
displayBuffer.setHeight(50)
|
||||
maxScrollTop = displayBuffer.getScrollHeight() - displayBuffer.getHeight()
|
||||
|
||||
expect(displayBuffer.setScrollTop(maxScrollTop)).toBe maxScrollTop
|
||||
expect(displayBuffer.getScrollTop()).toBe maxScrollTop
|
||||
|
||||
expect(displayBuffer.setScrollTop(maxScrollTop + 50)).toBe maxScrollTop
|
||||
expect(displayBuffer.getScrollTop()).toBe maxScrollTop
|
||||
|
||||
describe "editor.scrollPastEnd", ->
|
||||
describe "when editor.scrollPastEnd is false", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.scrollPastEnd", false)
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
|
||||
it "does not add the height of the view to the scroll height", ->
|
||||
lineHeight = displayBuffer.getLineHeightInPixels()
|
||||
originalScrollHeight = displayBuffer.getScrollHeight()
|
||||
displayBuffer.setHeight(50)
|
||||
|
||||
expect(displayBuffer.getScrollHeight()).toBe originalScrollHeight
|
||||
|
||||
describe "when editor.scrollPastEnd is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.scrollPastEnd", true)
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
|
||||
it "adds the height of the view to the scroll height", ->
|
||||
lineHeight = displayBuffer.getLineHeightInPixels()
|
||||
originalScrollHeight = displayBuffer.getScrollHeight()
|
||||
displayBuffer.setHeight(50)
|
||||
|
||||
expect(displayBuffer.getScrollHeight()).toEqual(originalScrollHeight + displayBuffer.height - (lineHeight * 3))
|
||||
|
||||
describe "::setScrollLeft", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
|
||||
it "disallows negative values", ->
|
||||
displayBuffer.setWidth(displayBuffer.getScrollWidth() + 100)
|
||||
expect(displayBuffer.setScrollLeft(-10)).toBe 0
|
||||
expect(displayBuffer.getScrollLeft()).toBe 0
|
||||
|
||||
it "disallows values that would make ::getScrollRight() exceed ::getScrollWidth()", ->
|
||||
displayBuffer.setWidth(50)
|
||||
maxScrollLeft = displayBuffer.getScrollWidth() - displayBuffer.getWidth()
|
||||
|
||||
expect(displayBuffer.setScrollLeft(maxScrollLeft)).toBe maxScrollLeft
|
||||
expect(displayBuffer.getScrollLeft()).toBe maxScrollLeft
|
||||
|
||||
expect(displayBuffer.setScrollLeft(maxScrollLeft + 50)).toBe maxScrollLeft
|
||||
expect(displayBuffer.getScrollLeft()).toBe maxScrollLeft
|
||||
|
||||
describe "::scrollToScreenPosition(position, [options])", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
displayBuffer.setHorizontalScrollbarHeight(0)
|
||||
displayBuffer.setHeight(50)
|
||||
displayBuffer.setWidth(150)
|
||||
|
||||
it "sets the scroll top and scroll left so the given screen position is in view", ->
|
||||
displayBuffer.scrollToScreenPosition([8, 20])
|
||||
expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10
|
||||
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
|
||||
it "triggers ::onDidRequestAutoscroll with the logical coordinates along with the options", ->
|
||||
scrollSpy = jasmine.createSpy("::onDidRequestAutoscroll")
|
||||
displayBuffer.onDidRequestAutoscroll(scrollSpy)
|
||||
|
||||
displayBuffer.scrollToScreenPosition([8, 20])
|
||||
expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10
|
||||
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
|
||||
displayBuffer.scrollToScreenPosition([8, 20], center: true)
|
||||
displayBuffer.scrollToScreenPosition([8, 20], center: false, reversed: true)
|
||||
|
||||
describe "when the 'center' option is true", ->
|
||||
it "vertically scrolls to center the given position vertically", ->
|
||||
displayBuffer.scrollToScreenPosition([8, 20], center: true)
|
||||
expect(displayBuffer.getScrollTop()).toBe (8 * 10) + 5 - (50 / 2)
|
||||
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
|
||||
|
||||
it "does not scroll vertically if the position is already in view", ->
|
||||
displayBuffer.scrollToScreenPosition([4, 20], center: true)
|
||||
expect(displayBuffer.getScrollTop()).toBe 0
|
||||
|
||||
describe "scroll width", ->
|
||||
cursorWidth = 1
|
||||
beforeEach ->
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
|
||||
it "recomputes the scroll width when the default character width changes", ->
|
||||
expect(displayBuffer.getScrollWidth()).toBe 10 * 65 + cursorWidth
|
||||
|
||||
displayBuffer.setDefaultCharWidth(12)
|
||||
expect(displayBuffer.getScrollWidth()).toBe 12 * 65 + cursorWidth
|
||||
|
||||
it "recomputes the scroll width when the max line length changes", ->
|
||||
buffer.insert([6, 12], ' ')
|
||||
expect(displayBuffer.getScrollWidth()).toBe 10 * 66 + cursorWidth
|
||||
|
||||
buffer.delete([[6, 10], [6, 12]], ' ')
|
||||
expect(displayBuffer.getScrollWidth()).toBe 10 * 64 + cursorWidth
|
||||
|
||||
it "recomputes the scroll width when the scoped character widths change", ->
|
||||
operatorWidth = 20
|
||||
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
|
||||
expect(displayBuffer.getScrollWidth()).toBe 10 * 64 + operatorWidth + cursorWidth
|
||||
|
||||
it "recomputes the scroll width when the scoped character widths change in a batch", ->
|
||||
operatorWidth = 20
|
||||
|
||||
displayBuffer.onDidChangeCharacterWidths changedSpy = jasmine.createSpy()
|
||||
|
||||
displayBuffer.batchCharacterMeasurement ->
|
||||
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
|
||||
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '?', operatorWidth)
|
||||
|
||||
expect(displayBuffer.getScrollWidth()).toBe 10 * 63 + operatorWidth * 2 + cursorWidth
|
||||
expect(changedSpy.callCount).toBe 1
|
||||
|
||||
describe "::getVisibleRowRange()", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
displayBuffer.setHeight(100)
|
||||
|
||||
it "returns the first and the last visible rows", ->
|
||||
displayBuffer.setScrollTop(0)
|
||||
|
||||
expect(displayBuffer.getVisibleRowRange()).toEqual [0, 9]
|
||||
|
||||
it "includes partially visible rows in the range", ->
|
||||
displayBuffer.setScrollTop(5)
|
||||
|
||||
expect(displayBuffer.getVisibleRowRange()).toEqual [0, 10]
|
||||
|
||||
it "returns an empty range when lineHeight is 0", ->
|
||||
displayBuffer.setLineHeightInPixels(0)
|
||||
|
||||
expect(displayBuffer.getVisibleRowRange()).toEqual [0, 0]
|
||||
|
||||
it "ends at last buffer row even if there's more space available", ->
|
||||
displayBuffer.setHeight(150)
|
||||
displayBuffer.setScrollTop(60)
|
||||
|
||||
expect(displayBuffer.getVisibleRowRange()).toEqual [0, 13]
|
||||
expect(scrollSpy).toHaveBeenCalledWith(screenRange: [[8, 20], [8, 20]], options: {})
|
||||
expect(scrollSpy).toHaveBeenCalledWith(screenRange: [[8, 20], [8, 20]], options: {center: true})
|
||||
expect(scrollSpy).toHaveBeenCalledWith(screenRange: [[8, 20], [8, 20]], options: {center: false, reversed: true})
|
||||
|
||||
describe "::decorateMarker", ->
|
||||
describe "when decorating gutters", ->
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{Git} = require 'atom'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
deprecate('Fake task deprecation')
|
||||
module.exports = ->
|
||||
|
||||
@@ -3,6 +3,7 @@ GitRepository = require '../src/git-repository'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
Task = require '../src/task'
|
||||
Project = require '../src/project'
|
||||
|
||||
copyRepository = ->
|
||||
workingDirPath = temp.mkdirSync('atom-working-dir')
|
||||
@@ -276,7 +277,7 @@ describe "GitRepository", ->
|
||||
atom.workspace.open('file.txt')
|
||||
|
||||
runs ->
|
||||
project2 = atom.project.testSerialization()
|
||||
project2 = Project.deserialize(atom.project.serialize())
|
||||
buffer = project2.getBuffers()[0]
|
||||
|
||||
waitsFor ->
|
||||
|
||||
@@ -52,7 +52,7 @@ describe "MenuManager", ->
|
||||
it "sends the current menu template and associated key bindings to the browser process", ->
|
||||
spyOn(menu, 'sendToBrowserProcess')
|
||||
menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
atom.keymap.add 'test', 'atom-workspace': 'ctrl-b': 'b'
|
||||
atom.keymaps.add 'test', 'atom-workspace': 'ctrl-b': 'b'
|
||||
menu.update()
|
||||
|
||||
waits 1
|
||||
@@ -64,8 +64,8 @@ describe "MenuManager", ->
|
||||
# more dynamic interaction between the currently focused element and the menu
|
||||
spyOn(menu, 'sendToBrowserProcess')
|
||||
menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
atom.keymap.add 'test', 'atom-workspace': 'ctrl-b': 'b'
|
||||
atom.keymap.add 'test', 'atom-text-editor': 'ctrl-b': 'unset!'
|
||||
atom.keymaps.add 'test', 'atom-workspace': 'ctrl-b': 'b'
|
||||
atom.keymaps.add 'test', 'atom-text-editor': 'ctrl-b': 'unset!'
|
||||
|
||||
waits 1
|
||||
|
||||
|
||||
@@ -62,17 +62,7 @@ describe "PackageManager", ->
|
||||
expect(console.warn.argsForCall[0][0]).toContain("Could not resolve")
|
||||
|
||||
describe "when the package is deprecated", ->
|
||||
grim = require 'grim'
|
||||
includeDeprecatedAPIs = null
|
||||
|
||||
beforeEach ->
|
||||
{includeDeprecatedAPIs} = grim
|
||||
|
||||
afterEach ->
|
||||
grim.includeDeprecatedAPIs = includeDeprecatedAPIs
|
||||
|
||||
it "returns null", ->
|
||||
grim.includeDeprecatedAPIs = false
|
||||
expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull()
|
||||
expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.9')).toBe true
|
||||
expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.0')).toBe true
|
||||
@@ -174,24 +164,6 @@ describe "PackageManager", ->
|
||||
expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe true
|
||||
expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 10
|
||||
|
||||
describe "when a package has configDefaults", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "still assigns configDefaults from the module though deprecated", ->
|
||||
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
|
||||
describe "when the package metadata includes `activationCommands`", ->
|
||||
[mainModule, promise, workspaceCommandListener, registration] = []
|
||||
|
||||
@@ -914,66 +886,3 @@ describe "PackageManager", ->
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
describe "deleting non-bundled autocomplete packages", ->
|
||||
[autocompleteCSSPath, autocompletePlusPath] = []
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
|
||||
beforeEach ->
|
||||
fixturePath = path.resolve(__dirname, './fixtures/packages')
|
||||
autocompleteCSSPath = path.join(fixturePath, 'autocomplete-css')
|
||||
autocompletePlusPath = path.join(fixturePath, 'autocomplete-plus')
|
||||
|
||||
try
|
||||
fs.mkdirSync(autocompleteCSSPath)
|
||||
fs.writeFileSync(path.join(autocompleteCSSPath, 'package.json'), '{}')
|
||||
fs.symlinkSync(path.join(fixturePath, 'package-with-main'), autocompletePlusPath, 'dir')
|
||||
|
||||
expect(fs.isDirectorySync(autocompleteCSSPath)).toBe true
|
||||
expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true
|
||||
|
||||
jasmine.unspy(atom.packages, 'uninstallAutocompletePlus')
|
||||
|
||||
afterEach ->
|
||||
try
|
||||
fs.unlink autocompletePlusPath, ->
|
||||
|
||||
it "removes the packages", ->
|
||||
atom.packages.loadPackages()
|
||||
|
||||
waitsFor ->
|
||||
not fs.isDirectorySync(autocompleteCSSPath)
|
||||
|
||||
runs ->
|
||||
expect(fs.isDirectorySync(autocompleteCSSPath)).toBe false
|
||||
expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true
|
||||
|
||||
describe "when the deprecated sublime-tabs package is installed", ->
|
||||
grim = require 'grim'
|
||||
includeDeprecatedAPIs = null
|
||||
|
||||
beforeEach ->
|
||||
{includeDeprecatedAPIs} = grim
|
||||
grim.includeDeprecatedAPIs = false
|
||||
|
||||
afterEach ->
|
||||
grim.includeDeprecatedAPIs = includeDeprecatedAPIs
|
||||
|
||||
it "enables the tree-view and tabs package", ->
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', 'tree-view')
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', 'tabs')
|
||||
|
||||
spyOn(atom.packages, 'getAvailablePackagePaths').andReturn [
|
||||
path.join(__dirname, 'fixtures', 'packages', 'sublime-tabs')
|
||||
path.resolve(__dirname, '..', 'node_modules', 'tree-view')
|
||||
path.resolve(__dirname, '..', 'node_modules', 'tabs')
|
||||
]
|
||||
atom.packages.loadPackages()
|
||||
|
||||
waitsFor ->
|
||||
not atom.packages.isPackageDisabled('tree-view') and not atom.packages.isPackageDisabled('tabs')
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageLoaded('tree-view')).toBe true
|
||||
expect(atom.packages.isPackageLoaded('tabs')).toBe true
|
||||
|
||||
@@ -21,7 +21,7 @@ describe "PaneContainer", ->
|
||||
it "preserves the focused pane across serialization", ->
|
||||
expect(pane3A.focused).toBe true
|
||||
|
||||
containerB = containerA.testSerialization()
|
||||
containerB = PaneContainer.deserialize(containerA.serialize())
|
||||
[pane1B, pane2B, pane3B] = containerB.getPanes()
|
||||
expect(pane3B.focused).toBe true
|
||||
|
||||
@@ -29,7 +29,7 @@ describe "PaneContainer", ->
|
||||
pane3A.activate()
|
||||
expect(containerA.getActivePane()).toBe pane3A
|
||||
|
||||
containerB = containerA.testSerialization()
|
||||
containerB = PaneContainer.deserialize(containerA.serialize())
|
||||
[pane1B, pane2B, pane3B] = containerB.getPanes()
|
||||
expect(containerB.getActivePane()).toBe pane3B
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{Model} = require 'theorist'
|
||||
{Emitter} = require 'event-kit'
|
||||
Pane = require '../src/pane'
|
||||
PaneAxis = require '../src/pane-axis'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
@@ -6,13 +6,17 @@ PaneContainer = require '../src/pane-container'
|
||||
describe "Pane", ->
|
||||
deserializerDisposable = null
|
||||
|
||||
class Item extends Model
|
||||
class Item
|
||||
@deserialize: ({name, uri}) -> new this(name, uri)
|
||||
constructor: (@name, @uri) ->
|
||||
constructor: (@name, @uri) -> @emitter = new Emitter
|
||||
destroyed: false
|
||||
getURI: -> @uri
|
||||
getPath: -> @path
|
||||
serialize: -> {deserializer: 'Item', @name, @uri}
|
||||
isEqual: (other) -> @name is other?.name
|
||||
onDidDestroy: (fn) -> @emitter.on('did-destroy', fn)
|
||||
destroy: -> @destroyed = true; @emitter.emit('did-destroy')
|
||||
isDestroyed: -> @destroyed
|
||||
|
||||
beforeEach ->
|
||||
deserializerDisposable = atom.deserializers.add(Item)
|
||||
@@ -728,12 +732,12 @@ describe "Pane", ->
|
||||
pane = new Pane(params)
|
||||
|
||||
it "can serialize and deserialize the pane and all its items", ->
|
||||
newPane = pane.testSerialization()
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
expect(newPane.getItems()).toEqual pane.getItems()
|
||||
|
||||
it "restores the active item on deserialization", ->
|
||||
pane.activateItemAtIndex(1)
|
||||
newPane = pane.testSerialization()
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
|
||||
|
||||
it "does not include items that cannot be deserialized", ->
|
||||
@@ -741,11 +745,11 @@ describe "Pane", ->
|
||||
unserializable = {}
|
||||
pane.activateItem(unserializable)
|
||||
|
||||
newPane = pane.testSerialization()
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
expect(newPane.getActiveItem()).toEqual pane.itemAtIndex(0)
|
||||
expect(newPane.getItems().length).toBe pane.getItems().length - 1
|
||||
|
||||
it "includes the pane's focus state in the serialized state", ->
|
||||
pane.focus()
|
||||
newPane = pane.testSerialization()
|
||||
newPane = Pane.deserialize(pane.serialize())
|
||||
expect(newPane.focused).toBe true
|
||||
|
||||
@@ -66,7 +66,7 @@ describe "Project", ->
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", ->
|
||||
@@ -75,7 +75,7 @@ describe "Project", ->
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
|
||||
expect(deserializedProject.getBuffers().length).toBe 1
|
||||
deserializedProject.getBuffers()[0].destroy()
|
||||
@@ -91,7 +91,7 @@ describe "Project", ->
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
fs.mkdirSync(pathToOpen)
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
it "does not deserialize buffers when their path is inaccessible", ->
|
||||
@@ -104,7 +104,7 @@ describe "Project", ->
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
fs.chmodSync(pathToOpen, '000')
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
deserializedProject = Project.deserialize(atom.project.serialize())
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
describe "when an editor is saved and the project has no path", ->
|
||||
@@ -508,36 +508,3 @@ describe "Project", ->
|
||||
|
||||
randomPath = path.join("some", "random", "path")
|
||||
expect(atom.project.contains(randomPath)).toBe false
|
||||
|
||||
describe ".eachBuffer(callback)", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
atom.project.bufferForPathSync('a')
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "invokes the callback for existing buffer", ->
|
||||
count = 0
|
||||
count = 0
|
||||
callbackBuffer = null
|
||||
callback = (buffer) ->
|
||||
callbackBuffer = buffer
|
||||
count++
|
||||
atom.project.eachBuffer(callback)
|
||||
expect(count).toBe 1
|
||||
expect(callbackBuffer).toBe atom.project.getBuffers()[0]
|
||||
|
||||
it "invokes the callback for new buffers", ->
|
||||
count = 0
|
||||
callbackBuffer = null
|
||||
callback = (buffer) ->
|
||||
callbackBuffer = buffer
|
||||
count++
|
||||
|
||||
atom.project.eachBuffer(callback)
|
||||
count = 0
|
||||
callbackBuffer = null
|
||||
atom.project.bufferForPathSync(require.resolve('./fixtures/sample.txt'))
|
||||
expect(count).toBe 1
|
||||
expect(callbackBuffer).toBe atom.project.getBuffers()[1]
|
||||
|
||||
@@ -156,8 +156,6 @@ beforeEach ->
|
||||
spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text
|
||||
spyOn(clipboard, 'readText').andCallFake -> clipboardContent
|
||||
|
||||
spyOn(atom.packages, 'uninstallAutocompletePlus')
|
||||
|
||||
addCustomMatchers(this)
|
||||
|
||||
afterEach ->
|
||||
|
||||
@@ -285,18 +285,18 @@ describe "TextEditorComponent", ->
|
||||
componentNode.style.width = gutterWidth + (30 * charWidth) + 'px'
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
expect(editor.getScrollWidth()).toBeGreaterThan scrollViewNode.offsetWidth
|
||||
expect(wrapperNode.getScrollWidth()).toBeGreaterThan scrollViewNode.offsetWidth
|
||||
|
||||
# At the time of writing, using width: 100% to achieve the full-width
|
||||
# lines caused full-screen repaints after switching away from an editor
|
||||
# and back again Please ensure you don't cause a performance regression if
|
||||
# you change this behavior.
|
||||
editorFullWidth = editor.getScrollWidth() + editor.getVerticalScrollbarWidth()
|
||||
editorFullWidth = wrapperNode.getScrollWidth() + wrapperNode.getVerticalScrollbarWidth()
|
||||
|
||||
for lineNode in lineNodes
|
||||
expect(lineNode.getBoundingClientRect().width).toBe(editorFullWidth)
|
||||
|
||||
componentNode.style.width = gutterWidth + editor.getScrollWidth() + 100 + 'px'
|
||||
componentNode.style.width = gutterWidth + wrapperNode.getScrollWidth() + 100 + 'px'
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
scrollViewWidth = scrollViewNode.offsetWidth
|
||||
@@ -473,7 +473,7 @@ describe "TextEditorComponent", ->
|
||||
editor.setText "a line that wraps \n"
|
||||
editor.setSoftWrapped(true)
|
||||
nextAnimationFrame()
|
||||
componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
|
||||
componentNode.style.width = 16 * charWidth + wrapperNode.getVerticalScrollbarWidth() + 'px'
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -893,7 +893,7 @@ describe "TextEditorComponent", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
nextAnimationFrame()
|
||||
componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
|
||||
componentNode.style.width = 16 * charWidth + wrapperNode.getVerticalScrollbarWidth() + 'px'
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -1336,15 +1336,13 @@ describe "TextEditorComponent", ->
|
||||
expect(lineAndLineNumberHaveClass(6, 'a')).toBe true
|
||||
expect(lineAndLineNumberHaveClass(7, 'a')).toBe false
|
||||
|
||||
it "remove decoration classes and unsubscribes from markers decorations are removed", ->
|
||||
expect(marker.getSubscriptionCount('changed'))
|
||||
it "remove decoration classes when decorations are removed", ->
|
||||
decoration.destroy()
|
||||
nextAnimationFrame()
|
||||
expect(lineNumberHasClass(1, 'a')).toBe false
|
||||
expect(lineNumberHasClass(2, 'a')).toBe false
|
||||
expect(lineNumberHasClass(3, 'a')).toBe false
|
||||
expect(lineNumberHasClass(4, 'a')).toBe false
|
||||
expect(marker.getSubscriptionCount('changed')).toBe 0
|
||||
|
||||
it "removes decorations when their marker is invalidated", ->
|
||||
editor.getBuffer().insert([3, 2], 'n')
|
||||
@@ -1674,8 +1672,8 @@ describe "TextEditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
|
||||
editor.setScrollTop(3 * lineHeightInPixels)
|
||||
editor.setScrollLeft(3 * charWidth)
|
||||
wrapperNode.setScrollTop(3 * lineHeightInPixels)
|
||||
wrapperNode.setScrollLeft(3 * charWidth)
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(inputNode.offsetTop).toBe 0
|
||||
@@ -1690,8 +1688,8 @@ describe "TextEditorComponent", ->
|
||||
# In bounds and focused
|
||||
wrapperNode.focus() # updates via state change
|
||||
nextAnimationFrame()
|
||||
expect(inputNode.offsetTop).toBe (5 * lineHeightInPixels) - editor.getScrollTop()
|
||||
expect(inputNode.offsetLeft).toBe (4 * charWidth) - editor.getScrollLeft()
|
||||
expect(inputNode.offsetTop).toBe (5 * lineHeightInPixels) - wrapperNode.getScrollTop()
|
||||
expect(inputNode.offsetLeft).toBe (4 * charWidth) - wrapperNode.getScrollLeft()
|
||||
|
||||
# In bounds, not focused
|
||||
inputNode.blur() # updates via state change
|
||||
@@ -1755,8 +1753,8 @@ describe "TextEditorComponent", ->
|
||||
wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
wrapperNode.style.width = 10 * charWidth + 'px'
|
||||
component.measureDimensions()
|
||||
editor.setScrollTop(3.5 * lineHeightInPixels)
|
||||
editor.setScrollLeft(2 * charWidth)
|
||||
wrapperNode.setScrollTop(3.5 * lineHeightInPixels)
|
||||
wrapperNode.setScrollLeft(2 * charWidth)
|
||||
nextAnimationFrame()
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([4, 8])))
|
||||
@@ -1873,33 +1871,33 @@ describe "TextEditorComponent", ->
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollTop()).toBe(0)
|
||||
expect(editor.getScrollLeft()).toBe(0)
|
||||
expect(wrapperNode.getScrollTop()).toBe(0)
|
||||
expect(wrapperNode.getScrollLeft()).toBe(0)
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousedown', {clientX: 0, clientY: 0}, which: 1))
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', {clientX: 100, clientY: 50}, which: 1))
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollTop()).toBe(0)
|
||||
expect(editor.getScrollLeft()).toBeGreaterThan(0)
|
||||
expect(wrapperNode.getScrollTop()).toBe(0)
|
||||
expect(wrapperNode.getScrollLeft()).toBeGreaterThan(0)
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', {clientX: 100, clientY: 100}, which: 1))
|
||||
nextAnimationFrame()
|
||||
expect(editor.getScrollTop()).toBeGreaterThan(0)
|
||||
expect(wrapperNode.getScrollTop()).toBeGreaterThan(0)
|
||||
|
||||
previousScrollTop = editor.getScrollTop()
|
||||
previousScrollLeft = editor.getScrollLeft()
|
||||
previousScrollTop = wrapperNode.getScrollTop()
|
||||
previousScrollLeft = wrapperNode.getScrollLeft()
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', {clientX: 10, clientY: 50}, which: 1))
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollTop()).toBe(previousScrollTop)
|
||||
expect(editor.getScrollLeft()).toBeLessThan(previousScrollLeft)
|
||||
expect(wrapperNode.getScrollTop()).toBe(previousScrollTop)
|
||||
expect(wrapperNode.getScrollLeft()).toBeLessThan(previousScrollLeft)
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', {clientX: 10, clientY: 10}, which: 1))
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollTop()).toBeLessThan(previousScrollTop)
|
||||
expect(wrapperNode.getScrollTop()).toBeLessThan(previousScrollTop)
|
||||
|
||||
it "stops selecting if the mouse is dragged into the dev tools", ->
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([2, 4]), which: 1))
|
||||
@@ -1992,12 +1990,12 @@ describe "TextEditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
expect(editor.getSelectedScreenRange()).toEqual [[5, 6], [12, 2]]
|
||||
|
||||
maximalScrollTop = editor.getScrollTop()
|
||||
maximalScrollTop = wrapperNode.getScrollTop()
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([9, 3]), which: 1))
|
||||
nextAnimationFrame()
|
||||
expect(editor.getSelectedScreenRange()).toEqual [[5, 6], [9, 4]]
|
||||
expect(editor.getScrollTop()).toBe maximalScrollTop # does not autoscroll upward (regression)
|
||||
expect(wrapperNode.getScrollTop()).toBe maximalScrollTop # does not autoscroll upward (regression)
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenPosition([9, 3]), which: 1))
|
||||
|
||||
@@ -2019,12 +2017,12 @@ describe "TextEditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
expect(editor.getSelectedScreenRange()).toEqual [[5, 0], [12, 2]]
|
||||
|
||||
maximalScrollTop = editor.getScrollTop()
|
||||
maximalScrollTop = wrapperNode.getScrollTop()
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([8, 4]), which: 1))
|
||||
nextAnimationFrame()
|
||||
expect(editor.getSelectedScreenRange()).toEqual [[5, 0], [8, 0]]
|
||||
expect(editor.getScrollTop()).toBe maximalScrollTop # does not autoscroll upward (regression)
|
||||
expect(wrapperNode.getScrollTop()).toBe maximalScrollTop # does not autoscroll upward (regression)
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenPosition([9, 3]), which: 1))
|
||||
|
||||
@@ -2119,23 +2117,23 @@ describe "TextEditorComponent", ->
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(2)))
|
||||
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(8)))
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollTop()).toBeGreaterThan 0
|
||||
maxScrollTop = editor.getScrollTop()
|
||||
expect(wrapperNode.getScrollTop()).toBeGreaterThan 0
|
||||
maxScrollTop = wrapperNode.getScrollTop()
|
||||
|
||||
|
||||
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(10)))
|
||||
nextAnimationFrame()
|
||||
expect(editor.getScrollTop()).toBe maxScrollTop
|
||||
expect(wrapperNode.getScrollTop()).toBe maxScrollTop
|
||||
|
||||
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(7)))
|
||||
nextAnimationFrame()
|
||||
expect(editor.getScrollTop()).toBeLessThan maxScrollTop
|
||||
expect(wrapperNode.getScrollTop()).toBeLessThan maxScrollTop
|
||||
|
||||
it "stops selecting if a textInput event occurs during the drag", ->
|
||||
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(2)))
|
||||
@@ -2244,7 +2242,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.setSoftWrapped(true)
|
||||
nextAnimationFrame()
|
||||
componentNode.style.width = 21 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
|
||||
componentNode.style.width = 21 * charWidth + wrapperNode.getVerticalScrollbarWidth() + 'px'
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -2416,7 +2414,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
expect(verticalScrollbarNode.scrollTop).toBe 0
|
||||
|
||||
editor.setScrollTop(10)
|
||||
wrapperNode.setScrollTop(10)
|
||||
nextAnimationFrame()
|
||||
expect(verticalScrollbarNode.scrollTop).toBe 10
|
||||
|
||||
@@ -2434,7 +2432,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
expect(horizontalScrollbarNode.scrollLeft).toBe 0
|
||||
|
||||
editor.setScrollLeft(100)
|
||||
wrapperNode.setScrollLeft(100)
|
||||
nextAnimationFrame()
|
||||
|
||||
top = 0
|
||||
@@ -2449,18 +2447,18 @@ describe "TextEditorComponent", ->
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
expect(wrapperNode.getScrollLeft()).toBe 0
|
||||
horizontalScrollbarNode.scrollLeft = 100
|
||||
horizontalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(editor.getScrollLeft()).toBe 100
|
||||
expect(wrapperNode.getScrollLeft()).toBe 100
|
||||
|
||||
it "does not obscure the last line with the horizontal scrollbar", ->
|
||||
wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
wrapperNode.style.width = 10 * charWidth + 'px'
|
||||
component.measureDimensions()
|
||||
editor.setScrollBottom(editor.getScrollHeight())
|
||||
wrapperNode.setScrollBottom(wrapperNode.getScrollHeight())
|
||||
nextAnimationFrame()
|
||||
lastLineNode = component.lineNodeForScreenRow(editor.getLastScreenRow())
|
||||
bottomOfLastLine = lastLineNode.getBoundingClientRect().bottom
|
||||
@@ -2479,7 +2477,7 @@ describe "TextEditorComponent", ->
|
||||
wrapperNode.style.height = 7 * lineHeightInPixels + 'px'
|
||||
wrapperNode.style.width = 10 * charWidth + 'px'
|
||||
component.measureDimensions()
|
||||
editor.setScrollLeft(Infinity)
|
||||
wrapperNode.setScrollLeft(Infinity)
|
||||
nextAnimationFrame()
|
||||
|
||||
rightOfLongestLine = component.lineNodeForScreenRow(6).querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
@@ -2570,7 +2568,7 @@ describe "TextEditorComponent", ->
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(horizontalScrollbarNode.scrollWidth).toBe editor.getScrollWidth()
|
||||
expect(horizontalScrollbarNode.scrollWidth).toBe wrapperNode.getScrollWidth()
|
||||
expect(horizontalScrollbarNode.style.left).toBe '0px'
|
||||
|
||||
describe "mousewheel events", ->
|
||||
@@ -2649,14 +2647,14 @@ describe "TextEditorComponent", ->
|
||||
expect(component.presenter.mouseWheelScreenRow).toBe null
|
||||
|
||||
it "clears the mouseWheelScreenRow after a delay even if the event does not cause scrolling", ->
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
lineNode = componentNode.querySelector('.line')
|
||||
wheelEvent = new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: 10)
|
||||
Object.defineProperty(wheelEvent, 'target', get: -> lineNode)
|
||||
componentNode.dispatchEvent(wheelEvent)
|
||||
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
expect(component.presenter.mouseWheelScreenRow).toBe 0
|
||||
advanceClock(component.presenter.stoppedScrollingDelay)
|
||||
@@ -2701,36 +2699,36 @@ describe "TextEditorComponent", ->
|
||||
|
||||
# try to scroll past the top, which is impossible
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: 50))
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
expect(WheelEvent::preventDefault).not.toHaveBeenCalled()
|
||||
|
||||
# scroll to the bottom in one huge event
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -3000))
|
||||
nextAnimationFrame()
|
||||
maxScrollTop = editor.getScrollTop()
|
||||
maxScrollTop = wrapperNode.getScrollTop()
|
||||
expect(WheelEvent::preventDefault).toHaveBeenCalled()
|
||||
WheelEvent::preventDefault.reset()
|
||||
|
||||
# try to scroll past the bottom, which is impossible
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -30))
|
||||
expect(editor.getScrollTop()).toBe maxScrollTop
|
||||
expect(wrapperNode.getScrollTop()).toBe maxScrollTop
|
||||
expect(WheelEvent::preventDefault).not.toHaveBeenCalled()
|
||||
|
||||
# try to scroll past the left side, which is impossible
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 50, wheelDeltaY: 0))
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
expect(wrapperNode.getScrollLeft()).toBe 0
|
||||
expect(WheelEvent::preventDefault).not.toHaveBeenCalled()
|
||||
|
||||
# scroll all the way right
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -3000, wheelDeltaY: 0))
|
||||
nextAnimationFrame()
|
||||
maxScrollLeft = editor.getScrollLeft()
|
||||
maxScrollLeft = wrapperNode.getScrollLeft()
|
||||
expect(WheelEvent::preventDefault).toHaveBeenCalled()
|
||||
WheelEvent::preventDefault.reset()
|
||||
|
||||
# try to scroll past the right side, which is impossible
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -30, wheelDeltaY: 0))
|
||||
expect(editor.getScrollLeft()).toBe maxScrollLeft
|
||||
expect(wrapperNode.getScrollLeft()).toBe maxScrollLeft
|
||||
expect(WheelEvent::preventDefault).not.toHaveBeenCalled()
|
||||
|
||||
describe "input events", ->
|
||||
@@ -3056,7 +3054,7 @@ describe "TextEditorComponent", ->
|
||||
expect(componentNode.querySelectorAll('.line')).toHaveLength(6)
|
||||
|
||||
gutterWidth = componentNode.querySelector('.gutter').offsetWidth
|
||||
componentNode.style.width = gutterWidth + 14 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
|
||||
componentNode.style.width = gutterWidth + 14 * charWidth + wrapperNode.getVerticalScrollbarWidth() + 'px'
|
||||
atom.views.performDocumentPoll()
|
||||
nextAnimationFrame()
|
||||
expect(componentNode.querySelector('.line').textContent).toBe "var quicksort "
|
||||
@@ -3326,6 +3324,273 @@ describe "TextEditorComponent", ->
|
||||
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe false
|
||||
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
|
||||
|
||||
describe "autoscroll", ->
|
||||
beforeEach ->
|
||||
editor.setVerticalScrollMargin(2)
|
||||
editor.setHorizontalScrollMargin(2)
|
||||
component.setLineHeight("10px")
|
||||
component.setFontSize(17)
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
wrapperNode.setWidth(55)
|
||||
wrapperNode.setHeight(55)
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
component.presenter.setHorizontalScrollbarHeight(0)
|
||||
component.presenter.setVerticalScrollbarWidth(0)
|
||||
nextAnimationFrame()
|
||||
|
||||
describe "when selecting buffer ranges", ->
|
||||
it "autoscrolls the selection if it is last unless the 'autoscroll' option is false", ->
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
editor.setSelectedBufferRange([[5, 6], [6, 8]])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
editor.setSelectedBufferRange([[0, 0], [0, 0]])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollLeft()).toBe 0
|
||||
|
||||
editor.setSelectedBufferRange([[6, 6], [6, 8]])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
describe "when adding selections for buffer ranges", ->
|
||||
it "autoscrolls to the added selection if needed", ->
|
||||
editor.addSelectionForBufferRange([[8, 10], [8, 15]])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe (9 * 10) + (2 * 10)
|
||||
expect(wrapperNode.getScrollRight()).toBe (15 * 10) + (2 * 10)
|
||||
|
||||
describe "when selecting lines containing cursors", ->
|
||||
it "autoscrolls to the selection", ->
|
||||
editor.setCursorScreenPosition([5, 6])
|
||||
nextAnimationFrame()
|
||||
|
||||
wrapperNode.scrollToTop()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
editor.selectLinesContainingCursors()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
|
||||
describe "when inserting text", ->
|
||||
describe "when there are multiple empty selections on different lines", ->
|
||||
it "autoscrolls to the last cursor", ->
|
||||
editor.setCursorScreenPosition([1, 2], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
|
||||
editor.addCursorAtScreenPosition([10, 4], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.insertText('a')
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 75
|
||||
|
||||
describe "when scrolled to cursor position", ->
|
||||
it "scrolls the last cursor into view, centering around the cursor if possible and the 'center' option isn't false", ->
|
||||
editor.setCursorScreenPosition([8, 8], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollLeft()).toBe 0
|
||||
|
||||
editor.scrollToCursorPosition()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe (8.8 * 10) - 30
|
||||
expect(wrapperNode.getScrollBottom()).toBe (8.3 * 10) + 30
|
||||
expect(wrapperNode.getScrollRight()).toBe (9 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
wrapperNode.setScrollTop(0)
|
||||
editor.scrollToCursorPosition(center: false)
|
||||
expect(wrapperNode.getScrollTop()).toBe (7.8 - editor.getVerticalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollBottom()).toBe (9.3 + editor.getVerticalScrollMargin()) * 10
|
||||
|
||||
describe "moving cursors", ->
|
||||
it "scrolls down when the last cursor gets closer than ::verticalScrollMargin to the bottom of the editor", ->
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
expect(wrapperNode.getScrollBottom()).toBe 5.5 * 10
|
||||
|
||||
editor.setCursorScreenPosition([2, 0])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe 5.5 * 10
|
||||
|
||||
editor.moveDown()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe 6 * 10
|
||||
|
||||
editor.moveDown()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe 7 * 10
|
||||
|
||||
it "scrolls up when the last cursor gets closer than ::verticalScrollMargin to the top of the editor", ->
|
||||
editor.setCursorScreenPosition([11, 0])
|
||||
nextAnimationFrame()
|
||||
wrapperNode.setScrollBottom(wrapperNode.getScrollHeight())
|
||||
nextAnimationFrame()
|
||||
|
||||
editor.moveUp()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe wrapperNode.getScrollHeight()
|
||||
|
||||
editor.moveUp()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 7 * 10
|
||||
|
||||
editor.moveUp()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 6 * 10
|
||||
|
||||
it "scrolls right when the last cursor gets closer than ::horizontalScrollMargin to the right of the editor", ->
|
||||
expect(wrapperNode.getScrollLeft()).toBe 0
|
||||
expect(wrapperNode.getScrollRight()).toBe 5.5 * 10
|
||||
|
||||
editor.setCursorScreenPosition([0, 2])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollRight()).toBe 5.5 * 10
|
||||
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollRight()).toBe 6 * 10
|
||||
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollRight()).toBe 7 * 10
|
||||
|
||||
it "scrolls left when the last cursor gets closer than ::horizontalScrollMargin to the left of the editor", ->
|
||||
wrapperNode.setScrollRight(wrapperNode.getScrollWidth())
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollRight()).toBe wrapperNode.getScrollWidth()
|
||||
editor.setCursorScreenPosition([6, 62], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
|
||||
editor.moveLeft()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollLeft()).toBe 59 * 10
|
||||
|
||||
editor.moveLeft()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollLeft()).toBe 58 * 10
|
||||
|
||||
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
|
||||
editor.setCursorScreenPosition([13, Infinity])
|
||||
editor.insertNewline()
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(wrapperNode.getScrollBottom()).toBe 14 * 10
|
||||
editor.insertNewline()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe 15 * 10
|
||||
|
||||
it "autoscrolls to the cursor when it moves due to undo", ->
|
||||
editor.insertText('abc')
|
||||
wrapperNode.setScrollTop(Infinity)
|
||||
nextAnimationFrame()
|
||||
|
||||
editor.undo()
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
it "doesn't scroll when the cursor moves into the visible area", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
nextAnimationFrame()
|
||||
|
||||
wrapperNode.setScrollTop(40)
|
||||
nextAnimationFrame()
|
||||
|
||||
editor.setCursorBufferPosition([6, 0])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 40
|
||||
|
||||
it "honors the autoscroll option on cursor and selection manipulation methods", ->
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.addCursorAtScreenPosition([11, 11], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.addCursorAtBufferPosition([11, 11], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.setCursorScreenPosition([11, 11], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.setCursorBufferPosition([11, 11], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.addSelectionForBufferRange([[11, 11], [11, 11]], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.addSelectionForScreenRange([[11, 11], [11, 12]], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.setSelectedBufferRange([[11, 0], [11, 1]], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.setSelectedScreenRange([[11, 0], [11, 6]], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.clearSelections(autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
editor.addSelectionForScreenRange([[0, 0], [0, 4]])
|
||||
nextAnimationFrame()
|
||||
|
||||
editor.getCursors()[0].setScreenPosition([11, 11], autoscroll: true)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBeGreaterThan 0
|
||||
editor.getCursors()[0].setBufferPosition([0, 0], autoscroll: true)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
editor.getSelections()[0].setScreenRange([[11, 0], [11, 4]], autoscroll: true)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBeGreaterThan 0
|
||||
editor.getSelections()[0].setBufferRange([[0, 0], [0, 4]], autoscroll: true)
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollTop()).toBe 0
|
||||
|
||||
describe "::screenPositionForPixelPosition(pixelPosition)", ->
|
||||
it "clips pixel positions above buffer start", ->
|
||||
expect(component.screenPositionForPixelPosition(top: -Infinity, left: -Infinity)).toEqual [0, 0]
|
||||
expect(component.screenPositionForPixelPosition(top: -Infinity, left: Infinity)).toEqual [0, 0]
|
||||
expect(component.screenPositionForPixelPosition(top: -1, left: Infinity)).toEqual [0, 0]
|
||||
expect(component.screenPositionForPixelPosition(top: 0, left: Infinity)).toEqual [0, 29]
|
||||
|
||||
it "clips pixel positions below buffer end", ->
|
||||
expect(component.screenPositionForPixelPosition(top: Infinity, left: -Infinity)).toEqual [12, 2]
|
||||
expect(component.screenPositionForPixelPosition(top: Infinity, left: Infinity)).toEqual [12, 2]
|
||||
expect(component.screenPositionForPixelPosition(top: component.getScrollHeight() + 1, left: 0)).toEqual [12, 2]
|
||||
expect(component.screenPositionForPixelPosition(top: component.getScrollHeight() - 1, left: 0)).toEqual [12, 0]
|
||||
|
||||
describe "::getVisibleRowRange()", ->
|
||||
beforeEach ->
|
||||
wrapperNode.style.height = lineHeightInPixels * 8 + "px"
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
it "returns the first and the last visible rows", ->
|
||||
component.setScrollTop(0)
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(component.getVisibleRowRange()).toEqual [0, 9]
|
||||
|
||||
it "ends at last buffer row even if there's more space available", ->
|
||||
wrapperNode.style.height = lineHeightInPixels * 13 + "px"
|
||||
component.measureDimensions()
|
||||
nextAnimationFrame()
|
||||
|
||||
component.setScrollTop(60)
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(component.getVisibleRowRange()).toEqual [0, 13]
|
||||
|
||||
describe "middle mouse paste on Linux", ->
|
||||
originalPlatform = null
|
||||
|
||||
@@ -3370,15 +3635,15 @@ describe "TextEditorComponent", ->
|
||||
clientCoordinatesForScreenPosition = (screenPosition) ->
|
||||
positionOffset = wrapperNode.pixelPositionForScreenPosition(screenPosition)
|
||||
scrollViewClientRect = componentNode.querySelector('.scroll-view').getBoundingClientRect()
|
||||
clientX = scrollViewClientRect.left + positionOffset.left - editor.getScrollLeft()
|
||||
clientY = scrollViewClientRect.top + positionOffset.top - editor.getScrollTop()
|
||||
clientX = scrollViewClientRect.left + positionOffset.left - wrapperNode.getScrollLeft()
|
||||
clientY = scrollViewClientRect.top + positionOffset.top - wrapperNode.getScrollTop()
|
||||
{clientX, clientY}
|
||||
|
||||
clientCoordinatesForScreenRowInGutter = (screenRow) ->
|
||||
positionOffset = wrapperNode.pixelPositionForScreenPosition([screenRow, Infinity])
|
||||
gutterClientRect = componentNode.querySelector('.gutter').getBoundingClientRect()
|
||||
clientX = gutterClientRect.left + positionOffset.left - editor.getScrollLeft()
|
||||
clientY = gutterClientRect.top + positionOffset.top - editor.getScrollTop()
|
||||
clientX = gutterClientRect.left + positionOffset.left - wrapperNode.getScrollLeft()
|
||||
clientY = gutterClientRect.top + positionOffset.top - wrapperNode.getScrollTop()
|
||||
{clientX, clientY}
|
||||
|
||||
lineAndLineNumberHaveClass = (screenRow, klass) ->
|
||||
|
||||
@@ -386,6 +386,18 @@ describe "TextEditorPresenter", ->
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(-300)
|
||||
expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 0
|
||||
|
||||
it "is always 0 when soft wrapping is enabled", ->
|
||||
presenter = buildPresenter(scrollLeft: 0, verticalScrollbarWidth: 0, contentFrameWidth: 85, baseCharacterWidth: 10)
|
||||
|
||||
editor.setSoftWrapped(false)
|
||||
presenter.setScrollLeft(Infinity)
|
||||
expect(presenter.getState().content.scrollLeft).toBeGreaterThan 0
|
||||
|
||||
editor.setSoftWrapped(true)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 0
|
||||
presenter.setScrollLeft(10)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 0
|
||||
|
||||
describe ".verticalScrollbar", ->
|
||||
describe ".visible", ->
|
||||
it "is true if the scrollHeight exceeds the computed client height", ->
|
||||
@@ -533,11 +545,11 @@ describe "TextEditorPresenter", ->
|
||||
expectValues presenter.getState().hiddenInput, {top: 0, left: 0}
|
||||
|
||||
expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43])
|
||||
expectValues presenter.getState().hiddenInput, {top: 11 * 10 - editor.getScrollTop(), left: 43 * 10 - editor.getScrollLeft()}
|
||||
expectValues presenter.getState().hiddenInput, {top: 11 * 10 - presenter.getScrollTop(), left: 43 * 10 - presenter.getScrollLeft()}
|
||||
|
||||
newCursor = null
|
||||
expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10])
|
||||
expectValues presenter.getState().hiddenInput, {top: (6 * 10) - editor.getScrollTop(), left: (10 * 10) - editor.getScrollLeft()}
|
||||
expectValues presenter.getState().hiddenInput, {top: (6 * 10) - presenter.getScrollTop(), left: (10 * 10) - presenter.getScrollLeft()}
|
||||
|
||||
expectStateUpdate presenter, -> newCursor.destroy()
|
||||
expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10}
|
||||
@@ -582,6 +594,7 @@ describe "TextEditorPresenter", ->
|
||||
advanceClock(100)
|
||||
expect(presenter.getState().content.scrollingVertically).toBe true
|
||||
presenter.setScrollTop(10)
|
||||
presenter.getState() # commits scroll position
|
||||
advanceClock(100)
|
||||
expect(presenter.getState().content.scrollingVertically).toBe true
|
||||
expectStateUpdate presenter, -> advanceClock(100)
|
||||
@@ -685,12 +698,55 @@ describe "TextEditorPresenter", ->
|
||||
expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
|
||||
describe ".scrollTop", ->
|
||||
it "changes based on the scroll operation that was performed last", ->
|
||||
presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20)
|
||||
expect(presenter.getState().content.scrollTop).toBe(0)
|
||||
|
||||
presenter.setScrollTop(20)
|
||||
editor.setCursorBufferPosition([5, 0])
|
||||
|
||||
expect(presenter.getState().content.scrollTop).toBe(50)
|
||||
|
||||
editor.setCursorBufferPosition([8, 0])
|
||||
presenter.setScrollTop(10)
|
||||
|
||||
expect(presenter.getState().content.scrollTop).toBe(10)
|
||||
|
||||
it "corresponds to the passed logical coordinates when building the presenter", ->
|
||||
presenter = buildPresenter(scrollRow: 4, lineHeight: 10, explicitHeight: 20)
|
||||
expect(presenter.getState().content.scrollTop).toBe(40)
|
||||
|
||||
it "tracks the value of ::scrollTop", ->
|
||||
presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20)
|
||||
expect(presenter.getState().content.scrollTop).toBe 10
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(50)
|
||||
expect(presenter.getState().content.scrollTop).toBe 50
|
||||
|
||||
it "keeps the model up to date with the corresponding logical coordinates", ->
|
||||
presenter = buildPresenter(scrollTop: 0, explicitHeight: 20, horizontalScrollbarHeight: 10, lineHeight: 10)
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(50)
|
||||
presenter.getState() # commits scroll position
|
||||
expect(editor.getScrollRow()).toBe(5)
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(57)
|
||||
presenter.getState() # commits scroll position
|
||||
expect(editor.getScrollRow()).toBe(6)
|
||||
|
||||
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
|
||||
presenter = buildPresenter(scrollTop: 80, lineHeight: 10, explicitHeight: 50, horizontalScrollbarHeight: 0)
|
||||
expect(presenter.getState().content.scrollTop).toBe(80)
|
||||
buffer.deleteRows(10, 9, 8)
|
||||
expect(presenter.getState().content.scrollTop).toBe(60)
|
||||
|
||||
it "is always rounded to the nearest integer", ->
|
||||
presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20)
|
||||
expect(presenter.getState().content.scrollTop).toBe 10
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(11.4)
|
||||
expect(presenter.getState().content.scrollTop).toBe 11
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(12.6)
|
||||
expect(presenter.getState().content.scrollTop).toBe 13
|
||||
|
||||
it "scrolls down automatically when the model is changed", ->
|
||||
presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20)
|
||||
|
||||
@@ -708,17 +764,21 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setExplicitHeight(60)
|
||||
expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight
|
||||
expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5)
|
||||
expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight
|
||||
expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight
|
||||
|
||||
expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]])
|
||||
expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight
|
||||
expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight
|
||||
|
||||
# Scroll top only gets smaller when needed as dimensions change, never bigger
|
||||
scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop
|
||||
expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n')
|
||||
expect(presenter.getState().content.scrollTop).toBe scrollTopBefore
|
||||
expect(presenter.getRealScrollTop()).toBe scrollTopBefore
|
||||
|
||||
it "never goes negative", ->
|
||||
presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10)
|
||||
@@ -738,30 +798,72 @@ describe "TextEditorPresenter", ->
|
||||
expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight
|
||||
|
||||
describe ".scrollLeft", ->
|
||||
it "changes based on the scroll operation that was performed last", ->
|
||||
presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10)
|
||||
expect(presenter.getState().content.scrollLeft).toBe(0)
|
||||
|
||||
presenter.setScrollLeft(20)
|
||||
editor.setCursorBufferPosition([0, 9])
|
||||
|
||||
expect(presenter.getState().content.scrollLeft).toBe(90)
|
||||
|
||||
editor.setCursorBufferPosition([0, 18])
|
||||
presenter.setScrollLeft(50)
|
||||
|
||||
expect(presenter.getState().content.scrollLeft).toBe(50)
|
||||
|
||||
it "corresponds to the passed logical coordinates when building the presenter", ->
|
||||
presenter = buildPresenter(scrollColumn: 3, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
|
||||
expect(presenter.getState().content.scrollLeft).toBe(30)
|
||||
|
||||
it "tracks the value of ::scrollLeft", ->
|
||||
presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 10
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(50)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 50
|
||||
|
||||
it "keeps the model up to date with the corresponding logical coordinates", ->
|
||||
presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(50)
|
||||
presenter.getState() # commits scroll position
|
||||
expect(editor.getScrollColumn()).toBe(5)
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(57)
|
||||
presenter.getState() # commits scroll position
|
||||
expect(editor.getScrollColumn()).toBe(6)
|
||||
|
||||
it "is always rounded to the nearest integer", ->
|
||||
presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 10
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(11.4)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 11
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(12.6)
|
||||
expect(presenter.getState().content.scrollLeft).toBe 13
|
||||
|
||||
it "never exceeds the computed scrollWidth minus the computed clientWidth", ->
|
||||
presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
|
||||
expectStateUpdate presenter, -> presenter.setScrollLeft(300)
|
||||
expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setContentFrameWidth(600)
|
||||
expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
|
||||
expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5)
|
||||
expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
|
||||
expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]])
|
||||
expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth
|
||||
|
||||
# Scroll top only gets smaller when needed as dimensions change, never bigger
|
||||
scrollLeftBefore = presenter.getState().content.scrollLeft
|
||||
expectStateUpdate presenter, -> editor.getBuffer().insert([6, 0], new Array(100).join('x'))
|
||||
expect(presenter.getState().content.scrollLeft).toBe scrollLeftBefore
|
||||
expect(presenter.getRealScrollLeft()).toBe scrollLeftBefore
|
||||
|
||||
it "never goes negative", ->
|
||||
presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
|
||||
@@ -1807,7 +1909,8 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
expectStateUpdate presenter, ->
|
||||
editor.insertNewline()
|
||||
editor.setScrollTop(scrollTop) # I'm fighting the editor
|
||||
presenter.setScrollTop(scrollTop) # I'm fighting the editor
|
||||
|
||||
expectValues stateForOverlay(presenter, decoration), {
|
||||
item: item
|
||||
pixelPosition: {top: 6 * 10 - scrollTop - itemHeight, left: gutterWidth}
|
||||
@@ -2084,6 +2187,12 @@ describe "TextEditorPresenter", ->
|
||||
expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 3, softWrapped: true}
|
||||
expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 4, softWrapped: false}
|
||||
|
||||
presenter.setContentFrameWidth(500)
|
||||
|
||||
expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false}
|
||||
expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 5, softWrapped: false}
|
||||
expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 6, softWrapped: false}
|
||||
|
||||
describe ".decorationClasses", ->
|
||||
it "adds decoration classes to the relevant line number state objects, both initially and when decorations change", ->
|
||||
marker1 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch', maintainHistory: true)
|
||||
|
||||
@@ -31,7 +31,7 @@ describe "TextEditor", ->
|
||||
|
||||
runs ->
|
||||
fs.mkdirSync(pathToOpen)
|
||||
expect(editor1.testSerialization()).toBeUndefined()
|
||||
expect(TextEditor.deserialize(editor1.serialize())).toBeUndefined()
|
||||
|
||||
it "restores selections and folds based on markers in the buffer", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
@@ -39,7 +39,7 @@ describe "TextEditor", ->
|
||||
editor.foldBufferRow(4)
|
||||
expect(editor.isFoldedAtBufferRow(4)).toBeTruthy()
|
||||
|
||||
editor2 = editor.testSerialization()
|
||||
editor2 = TextEditor.deserialize(editor.serialize())
|
||||
|
||||
expect(editor2.id).toBe editor.id
|
||||
expect(editor2.getBuffer().getPath()).toBe editor.getBuffer().getPath()
|
||||
@@ -52,7 +52,7 @@ describe "TextEditor", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
previousInvisibles = editor.tokenizedLineForScreenRow(0).invisibles
|
||||
|
||||
editor2 = editor.testSerialization()
|
||||
editor2 = TextEditor.deserialize(editor.serialize())
|
||||
|
||||
expect(previousInvisibles).toBeDefined()
|
||||
expect(editor2.displayBuffer.tokenizedLineForScreenRow(0).invisibles).toEqual previousInvisibles
|
||||
@@ -909,118 +909,6 @@ describe "TextEditor", ->
|
||||
cursor2 = editor.addCursorAtBufferPosition([1, 4])
|
||||
expect(cursor2.marker).toBe cursor1.marker
|
||||
|
||||
describe "autoscroll", ->
|
||||
beforeEach ->
|
||||
editor.setVerticalScrollMargin(2)
|
||||
editor.setHorizontalScrollMargin(2)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
editor.setHeight(5.5 * 10)
|
||||
editor.setWidth(5.5 * 10)
|
||||
|
||||
it "scrolls down when the last cursor gets closer than ::verticalScrollMargin to the bottom of the editor", ->
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getScrollBottom()).toBe 5.5 * 10
|
||||
|
||||
editor.setCursorScreenPosition([2, 0])
|
||||
expect(editor.getScrollBottom()).toBe 5.5 * 10
|
||||
|
||||
editor.moveDown()
|
||||
expect(editor.getScrollBottom()).toBe 6 * 10
|
||||
|
||||
editor.moveDown()
|
||||
expect(editor.getScrollBottom()).toBe 7 * 10
|
||||
|
||||
it "scrolls up when the last cursor gets closer than ::verticalScrollMargin to the top of the editor", ->
|
||||
editor.setCursorScreenPosition([11, 0])
|
||||
editor.setScrollBottom(editor.getScrollHeight())
|
||||
|
||||
editor.moveUp()
|
||||
expect(editor.getScrollBottom()).toBe editor.getScrollHeight()
|
||||
|
||||
editor.moveUp()
|
||||
expect(editor.getScrollTop()).toBe 7 * 10
|
||||
|
||||
editor.moveUp()
|
||||
expect(editor.getScrollTop()).toBe 6 * 10
|
||||
|
||||
it "scrolls right when the last cursor gets closer than ::horizontalScrollMargin to the right of the editor", ->
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
expect(editor.getScrollRight()).toBe 5.5 * 10
|
||||
|
||||
editor.setCursorScreenPosition([0, 2])
|
||||
expect(editor.getScrollRight()).toBe 5.5 * 10
|
||||
|
||||
editor.moveRight()
|
||||
expect(editor.getScrollRight()).toBe 6 * 10
|
||||
|
||||
editor.moveRight()
|
||||
expect(editor.getScrollRight()).toBe 7 * 10
|
||||
|
||||
it "scrolls left when the last cursor gets closer than ::horizontalScrollMargin to the left of the editor", ->
|
||||
editor.setScrollRight(editor.getScrollWidth())
|
||||
expect(editor.getScrollRight()).toBe editor.getScrollWidth()
|
||||
editor.setCursorScreenPosition([6, 62], autoscroll: false)
|
||||
|
||||
editor.moveLeft()
|
||||
expect(editor.getScrollLeft()).toBe 59 * 10
|
||||
|
||||
editor.moveLeft()
|
||||
expect(editor.getScrollLeft()).toBe 58 * 10
|
||||
|
||||
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
|
||||
editor.setCursorScreenPosition([13, Infinity])
|
||||
editor.insertNewline()
|
||||
expect(editor.getScrollBottom()).toBe 14 * 10
|
||||
editor.insertNewline()
|
||||
expect(editor.getScrollBottom()).toBe 15 * 10
|
||||
|
||||
it "autoscrolls to the cursor when it moves due to undo", ->
|
||||
editor.insertText('abc')
|
||||
editor.setScrollTop(Infinity)
|
||||
editor.undo()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
it "doesn't scroll when the cursor moves into the visible area", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.setScrollTop(40)
|
||||
expect(editor.getVisibleRowRange()).toEqual([4, 9])
|
||||
editor.setCursorBufferPosition([6, 0])
|
||||
expect(editor.getScrollTop()).toBe 40
|
||||
|
||||
it "honors the autoscroll option on cursor and selection manipulation methods", ->
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.addCursorAtScreenPosition([11, 11], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.addCursorAtBufferPosition([11, 11], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.setCursorScreenPosition([11, 11], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.setCursorBufferPosition([11, 11], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.addSelectionForBufferRange([[11, 11], [11, 11]], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.addSelectionForScreenRange([[11, 11], [11, 12]], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.setSelectedBufferRange([[11, 0], [11, 1]], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.setSelectedScreenRange([[11, 0], [11, 6]], autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.clearSelections(autoscroll: false)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
editor.addSelectionForScreenRange([[0, 0], [0, 4]])
|
||||
|
||||
editor.getCursors()[0].setScreenPosition([11, 11], autoscroll: true)
|
||||
expect(editor.getScrollTop()).toBeGreaterThan 0
|
||||
editor.getCursors()[0].setBufferPosition([0, 0], autoscroll: true)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.getSelections()[0].setScreenRange([[11, 0], [11, 4]], autoscroll: true)
|
||||
expect(editor.getScrollTop()).toBeGreaterThan 0
|
||||
editor.getSelections()[0].setBufferRange([[0, 0], [0, 4]], autoscroll: true)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
describe '.logCursorScope()', ->
|
||||
beforeEach ->
|
||||
spyOn(atom.notifications, 'addInfo')
|
||||
@@ -1306,20 +1194,6 @@ describe "TextEditor", ->
|
||||
editor.selectLinesContainingCursors()
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[1, 0], [4, 0]]
|
||||
|
||||
it "autoscrolls to the selection", ->
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setWidth(50)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
editor.setCursorScreenPosition([5, 6])
|
||||
|
||||
editor.scrollToTop()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
editor.selectLinesContainingCursors()
|
||||
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
|
||||
describe ".selectToBeginningOfWord()", ->
|
||||
it "selects text from cusor position to beginning of word", ->
|
||||
editor.setCursorScreenPosition [0, 13]
|
||||
@@ -1572,30 +1446,6 @@ describe "TextEditor", ->
|
||||
expect(selection1).toBe selection
|
||||
expect(selection1.getScreenRange()).toEqual [[2, 2], [3, 4]]
|
||||
|
||||
describe ".setSelectedBufferRange(range)", ->
|
||||
it "autoscrolls the selection if it is last unless the 'autoscroll' option is false", ->
|
||||
editor.setVerticalScrollMargin(2)
|
||||
editor.setHorizontalScrollMargin(2)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(70)
|
||||
editor.setWidth(100)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
editor.setSelectedBufferRange([[5, 6], [6, 8]])
|
||||
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
editor.setSelectedBufferRange([[0, 0], [0, 0]])
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
|
||||
editor.setSelectedBufferRange([[6, 6], [6, 8]])
|
||||
expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
describe ".selectMarker(marker)", ->
|
||||
describe "if the marker is valid", ->
|
||||
it "selects the marker's range and returns the selected range", ->
|
||||
@@ -1615,17 +1465,6 @@ describe "TextEditor", ->
|
||||
editor.addSelectionForBufferRange([[3, 4], [5, 6]])
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
|
||||
|
||||
it "autoscrolls to the added selection if needed", ->
|
||||
editor.setVerticalScrollMargin(2)
|
||||
editor.setHorizontalScrollMargin(2)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(80)
|
||||
editor.setWidth(100)
|
||||
editor.addSelectionForBufferRange([[8, 10], [8, 15]])
|
||||
expect(editor.getScrollBottom()).toBe (9 * 10) + (2 * 10)
|
||||
expect(editor.getScrollRight()).toBe (15 * 10) + (2 * 10)
|
||||
|
||||
describe ".addSelectionBelow()", ->
|
||||
describe "when the selection is non-empty", ->
|
||||
it "selects the same region of the line below current selections if possible", ->
|
||||
@@ -1890,7 +1729,7 @@ describe "TextEditor", ->
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 3]]]
|
||||
|
||||
describe ".consolidateSelections()", ->
|
||||
it "destroys all selections but the most recent, returning true if any selections were destroyed", ->
|
||||
it "destroys all selections but the least recent, returning true if any selections were destroyed", ->
|
||||
editor.setSelectedBufferRange([[3, 16], [3, 21]])
|
||||
selection1 = editor.getLastSelection()
|
||||
selection2 = editor.addSelectionForBufferRange([[3, 25], [3, 34]])
|
||||
@@ -1898,10 +1737,10 @@ describe "TextEditor", ->
|
||||
|
||||
expect(editor.getSelections()).toEqual [selection1, selection2, selection3]
|
||||
expect(editor.consolidateSelections()).toBeTruthy()
|
||||
expect(editor.getSelections()).toEqual [selection3]
|
||||
expect(selection3.isEmpty()).toBeFalsy()
|
||||
expect(editor.getSelections()).toEqual [selection1]
|
||||
expect(selection1.isEmpty()).toBeFalsy()
|
||||
expect(editor.consolidateSelections()).toBeFalsy()
|
||||
expect(editor.getSelections()).toEqual [selection3]
|
||||
expect(editor.getSelections()).toEqual [selection1]
|
||||
|
||||
describe "when the cursor is moved while there is a selection", ->
|
||||
makeSelection = -> selection.setBufferRange [[1, 2], [1, 5]]
|
||||
@@ -1976,16 +1815,6 @@ describe "TextEditor", ->
|
||||
expect(cursor1.getBufferPosition()).toEqual [1, 5]
|
||||
expect(cursor2.getBufferPosition()).toEqual [2, 7]
|
||||
|
||||
it "autoscrolls to the last cursor", ->
|
||||
editor.setCursorScreenPosition([1, 2])
|
||||
editor.addCursorAtScreenPosition([10, 4])
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setHeight(50)
|
||||
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
editor.insertText('a')
|
||||
expect(editor.getScrollTop()).toBe 80
|
||||
|
||||
describe "when there are multiple non-empty selections", ->
|
||||
describe "when the selections are on the same line", ->
|
||||
it "replaces each selection range with the inserted characters", ->
|
||||
@@ -3855,19 +3684,6 @@ describe "TextEditor", ->
|
||||
runs ->
|
||||
expect(editor.softTabs).toBe false
|
||||
|
||||
it "uses hard tabs in Makefile files", ->
|
||||
# FIXME remove once this is handled by a scoped setting in the
|
||||
# language-make package
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-make')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('Makefile').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.softTabs).toBe false
|
||||
|
||||
describe "when editor.tabType is 'hard'", ->
|
||||
beforeEach ->
|
||||
atom.config.set('editor.tabType', 'hard')
|
||||
@@ -4547,30 +4363,10 @@ describe "TextEditor", ->
|
||||
editor.normalizeTabsInBufferRange([[0, 0], [Infinity, Infinity]])
|
||||
expect(editor.getText()).toBe ' '
|
||||
|
||||
describe ".scrollToCursorPosition()", ->
|
||||
it "scrolls the last cursor into view, centering around the cursor if possible and the 'center' option isn't false", ->
|
||||
editor.setCursorScreenPosition([8, 8])
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(60)
|
||||
editor.setWidth(130)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
|
||||
editor.scrollToCursorPosition()
|
||||
expect(editor.getScrollTop()).toBe (8.5 * 10) - 30
|
||||
expect(editor.getScrollBottom()).toBe (8.5 * 10) + 30
|
||||
expect(editor.getScrollRight()).toBe (9 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
editor.setScrollTop(0)
|
||||
editor.scrollToCursorPosition(center: false)
|
||||
expect(editor.getScrollBottom()).toBe (9 + editor.getVerticalScrollMargin()) * 10
|
||||
|
||||
describe ".pageUp/Down()", ->
|
||||
it "moves the cursor down one page length", ->
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setHeight(50)
|
||||
editor.setHeight(50, true)
|
||||
expect(editor.getCursorBufferPosition().row).toBe 0
|
||||
|
||||
editor.pageDown()
|
||||
@@ -4588,8 +4384,7 @@ describe "TextEditor", ->
|
||||
describe ".selectPageUp/Down()", ->
|
||||
it "selects one screen height of text up or down", ->
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setHeight(50)
|
||||
expect(editor.getScrollHeight()).toBe 130
|
||||
editor.setHeight(50, true)
|
||||
expect(editor.getCursorBufferPosition().row).toBe 0
|
||||
|
||||
editor.selectPageDown()
|
||||
@@ -4979,18 +4774,6 @@ describe "TextEditor", ->
|
||||
beforeEach ->
|
||||
marker = editor.markBufferRange([[1, 0], [1, 0]])
|
||||
|
||||
it "casts 'gutter' type to 'line-number' unless a gutter name is specified.", ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
lineNumberDecoration = editor.decorateMarker(marker, {type: 'gutter'})
|
||||
customGutterDecoration = editor.decorateMarker(marker, {type: 'gutter', gutterName: 'custom'})
|
||||
expect(lineNumberDecoration.getProperties().type).toBe 'line-number'
|
||||
expect(lineNumberDecoration.getProperties().gutterName).toBe 'line-number'
|
||||
expect(customGutterDecoration.getProperties().type).toBe 'gutter'
|
||||
expect(customGutterDecoration.getProperties().gutterName).toBe 'custom'
|
||||
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it 'reflects an added decoration when one of its custom gutters is decorated.', ->
|
||||
gutter = editor.addGutter {'name': 'custom-gutter'}
|
||||
decoration = gutter.decorateMarker marker, {class: 'custom-class'}
|
||||
|
||||
@@ -2,19 +2,17 @@ path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
|
||||
ThemeManager = require '../src/theme-manager'
|
||||
Package = require '../src/package'
|
||||
|
||||
describe "ThemeManager", ->
|
||||
themeManager = null
|
||||
describe "atom.themes", ->
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
configDirPath = atom.getConfigDirPath()
|
||||
|
||||
beforeEach ->
|
||||
themeManager = new ThemeManager({packageManager: atom.packages, resourcePath, configDirPath})
|
||||
spyOn(console, 'warn')
|
||||
|
||||
afterEach ->
|
||||
themeManager.deactivateThemes()
|
||||
atom.themes.deactivateThemes()
|
||||
|
||||
describe "theme getters and setters", ->
|
||||
beforeEach ->
|
||||
@@ -26,17 +24,17 @@ describe "ThemeManager", ->
|
||||
|
||||
describe 'getLoadedThemes', ->
|
||||
it 'gets all the loaded themes', ->
|
||||
themes = themeManager.getLoadedThemes()
|
||||
themes = atom.themes.getLoadedThemes()
|
||||
expect(themes.length).toBeGreaterThan(2)
|
||||
|
||||
describe "getActiveThemes", ->
|
||||
it 'gets all the active themes', ->
|
||||
waitsForPromise -> themeManager.activateThemes()
|
||||
waitsForPromise -> atom.themes.activateThemes()
|
||||
|
||||
runs ->
|
||||
names = atom.config.get('core.themes')
|
||||
expect(names.length).toBeGreaterThan(0)
|
||||
themes = themeManager.getActiveThemes()
|
||||
themes = atom.themes.getActiveThemes()
|
||||
expect(themes).toHaveLength(names.length)
|
||||
|
||||
describe "when the core.themes config value contains invalid entry", ->
|
||||
@@ -53,13 +51,13 @@ describe "ThemeManager", ->
|
||||
'atom-dark-ui'
|
||||
]
|
||||
|
||||
expect(themeManager.getEnabledThemeNames()).toEqual ['atom-dark-ui', 'atom-light-ui']
|
||||
expect(atom.themes.getEnabledThemeNames()).toEqual ['atom-dark-ui', 'atom-light-ui']
|
||||
|
||||
describe "::getImportPaths()", ->
|
||||
it "returns the theme directories before the themes are loaded", ->
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui', 'atom-light-ui'])
|
||||
|
||||
paths = themeManager.getImportPaths()
|
||||
paths = atom.themes.getImportPaths()
|
||||
|
||||
# syntax theme is not a dir at this time, so only two.
|
||||
expect(paths.length).toBe 2
|
||||
@@ -68,21 +66,21 @@ describe "ThemeManager", ->
|
||||
|
||||
it "ignores themes that cannot be resolved to a directory", ->
|
||||
atom.config.set('core.themes', ['definitely-not-a-theme'])
|
||||
expect(-> themeManager.getImportPaths()).not.toThrow()
|
||||
expect(-> atom.themes.getImportPaths()).not.toThrow()
|
||||
|
||||
describe "when the core.themes config value changes", ->
|
||||
it "add/removes stylesheets to reflect the new config value", ->
|
||||
themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.themes.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
spyOn(atom.styles, 'getUserStyleSheetPath').andCallFake -> null
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
atom.config.set('core.themes', [])
|
||||
|
||||
waitsFor ->
|
||||
waitsFor 'a', ->
|
||||
didChangeActiveThemesHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
@@ -90,7 +88,7 @@ describe "ThemeManager", ->
|
||||
expect(document.querySelectorAll('style.theme')).toHaveLength 0
|
||||
atom.config.set('core.themes', ['atom-dark-ui'])
|
||||
|
||||
waitsFor ->
|
||||
waitsFor 'b', ->
|
||||
didChangeActiveThemesHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
@@ -99,7 +97,7 @@ describe "ThemeManager", ->
|
||||
expect(document.querySelector('style[priority="1"]').getAttribute('source-path')).toMatch /atom-dark-ui/
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui'])
|
||||
|
||||
waitsFor ->
|
||||
waitsFor 'c', ->
|
||||
didChangeActiveThemesHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
@@ -123,22 +121,22 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
|
||||
importPaths = themeManager.getImportPaths()
|
||||
importPaths = atom.themes.getImportPaths()
|
||||
expect(importPaths.length).toBe 1
|
||||
expect(importPaths[0]).toContain 'atom-dark-ui'
|
||||
|
||||
it 'adds theme-* classes to the workspace for each active theme', ->
|
||||
atom.config.set('core.themes', ['atom-dark-ui', 'atom-dark-syntax'])
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.themes.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
runs ->
|
||||
expect(workspaceElement).toHaveClass 'theme-atom-dark-ui'
|
||||
|
||||
themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.themes.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
|
||||
waitsFor ->
|
||||
@@ -153,8 +151,8 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "when a theme fails to load", ->
|
||||
it "logs a warning", ->
|
||||
spyOn(console, 'warn')
|
||||
atom.packages.activatePackage('a-theme-that-will-not-be-found')
|
||||
console.warn.reset()
|
||||
atom.packages.activatePackage('a-theme-that-will-not-be-found').then((->), (->))
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0]).toContain "Could not resolve 'a-theme-that-will-not-be-found'"
|
||||
|
||||
@@ -167,27 +165,22 @@ describe "ThemeManager", ->
|
||||
|
||||
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
|
||||
atom.styles.onDidAddStyleElement styleElementAddedHandler = jasmine.createSpy("styleElementAddedHandler")
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
|
||||
cssPath = atom.project.getDirectories()[0]?.resolve('css.css')
|
||||
lengthBefore = document.querySelectorAll('head style').length
|
||||
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
atom.themes.requireStylesheet(cssPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
element = document.querySelector('head style[source-path*="css.css"]')
|
||||
expect(element.getAttribute('source-path')).toBe themeManager.stringToId(cssPath)
|
||||
expect(element.getAttribute('source-path')).toBe atom.themes.stringToId(cssPath)
|
||||
expect(element.textContent).toBe fs.readFileSync(cssPath, 'utf8')
|
||||
expect(element.sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
|
||||
|
||||
# doesn't append twice
|
||||
styleElementAddedHandler.reset()
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
atom.themes.requireStylesheet(cssPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
expect(styleElementAddedHandler).not.toHaveBeenCalled()
|
||||
|
||||
@@ -197,11 +190,11 @@ describe "ThemeManager", ->
|
||||
it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", ->
|
||||
lessPath = atom.project.getDirectories()[0]?.resolve('sample.less')
|
||||
lengthBefore = document.querySelectorAll('head style').length
|
||||
themeManager.requireStylesheet(lessPath)
|
||||
atom.themes.requireStylesheet(lessPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
|
||||
element = document.querySelector('head style[source-path*="sample.less"]')
|
||||
expect(element.getAttribute('source-path')).toBe themeManager.stringToId(lessPath)
|
||||
expect(element.getAttribute('source-path')).toBe atom.themes.stringToId(lessPath)
|
||||
expect(element.textContent).toBe """
|
||||
#header {
|
||||
color: #4d926f;
|
||||
@@ -213,16 +206,16 @@ describe "ThemeManager", ->
|
||||
"""
|
||||
|
||||
# doesn't append twice
|
||||
themeManager.requireStylesheet(lessPath)
|
||||
atom.themes.requireStylesheet(lessPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
for styleElement in document.querySelectorAll('head style[id*="sample.less"]')
|
||||
styleElement.remove()
|
||||
|
||||
it "supports requiring css and less stylesheets without an explicit extension", ->
|
||||
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'css')
|
||||
expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('css.css'))
|
||||
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'sample')
|
||||
expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less'))
|
||||
atom.themes.requireStylesheet path.join(__dirname, 'fixtures', 'css')
|
||||
expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toBe atom.themes.stringToId(atom.project.getDirectories()[0]?.resolve('css.css'))
|
||||
atom.themes.requireStylesheet path.join(__dirname, 'fixtures', 'sample')
|
||||
expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toBe atom.themes.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less'))
|
||||
|
||||
document.querySelector('head style[source-path*="css.css"]').remove()
|
||||
document.querySelector('head style[source-path*="sample.less"]').remove()
|
||||
@@ -231,24 +224,17 @@ describe "ThemeManager", ->
|
||||
cssPath = require.resolve('./fixtures/css.css')
|
||||
|
||||
expect(getComputedStyle(document.body).fontWeight).not.toBe("bold")
|
||||
disposable = themeManager.requireStylesheet(cssPath)
|
||||
disposable = atom.themes.requireStylesheet(cssPath)
|
||||
expect(getComputedStyle(document.body).fontWeight).toBe("bold")
|
||||
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
disposable.dispose()
|
||||
|
||||
expect(getComputedStyle(document.body).fontWeight).not.toBe("bold")
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
stylesheet = stylesheetRemovedHandler.argsForCall[0][0]
|
||||
expect(stylesheet instanceof CSSStyleSheet).toBe true
|
||||
expect(stylesheet.cssRules[0].selectorText).toBe 'body'
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "base style sheet loading", ->
|
||||
workspaceElement = null
|
||||
@@ -258,10 +244,10 @@ describe "ThemeManager", ->
|
||||
workspaceElement.appendChild document.createElement('atom-text-editor')
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
it "loads the correct values from the theme's ui-variables file", ->
|
||||
themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.themes.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
|
||||
waitsFor ->
|
||||
@@ -278,7 +264,7 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "when there is a theme with incomplete variables", ->
|
||||
it "loads the correct values from the fallback ui-variables", ->
|
||||
themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.themes.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-incomplete-ui-variables', 'theme-with-syntax-variables'])
|
||||
|
||||
waitsFor ->
|
||||
@@ -307,67 +293,52 @@ describe "ThemeManager", ->
|
||||
|
||||
it "reloads it", ->
|
||||
[styleElementAddedHandler, styleElementRemovedHandler] = []
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
runs ->
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
atom.styles.onDidAddStyleElement styleElementAddedHandler = jasmine.createSpy("styleElementAddedHandler")
|
||||
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
spyOn(atom.themes, 'loadUserStylesheet').andCallThrough()
|
||||
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe 'dotted'
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 1
|
||||
atom.themes.loadUserStylesheet.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe 'dashed'
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dotted'
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(styleElementAddedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
styleElementRemovedHandler.reset()
|
||||
stylesheetRemovedHandler.reset()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 2
|
||||
atom.themes.loadUserStylesheet.callCount is 2
|
||||
|
||||
runs ->
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when there is an error reading the stylesheet", ->
|
||||
addErrorHandler = null
|
||||
beforeEach ->
|
||||
themeManager.loadUserStylesheet()
|
||||
spyOn(themeManager.lessCache, 'cssForFile').andCallFake ->
|
||||
atom.themes.loadUserStylesheet()
|
||||
spyOn(atom.themes.lessCache, 'cssForFile').andCallFake ->
|
||||
throw new Error('EACCES permission denied "styles.less"')
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
|
||||
it "creates an error notification and does not add the stylesheet", ->
|
||||
themeManager.loadUserStylesheet()
|
||||
atom.themes.loadUserStylesheet()
|
||||
expect(addErrorHandler).toHaveBeenCalled()
|
||||
note = addErrorHandler.mostRecentCall.args[0]
|
||||
expect(note.getType()).toBe 'error'
|
||||
@@ -381,11 +352,11 @@ describe "ThemeManager", ->
|
||||
spyOn(File::, 'on').andCallFake (event) ->
|
||||
if event.indexOf('contents-changed') > -1
|
||||
throw new Error('Unable to watch path')
|
||||
spyOn(themeManager, 'loadStylesheet').andReturn ''
|
||||
spyOn(atom.themes, 'loadStylesheet').andReturn ''
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
|
||||
it "creates an error notification", ->
|
||||
themeManager.loadUserStylesheet()
|
||||
atom.themes.loadUserStylesheet()
|
||||
expect(addErrorHandler).toHaveBeenCalled()
|
||||
note = addErrorHandler.mostRecentCall.args[0]
|
||||
expect(note.getType()).toBe 'error'
|
||||
@@ -394,38 +365,35 @@ describe "ThemeManager", ->
|
||||
it "adds a notification when a theme's stylesheet is invalid", ->
|
||||
addErrorHandler = jasmine.createSpy()
|
||||
atom.notifications.onDidAddNotification(addErrorHandler)
|
||||
expect(-> atom.packages.activatePackage('theme-with-invalid-styles')).not.toThrow()
|
||||
expect(-> atom.packages.activatePackage('theme-with-invalid-styles').then((->), (->))).not.toThrow()
|
||||
expect(addErrorHandler.callCount).toBe 2
|
||||
expect(addErrorHandler.argsForCall[1][0].message).toContain("Failed to activate the theme-with-invalid-styles theme")
|
||||
|
||||
describe "when a non-existent theme is present in the config", ->
|
||||
beforeEach ->
|
||||
spyOn(console, 'warn')
|
||||
console.warn.reset()
|
||||
atom.config.set('core.themes', ['non-existent-dark-ui', 'non-existent-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
it 'uses the default dark UI and syntax themes and logs a warning', ->
|
||||
activeThemeNames = themeManager.getActiveThemeNames()
|
||||
activeThemeNames = atom.themes.getActiveThemeNames()
|
||||
expect(console.warn.callCount).toBe 2
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-dark-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
|
||||
describe "when in safe mode", ->
|
||||
beforeEach ->
|
||||
themeManager = new ThemeManager({packageManager: atom.packages, resourcePath, configDirPath, safeMode: true})
|
||||
|
||||
describe 'when the enabled UI and syntax themes are bundled with Atom', ->
|
||||
beforeEach ->
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
it 'uses the enabled themes', ->
|
||||
activeThemeNames = themeManager.getActiveThemeNames()
|
||||
activeThemeNames = atom.themes.getActiveThemeNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-light-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
@@ -435,10 +403,10 @@ describe "ThemeManager", ->
|
||||
atom.config.set('core.themes', ['installed-dark-ui', 'installed-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
it 'uses the default dark UI and syntax themes', ->
|
||||
activeThemeNames = themeManager.getActiveThemeNames()
|
||||
activeThemeNames = atom.themes.getActiveThemeNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-dark-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
@@ -448,10 +416,10 @@ describe "ThemeManager", ->
|
||||
atom.config.set('core.themes', ['installed-dark-ui', 'atom-light-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
it 'uses the default dark UI theme', ->
|
||||
activeThemeNames = themeManager.getActiveThemeNames()
|
||||
activeThemeNames = atom.themes.getActiveThemeNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-dark-ui')
|
||||
expect(activeThemeNames).toContain('atom-light-syntax')
|
||||
@@ -461,10 +429,10 @@ describe "ThemeManager", ->
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'installed-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
atom.themes.activateThemes()
|
||||
|
||||
it 'uses the default dark syntax theme', ->
|
||||
activeThemeNames = themeManager.getActiveThemeNames()
|
||||
activeThemeNames = atom.themes.getActiveThemeNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-light-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
|
||||
@@ -6,7 +6,6 @@ platform = require './spec-helper-platform'
|
||||
_ = require 'underscore-plus'
|
||||
fstream = require 'fstream'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
|
||||
describe "Workspace", ->
|
||||
workspace = null
|
||||
@@ -383,21 +382,6 @@ describe "Workspace", ->
|
||||
runs ->
|
||||
expect(newEditorHandler.argsForCall[0][0].textEditor).toBe editor
|
||||
|
||||
it "records a deprecation warning on the appropriate package if the item has a ::getUri method instead of ::getURI", ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
waitsForPromise -> atom.packages.activatePackage('package-with-deprecated-pane-item-method')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("test")
|
||||
|
||||
runs ->
|
||||
deprecations = Grim.getDeprecations()
|
||||
expect(deprecations.length).toBe 1
|
||||
expect(deprecations[0].message).toBe "Pane item with class `TestItem` should implement `::getURI` instead of `::getUri`."
|
||||
expect(deprecations[0].getStacks()[0].metadata.packageName).toBe "package-with-deprecated-pane-item-method"
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "when there is an error opening the file", ->
|
||||
notificationSpy = null
|
||||
beforeEach ->
|
||||
@@ -682,7 +666,7 @@ describe "Workspace", ->
|
||||
|
||||
it "updates the title to contain the project's path", ->
|
||||
document.title = null
|
||||
workspace2 = atom.workspace.testSerialization()
|
||||
workspace2 = Workspace.deserialize(atom.workspace.serialize())
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom"
|
||||
workspace2.destroy()
|
||||
|
||||
@@ -6,7 +6,7 @@ remote = require 'remote'
|
||||
shell = require 'shell'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{deprecate, includeDeprecatedAPIs} = require 'grim'
|
||||
{deprecate} = require 'grim'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
fs = require 'fs-plus'
|
||||
{mapSourcePosition} = require 'source-map-support'
|
||||
@@ -32,22 +32,6 @@ class Atom extends Model
|
||||
startTime = Date.now()
|
||||
atom = @deserialize(@loadState(mode)) ? new this({mode, @version})
|
||||
atom.deserializeTimings.atom = Date.now() - startTime
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
serviceHubDeprecationMessage = """
|
||||
atom.services is no longer available. To register service providers and
|
||||
consumers, use the `providedServices` and `consumedServices` fields in
|
||||
your package's package.json.
|
||||
"""
|
||||
|
||||
Object.defineProperty atom, 'services',
|
||||
get: ->
|
||||
deprecate(serviceHubDeprecationMessage)
|
||||
atom.packages.serviceHub
|
||||
set: (newValue) ->
|
||||
deprecate(serviceHubDeprecationMessage)
|
||||
atom.packages.serviceHub = newValue
|
||||
|
||||
atom
|
||||
|
||||
# Deserializes the Atom environment from a state object
|
||||
@@ -196,7 +180,6 @@ class Atom extends Model
|
||||
@openDevTools()
|
||||
@executeJavaScriptInDevTools('DevToolsAPI.showConsole()')
|
||||
|
||||
@emit 'uncaught-error', arguments... if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-throw-error', {message, url, line, column, originalError}
|
||||
|
||||
@disposables?.dispose()
|
||||
@@ -235,10 +218,6 @@ class Atom extends Model
|
||||
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
@keymap = @keymaps # Deprecated
|
||||
|
||||
@keymaps.subscribeToFileReadFailure()
|
||||
@tooltips = new TooltipManager
|
||||
@notifications = new NotificationManager
|
||||
@@ -252,14 +231,7 @@ class Atom extends Model
|
||||
@contextMenu = new ContextMenuManager({resourcePath, devMode})
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@clipboard = new Clipboard()
|
||||
|
||||
@grammars = @deserializers.deserialize(@state.grammars ? @state.syntax) ? new GrammarRegistry()
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
Object.defineProperty this, 'syntax', get: ->
|
||||
deprecate "The atom.syntax global is deprecated. Use atom.grammars instead."
|
||||
@grammars
|
||||
|
||||
@disposables.add @packages.onDidActivateInitialPackages => @watchThemes()
|
||||
|
||||
Project = require './project'
|
||||
@@ -485,10 +457,6 @@ class Atom extends Model
|
||||
isMaximized: ->
|
||||
@getCurrentWindow().isMaximized()
|
||||
|
||||
isMaximixed: ->
|
||||
deprecate "Use atom.isMaximized() instead"
|
||||
@isMaximized()
|
||||
|
||||
maximize: ->
|
||||
ipc.send('call-window-method', 'maximize')
|
||||
|
||||
@@ -605,9 +573,11 @@ class Atom extends Model
|
||||
{safeMode} = @getLoadSettings()
|
||||
|
||||
CommandInstaller = require './command-installer'
|
||||
CommandInstaller.installAtomCommand false, (error) ->
|
||||
|
||||
commandInstaller = new CommandInstaller(@getVersion())
|
||||
commandInstaller.installAtomCommand false, (error) ->
|
||||
console.warn error.message if error?
|
||||
CommandInstaller.installApmCommand false, (error) ->
|
||||
commandInstaller.installApmCommand false, (error) ->
|
||||
console.warn error.message if error?
|
||||
|
||||
@loadConfig()
|
||||
@@ -748,11 +718,9 @@ class Atom extends Model
|
||||
|
||||
startTime = Date.now()
|
||||
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
|
||||
|
||||
workspaceElement = @views.getView(@workspace)
|
||||
|
||||
@deserializeTimings.workspace = Date.now() - startTime
|
||||
|
||||
workspaceElement = @views.getView(@workspace)
|
||||
@keymaps.defaultTarget = workspaceElement
|
||||
document.querySelector(@workspaceParentSelectorctor).appendChild(workspaceElement)
|
||||
|
||||
@@ -877,12 +845,3 @@ class Atom extends Model
|
||||
Promise.prototype.done = (callback) ->
|
||||
deprecate("Atom now uses ES6 Promises instead of Q. Call promise.then instead of promise.done")
|
||||
@then(callback)
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
# Deprecated: Callers should be converted to use atom.deserializers
|
||||
Atom::registerRepresentationClass = ->
|
||||
deprecate("Callers should be converted to use atom.deserializers")
|
||||
|
||||
# Deprecated: Callers should be converted to use atom.deserializers
|
||||
Atom::registerRepresentationClasses = ->
|
||||
deprecate("Callers should be converted to use atom.deserializers")
|
||||
|
||||
@@ -103,6 +103,8 @@ class ApplicationMenu
|
||||
downloadingUpdateItem.visible = false
|
||||
installUpdateItem.visible = false
|
||||
|
||||
return if @autoUpdateManager.isDisabled()
|
||||
|
||||
switch state
|
||||
when 'idle', 'error', 'no-update-available'
|
||||
checkForUpdateItem.visible = true
|
||||
@@ -117,10 +119,9 @@ class ApplicationMenu
|
||||
#
|
||||
# Returns an Array of menu item Objects.
|
||||
getDefaultTemplate: ->
|
||||
[
|
||||
template = [
|
||||
label: "Atom"
|
||||
submenu: [
|
||||
{label: "Check for Update", metadata: {autoUpdate: true}}
|
||||
{label: 'Reload', accelerator: 'Command+R', click: => @focusedWindow()?.reload()}
|
||||
{label: 'Close Window', accelerator: 'Command+Shift+W', click: => @focusedWindow()?.close()}
|
||||
{label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: => @focusedWindow()?.toggleDevTools()}
|
||||
@@ -128,6 +129,10 @@ class ApplicationMenu
|
||||
]
|
||||
]
|
||||
|
||||
# Add `Check for Update` button if autoUpdateManager is enabled.
|
||||
template[0].submenu.unshift({label: "Check for Update", metadata: {autoUpdate: true}}) unless @autoUpdateManager.isDisabled()
|
||||
template
|
||||
|
||||
focusedWindow: ->
|
||||
_.find global.atomApplication.windows, (atomWindow) -> atomWindow.isFocused()
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ class AtomApplication
|
||||
@pidsToOpenWindows = {}
|
||||
@windows = []
|
||||
|
||||
@autoUpdateManager = new AutoUpdateManager(@version, options.test)
|
||||
disableAutoUpdate = require(path.join(@resourcePath, 'package.json'))._disableAutoUpdate ? false
|
||||
@autoUpdateManager = new AutoUpdateManager(@version, options.test, disableAutoUpdate)
|
||||
@applicationMenu = new ApplicationMenu(@version, @autoUpdateManager)
|
||||
@atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ module.exports =
|
||||
class AutoUpdateManager
|
||||
_.extend @prototype, EventEmitter.prototype
|
||||
|
||||
constructor: (@version, @testMode) ->
|
||||
constructor: (@version, @testMode, @disabled) ->
|
||||
@state = IdleState
|
||||
if process.platform is 'win32'
|
||||
# Squirrel for Windows can't handle query params
|
||||
@@ -52,8 +52,9 @@ class AutoUpdateManager
|
||||
@setState(UpdateAvailableState)
|
||||
@emitUpdateAvailableEvent(@getWindows()...)
|
||||
|
||||
# Only released versions should check for updates.
|
||||
@scheduleUpdateCheck() unless /\w{7}/.test(@version)
|
||||
# Only check for updates periodically if enabled and running in release
|
||||
# version.
|
||||
@scheduleUpdateCheck() unless /\w{7}/.test(@version) or @disabled
|
||||
|
||||
switch process.platform
|
||||
when 'win32'
|
||||
@@ -61,6 +62,9 @@ class AutoUpdateManager
|
||||
when 'linux'
|
||||
@setState(UnsupportedState)
|
||||
|
||||
isDisabled: ->
|
||||
@disabled
|
||||
|
||||
emitUpdateAvailableEvent: (windows...) ->
|
||||
return unless @releaseVersion?
|
||||
for atomWindow in windows
|
||||
|
||||
@@ -16,8 +16,8 @@ start = ->
|
||||
setupCompileCache()
|
||||
return if handleStartupEventWithSquirrel()
|
||||
|
||||
# NB: This prevents Win10 from showing dupe items in the taskbar
|
||||
app.setAppUserModelId('com.squirrel.atom.atom')
|
||||
# NB: This prevents Win10 from showing dupe items in the taskbar
|
||||
app.setAppUserModelId('com.squirrel.atom.atom')
|
||||
|
||||
args = parseCommandLine()
|
||||
|
||||
|
||||
@@ -25,9 +25,15 @@ symlinkCommandWithPrivilegeSync = (sourcePath, destinationPath) ->
|
||||
throw new Error("Failed to symlink '#{sourcePath}' to '#{destinationPath}'")
|
||||
|
||||
module.exports =
|
||||
class CommandInstaller
|
||||
constructor: (@appVersion) ->
|
||||
|
||||
getInstallDirectory: ->
|
||||
"/usr/local/bin"
|
||||
|
||||
getResourcesDirectory: ->
|
||||
process.resourcesPath
|
||||
|
||||
installShellCommandsInteractively: ->
|
||||
showErrorDialog = (error) ->
|
||||
atom.confirm
|
||||
@@ -47,17 +53,26 @@ module.exports =
|
||||
detailedMessage: "The shell commands `atom` and `apm` are installed."
|
||||
|
||||
installAtomCommand: (askForPrivilege, callback) ->
|
||||
commandPath = path.join(process.resourcesPath, 'app', 'atom.sh')
|
||||
@createSymlink commandPath, askForPrivilege, callback
|
||||
programName = if @appVersion.includes("beta")
|
||||
"atom-beta"
|
||||
else
|
||||
"atom"
|
||||
|
||||
commandPath = path.join(@getResourcesDirectory(), 'app', 'atom.sh')
|
||||
@createSymlink commandPath, programName, askForPrivilege, callback
|
||||
|
||||
installApmCommand: (askForPrivilege, callback) ->
|
||||
commandPath = path.join(process.resourcesPath, 'app', 'apm', 'node_modules', '.bin', 'apm')
|
||||
@createSymlink commandPath, askForPrivilege, callback
|
||||
programName = if @appVersion.includes("beta")
|
||||
"apm-beta"
|
||||
else
|
||||
"apm"
|
||||
|
||||
createSymlink: (commandPath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(@getResourcesDirectory(), 'app', 'apm', 'node_modules', '.bin', 'apm')
|
||||
@createSymlink commandPath, programName, askForPrivilege, callback
|
||||
|
||||
createSymlink: (commandPath, commandName, askForPrivilege, callback) ->
|
||||
return unless process.platform is 'darwin'
|
||||
|
||||
commandName = path.basename(commandPath, path.extname(commandPath))
|
||||
destinationPath = path.join(@getInstallDirectory(), commandName)
|
||||
|
||||
fs.readlink destinationPath, (error, realpath) ->
|
||||
@@ -70,6 +85,7 @@ module.exports =
|
||||
try
|
||||
error = null
|
||||
symlinkCommandWithPrivilegeSync(commandPath, destinationPath)
|
||||
catch error
|
||||
catch err
|
||||
error = err
|
||||
|
||||
callback?(error)
|
||||
|
||||
@@ -5,7 +5,6 @@ CSON = require 'season'
|
||||
path = require 'path'
|
||||
async = require 'async'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
Grim = require 'grim'
|
||||
|
||||
Color = require './color'
|
||||
ScopedPropertyStore = require 'scoped-property-store'
|
||||
@@ -387,21 +386,9 @@ class Config
|
||||
observe: ->
|
||||
if arguments.length is 2
|
||||
[keyPath, callback] = arguments
|
||||
else if Grim.includeDeprecatedAPIs and arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor)
|
||||
Grim.deprecate """
|
||||
Passing a scope descriptor as the first argument to Config::observe is deprecated.
|
||||
Pass a `scope` in an options hash as the third argument instead.
|
||||
"""
|
||||
[scopeDescriptor, keyPath, callback] = arguments
|
||||
else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1]))
|
||||
[keyPath, options, callback] = arguments
|
||||
scopeDescriptor = options.scope
|
||||
if Grim.includeDeprecatedAPIs and options.callNow?
|
||||
Grim.deprecate """
|
||||
Config::observe no longer takes a `callNow` option. Use ::onDidChange instead.
|
||||
Note that ::onDidChange passes its callback different arguments.
|
||||
See https://atom.io/docs/api/latest/Config
|
||||
"""
|
||||
else
|
||||
console.error 'An unsupported form of Config::observe is being used. See https://atom.io/docs/api/latest/Config for details'
|
||||
return
|
||||
@@ -435,12 +422,6 @@ class Config
|
||||
[callback] = arguments
|
||||
else if arguments.length is 2
|
||||
[keyPath, callback] = arguments
|
||||
else if Grim.includeDeprecatedAPIs and _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor
|
||||
Grim.deprecate """
|
||||
Passing a scope descriptor as the first argument to Config::onDidChange is deprecated.
|
||||
Pass a `scope` in an options hash as the third argument instead.
|
||||
"""
|
||||
[scopeDescriptor, keyPath, callback] = arguments
|
||||
else
|
||||
[keyPath, options, callback] = arguments
|
||||
scopeDescriptor = options.scope
|
||||
@@ -514,12 +495,6 @@ class Config
|
||||
if typeof arguments[0] is 'string' or not arguments[0]?
|
||||
[keyPath, options] = arguments
|
||||
{scope} = options
|
||||
else if Grim.includeDeprecatedAPIs
|
||||
Grim.deprecate """
|
||||
Passing a scope descriptor as the first argument to Config::get is deprecated.
|
||||
Pass a `scope` in an options hash as the final argument instead.
|
||||
"""
|
||||
[scope, keyPath] = arguments
|
||||
else
|
||||
[keyPath] = arguments
|
||||
|
||||
@@ -594,18 +569,10 @@ class Config
|
||||
# * `true` if the value was set.
|
||||
# * `false` if the value was not able to be coerced to the type specified in the setting's schema.
|
||||
set: ->
|
||||
if Grim.includeDeprecatedAPIs and arguments[0]?[0] is '.'
|
||||
Grim.deprecate """
|
||||
Passing a scope selector as the first argument to Config::set is deprecated.
|
||||
Pass a `scopeSelector` in an options hash as the final argument instead.
|
||||
"""
|
||||
[scopeSelector, keyPath, value] = arguments
|
||||
shouldSave = true
|
||||
else
|
||||
[keyPath, value, options] = arguments
|
||||
scopeSelector = options?.scopeSelector
|
||||
source = options?.source
|
||||
shouldSave = options?.save ? true
|
||||
[keyPath, value, options] = arguments
|
||||
scopeSelector = options?.scopeSelector
|
||||
source = options?.source
|
||||
shouldSave = options?.save ? true
|
||||
|
||||
if source and not scopeSelector
|
||||
throw new Error("::set with a 'source' and no 'sourceSelector' is not yet implemented!")
|
||||
@@ -633,16 +600,7 @@ class Config
|
||||
# * `scopeSelector` (optional) {String}. See {::set}
|
||||
# * `source` (optional) {String}. See {::set}
|
||||
unset: (keyPath, options) ->
|
||||
if Grim.includeDeprecatedAPIs and typeof options is 'string'
|
||||
Grim.deprecate """
|
||||
Passing a scope selector as the first argument to Config::unset is deprecated.
|
||||
Pass a `scopeSelector` in an options hash as the second argument instead.
|
||||
"""
|
||||
scopeSelector = keyPath
|
||||
keyPath = options
|
||||
else
|
||||
{scopeSelector, source} = options ? {}
|
||||
|
||||
{scopeSelector, source} = options ? {}
|
||||
source ?= @getUserConfigPath()
|
||||
|
||||
if scopeSelector?
|
||||
@@ -1206,71 +1164,3 @@ withoutEmptyObjects = (object) ->
|
||||
else
|
||||
resultObject = object
|
||||
resultObject
|
||||
|
||||
# TODO remove in 1.0 API
|
||||
Config::unobserve = (keyPath) ->
|
||||
Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.'
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(Config)
|
||||
|
||||
Config::restoreDefault = (scopeSelector, keyPath) ->
|
||||
Grim.deprecate("Use ::unset instead.")
|
||||
@unset(scopeSelector, keyPath)
|
||||
@get(keyPath)
|
||||
|
||||
Config::getDefault = ->
|
||||
Grim.deprecate("Use `::get(keyPath, {scope, excludeSources: [atom.config.getUserConfigPath()]})` instead")
|
||||
if arguments.length is 1
|
||||
[keyPath] = arguments
|
||||
else
|
||||
[scopeSelector, keyPath] = arguments
|
||||
scope = [scopeSelector]
|
||||
@get(keyPath, {scope, excludeSources: [@getUserConfigPath()]})
|
||||
|
||||
Config::isDefault = ->
|
||||
Grim.deprecate("Use `not ::get(keyPath, {scope, sources: [atom.config.getUserConfigPath()]})?` instead")
|
||||
if arguments.length is 1
|
||||
[keyPath] = arguments
|
||||
else
|
||||
[scopeSelector, keyPath] = arguments
|
||||
scope = [scopeSelector]
|
||||
not @get(keyPath, {scope, sources: [@getUserConfigPath()]})?
|
||||
|
||||
Config::getSettings = ->
|
||||
Grim.deprecate "Use ::get(keyPath) instead"
|
||||
_.deepExtend({}, @settings, @defaultSettings)
|
||||
|
||||
Config::getInt = (keyPath) ->
|
||||
Grim.deprecate '''Config::getInt is no longer necessary. Use ::get instead.
|
||||
Make sure the config option you are accessing has specified an `integer`
|
||||
schema. See the schema section of
|
||||
https://atom.io/docs/api/latest/Config for more info.'''
|
||||
parseInt(@get(keyPath))
|
||||
|
||||
Config::getPositiveInt = (keyPath, defaultValue=0) ->
|
||||
Grim.deprecate '''Config::getPositiveInt is no longer necessary. Use ::get instead.
|
||||
Make sure the config option you are accessing has specified an `integer`
|
||||
schema with `minimum: 1`. See the schema section of
|
||||
https://atom.io/docs/api/latest/Config for more info.'''
|
||||
Math.max(@getInt(keyPath), 0) or defaultValue
|
||||
|
||||
Config::toggle = (keyPath) ->
|
||||
Grim.deprecate 'Config::toggle is no longer supported. Please remove from your code.'
|
||||
@set(keyPath, not @get(keyPath))
|
||||
|
||||
Config::addScopedSettings = (source, selector, value, options) ->
|
||||
Grim.deprecate("Use ::set instead")
|
||||
settingsBySelector = {}
|
||||
settingsBySelector[selector] = value
|
||||
disposable = @scopedSettingsStore.addProperties(source, settingsBySelector, options)
|
||||
@emitChangeEvent()
|
||||
new Disposable =>
|
||||
disposable.dispose()
|
||||
@emitChangeEvent()
|
||||
|
||||
Config::settingsForScopeDescriptor = (scopeDescriptor, keyPath) ->
|
||||
Grim.deprecate("Use Config::getAll instead")
|
||||
entries = @getAll(null, scope: scopeDescriptor)
|
||||
value for {value} in entries when _.valueForKeyPath(value, keyPath)?
|
||||
|
||||
@@ -4,7 +4,6 @@ CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
{calculateSpecificity, validateSelector} = require 'clear-cut'
|
||||
{Disposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
MenuHelpers = require './menu-helpers'
|
||||
|
||||
platformContextMenu = require('../package.json')?._atomMenu?['context-menu']
|
||||
@@ -83,25 +82,25 @@ class ContextMenuManager
|
||||
#
|
||||
# * `itemsBySelector` An {Object} whose keys are CSS selectors and whose
|
||||
# values are {Array}s of item {Object}s containing the following keys:
|
||||
# * `label` (Optional) A {String} containing the menu item's label.
|
||||
# * `command` (Optional) A {String} containing the command to invoke on the
|
||||
# * `label` (optional) A {String} containing the menu item's label.
|
||||
# * `command` (optional) A {String} containing the command to invoke on the
|
||||
# target of the right click that invoked the context menu.
|
||||
# * `enabled` (Optional) A {Boolean} indicating whether the menu item
|
||||
# * `enabled` (optional) A {Boolean} indicating whether the menu item
|
||||
# should be clickable. Disabled menu items typically appear grayed out.
|
||||
# Defaults to `true`.
|
||||
# * `submenu` (Optional) An {Array} of additional items.
|
||||
# * `type` (Optional) If you want to create a separator, provide an item
|
||||
# * `submenu` (optional) An {Array} of additional items.
|
||||
# * `type` (optional) If you want to create a separator, provide an item
|
||||
# with `type: 'separator'` and no other keys.
|
||||
# * `visible` (Optional) A {Boolean} indicating whether the menu item
|
||||
# * `visible` (optional) A {Boolean} indicating whether the menu item
|
||||
# should appear in the menu. Defaults to `true`.
|
||||
# * `created` (Optional) A {Function} that is called on the item each time a
|
||||
# * `created` (optional) A {Function} that is called on the item each time a
|
||||
# context menu is created via a right click. You can assign properties to
|
||||
# `this` to dynamically compute the command, label, etc. This method is
|
||||
# actually called on a clone of the original item template to prevent state
|
||||
# from leaking across context menu deployments. Called with the following
|
||||
# argument:
|
||||
# * `event` The click event that deployed the context menu.
|
||||
# * `shouldDisplay` (Optional) A {Function} that is called to determine
|
||||
# * `shouldDisplay` (optional) A {Function} that is called to determine
|
||||
# whether to display this item on a given context menu deployment. Called
|
||||
# with the following argument:
|
||||
# * `event` The click event that deployed the context menu.
|
||||
@@ -109,27 +108,6 @@ class ContextMenuManager
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# added menu items.
|
||||
add: (itemsBySelector) ->
|
||||
if Grim.includeDeprecatedAPIs
|
||||
# Detect deprecated file path as first argument
|
||||
if itemsBySelector? and typeof itemsBySelector isnt 'object'
|
||||
Grim.deprecate """
|
||||
`ContextMenuManager::add` has changed to take a single object as its
|
||||
argument. Please see
|
||||
https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format for more info.
|
||||
"""
|
||||
itemsBySelector = arguments[1]
|
||||
devMode = arguments[2]?.devMode
|
||||
|
||||
# Detect deprecated format for items object
|
||||
for key, value of itemsBySelector
|
||||
unless _.isArray(value)
|
||||
Grim.deprecate """
|
||||
`ContextMenuManager::add` has changed to take a single object as its
|
||||
argument. Please see
|
||||
https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format for more info.
|
||||
"""
|
||||
itemsBySelector = @convertLegacyItemsBySelector(itemsBySelector, devMode)
|
||||
|
||||
addedItemSets = []
|
||||
|
||||
for selector, items of itemsBySelector
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{Emitter} = require 'event-kit'
|
||||
_ = require 'underscore-plus'
|
||||
Grim = require 'grim'
|
||||
Model = require './model'
|
||||
|
||||
# Extended: The `Cursor` class represents the little blinking line identifying
|
||||
@@ -62,18 +61,6 @@ class Cursor extends Model
|
||||
onDidChangeVisibility: (callback) ->
|
||||
@emitter.on 'did-change-visibility', callback
|
||||
|
||||
on: (eventName) ->
|
||||
return unless Grim.includeDeprecatedAPIs
|
||||
|
||||
switch eventName
|
||||
when 'moved'
|
||||
Grim.deprecate("Use Cursor::onDidChangePosition instead")
|
||||
when 'destroyed'
|
||||
Grim.deprecate("Use Cursor::onDidDestroy instead")
|
||||
else
|
||||
Grim.deprecate("::on is no longer supported. Use the event subscription methods instead")
|
||||
super
|
||||
|
||||
###
|
||||
Section: Managing Cursor Position
|
||||
###
|
||||
@@ -578,7 +565,6 @@ class Cursor extends Model
|
||||
setVisible: (visible) ->
|
||||
if @visible isnt visible
|
||||
@visible = visible
|
||||
@emit 'visibility-changed', @visible if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-visibility', @visible
|
||||
|
||||
# Public: Returns the visibility of the cursor.
|
||||
@@ -698,12 +684,3 @@ class Cursor extends Model
|
||||
position = range.start
|
||||
stop()
|
||||
position
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
Cursor::getScopes = ->
|
||||
Grim.deprecate 'Use Cursor::getScopeDescriptor() instead'
|
||||
@getScopeDescriptor().getScopesArray()
|
||||
|
||||
Cursor::getMoveNextWordBoundaryBufferPosition = (options) ->
|
||||
Grim.deprecate 'Use `::getNextWordBoundaryBufferPosition(options)` instead'
|
||||
@getNextWordBoundaryBufferPosition(options)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
idCounter = 0
|
||||
nextId = -> idCounter++
|
||||
@@ -82,7 +81,6 @@ class Decoration
|
||||
@markerDestroyDisposable.dispose()
|
||||
@markerDestroyDisposable = null
|
||||
@destroyed = true
|
||||
@emit 'destroyed' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-destroy'
|
||||
@emitter.dispose()
|
||||
|
||||
@@ -155,7 +153,6 @@ class Decoration
|
||||
@properties.id = @id
|
||||
if newProperties.type?
|
||||
@displayBuffer.decorationDidChangeType(this)
|
||||
@emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-properties', {oldProperties, newProperties}
|
||||
|
||||
###
|
||||
@@ -175,34 +172,8 @@ class Decoration
|
||||
flashObject = {class: klass, duration}
|
||||
@flashQueue ?= []
|
||||
@flashQueue.push(flashObject)
|
||||
@emit 'flash' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-flash'
|
||||
|
||||
consumeNextFlash: ->
|
||||
return @flashQueue.shift() if @flashQueue?.length > 0
|
||||
null
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(Decoration)
|
||||
|
||||
Decoration::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'updated'
|
||||
Grim.deprecate 'Use Decoration::onDidChangeProperties instead'
|
||||
when 'destroyed'
|
||||
Grim.deprecate 'Use Decoration::onDidDestroy instead'
|
||||
when 'flash'
|
||||
Grim.deprecate 'Use Decoration::onDidFlash instead'
|
||||
else
|
||||
Grim.deprecate 'Decoration::on is deprecated. Use event subscription methods instead.'
|
||||
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
Decoration::getParams = ->
|
||||
Grim.deprecate 'Use Decoration::getProperties instead'
|
||||
@getProperties()
|
||||
|
||||
Decoration::update = (newProperties) ->
|
||||
Grim.deprecate 'Use Decoration::setProperties instead'
|
||||
@setProperties(newProperties)
|
||||
|
||||
@@ -5,7 +5,7 @@ function listen (element, eventName, selector, handler) {
|
||||
var innerHandler = function (event) {
|
||||
if (selector) {
|
||||
var currentTarget = event.target
|
||||
while (true) {
|
||||
while (currentTarget) {
|
||||
if (currentTarget.matches && currentTarget.matches(selector)) {
|
||||
handler({
|
||||
type: event.type,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{Disposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
# Extended: Manages the deserializers used for serialized state
|
||||
#
|
||||
@@ -60,9 +59,3 @@ class DeserializerManager
|
||||
|
||||
name = state.get?('deserializer') ? state.deserializer
|
||||
@deserializers[name]
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
DeserializerManager::remove = (classes...) ->
|
||||
Grim.deprecate("Call .dispose() on the Disposable return from ::add instead")
|
||||
delete @deserializers[name] for {name} in classes
|
||||
return
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
_ = require 'underscore-plus'
|
||||
Serializable = require 'serializable'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
{Point, Range} = require 'text-buffer'
|
||||
Grim = require 'grim'
|
||||
TokenizedBuffer = require './tokenized-buffer'
|
||||
RowMap = require './row-map'
|
||||
Fold = require './fold'
|
||||
@@ -18,12 +16,20 @@ class BufferToScreenConversionError extends Error
|
||||
|
||||
module.exports =
|
||||
class DisplayBuffer extends Model
|
||||
Serializable.includeInto(this)
|
||||
|
||||
verticalScrollMargin: 2
|
||||
horizontalScrollMargin: 6
|
||||
scopedCharacterWidthsChangeCount: 0
|
||||
changeCount: 0
|
||||
softWrapped: null
|
||||
editorWidthInChars: null
|
||||
lineHeightInPixels: null
|
||||
defaultCharWidth: null
|
||||
height: null
|
||||
width: null
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer)
|
||||
new this(state)
|
||||
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles, @largeFileMode}={}) ->
|
||||
super
|
||||
@@ -83,23 +89,16 @@ class DisplayBuffer extends Model
|
||||
|
||||
@updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings)
|
||||
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
deserializer: 'DisplayBuffer'
|
||||
id: @id
|
||||
softWrapped: @isSoftWrapped()
|
||||
editorWidthInChars: @editorWidthInChars
|
||||
scrollTop: @scrollTop
|
||||
scrollLeft: @scrollLeft
|
||||
tokenizedBuffer: @tokenizedBuffer.serialize()
|
||||
largeFileMode: @largeFileMode
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer)
|
||||
params
|
||||
|
||||
copy: ->
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @largeFileMode})
|
||||
newDisplayBuffer.setScrollTop(@getScrollTop())
|
||||
newDisplayBuffer.setScrollLeft(@getScrollLeft())
|
||||
|
||||
for marker in @findMarkers(displayBufferId: @id)
|
||||
marker.copy(displayBufferId: newDisplayBuffer.id)
|
||||
@@ -126,19 +125,8 @@ class DisplayBuffer extends Model
|
||||
onDidChangeCharacterWidths: (callback) ->
|
||||
@emitter.on 'did-change-character-widths', callback
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@emitter.on 'did-change-scroll-top', callback
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@emitter.on 'did-change-scroll-left', callback
|
||||
|
||||
observeScrollTop: (callback) ->
|
||||
callback(@scrollTop)
|
||||
@onDidChangeScrollTop(callback)
|
||||
|
||||
observeScrollLeft: (callback) ->
|
||||
callback(@scrollLeft)
|
||||
@onDidChangeScrollLeft(callback)
|
||||
onDidRequestAutoscroll: (callback) ->
|
||||
@emitter.on 'did-request-autoscroll', callback
|
||||
|
||||
observeDecorations: (callback) ->
|
||||
callback(decoration) for decoration in @getDecorations()
|
||||
@@ -157,11 +145,9 @@ class DisplayBuffer extends Model
|
||||
@emitter.on 'did-update-markers', callback
|
||||
|
||||
emitDidChange: (eventProperties, refreshMarkers=true) ->
|
||||
@emit 'changed', eventProperties if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change', eventProperties
|
||||
if refreshMarkers
|
||||
@refreshMarkerScreenPositions()
|
||||
@emit 'markers-updated' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-update-markers'
|
||||
|
||||
updateWrappedScreenLines: ->
|
||||
@@ -183,105 +169,24 @@ class DisplayBuffer extends Model
|
||||
|
||||
setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin
|
||||
|
||||
getVerticalScrollMarginInPixels: -> @getVerticalScrollMargin() * @getLineHeightInPixels()
|
||||
|
||||
getHorizontalScrollMargin: -> Math.min(@horizontalScrollMargin, Math.floor(((@getWidth() / @getDefaultCharWidth()) - 1) / 2))
|
||||
setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin
|
||||
|
||||
getHorizontalScrollMarginInPixels: -> scrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
|
||||
|
||||
getHorizontalScrollbarHeight: -> @horizontalScrollbarHeight
|
||||
setHorizontalScrollbarHeight: (@horizontalScrollbarHeight) -> @horizontalScrollbarHeight
|
||||
|
||||
getVerticalScrollbarWidth: -> @verticalScrollbarWidth
|
||||
setVerticalScrollbarWidth: (@verticalScrollbarWidth) -> @verticalScrollbarWidth
|
||||
|
||||
getHeight: ->
|
||||
if @height?
|
||||
@height
|
||||
else
|
||||
if @horizontallyScrollable()
|
||||
@getScrollHeight() + @getHorizontalScrollbarHeight()
|
||||
else
|
||||
@getScrollHeight()
|
||||
@height
|
||||
|
||||
setHeight: (@height) -> @height
|
||||
|
||||
getClientHeight: (reentrant) ->
|
||||
if @horizontallyScrollable(reentrant)
|
||||
@getHeight() - @getHorizontalScrollbarHeight()
|
||||
else
|
||||
@getHeight()
|
||||
|
||||
getClientWidth: (reentrant) ->
|
||||
if @verticallyScrollable(reentrant)
|
||||
@getWidth() - @getVerticalScrollbarWidth()
|
||||
else
|
||||
@getWidth()
|
||||
|
||||
horizontallyScrollable: (reentrant) ->
|
||||
return false unless @width?
|
||||
return false if @isSoftWrapped()
|
||||
if reentrant
|
||||
@getScrollWidth() > @getWidth()
|
||||
else
|
||||
@getScrollWidth() > @getClientWidth(true)
|
||||
|
||||
verticallyScrollable: (reentrant) ->
|
||||
return false unless @height?
|
||||
if reentrant
|
||||
@getScrollHeight() > @getHeight()
|
||||
else
|
||||
@getScrollHeight() > @getClientHeight(true)
|
||||
setHeight: (@height) ->
|
||||
@height
|
||||
|
||||
getWidth: ->
|
||||
if @width?
|
||||
@width
|
||||
else
|
||||
if @verticallyScrollable()
|
||||
@getScrollWidth() + @getVerticalScrollbarWidth()
|
||||
else
|
||||
@getScrollWidth()
|
||||
@width
|
||||
|
||||
setWidth: (newWidth) ->
|
||||
oldWidth = @width
|
||||
@width = newWidth
|
||||
@updateWrappedScreenLines() if newWidth isnt oldWidth and @isSoftWrapped()
|
||||
@setScrollTop(@getScrollTop()) # Ensure scrollTop is still valid in case horizontal scrollbar disappeared
|
||||
@width
|
||||
|
||||
getScrollTop: -> @scrollTop
|
||||
setScrollTop: (scrollTop) ->
|
||||
scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop)))
|
||||
unless scrollTop is @scrollTop
|
||||
@scrollTop = scrollTop
|
||||
@emitter.emit 'did-change-scroll-top', @scrollTop
|
||||
@scrollTop
|
||||
|
||||
getMaxScrollTop: ->
|
||||
@getScrollHeight() - @getClientHeight()
|
||||
|
||||
getScrollBottom: -> @scrollTop + @getClientHeight()
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@setScrollTop(scrollBottom - @getClientHeight())
|
||||
@getScrollBottom()
|
||||
|
||||
getScrollLeft: -> @scrollLeft
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft)))
|
||||
unless scrollLeft is @scrollLeft
|
||||
@scrollLeft = scrollLeft
|
||||
@emitter.emit 'did-change-scroll-left', @scrollLeft
|
||||
@scrollLeft
|
||||
|
||||
getMaxScrollLeft: ->
|
||||
@getScrollWidth() - @getClientWidth()
|
||||
|
||||
getScrollRight: -> @scrollLeft + @width
|
||||
setScrollRight: (scrollRight) ->
|
||||
@setScrollLeft(scrollRight - @width)
|
||||
@getScrollRight()
|
||||
|
||||
getLineHeightInPixels: -> @lineHeightInPixels
|
||||
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
|
||||
|
||||
@@ -289,7 +194,6 @@ class DisplayBuffer extends Model
|
||||
setDefaultCharWidth: (defaultCharWidth) ->
|
||||
if defaultCharWidth isnt @defaultCharWidth
|
||||
@defaultCharWidth = defaultCharWidth
|
||||
@computeScrollWidth()
|
||||
defaultCharWidth
|
||||
|
||||
getCursorWidth: -> 1
|
||||
@@ -318,85 +222,14 @@ class DisplayBuffer extends Model
|
||||
@characterWidthsChanged() unless @batchingCharacterMeasurement
|
||||
|
||||
characterWidthsChanged: ->
|
||||
@computeScrollWidth()
|
||||
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-character-widths', @scopedCharacterWidthsChangeCount
|
||||
|
||||
clearScopedCharWidths: ->
|
||||
@charWidthsByScope = {}
|
||||
|
||||
getScrollHeight: ->
|
||||
lineHeight = @getLineHeightInPixels()
|
||||
return 0 unless lineHeight > 0
|
||||
|
||||
scrollHeight = @getLineCount() * lineHeight
|
||||
if @height? and @configSettings.scrollPastEnd
|
||||
scrollHeight = scrollHeight + @height - (lineHeight * 3)
|
||||
|
||||
scrollHeight
|
||||
|
||||
getScrollWidth: ->
|
||||
@scrollWidth
|
||||
|
||||
# Returns an {Array} of two numbers representing the first and the last visible rows.
|
||||
getVisibleRowRange: ->
|
||||
return [0, 0] unless @getLineHeightInPixels() > 0
|
||||
|
||||
startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels())
|
||||
endRow = Math.ceil((@getScrollTop() + @getHeight()) / @getLineHeightInPixels()) - 1
|
||||
endRow = Math.min(@getLineCount(), endRow)
|
||||
|
||||
[startRow, endRow]
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
[visibleStart, visibleEnd] = @getVisibleRowRange()
|
||||
not (endRow <= visibleStart or visibleEnd <= startRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
{start, end} = selection.getScreenRange()
|
||||
@intersectsVisibleRowRange(start.row, end.row + 1)
|
||||
|
||||
scrollToScreenRange: (screenRange, options) ->
|
||||
verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels()
|
||||
horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels()
|
||||
|
||||
{top, left} = @pixelRectForScreenRange(new Range(screenRange.start, screenRange.start))
|
||||
{top: endTop, left: endLeft, height: endHeight} = @pixelRectForScreenRange(new Range(screenRange.end, screenRange.end))
|
||||
bottom = endTop + endHeight
|
||||
right = endLeft
|
||||
|
||||
if options?.center
|
||||
desiredScrollCenter = (top + bottom) / 2
|
||||
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
|
||||
desiredScrollTop = desiredScrollCenter - @getHeight() / 2
|
||||
desiredScrollBottom = desiredScrollCenter + @getHeight() / 2
|
||||
else
|
||||
desiredScrollTop = top - verticalScrollMarginInPixels
|
||||
desiredScrollBottom = bottom + verticalScrollMarginInPixels
|
||||
|
||||
desiredScrollLeft = left - horizontalScrollMarginInPixels
|
||||
desiredScrollRight = right + horizontalScrollMarginInPixels
|
||||
|
||||
if options?.reversed ? true
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
else
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
scrollToScreenRange: (screenRange, options = {}) ->
|
||||
scrollEvent = {screenRange, options}
|
||||
@emitter.emit "did-request-autoscroll", scrollEvent
|
||||
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
@scrollToScreenRange(new Range(screenPosition, screenPosition), options)
|
||||
@@ -404,19 +237,6 @@ class DisplayBuffer extends Model
|
||||
scrollToBufferPosition: (bufferPosition, options) ->
|
||||
@scrollToScreenPosition(@screenPositionForBufferPosition(bufferPosition), options)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
if screenRange.end.row > screenRange.start.row
|
||||
top = @pixelPositionForScreenPosition(screenRange.start).top
|
||||
left = 0
|
||||
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeightInPixels()
|
||||
width = @getScrollWidth()
|
||||
else
|
||||
{top, left} = @pixelPositionForScreenPosition(screenRange.start, false)
|
||||
height = @getLineHeightInPixels()
|
||||
width = @pixelPositionForScreenPosition(screenRange.end, false).left - left
|
||||
|
||||
{top, left, width, height}
|
||||
|
||||
# Retrieves the current tab length.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
@@ -437,7 +257,6 @@ class DisplayBuffer extends Model
|
||||
@softWrapped = softWrapped
|
||||
@updateWrappedScreenLines()
|
||||
softWrapped = @isSoftWrapped()
|
||||
@emit 'soft-wrap-changed', softWrapped if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-soft-wrapped', softWrapped
|
||||
softWrapped
|
||||
else
|
||||
@@ -461,8 +280,7 @@ class DisplayBuffer extends Model
|
||||
|
||||
# Returns the editor width in characters for soft wrap.
|
||||
getEditorWidthInChars: ->
|
||||
width = @width ? @getScrollWidth()
|
||||
width -= @getVerticalScrollbarWidth()
|
||||
width = @getWidth()
|
||||
if width? and @defaultCharWidth > 0
|
||||
Math.max(0, Math.floor(width / @defaultCharWidth))
|
||||
else
|
||||
@@ -674,80 +492,6 @@ class DisplayBuffer extends Model
|
||||
end = @bufferPositionForScreenPosition(screenRange.end)
|
||||
new Range(start, end)
|
||||
|
||||
pixelRangeForScreenRange: (screenRange, clip=true) ->
|
||||
{start, end} = Range.fromObject(screenRange)
|
||||
{start: @pixelPositionForScreenPosition(start, clip), end: @pixelPositionForScreenPosition(end, clip)}
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
|
||||
screenPosition = Point.fromObject(screenPosition)
|
||||
screenPosition = @clipScreenPosition(screenPosition) if clip
|
||||
|
||||
targetRow = screenPosition.row
|
||||
targetColumn = screenPosition.column
|
||||
defaultCharWidth = @defaultCharWidth
|
||||
|
||||
top = targetRow * @lineHeightInPixels
|
||||
left = 0
|
||||
column = 0
|
||||
|
||||
iterator = @tokenizedLineForScreenRow(targetRow).getTokenIterator()
|
||||
while iterator.next()
|
||||
charWidths = @getScopedCharWidths(iterator.getScopes())
|
||||
valueIndex = 0
|
||||
value = iterator.getText()
|
||||
while valueIndex < value.length
|
||||
if iterator.isPairedCharacter()
|
||||
char = value
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
return {top, left} if column is targetColumn
|
||||
left += charWidths[char] ? defaultCharWidth unless char is '\0'
|
||||
column += charLength
|
||||
{top, left}
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
targetTop = pixelPosition.top
|
||||
targetLeft = pixelPosition.left
|
||||
defaultCharWidth = @defaultCharWidth
|
||||
row = Math.floor(targetTop / @getLineHeightInPixels())
|
||||
targetLeft = 0 if row < 0
|
||||
targetLeft = Infinity if row > @getLastRow()
|
||||
row = Math.min(row, @getLastRow())
|
||||
row = Math.max(0, row)
|
||||
|
||||
left = 0
|
||||
column = 0
|
||||
|
||||
iterator = @tokenizedLineForScreenRow(row).getTokenIterator()
|
||||
while iterator.next()
|
||||
charWidths = @getScopedCharWidths(iterator.getScopes())
|
||||
value = iterator.getText()
|
||||
valueIndex = 0
|
||||
while valueIndex < value.length
|
||||
if iterator.isPairedCharacter()
|
||||
char = value
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
charWidth = charWidths[char] ? defaultCharWidth
|
||||
break if targetLeft <= left + (charWidth / 2)
|
||||
left += charWidth
|
||||
column += charLength
|
||||
|
||||
new Point(row, column)
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@pixelPositionForScreenPosition(@screenPositionForBufferPosition(bufferPosition))
|
||||
|
||||
# Gets the number of screen lines.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
@@ -999,7 +743,6 @@ class DisplayBuffer extends Model
|
||||
@decorationsByMarkerId[marker.id].push(decoration)
|
||||
@overlayDecorationsById[decoration.id] = decoration if decoration.isType('overlay')
|
||||
@decorationsById[decoration.id] = decoration
|
||||
@emit 'decoration-added', decoration if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-decoration', decoration
|
||||
decoration
|
||||
|
||||
@@ -1011,7 +754,6 @@ class DisplayBuffer extends Model
|
||||
if index > -1
|
||||
decorations.splice(index, 1)
|
||||
delete @decorationsById[decoration.id]
|
||||
@emit 'decoration-removed', decoration if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-remove-decoration', decoration
|
||||
delete @decorationsByMarkerId[marker.id] if decorations.length is 0
|
||||
delete @overlayDecorationsById[decoration.id]
|
||||
@@ -1189,7 +931,6 @@ class DisplayBuffer extends Model
|
||||
@changeCount = @tokenizedBuffer.changeCount
|
||||
{start, end, delta, bufferChange} = tokenizedBufferChange
|
||||
@updateScreenLines(start, end + 1, delta, refreshMarkers: false)
|
||||
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0
|
||||
|
||||
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
|
||||
return if @largeFileMode
|
||||
@@ -1294,13 +1035,6 @@ class DisplayBuffer extends Model
|
||||
@longestScreenRow = screenRow
|
||||
@maxLineLength = length
|
||||
|
||||
@computeScrollWidth() if oldMaxLineLength isnt @maxLineLength
|
||||
|
||||
computeScrollWidth: ->
|
||||
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left
|
||||
@scrollWidth += 1 unless @isSoftWrapped()
|
||||
@setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft()))
|
||||
|
||||
handleBufferMarkerCreated: (textBufferMarker) =>
|
||||
if textBufferMarker.matchesParams(@getFoldMarkerAttributes())
|
||||
fold = new Fold(this, textBufferMarker)
|
||||
@@ -1310,7 +1044,6 @@ class DisplayBuffer extends Model
|
||||
if marker = @getMarker(textBufferMarker.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', marker if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-create-marker', marker
|
||||
|
||||
decorateFold: (fold) ->
|
||||
@@ -1338,58 +1071,3 @@ class DisplayBuffer extends Model
|
||||
|
||||
atom.assert screenLinesCount is bufferLinesCount, "Display buffer line count out of sync with buffer", (error) ->
|
||||
error.metadata = {screenLinesCount, tokenizedLinesCount, bufferLinesCount}
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
DisplayBuffer.properties
|
||||
softWrapped: null
|
||||
editorWidthInChars: null
|
||||
lineHeightInPixels: null
|
||||
defaultCharWidth: null
|
||||
height: null
|
||||
width: null
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
scrollWidth: 0
|
||||
verticalScrollbarWidth: 15
|
||||
horizontalScrollbarHeight: 15
|
||||
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
|
||||
DisplayBuffer::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'changed'
|
||||
Grim.deprecate("Use DisplayBuffer::onDidChange instead")
|
||||
when 'grammar-changed'
|
||||
Grim.deprecate("Use DisplayBuffer::onDidChangeGrammar instead")
|
||||
when 'soft-wrap-changed'
|
||||
Grim.deprecate("Use DisplayBuffer::onDidChangeSoftWrap instead")
|
||||
when 'character-widths-changed'
|
||||
Grim.deprecate("Use DisplayBuffer::onDidChangeCharacterWidths instead")
|
||||
when 'decoration-added'
|
||||
Grim.deprecate("Use DisplayBuffer::onDidAddDecoration instead")
|
||||
when 'decoration-removed'
|
||||
Grim.deprecate("Use DisplayBuffer::onDidRemoveDecoration instead")
|
||||
when 'decoration-changed'
|
||||
Grim.deprecate("Use decoration.getMarker().onDidChange() instead")
|
||||
when 'decoration-updated'
|
||||
Grim.deprecate("Use Decoration::onDidChangeProperties instead")
|
||||
when 'marker-created'
|
||||
Grim.deprecate("Use Decoration::onDidCreateMarker instead")
|
||||
when 'markers-updated'
|
||||
Grim.deprecate("Use Decoration::onDidUpdateMarkers instead")
|
||||
else
|
||||
Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.")
|
||||
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
else
|
||||
DisplayBuffer::softWrapped = null
|
||||
DisplayBuffer::editorWidthInChars = null
|
||||
DisplayBuffer::lineHeightInPixels = null
|
||||
DisplayBuffer::defaultCharWidth = null
|
||||
DisplayBuffer::height = null
|
||||
DisplayBuffer::width = null
|
||||
DisplayBuffer::scrollTop = 0
|
||||
DisplayBuffer::scrollLeft = 0
|
||||
DisplayBuffer::scrollWidth = 0
|
||||
DisplayBuffer::verticalScrollbarWidth = 15
|
||||
DisplayBuffer::horizontalScrollbarHeight = 15
|
||||
|
||||
@@ -4,7 +4,6 @@ _ = require 'underscore-plus'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
fs = require 'fs-plus'
|
||||
GitUtils = require 'git-utils'
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
|
||||
Task = require './task'
|
||||
|
||||
@@ -327,7 +326,6 @@ class GitRepository
|
||||
else
|
||||
delete @statuses[relativePath]
|
||||
if currentPathStatus isnt pathStatus
|
||||
@emit 'status-changed', path, pathStatus if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-status', {path, pathStatus}
|
||||
|
||||
pathStatus
|
||||
@@ -496,23 +494,4 @@ class GitRepository
|
||||
submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0}
|
||||
|
||||
unless statusesUnchanged
|
||||
@emit 'statuses-changed' if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-statuses'
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(GitRepository)
|
||||
|
||||
GitRepository::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'status-changed'
|
||||
deprecate 'Use GitRepository::onDidChangeStatus instead'
|
||||
when 'statuses-changed'
|
||||
deprecate 'Use GitRepository::onDidChangeStatuses instead'
|
||||
else
|
||||
deprecate 'GitRepository::on is deprecated. Use event subscription methods instead.'
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
GitRepository::getOriginUrl = (path) ->
|
||||
deprecate 'Use ::getOriginURL instead.'
|
||||
@getOriginURL(path)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
FirstMate = require 'first-mate'
|
||||
Token = require './token'
|
||||
fs = require 'fs-plus'
|
||||
@@ -136,37 +135,4 @@ class GrammarRegistry extends FirstMate.GrammarRegistry
|
||||
undefined
|
||||
|
||||
clearObservers: ->
|
||||
@off() if includeDeprecatedAPIs
|
||||
@emitter = new Emitter
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
PropertyAccessors = require 'property-accessors'
|
||||
PropertyAccessors.includeInto(GrammarRegistry)
|
||||
|
||||
{Subscriber} = require 'emissary'
|
||||
Subscriber.includeInto(GrammarRegistry)
|
||||
|
||||
# Support old serialization
|
||||
atom.deserializers.add(name: 'Syntax', deserialize: GrammarRegistry.deserialize)
|
||||
|
||||
# Deprecated: Used by settings-view to display snippets for packages
|
||||
GrammarRegistry::accessor 'propertyStore', ->
|
||||
deprecate("Do not use this. Use a public method on Config")
|
||||
atom.config.scopedSettingsStore
|
||||
|
||||
GrammarRegistry::addProperties = (args...) ->
|
||||
args.unshift(null) if args.length is 2
|
||||
deprecate 'Consider using atom.config.set() instead. A direct (but private) replacement is available at atom.config.addScopedSettings().'
|
||||
atom.config.addScopedSettings(args...)
|
||||
|
||||
GrammarRegistry::removeProperties = (name) ->
|
||||
deprecate 'atom.config.addScopedSettings() now returns a disposable you can call .dispose() on'
|
||||
atom.config.scopedSettingsStore.removeProperties(name)
|
||||
|
||||
GrammarRegistry::getProperty = (scope, keyPath) ->
|
||||
deprecate 'A direct (but private) replacement is available at atom.config.getRawScopedValue().'
|
||||
atom.config.getRawScopedValue(scope, keyPath)
|
||||
|
||||
GrammarRegistry::propertiesForScope = (scope, keyPath) ->
|
||||
deprecate 'Use atom.config.getAll instead.'
|
||||
atom.config.settingsForScopeDescriptor(scope, keyPath)
|
||||
|
||||
@@ -2,7 +2,6 @@ fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
KeymapManager = require 'atom-keymap'
|
||||
CSON = require 'season'
|
||||
Grim = require 'grim'
|
||||
|
||||
bundledKeymaps = require('../package.json')?._atomKeymaps
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
# Essential: Represents a buffer annotation that remains logically stationary
|
||||
# even as the buffer changes. This is used to represent cursors, folds, snippet
|
||||
@@ -335,7 +334,6 @@ class Marker
|
||||
|
||||
destroyed: ->
|
||||
delete @displayBuffer.markers[@id]
|
||||
@emit 'destroyed' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-destroy'
|
||||
@emitter.dispose()
|
||||
|
||||
@@ -369,35 +367,4 @@ class Marker
|
||||
@oldTailScreenPosition = newTailScreenPosition
|
||||
@wasValid = isValid
|
||||
|
||||
@emit 'changed', changeEvent if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change', changeEvent
|
||||
|
||||
getPixelRange: ->
|
||||
@displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false)
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(Marker)
|
||||
|
||||
Marker::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'changed'
|
||||
Grim.deprecate("Use Marker::onDidChange instead")
|
||||
when 'destroyed'
|
||||
Grim.deprecate("Use Marker::onDidDestroy instead")
|
||||
else
|
||||
Grim.deprecate("Marker::on is deprecated. Use documented event subscription methods instead.")
|
||||
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
Marker::getAttributes = ->
|
||||
Grim.deprecate 'Use Marker::getProperties instead'
|
||||
@getProperties()
|
||||
|
||||
Marker::setAttributes = (properties) ->
|
||||
Grim.deprecate 'Use Marker::setProperties instead'
|
||||
@setProperties(properties)
|
||||
|
||||
Marker::matchesAttributes = (attributes) ->
|
||||
Grim.deprecate 'Use Marker::matchesProperties instead'
|
||||
@matchesProperties(attributes)
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
Grim = require 'grim'
|
||||
if Grim.includeDeprecatedAPIs
|
||||
module.exports = require('theorist').Model
|
||||
return
|
||||
|
||||
PropertyAccessors = require 'property-accessors'
|
||||
|
||||
nextInstanceId = 1
|
||||
|
||||
module.exports =
|
||||
class Model
|
||||
PropertyAccessors.includeInto(this)
|
||||
|
||||
@resetNextInstanceId: -> nextInstanceId = 1
|
||||
|
||||
alive: true
|
||||
@@ -20,9 +11,7 @@ class Model
|
||||
|
||||
assignId: (id) ->
|
||||
@id ?= id ? nextInstanceId++
|
||||
|
||||
@::advisedAccessor 'id',
|
||||
set: (id) -> nextInstanceId = id + 1 if id >= nextInstanceId
|
||||
nextInstanceId = id + 1 if id >= nextInstanceId
|
||||
|
||||
destroy: ->
|
||||
return unless @isAlive()
|
||||
|
||||
@@ -3,7 +3,6 @@ path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
|
||||
ServiceHub = require 'service-hub'
|
||||
Package = require './package'
|
||||
@@ -327,18 +326,10 @@ class PackageManager
|
||||
# of the first package isn't skewed by being the first to require atom
|
||||
require '../exports/atom'
|
||||
|
||||
# TODO: remove after a few atom versions.
|
||||
@uninstallAutocompletePlus()
|
||||
|
||||
packagePaths = @getAvailablePackagePaths()
|
||||
|
||||
# TODO: remove after a few atom versions.
|
||||
@migrateSublimeTabsSettings(packagePaths)
|
||||
|
||||
packagePaths = packagePaths.filter (packagePath) => not @isPackageDisabled(path.basename(packagePath))
|
||||
packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath)
|
||||
@loadPackage(packagePath) for packagePath in packagePaths
|
||||
@emit 'loaded' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-load-initial-packages'
|
||||
|
||||
loadPackage: (nameOrPath) ->
|
||||
@@ -354,7 +345,7 @@ class PackageManager
|
||||
@handleMetadataError(error, packagePath)
|
||||
return null
|
||||
|
||||
unless @isBundledPackage(metadata.name) or Grim.includeDeprecatedAPIs
|
||||
unless @isBundledPackage(metadata.name)
|
||||
if @isDeprecatedPackage(metadata.name, metadata.version)
|
||||
console.warn "Could not load #{metadata.name}@#{metadata.version} because it uses deprecated APIs that have been removed."
|
||||
return null
|
||||
@@ -392,7 +383,6 @@ class PackageManager
|
||||
packages = @getLoadedPackagesForTypes(types)
|
||||
promises = promises.concat(activator.activatePackages(packages))
|
||||
Promise.all(promises).then =>
|
||||
@emit 'activated' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-activate-initial-packages'
|
||||
|
||||
# another type of package manager can handle other package types.
|
||||
@@ -455,35 +445,6 @@ class PackageManager
|
||||
message = "Failed to load the #{path.basename(packagePath)} package"
|
||||
atom.notifications.addError(message, {stack, detail, dismissable: true})
|
||||
|
||||
# TODO: remove these autocomplete-plus specific helpers after a few versions.
|
||||
uninstallAutocompletePlus: ->
|
||||
packageDir = null
|
||||
devDir = path.join("dev", "packages")
|
||||
for packageDirPath in @packageDirPaths
|
||||
if not packageDirPath.endsWith(devDir)
|
||||
packageDir = packageDirPath
|
||||
break
|
||||
|
||||
if packageDir?
|
||||
dirsToRemove = [
|
||||
path.join(packageDir, 'autocomplete-plus')
|
||||
path.join(packageDir, 'autocomplete-atom-api')
|
||||
path.join(packageDir, 'autocomplete-css')
|
||||
path.join(packageDir, 'autocomplete-html')
|
||||
path.join(packageDir, 'autocomplete-snippets')
|
||||
]
|
||||
for dirToRemove in dirsToRemove
|
||||
@uninstallDirectory(dirToRemove)
|
||||
return
|
||||
|
||||
# TODO: remove this after a few versions
|
||||
migrateSublimeTabsSettings: (packagePaths) ->
|
||||
return if Grim.includeDeprecatedAPIs
|
||||
for packagePath in packagePaths when path.basename(packagePath) is 'sublime-tabs'
|
||||
atom.config.removeAtKeyPath('core.disabledPackages', 'tree-view')
|
||||
atom.config.removeAtKeyPath('core.disabledPackages', 'tabs')
|
||||
return
|
||||
|
||||
uninstallDirectory: (directory) ->
|
||||
symlinkPromise = new Promise (resolve) ->
|
||||
fs.isSymbolicLink directory, (isSymLink) -> resolve(isSymLink)
|
||||
@@ -495,25 +456,3 @@ class PackageManager
|
||||
[isSymLink, isDir] = values
|
||||
if not isSymLink and isDir
|
||||
fs.remove directory, ->
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(PackageManager)
|
||||
|
||||
PackageManager::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'loaded'
|
||||
Grim.deprecate 'Use PackageManager::onDidLoadInitialPackages instead'
|
||||
when 'activated'
|
||||
Grim.deprecate 'Use PackageManager::onDidActivateInitialPackages instead'
|
||||
else
|
||||
Grim.deprecate 'PackageManager::on is deprecated. Use event subscription methods instead.'
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
PackageManager::onDidLoadAll = (callback) ->
|
||||
Grim.deprecate("Use `::onDidLoadInitialPackages` instead.")
|
||||
@onDidLoadInitialPackages(callback)
|
||||
|
||||
PackageManager::onDidActivateAll = (callback) ->
|
||||
Grim.deprecate("Use `::onDidActivateInitialPackages` instead.")
|
||||
@onDidActivateInitialPackages(callback)
|
||||
|
||||
@@ -6,7 +6,6 @@ async = require 'async'
|
||||
CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
|
||||
ModuleCache = require './module-cache'
|
||||
ScopedProperties = require './scoped-properties'
|
||||
@@ -14,7 +13,7 @@ BufferedProcess = require './buffered-process'
|
||||
|
||||
packagesCache = require('../package.json')?._atomPackages ? {}
|
||||
|
||||
# Loads and activates a package's main module and resources such as
|
||||
# Extended: Loads and activates a package's main module and resources such as
|
||||
# stylesheets, keymaps, grammar, editor properties, and menus.
|
||||
module.exports =
|
||||
class Package
|
||||
@@ -48,14 +47,6 @@ class Package
|
||||
unless typeof metadata.name is 'string' and metadata.name.length > 0
|
||||
metadata.name = packageName
|
||||
|
||||
if includeDeprecatedAPIs and metadata.stylesheetMain?
|
||||
deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName})
|
||||
metadata.mainStyleSheet = metadata.stylesheetMain
|
||||
|
||||
if includeDeprecatedAPIs and metadata.stylesheets?
|
||||
deprecate("Use the `styleSheets` key instead of `stylesheets` in the `package.json` of `#{packageName}`", {packageName})
|
||||
metadata.styleSheets = metadata.stylesheets
|
||||
|
||||
metadata
|
||||
|
||||
keymaps: null
|
||||
@@ -174,11 +165,6 @@ class Package
|
||||
if @mainModule?
|
||||
if @mainModule.config? and typeof @mainModule.config is 'object'
|
||||
atom.config.setSchema @name, {type: 'object', properties: @mainModule.config}
|
||||
else if @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object'
|
||||
deprecate("""Use a config schema instead. See the configuration section
|
||||
of https://atom.io/docs/latest/hacking-atom-package-word-count and
|
||||
https://atom.io/docs/api/latest/Config for more details""", {packageName: @name})
|
||||
atom.config.setDefaults(@name, @mainModule.configDefaults)
|
||||
@mainModule.activateConfig?()
|
||||
@configActivated = true
|
||||
|
||||
@@ -211,17 +197,6 @@ class Package
|
||||
for [menuPath, map] in @menus when map['context-menu']?
|
||||
try
|
||||
itemsBySelector = map['context-menu']
|
||||
|
||||
# Detect deprecated format for items object
|
||||
for key, value of itemsBySelector
|
||||
unless _.isArray(value)
|
||||
deprecate("""
|
||||
The context menu CSON format has changed. Please see
|
||||
https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format
|
||||
for more info.
|
||||
""", {packageName: @name})
|
||||
itemsBySelector = atom.contextMenu.convertLegacyItemsBySelector(itemsBySelector)
|
||||
|
||||
@activationDisposables.add(atom.contextMenu.add(itemsBySelector))
|
||||
catch error
|
||||
if error.code is 'EBADSELECTOR'
|
||||
@@ -309,11 +284,7 @@ class Package
|
||||
[stylesheetPath, atom.themes.loadStylesheet(stylesheetPath, true)]
|
||||
|
||||
getStylesheetsPath: ->
|
||||
if fs.isDirectorySync(path.join(@path, 'stylesheets'))
|
||||
deprecate("Store package style sheets in the `styles/` directory instead of `stylesheets/` in the `#{@name}` package", packageName: @name)
|
||||
path.join(@path, 'stylesheets')
|
||||
else
|
||||
path.join(@path, 'styles')
|
||||
path.join(@path, 'styles')
|
||||
|
||||
getStylesheetPaths: ->
|
||||
stylesheetDirPath = @getStylesheetsPath()
|
||||
@@ -383,11 +354,7 @@ class Package
|
||||
callback()
|
||||
|
||||
new Promise (resolve) =>
|
||||
if fs.isDirectorySync(path.join(@path, 'scoped-properties'))
|
||||
settingsDirPath = path.join(@path, 'scoped-properties')
|
||||
deprecate("Store package settings files in the `settings/` directory instead of `scoped-properties/`", packageName: @name)
|
||||
else
|
||||
settingsDirPath = path.join(@path, 'settings')
|
||||
settingsDirPath = path.join(@path, 'settings')
|
||||
|
||||
fs.exists settingsDirPath, (settingsDirExists) ->
|
||||
return resolve() unless settingsDirExists
|
||||
@@ -417,7 +384,6 @@ class Package
|
||||
@mainActivated = false
|
||||
catch e
|
||||
console.error "Error deactivating package '#{@name}'", e.stack
|
||||
@emit 'deactivated' if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-deactivate'
|
||||
|
||||
deactivateConfig: ->
|
||||
@@ -533,31 +499,6 @@ class Package
|
||||
else if _.isArray(commands)
|
||||
@activationCommands[selector].push(commands...)
|
||||
|
||||
if @metadata.activationEvents?
|
||||
deprecate("""
|
||||
Use `activationCommands` instead of `activationEvents` in your package.json
|
||||
Commands should be grouped by selector as follows:
|
||||
```json
|
||||
"activationCommands": {
|
||||
"atom-workspace": ["foo:bar", "foo:baz"],
|
||||
"atom-text-editor": ["foo:quux"]
|
||||
}
|
||||
```
|
||||
""", {packageName: @name})
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
for eventName in @metadata.activationEvents
|
||||
@activationCommands['atom-workspace'] ?= []
|
||||
@activationCommands['atom-workspace'].push(eventName)
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
eventName = @metadata.activationEvents
|
||||
@activationCommands['atom-workspace'] ?= []
|
||||
@activationCommands['atom-workspace'].push(eventName)
|
||||
else
|
||||
for eventName, selector of @metadata.activationEvents
|
||||
selector ?= 'atom-workspace'
|
||||
@activationCommands[selector] ?= []
|
||||
@activationCommands[selector].push(eventName)
|
||||
|
||||
@activationCommands
|
||||
|
||||
subscribeToActivationHooks: ->
|
||||
@@ -726,15 +667,3 @@ class Package
|
||||
stack = error.stack ? error
|
||||
|
||||
atom.notifications.addFatalError(message, {stack, detail, dismissable: true})
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(Package)
|
||||
|
||||
Package::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'deactivated'
|
||||
deprecate 'Use Package::onDidDeactivate instead'
|
||||
else
|
||||
deprecate 'Package::on is deprecated. Use event subscription methods instead.'
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
{flatten} = require 'underscore-plus'
|
||||
Serializable = require 'serializable'
|
||||
Model = require './model'
|
||||
|
||||
module.exports =
|
||||
class PaneAxis extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
parent: null
|
||||
container: null
|
||||
orientation: null
|
||||
|
||||
@deserialize: (state, params) ->
|
||||
container = params?.container
|
||||
state.container = container
|
||||
state.children = state.children.map (childState) -> atom.deserializers.deserialize(childState, {container})
|
||||
new this(state)
|
||||
|
||||
constructor: ({@container, @orientation, children, flexScale}={}) ->
|
||||
@emitter = new Emitter
|
||||
@subscriptionsByChild = new WeakMap
|
||||
@@ -21,12 +25,8 @@ class PaneAxis extends Model
|
||||
@addChild(child) for child in children
|
||||
@flexScale = flexScale ? 1
|
||||
|
||||
deserializeParams: (params) ->
|
||||
{container} = params
|
||||
params.children = params.children.map (childState) -> atom.deserializers.deserialize(childState, {container})
|
||||
params
|
||||
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
deserializer: 'PaneAxis'
|
||||
children: @children.map (child) -> child.serialize()
|
||||
orientation: @orientation
|
||||
flexScale: @flexScale
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{find, flatten} = require 'underscore-plus'
|
||||
Grim = require 'grim'
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Gutter = require './gutter'
|
||||
Model = require './model'
|
||||
Pane = require './pane'
|
||||
@@ -10,17 +8,23 @@ ItemRegistry = require './item-registry'
|
||||
module.exports =
|
||||
class PaneContainer extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
@version: 1
|
||||
|
||||
root: null
|
||||
|
||||
@deserialize: (state) ->
|
||||
container = Object.create(@prototype) # allows us to pass a self reference to our child before invoking constructor
|
||||
state.root = atom.deserializers.deserialize(state.root, {container})
|
||||
state.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
||||
state.activePane = find state.root.getPanes(), (pane) -> pane.id is state.activePaneId
|
||||
@call(container, state) # run constructor
|
||||
container
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
unless Grim.includeDeprecatedAPIs
|
||||
@activePane = params?.activePane
|
||||
@activePane = params?.activePane
|
||||
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
@@ -35,13 +39,9 @@ class PaneContainer extends Model
|
||||
@monitorActivePaneItem()
|
||||
@monitorPaneItems()
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.root = atom.deserializers.deserialize(params.root, container: this)
|
||||
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
||||
params.activePane = find params.root.getPanes(), (pane) -> pane.id is params.activePaneId
|
||||
params
|
||||
|
||||
serializeParams: (params) ->
|
||||
serialize: (params) ->
|
||||
deserializer: 'PaneContainer'
|
||||
version: @constructor.version
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
@@ -222,12 +222,3 @@ class PaneContainer extends Model
|
||||
|
||||
removedPaneItem: (item) ->
|
||||
@itemRegistry.removeItem(item)
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
PaneContainer.properties
|
||||
activePane: null
|
||||
|
||||
PaneContainer.behavior 'activePaneItem', ->
|
||||
@$activePane
|
||||
.switch((activePane) -> activePane?.$activeItem)
|
||||
.distinctUntilChanged()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
path = require 'path'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
class PaneElement extends HTMLElement
|
||||
attached: false
|
||||
|
||||
113
src/pane.coffee
113
src/pane.coffee
@@ -1,7 +1,5 @@
|
||||
{find, compact, extend, last} = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Grim = require 'grim'
|
||||
Model = require './model'
|
||||
PaneAxis = require './pane-axis'
|
||||
TextEditor = require './text-editor'
|
||||
@@ -13,14 +11,29 @@ TextEditor = require './text-editor'
|
||||
module.exports =
|
||||
class Pane extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
container: undefined
|
||||
activeItem: undefined
|
||||
focused: false
|
||||
|
||||
@deserialize: (state, params) ->
|
||||
{items, activeItemURI, activeItemUri} = state
|
||||
state.container = params?.container
|
||||
activeItemURI ?= activeItemUri
|
||||
state.items = compact(items.map (itemState) -> atom.deserializers.deserialize(itemState))
|
||||
state.activeItem = find state.items, (item) ->
|
||||
if typeof item.getURI is 'function'
|
||||
itemURI = item.getURI()
|
||||
itemURI is activeItemURI
|
||||
|
||||
new this(state)
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
unless Grim.includeDeprecatedAPIs
|
||||
@container = params?.container
|
||||
@activeItem = params?.activeItem
|
||||
@container = params?.container
|
||||
@activeItem = params?.activeItem
|
||||
@focused = params?.focused
|
||||
|
||||
@emitter = new Emitter
|
||||
@itemSubscriptions = new WeakMap
|
||||
@@ -30,33 +43,17 @@ class Pane extends Model
|
||||
@setActiveItem(@items[0]) unless @getActiveItem()?
|
||||
@setFlexScale(params?.flexScale ? 1)
|
||||
|
||||
# Called by the Serializable mixin during serialization.
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
if typeof @activeItem?.getURI is 'function'
|
||||
activeItemURI = @activeItem.getURI()
|
||||
else if Grim.includeDeprecatedAPIs and typeof @activeItem?.getUri is 'function'
|
||||
activeItemURI = @activeItem.getUri()
|
||||
|
||||
deserializer: 'Pane'
|
||||
id: @id
|
||||
items: compact(@items.map((item) -> item.serialize?()))
|
||||
activeItemURI: activeItemURI
|
||||
focused: @focused
|
||||
flexScale: @flexScale
|
||||
|
||||
# Called by the Serializable mixin during deserialization.
|
||||
deserializeParams: (params) ->
|
||||
{items, activeItemURI, activeItemUri} = params
|
||||
activeItemURI ?= activeItemUri
|
||||
params.items = compact(items.map (itemState) -> atom.deserializers.deserialize(itemState))
|
||||
params.activeItem = find params.items, (item) ->
|
||||
if typeof item.getURI is 'function'
|
||||
itemURI = item.getURI()
|
||||
else if Grim.includeDeprecatedAPIs and typeof item.getUri is 'function'
|
||||
itemURI = item.getUri()
|
||||
|
||||
itemURI is activeItemURI
|
||||
params
|
||||
|
||||
getParent: -> @parent
|
||||
|
||||
setParent: (@parent) -> @parent
|
||||
@@ -355,16 +352,14 @@ class Pane extends Model
|
||||
# Returns the added item.
|
||||
addItem: (item, index=@getActiveItemIndex() + 1) ->
|
||||
throw new Error("Pane items must be objects. Attempted to add item #{item}.") unless item? and typeof item is 'object'
|
||||
throw new Error("Adding a pane item with URI '#{item.getURI?()}' that has already been destroyed") if item.isDestroyed?()
|
||||
|
||||
return if item in @items
|
||||
|
||||
if typeof item.onDidDestroy is 'function'
|
||||
@itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, true)
|
||||
else if Grim.includeDeprecatedAPIs and typeof item.on is 'function'
|
||||
@subscribe item, 'destroyed', => @removeItem(item, true)
|
||||
|
||||
@items.splice(index, 0, item)
|
||||
@emit 'item-added', item, index if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-item', {item, index}
|
||||
@setActiveItem(item) unless @getActiveItem()?
|
||||
item
|
||||
@@ -388,9 +383,6 @@ class Pane extends Model
|
||||
return if index is -1
|
||||
|
||||
@emitter.emit 'will-remove-item', {item, index, destroyed}
|
||||
|
||||
if Grim.includeDeprecatedAPIs and typeof item.on is 'function'
|
||||
@unsubscribe item
|
||||
@unsubscribeFromItem(item)
|
||||
|
||||
if item is @activeItem
|
||||
@@ -401,7 +393,6 @@ class Pane extends Model
|
||||
else
|
||||
@activatePreviousItem()
|
||||
@items.splice(index, 1)
|
||||
@emit 'item-removed', item, index, destroyed if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-remove-item', {item, index, destroyed}
|
||||
@container?.didDestroyPaneItem({item, index, pane: this}) if destroyed
|
||||
@destroy() if @items.length is 0 and atom.config.get('core.destroyEmptyPanes')
|
||||
@@ -414,7 +405,6 @@ class Pane extends Model
|
||||
oldIndex = @items.indexOf(item)
|
||||
@items.splice(oldIndex, 1)
|
||||
@items.splice(newIndex, 0, item)
|
||||
@emit 'item-moved', item, newIndex if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-move-item', {item, oldIndex, newIndex}
|
||||
|
||||
# Public: Move the given item to the given index on another pane.
|
||||
@@ -442,7 +432,6 @@ class Pane extends Model
|
||||
destroyItem: (item) ->
|
||||
index = @items.indexOf(item)
|
||||
if index isnt -1
|
||||
@emit 'before-item-destroyed', item if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'will-destroy-item', {item, index}
|
||||
@container?.willDestroyPaneItem({item, index, pane: this})
|
||||
if @promptToSaveItem(item)
|
||||
@@ -582,7 +571,6 @@ class Pane extends Model
|
||||
throw new Error("Pane has been destroyed") if @isDestroyed()
|
||||
|
||||
@container?.setActivePane(this)
|
||||
@emit 'activated' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-activate'
|
||||
|
||||
# Public: Close the pane and destroy all its items.
|
||||
@@ -731,60 +719,3 @@ class Pane extends Model
|
||||
atom.notifications.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to")
|
||||
else
|
||||
throw error
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
Pane.properties
|
||||
container: undefined
|
||||
activeItem: undefined
|
||||
focused: false
|
||||
|
||||
Pane.behavior 'active', ->
|
||||
@$container
|
||||
.switch((container) -> container?.$activePane)
|
||||
.map((activePane) => activePane is this)
|
||||
.distinctUntilChanged()
|
||||
|
||||
Pane::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'activated'
|
||||
Grim.deprecate("Use Pane::onDidActivate instead")
|
||||
when 'destroyed'
|
||||
Grim.deprecate("Use Pane::onDidDestroy instead")
|
||||
when 'item-added'
|
||||
Grim.deprecate("Use Pane::onDidAddItem instead")
|
||||
when 'item-removed'
|
||||
Grim.deprecate("Use Pane::onDidRemoveItem instead")
|
||||
when 'item-moved'
|
||||
Grim.deprecate("Use Pane::onDidMoveItem instead")
|
||||
when 'before-item-destroyed'
|
||||
Grim.deprecate("Use Pane::onWillDestroyItem instead")
|
||||
else
|
||||
Grim.deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.")
|
||||
super
|
||||
|
||||
Pane::behavior = (behaviorName) ->
|
||||
switch behaviorName
|
||||
when 'active'
|
||||
Grim.deprecate("The $active behavior property is deprecated. Use ::observeActive or ::onDidChangeActive instead.")
|
||||
when 'container'
|
||||
Grim.deprecate("The $container behavior property is deprecated.")
|
||||
when 'activeItem'
|
||||
Grim.deprecate("The $activeItem behavior property is deprecated. Use ::observeActiveItem or ::onDidChangeActiveItem instead.")
|
||||
when 'focused'
|
||||
Grim.deprecate("The $focused behavior property is deprecated.")
|
||||
else
|
||||
Grim.deprecate("Pane::behavior is deprecated. Use event subscription methods instead.")
|
||||
|
||||
super
|
||||
|
||||
Pane::itemForUri = (uri) ->
|
||||
Grim.deprecate("Use `::itemForURI` instead.")
|
||||
@itemForURI(uri)
|
||||
|
||||
Pane::activateItemForUri = (uri) ->
|
||||
Grim.deprecate("Use `::activateItemForURI` instead.")
|
||||
@activateItemForURI(uri)
|
||||
else
|
||||
Pane::container = undefined
|
||||
Pane::activeItem = undefined
|
||||
Pane::focused = undefined
|
||||
|
||||
@@ -3,11 +3,8 @@ url = require 'url'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
{Emitter} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Grim = require 'grim'
|
||||
|
||||
DefaultDirectoryProvider = require './default-directory-provider'
|
||||
Model = require './model'
|
||||
@@ -21,12 +18,25 @@ GitRepositoryProvider = require './git-repository-provider'
|
||||
module.exports =
|
||||
class Project extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
###
|
||||
Section: Construction and Destruction
|
||||
###
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.buffers = _.compact state.buffers.map (bufferState) ->
|
||||
# Check that buffer's file path is accessible
|
||||
return if fs.isDirectorySync(bufferState.filePath)
|
||||
if bufferState.filePath
|
||||
try
|
||||
fs.closeSync(fs.openSync(bufferState.filePath, 'r'))
|
||||
catch error
|
||||
return unless error.code is 'ENOENT'
|
||||
|
||||
atom.deserializers.deserialize(bufferState)
|
||||
|
||||
new this(state)
|
||||
|
||||
constructor: ({path, paths, @buffers}={}) ->
|
||||
@emitter = new Emitter
|
||||
@buffers ?= []
|
||||
@@ -62,9 +72,6 @@ class Project extends Model
|
||||
|
||||
@subscribeToBuffer(buffer) for buffer in @buffers
|
||||
|
||||
if Grim.includeDeprecatedAPIs and path?
|
||||
Grim.deprecate("Pass 'paths' array instead of 'path' to project constructor")
|
||||
|
||||
paths ?= _.compact([path])
|
||||
@setPaths(paths)
|
||||
|
||||
@@ -80,23 +87,11 @@ class Project extends Model
|
||||
Section: Serialization
|
||||
###
|
||||
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
deserializer: 'Project'
|
||||
paths: @getPaths()
|
||||
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.buffers = _.compact params.buffers.map (bufferState) ->
|
||||
# Check that buffer's file path is accessible
|
||||
return if fs.isDirectorySync(bufferState.filePath)
|
||||
if bufferState.filePath
|
||||
try
|
||||
fs.closeSync(fs.openSync(bufferState.filePath, 'r'))
|
||||
catch error
|
||||
return unless error.code is 'ENOENT'
|
||||
|
||||
atom.deserializers.deserialize(bufferState)
|
||||
params
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
@@ -166,16 +161,12 @@ class Project extends Model
|
||||
#
|
||||
# * `projectPaths` {Array} of {String} paths.
|
||||
setPaths: (projectPaths) ->
|
||||
if includeDeprecatedAPIs
|
||||
rootDirectory.off() for rootDirectory in @rootDirectories
|
||||
|
||||
repository?.destroy() for repository in @repositories
|
||||
@rootDirectories = []
|
||||
@repositories = []
|
||||
|
||||
@addPath(projectPath, emitEvent: false) for projectPath in projectPaths
|
||||
|
||||
@emit "path-changed" if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-paths', projectPaths
|
||||
|
||||
# Public: Add a path to the project's list of root paths
|
||||
@@ -200,7 +191,6 @@ class Project extends Model
|
||||
@repositories.push(repo ? null)
|
||||
|
||||
unless options?.emitEvent is false
|
||||
@emit "path-changed" if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-paths', @getPaths()
|
||||
|
||||
# Public: remove a path from the project's list of root paths.
|
||||
@@ -220,9 +210,7 @@ class Project extends Model
|
||||
if indexToRemove?
|
||||
[removedDirectory] = @rootDirectories.splice(indexToRemove, 1)
|
||||
[removedRepository] = @repositories.splice(indexToRemove, 1)
|
||||
removedDirectory.off() if includeDeprecatedAPIs
|
||||
removedRepository?.destroy() unless removedRepository in @repositories
|
||||
@emit "path-changed" if includeDeprecatedAPIs
|
||||
@emitter.emit "did-change-paths", @getPaths()
|
||||
true
|
||||
else
|
||||
@@ -402,7 +390,6 @@ class Project extends Model
|
||||
addBufferAtIndex: (buffer, index, options={}) ->
|
||||
@buffers.splice(index, 0, buffer)
|
||||
@subscribeToBuffer(buffer)
|
||||
@emit 'buffer-created', buffer if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-buffer', buffer
|
||||
buffer
|
||||
|
||||
@@ -442,66 +429,3 @@ class Project extends Model
|
||||
""",
|
||||
detail: error.message
|
||||
dismissable: true
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
Project.pathForRepositoryUrl = (repoUrl) ->
|
||||
deprecate '::pathForRepositoryUrl will be removed. Please remove from your code.'
|
||||
[repoName] = url.parse(repoUrl).path.split('/')[-1..]
|
||||
repoName = repoName.replace(/\.git$/, '')
|
||||
path.join(atom.config.get('core.projectHome'), repoName)
|
||||
|
||||
Project::registerOpener = (opener) ->
|
||||
deprecate("Use Workspace::addOpener instead")
|
||||
atom.workspace.addOpener(opener)
|
||||
|
||||
Project::unregisterOpener = (opener) ->
|
||||
deprecate("Call .dispose() on the Disposable returned from ::addOpener instead")
|
||||
atom.workspace.unregisterOpener(opener)
|
||||
|
||||
Project::eachEditor = (callback) ->
|
||||
deprecate("Use Workspace::observeTextEditors instead")
|
||||
atom.workspace.observeTextEditors(callback)
|
||||
|
||||
Project::getEditors = ->
|
||||
deprecate("Use Workspace::getTextEditors instead")
|
||||
atom.workspace.getTextEditors()
|
||||
|
||||
Project::on = (eventName) ->
|
||||
if eventName is 'path-changed'
|
||||
Grim.deprecate("Use Project::onDidChangePaths instead")
|
||||
else
|
||||
Grim.deprecate("Project::on is deprecated. Use documented event subscription methods instead.")
|
||||
super
|
||||
|
||||
Project::getRepo = ->
|
||||
Grim.deprecate("Use ::getRepositories instead")
|
||||
@getRepositories()[0]
|
||||
|
||||
Project::getPath = ->
|
||||
Grim.deprecate("Use ::getPaths instead")
|
||||
@getPaths()[0]
|
||||
|
||||
Project::setPath = (path) ->
|
||||
Grim.deprecate("Use ::setPaths instead")
|
||||
@setPaths([path])
|
||||
|
||||
Project::getRootDirectory = ->
|
||||
Grim.deprecate("Use ::getDirectories instead")
|
||||
@getDirectories()[0]
|
||||
|
||||
Project::resolve = (uri) ->
|
||||
Grim.deprecate("Use `Project::getDirectories()[0]?.resolve()` instead")
|
||||
@resolvePath(uri)
|
||||
|
||||
Project::scan = (regex, options={}, iterator) ->
|
||||
Grim.deprecate("Use atom.workspace.scan instead of atom.project.scan")
|
||||
atom.workspace.scan(regex, options, iterator)
|
||||
|
||||
Project::replace = (regex, replacementText, filePaths, iterator) ->
|
||||
Grim.deprecate("Use atom.workspace.replace instead of atom.project.replace")
|
||||
atom.workspace.replace(regex, replacementText, filePaths, iterator)
|
||||
|
||||
Project::openSync = (filePath, options={}) ->
|
||||
deprecate("Use Project::open instead")
|
||||
filePath = @resolvePath(filePath)
|
||||
@buildEditorForBuffer(@bufferForPathSync(filePath), options)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{pick} = _ = require 'underscore-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
Model = require './model'
|
||||
|
||||
NonWhitespaceRegExp = /\S/
|
||||
@@ -836,25 +835,3 @@ class Selection extends Model
|
||||
getGoalScreenRange: ->
|
||||
if goalScreenRange = @marker.getProperties().goalScreenRange
|
||||
Range.fromObject(goalScreenRange)
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
Selection::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'screen-range-changed'
|
||||
Grim.deprecate("Use Selection::onDidChangeRange instead. Call ::getScreenRange() yourself in your callback if you need the range.")
|
||||
when 'destroyed'
|
||||
Grim.deprecate("Use Selection::onDidDestroy instead.")
|
||||
else
|
||||
Grim.deprecate("Selection::on is deprecated. Use documented event subscription methods instead.")
|
||||
|
||||
super
|
||||
|
||||
# Deprecated: Use {::deleteToBeginningOfWord} instead.
|
||||
Selection::backspaceToBeginningOfWord = ->
|
||||
deprecate("Use Selection::deleteToBeginningOfWord() instead")
|
||||
@deleteToBeginningOfWord()
|
||||
|
||||
# Deprecated: Use {::deleteToBeginningOfLine} instead.
|
||||
Selection::backspaceToBeginningOfLine = ->
|
||||
deprecate("Use Selection::deleteToBeginningOfLine() instead")
|
||||
@deleteToBeginningOfLine()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{Subscriber} = require 'emissary'
|
||||
SubscriberMixin = componentDidUnmount: -> @unsubscribe()
|
||||
Subscriber.extend(SubscriberMixin)
|
||||
module.exports = SubscriberMixin
|
||||
@@ -1,6 +1,6 @@
|
||||
_ = require 'underscore-plus'
|
||||
ChildProcess = require 'child_process'
|
||||
{Emitter} = require 'emissary'
|
||||
{Emitter} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
# Extended: Run a node script in a separate process.
|
||||
@@ -38,8 +38,6 @@ Grim = require 'grim'
|
||||
# ```
|
||||
module.exports =
|
||||
class Task
|
||||
Emitter.includeInto(this)
|
||||
|
||||
# Public: A helper method to easily launch and run a task once.
|
||||
#
|
||||
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file which
|
||||
@@ -66,6 +64,8 @@ class Task
|
||||
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file that
|
||||
# exports a single {Function} to execute.
|
||||
constructor: (taskPath) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
compileCacheRequire = "require('#{require.resolve('./compile-cache')}')"
|
||||
compileCachePath = require('./compile-cache').getCacheDirectory()
|
||||
taskBootstrapRequire = "require('#{require.resolve('./task-bootstrap')}');"
|
||||
@@ -95,7 +95,7 @@ class Task
|
||||
handleEvents: ->
|
||||
@childProcess.removeAllListeners()
|
||||
@childProcess.on 'message', ({event, args}) =>
|
||||
@emit(event, args...) if @childProcess?
|
||||
@emitter.emit(event, args) if @childProcess?
|
||||
|
||||
# Catch the errors that happened before task-bootstrap.
|
||||
if @childProcess.stdout?
|
||||
@@ -143,7 +143,12 @@ class Task
|
||||
# * `callback` The {Function} to call when the event is emitted.
|
||||
#
|
||||
# Returns a {Disposable} that can be used to stop listening for the event.
|
||||
on: (eventName, callback) -> Emitter::on.call(this, eventName, callback)
|
||||
on: (eventName, callback) -> @emitter.on eventName, (args) -> callback(args...)
|
||||
|
||||
once: (eventName, callback) ->
|
||||
disposable = @on eventName, (args...) ->
|
||||
disposable.dispose()
|
||||
callback(args...)
|
||||
|
||||
# Public: Forcefully stop the running task.
|
||||
#
|
||||
@@ -162,5 +167,5 @@ class Task
|
||||
cancel: ->
|
||||
didForcefullyTerminate = @terminate()
|
||||
if didForcefullyTerminate
|
||||
@emit('task:cancelled')
|
||||
@emitter.emit('task:cancelled')
|
||||
didForcefullyTerminate
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
_ = require 'underscore-plus'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{Range, Point} = require 'text-buffer'
|
||||
grim = require 'grim'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
ipc = require 'ipc'
|
||||
|
||||
@@ -28,8 +27,6 @@ class TextEditorComponent
|
||||
updatesPaused: false
|
||||
updateRequestedWhilePaused: false
|
||||
heightAndWidthMeasurementRequested: false
|
||||
cursorMoved: false
|
||||
selectionChanged: false
|
||||
inputEnabled: true
|
||||
measureScrollbarsWhenShown: true
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: true
|
||||
@@ -37,6 +34,13 @@ class TextEditorComponent
|
||||
stylingChangeAnimationFrameRequested: false
|
||||
gutterComponent: null
|
||||
mounted: true
|
||||
initialized: false
|
||||
|
||||
Object.defineProperty @prototype, "domNode",
|
||||
get: -> @domNodeValue
|
||||
set: (domNode) ->
|
||||
atom.assert domNode?, "TextEditorComponent::domNode was set to null."
|
||||
@domNodeValue = domNode
|
||||
|
||||
constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize}) ->
|
||||
@tileSize = tileSize if tileSize?
|
||||
@@ -47,8 +51,10 @@ class TextEditorComponent
|
||||
|
||||
@presenter = new TextEditorPresenter
|
||||
model: @editor
|
||||
scrollTop: @editor.getScrollTop()
|
||||
scrollLeft: @editor.getScrollLeft()
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
scrollRow: @editor.getScrollRow()
|
||||
scrollColumn: @editor.getScrollColumn()
|
||||
tileSize: tileSize
|
||||
cursorBlinkPeriod: @cursorBlinkPeriod
|
||||
cursorBlinkResumeDelay: @cursorBlinkResumeDelay
|
||||
@@ -106,6 +112,7 @@ class TextEditorComponent
|
||||
|
||||
@updateSync()
|
||||
@checkForVisibilityChange()
|
||||
@initialized = true
|
||||
|
||||
destroy: ->
|
||||
@mounted = false
|
||||
@@ -121,11 +128,6 @@ class TextEditorComponent
|
||||
@oldState ?= {}
|
||||
@newState = @presenter.getState()
|
||||
|
||||
cursorMoved = @cursorMoved
|
||||
selectionChanged = @selectionChanged
|
||||
@cursorMoved = false
|
||||
@selectionChanged = false
|
||||
|
||||
if @editor.getLastSelection()? and not @editor.getLastSelection().isEmpty()
|
||||
@domNode.classList.add('has-selection')
|
||||
else
|
||||
@@ -221,8 +223,6 @@ class TextEditorComponent
|
||||
|
||||
observeEditor: ->
|
||||
@disposables.add @editor.observeGrammar(@onGrammarChanged)
|
||||
@disposables.add @editor.observeCursors(@onCursorAdded)
|
||||
@disposables.add @editor.observeSelections(@onSelectionAdded)
|
||||
|
||||
listenForDOMEvents: ->
|
||||
@domNode.addEventListener 'mousewheel', @onMouseWheel
|
||||
@@ -318,7 +318,7 @@ class TextEditorComponent
|
||||
inputNode.value = event.data if insertedRange
|
||||
|
||||
onVerticalScroll: (scrollTop) =>
|
||||
return if @updateRequested or scrollTop is @editor.getScrollTop()
|
||||
return if @updateRequested or scrollTop is @presenter.getScrollTop()
|
||||
|
||||
animationFramePending = @pendingScrollTop?
|
||||
@pendingScrollTop = scrollTop
|
||||
@@ -327,15 +327,17 @@ class TextEditorComponent
|
||||
pendingScrollTop = @pendingScrollTop
|
||||
@pendingScrollTop = null
|
||||
@presenter.setScrollTop(pendingScrollTop)
|
||||
@presenter.commitPendingScrollTopPosition()
|
||||
|
||||
onHorizontalScroll: (scrollLeft) =>
|
||||
return if @updateRequested or scrollLeft is @editor.getScrollLeft()
|
||||
return if @updateRequested or scrollLeft is @presenter.getScrollLeft()
|
||||
|
||||
animationFramePending = @pendingScrollLeft?
|
||||
@pendingScrollLeft = scrollLeft
|
||||
unless animationFramePending
|
||||
@requestAnimationFrame =>
|
||||
@presenter.setScrollLeft(@pendingScrollLeft)
|
||||
@presenter.commitPendingScrollLeftPosition()
|
||||
@pendingScrollLeft = null
|
||||
|
||||
onMouseWheel: (event) =>
|
||||
@@ -354,14 +356,18 @@ class TextEditorComponent
|
||||
if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)
|
||||
# Scrolling horizontally
|
||||
previousScrollLeft = @presenter.getScrollLeft()
|
||||
@presenter.setScrollLeft(previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft()
|
||||
updatedScrollLeft = previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity)
|
||||
|
||||
event.preventDefault() if @presenter.canScrollLeftTo(updatedScrollLeft)
|
||||
@presenter.setScrollLeft(updatedScrollLeft)
|
||||
else
|
||||
# Scrolling vertically
|
||||
@presenter.setMouseWheelScreenRow(@screenRowForNode(event.target))
|
||||
previousScrollTop = @presenter.getScrollTop()
|
||||
@presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollTop is @presenter.getScrollTop()
|
||||
updatedScrollTop = previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)
|
||||
|
||||
event.preventDefault() if @presenter.canScrollTopTo(updatedScrollTop)
|
||||
@presenter.setScrollTop(updatedScrollTop)
|
||||
|
||||
onScrollViewScroll: =>
|
||||
if @mounted
|
||||
@@ -369,6 +375,77 @@ class TextEditorComponent
|
||||
@scrollViewNode.scrollTop = 0
|
||||
@scrollViewNode.scrollLeft = 0
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@presenter.onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@presenter.onDidChangeScrollLeft(callback)
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
@presenter.setScrollLeft(scrollLeft)
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
@presenter.setScrollRight(scrollRight)
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
@presenter.setScrollTop(scrollTop)
|
||||
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@presenter.setScrollBottom(scrollBottom)
|
||||
|
||||
getScrollTop: ->
|
||||
@presenter.getScrollTop()
|
||||
|
||||
getScrollLeft: ->
|
||||
@presenter.getScrollLeft()
|
||||
|
||||
getScrollRight: ->
|
||||
@presenter.getScrollRight()
|
||||
|
||||
getScrollBottom: ->
|
||||
@presenter.getScrollBottom()
|
||||
|
||||
getScrollHeight: ->
|
||||
@presenter.getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
@presenter.getScrollWidth()
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@presenter.getVerticalScrollbarWidth()
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
@presenter.getHorizontalScrollbarHeight()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
@presenter.getVisibleRowRange()
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
position = @presenter.pixelPositionForScreenPosition(screenPosition)
|
||||
position.top += @presenter.getScrollTop()
|
||||
position.left += @presenter.getScrollLeft()
|
||||
position
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
@presenter.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
rect = @presenter.pixelRectForScreenRange(screenRange)
|
||||
rect.top += @presenter.getScrollTop()
|
||||
rect.bottom += @presenter.getScrollTop()
|
||||
rect.left += @presenter.getScrollLeft()
|
||||
rect.right += @presenter.getScrollLeft()
|
||||
rect
|
||||
|
||||
pixelRangeForScreenRange: (screenRange, clip=true) ->
|
||||
{start, end} = Range.fromObject(screenRange)
|
||||
{start: @pixelPositionForScreenPosition(start, clip), end: @pixelPositionForScreenPosition(end, clip)}
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@pixelPositionForScreenPosition(
|
||||
@editor.screenPositionForBufferPosition(bufferPosition)
|
||||
)
|
||||
|
||||
onMouseDown: (event) =>
|
||||
unless event.button is 0 or (event.button is 1 and process.platform is 'linux')
|
||||
# Only handle mouse down events for left mouse button on all platforms
|
||||
@@ -488,29 +565,6 @@ class TextEditorComponent
|
||||
@sampleBackgroundColors()
|
||||
@remeasureCharacterWidths()
|
||||
|
||||
onSelectionAdded: (selection) =>
|
||||
selectionDisposables = new CompositeDisposable
|
||||
selectionDisposables.add selection.onDidChangeRange => @onSelectionChanged(selection)
|
||||
selectionDisposables.add selection.onDidDestroy =>
|
||||
@onSelectionChanged(selection)
|
||||
selectionDisposables.dispose()
|
||||
@disposables.remove(selectionDisposables)
|
||||
|
||||
@disposables.add(selectionDisposables)
|
||||
|
||||
if @editor.selectionIntersectsVisibleRowRange(selection)
|
||||
@selectionChanged = true
|
||||
|
||||
onSelectionChanged: (selection) =>
|
||||
if @editor.selectionIntersectsVisibleRowRange(selection)
|
||||
@selectionChanged = true
|
||||
|
||||
onCursorAdded: (cursor) =>
|
||||
@disposables.add cursor.onDidChangePosition @onCursorMoved
|
||||
|
||||
onCursorMoved: =>
|
||||
@cursorMoved = true
|
||||
|
||||
handleDragUntilMouseUp: (dragHandler) =>
|
||||
dragging = false
|
||||
lastMousePosition = {}
|
||||
@@ -573,9 +627,11 @@ class TextEditorComponent
|
||||
|
||||
if mouseYDelta?
|
||||
@presenter.setScrollTop(@presenter.getScrollTop() + yDirection * scaleScrollDelta(mouseYDelta))
|
||||
@presenter.commitPendingScrollTopPosition()
|
||||
|
||||
if mouseXDelta?
|
||||
@presenter.setScrollLeft(@presenter.getScrollLeft() + xDirection * scaleScrollDelta(mouseXDelta))
|
||||
@presenter.commitPendingScrollLeftPosition()
|
||||
|
||||
scaleScrollDelta = (scrollDelta) ->
|
||||
Math.pow(scrollDelta / 2, 3) / 280
|
||||
@@ -592,7 +648,11 @@ class TextEditorComponent
|
||||
disposables.add(@editor.onDidDestroy(stopDragging))
|
||||
|
||||
isVisible: ->
|
||||
@domNode.offsetHeight > 0 or @domNode.offsetWidth > 0
|
||||
# Investigating an exception that occurs here due to ::domNode being null.
|
||||
atom.assert @domNode?, "TextEditorComponent::domNode was null.", (error) =>
|
||||
error.metadata = {@initialized}
|
||||
|
||||
@domNode? and (@domNode.offsetHeight > 0 or @domNode.offsetWidth > 0)
|
||||
|
||||
pollDOM: =>
|
||||
unless @checkForVisibilityChange()
|
||||
@@ -798,19 +858,22 @@ class TextEditorComponent
|
||||
|
||||
screenPositionForMouseEvent: (event, linesClientRect) ->
|
||||
pixelPosition = @pixelPositionForMouseEvent(event, linesClientRect)
|
||||
@editor.screenPositionForPixelPosition(pixelPosition)
|
||||
@presenter.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelPositionForMouseEvent: (event, linesClientRect) ->
|
||||
{clientX, clientY} = event
|
||||
|
||||
linesClientRect ?= @linesComponent.getDomNode().getBoundingClientRect()
|
||||
top = clientY - linesClientRect.top + @presenter.scrollTop
|
||||
left = clientX - linesClientRect.left + @presenter.scrollLeft
|
||||
bottom = linesClientRect.top + @presenter.scrollTop + linesClientRect.height - clientY
|
||||
right = linesClientRect.left + @presenter.scrollLeft + linesClientRect.width - clientX
|
||||
top = clientY - linesClientRect.top + @presenter.getRealScrollTop()
|
||||
left = clientX - linesClientRect.left + @presenter.getRealScrollLeft()
|
||||
bottom = linesClientRect.top + @presenter.getRealScrollTop() + linesClientRect.height - clientY
|
||||
right = linesClientRect.left + @presenter.getRealScrollLeft() + linesClientRect.width - clientX
|
||||
|
||||
{top, left, bottom, right}
|
||||
|
||||
getGutterWidth: ->
|
||||
@presenter.getGutterWidth()
|
||||
|
||||
getModel: ->
|
||||
@editor
|
||||
|
||||
@@ -830,12 +893,3 @@ class TextEditorComponent
|
||||
updateParentViewMiniClass: ->
|
||||
@hostElement.classList.toggle('mini', @editor.isMini())
|
||||
@rootElement.classList.toggle('mini', @editor.isMini())
|
||||
|
||||
if grim.includeDeprecatedAPIs
|
||||
TextEditorComponent::setInvisibles = (invisibles={}) ->
|
||||
grim.deprecate "Use config.set('editor.invisibles', invisibles) instead"
|
||||
atom.config.set('editor.invisibles', invisibles)
|
||||
|
||||
TextEditorComponent::setShowInvisibles = (showInvisibles) ->
|
||||
grim.deprecate "Use config.set('editor.showInvisibles', showInvisibles) instead"
|
||||
atom.config.set('editor.showInvisibles', showInvisibles)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Path = require 'path'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Grim = require 'grim'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorComponent = require './text-editor-component'
|
||||
|
||||
@@ -182,7 +181,7 @@ class TextEditorElement extends HTMLElement
|
||||
#
|
||||
# Returns an {Object} with two values: `top` and `left`, representing the pixel position.
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@getModel().pixelPositionForBufferPosition(bufferPosition, true)
|
||||
@component.pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
# Extended: Converts a screen position to a pixel position.
|
||||
#
|
||||
@@ -191,21 +190,21 @@ class TextEditorElement extends HTMLElement
|
||||
#
|
||||
# Returns an {Object} with two values: `top` and `left`, representing the pixel positions.
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
@getModel().pixelPositionForScreenPosition(screenPosition, true)
|
||||
@component.pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
# Extended: Retrieves the number of the row that is visible and currently at the
|
||||
# top of the editor.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getFirstVisibleScreenRow: ->
|
||||
@getModel().getFirstVisibleScreenRow(true)
|
||||
@getVisibleRowRange()[0]
|
||||
|
||||
# Extended: Retrieves the number of the row that is visible and currently at the
|
||||
# bottom of the editor.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getLastVisibleScreenRow: ->
|
||||
@getModel().getLastVisibleScreenRow(true)
|
||||
@getVisibleRowRange()[1]
|
||||
|
||||
# Extended: call the given `callback` when the editor is attached to the DOM.
|
||||
#
|
||||
@@ -219,6 +218,90 @@ class TextEditorElement extends HTMLElement
|
||||
onDidDetach: (callback) ->
|
||||
@emitter.on("did-detach", callback)
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@component.onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@component.onDidChangeScrollLeft(callback)
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
@component.setScrollLeft(scrollLeft)
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
@component.setScrollRight(scrollRight)
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
@component.setScrollTop(scrollTop)
|
||||
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@component.setScrollBottom(scrollBottom)
|
||||
|
||||
# Essential: Scrolls the editor to the top
|
||||
scrollToTop: ->
|
||||
@setScrollTop(0)
|
||||
|
||||
# Essential: Scrolls the editor to the bottom
|
||||
scrollToBottom: ->
|
||||
@setScrollBottom(Infinity)
|
||||
|
||||
getScrollTop: ->
|
||||
@component.getScrollTop()
|
||||
|
||||
getScrollLeft: ->
|
||||
@component.getScrollLeft()
|
||||
|
||||
getScrollRight: ->
|
||||
@component.getScrollRight()
|
||||
|
||||
getScrollBottom: ->
|
||||
@component.getScrollBottom()
|
||||
|
||||
getScrollHeight: ->
|
||||
@component.getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
@component.getScrollWidth()
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@component.getVerticalScrollbarWidth()
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
@component.getHorizontalScrollbarHeight()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
@component.getVisibleRowRange()
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
[visibleStart, visibleEnd] = @getVisibleRowRange()
|
||||
not (endRow <= visibleStart or visibleEnd <= startRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
{start, end} = selection.getScreenRange()
|
||||
@intersectsVisibleRowRange(start.row, end.row + 1)
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
@component.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
@component.pixelRectForScreenRange(screenRange)
|
||||
|
||||
pixelRangeForScreenRange: (screenRange) ->
|
||||
@component.pixelRangeForScreenRange(screenRange)
|
||||
|
||||
setWidth: (width) ->
|
||||
@style.width = (@component.getGutterWidth() + width) + "px"
|
||||
@component.measureDimensions()
|
||||
|
||||
getWidth: ->
|
||||
@style.offsetWidth - @component.getGutterWidth()
|
||||
|
||||
setHeight: (height) ->
|
||||
@style.height = height + "px"
|
||||
@component.measureDimensions()
|
||||
|
||||
getHeight: ->
|
||||
@style.offsetHeight
|
||||
|
||||
stopEventPropagation = (commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
|
||||
@@ -14,7 +14,7 @@ class TextEditorPresenter
|
||||
minimumReflowInterval: 200
|
||||
|
||||
constructor: (params) ->
|
||||
{@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
|
||||
{@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @scrollColumn, @scrollRow, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
|
||||
{horizontalScrollbarHeight, verticalScrollbarWidth} = params
|
||||
{@lineHeight, @baseCharacterWidth, @backgroundColor, @gutterBackgroundColor, @tileSize} = params
|
||||
{@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params
|
||||
@@ -32,6 +32,7 @@ class TextEditorPresenter
|
||||
@lineNumberDecorationsByScreenRow = {}
|
||||
@customGutterDecorationsByGutterNameAndScreenRow = {}
|
||||
@transferMeasurementsToModel()
|
||||
@transferMeasurementsFromModel()
|
||||
@observeModel()
|
||||
@observeConfig()
|
||||
@buildState()
|
||||
@@ -53,14 +54,11 @@ class TextEditorPresenter
|
||||
@emitter.emit "did-update-state" if @isBatching()
|
||||
|
||||
transferMeasurementsToModel: ->
|
||||
@model.setHeight(@explicitHeight) if @explicitHeight?
|
||||
@model.setWidth(@contentFrameWidth) if @contentFrameWidth?
|
||||
@model.setLineHeightInPixels(@lineHeight) if @lineHeight?
|
||||
@model.setDefaultCharWidth(@baseCharacterWidth) if @baseCharacterWidth?
|
||||
@model.setScrollTop(@scrollTop) if @scrollTop?
|
||||
@model.setScrollLeft(@scrollLeft) if @scrollLeft?
|
||||
@model.setVerticalScrollbarWidth(@measuredVerticalScrollbarWidth) if @measuredVerticalScrollbarWidth?
|
||||
@model.setHorizontalScrollbarHeight(@measuredHorizontalScrollbarHeight) if @measuredHorizontalScrollbarHeight?
|
||||
|
||||
transferMeasurementsFromModel: ->
|
||||
@editorWidthInChars = @model.getEditorWidthInChars()
|
||||
|
||||
# Private: Determines whether {TextEditorPresenter} is currently batching changes.
|
||||
# Returns a {Boolean}, `true` if is collecting changes, `false` if is applying them.
|
||||
@@ -70,9 +68,12 @@ class TextEditorPresenter
|
||||
getStateForMeasurements: ->
|
||||
@updateVerticalDimensions()
|
||||
@updateScrollbarDimensions()
|
||||
@updateScrollPosition()
|
||||
@updateStartRow()
|
||||
@updateEndRow()
|
||||
|
||||
@fetchVisibleDecorations() if @shouldUpdateDecorations
|
||||
|
||||
@updateLineDecorations() if @shouldUpdateDecorations
|
||||
@updateTilesState() if @shouldUpdateLineNumbersState or @shouldUpdateLinesState
|
||||
|
||||
@@ -148,10 +149,6 @@ class TextEditorPresenter
|
||||
|
||||
observeModel: ->
|
||||
@disposables.add @model.onDidChange =>
|
||||
@linesYardstick.measure [@model.getLongestScreenRow()], =>
|
||||
@updateVerticalDimensions()
|
||||
@updateHorizontalDimensions()
|
||||
|
||||
@shouldUpdateHeightState = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@@ -197,8 +194,7 @@ class TextEditorPresenter
|
||||
|
||||
@disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this))
|
||||
@disposables.add @model.onDidAddCursor(@didAddCursor.bind(this))
|
||||
@disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this))
|
||||
@disposables.add @model.onDidChangeScrollLeft(@setScrollLeft.bind(this))
|
||||
@disposables.add @model.onDidRequestAutoscroll(@requestAutoscroll.bind(this))
|
||||
@observeDecoration(decoration) for decoration in @model.getDecorations()
|
||||
@observeCursor(cursor) for cursor in @model.getCursors()
|
||||
@disposables.add @model.onDidAddGutter(@didAddGutter.bind(this))
|
||||
@@ -346,7 +342,7 @@ class TextEditorPresenter
|
||||
row - (row % @tileSize)
|
||||
|
||||
constrainRow: (row) ->
|
||||
Math.min(0, Math.max(0, @model.getScreenLineCount()))
|
||||
Math.max(0, Math.min(row, @model.getScreenLineCount()))
|
||||
|
||||
getStartTileRow: ->
|
||||
@constrainRow(@tileForRow(@startRow))
|
||||
@@ -724,6 +720,8 @@ class TextEditorPresenter
|
||||
return unless @height? and @horizontalScrollbarHeight?
|
||||
|
||||
clientHeight = @height - @horizontalScrollbarHeight
|
||||
@model.setHeight(clientHeight, true)
|
||||
|
||||
unless @clientHeight is clientHeight
|
||||
@clientHeight = clientHeight
|
||||
@updateScrollHeight()
|
||||
@@ -733,6 +731,8 @@ class TextEditorPresenter
|
||||
return unless @contentFrameWidth? and @verticalScrollbarWidth?
|
||||
|
||||
clientWidth = @contentFrameWidth - @verticalScrollbarWidth
|
||||
@model.setWidth(clientWidth, true) unless @editorWidthInChars
|
||||
|
||||
unless @clientWidth is clientWidth
|
||||
@clientWidth = clientWidth
|
||||
@updateScrollWidth()
|
||||
@@ -742,6 +742,7 @@ class TextEditorPresenter
|
||||
scrollTop = @constrainScrollTop(@scrollTop)
|
||||
unless @scrollTop is scrollTop
|
||||
@scrollTop = scrollTop
|
||||
@realScrollTop = @scrollTop
|
||||
@updateStartRow()
|
||||
@updateEndRow()
|
||||
|
||||
@@ -751,6 +752,7 @@ class TextEditorPresenter
|
||||
|
||||
updateScrollLeft: ->
|
||||
@scrollLeft = @constrainScrollLeft(@scrollLeft)
|
||||
@realScrollLeft = @scrollLeft
|
||||
|
||||
constrainScrollLeft: (scrollLeft) ->
|
||||
return scrollLeft unless scrollLeft? and @scrollWidth? and @clientWidth?
|
||||
@@ -843,26 +845,28 @@ class TextEditorPresenter
|
||||
@emitDidUpdateState()
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
scrollTop = @constrainScrollTop(scrollTop)
|
||||
return unless scrollTop?
|
||||
|
||||
unless @scrollTop is scrollTop or Number.isNaN(scrollTop)
|
||||
@scrollTop = scrollTop
|
||||
@model.setScrollTop(scrollTop)
|
||||
@didStartScrolling()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateLineNumbersState = true
|
||||
@shouldUpdateCustomGutterDecorationState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@pendingScrollLogicalPosition = null
|
||||
@pendingScrollTop = scrollTop
|
||||
|
||||
@emitDidUpdateState()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateLineNumbersState = true
|
||||
@shouldUpdateCustomGutterDecorationState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
getScrollTop: ->
|
||||
@scrollTop
|
||||
|
||||
getRealScrollTop: ->
|
||||
@realScrollTop ? @scrollTop
|
||||
|
||||
didStartScrolling: ->
|
||||
if @stoppedScrollingTimeoutId?
|
||||
clearTimeout(@stoppedScrollingTimeoutId)
|
||||
@@ -882,28 +886,58 @@ class TextEditorPresenter
|
||||
@emitDidUpdateState()
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
scrollLeft = @constrainScrollLeft(scrollLeft)
|
||||
unless @scrollLeft is scrollLeft or Number.isNaN(scrollLeft)
|
||||
oldScrollLeft = @scrollLeft
|
||||
@scrollLeft = scrollLeft
|
||||
@model.setScrollLeft(scrollLeft)
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
return unless scrollLeft?
|
||||
|
||||
@emitDidUpdateState()
|
||||
@pendingScrollLogicalPosition = null
|
||||
@pendingScrollLeft = scrollLeft
|
||||
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
getScrollLeft: ->
|
||||
@scrollLeft
|
||||
|
||||
getRealScrollLeft: ->
|
||||
@realScrollLeft ? @scrollLeft
|
||||
|
||||
getClientHeight: ->
|
||||
if @clientHeight
|
||||
@clientHeight
|
||||
else
|
||||
@explicitHeight - @horizontalScrollbarHeight
|
||||
|
||||
getClientWidth: ->
|
||||
if @clientWidth
|
||||
@clientWidth
|
||||
else
|
||||
@contentFrameWidth - @verticalScrollbarWidth
|
||||
|
||||
getScrollBottom: -> @getScrollTop() + @getClientHeight()
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@setScrollTop(scrollBottom - @getClientHeight())
|
||||
@getScrollBottom()
|
||||
|
||||
getScrollRight: -> @getScrollLeft() + @getClientWidth()
|
||||
setScrollRight: (scrollRight) ->
|
||||
@setScrollLeft(scrollRight - @getClientWidth())
|
||||
@getScrollRight()
|
||||
|
||||
getScrollHeight: ->
|
||||
@scrollHeight
|
||||
|
||||
getScrollWidth: ->
|
||||
@scrollWidth
|
||||
|
||||
setHorizontalScrollbarHeight: (horizontalScrollbarHeight) ->
|
||||
unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight
|
||||
oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight
|
||||
@measuredHorizontalScrollbarHeight = horizontalScrollbarHeight
|
||||
@model.setHorizontalScrollbarHeight(horizontalScrollbarHeight)
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@@ -915,7 +949,6 @@ class TextEditorPresenter
|
||||
unless @measuredVerticalScrollbarWidth is verticalScrollbarWidth
|
||||
oldVerticalScrollbarWidth = @measuredVerticalScrollbarWidth
|
||||
@measuredVerticalScrollbarWidth = verticalScrollbarWidth
|
||||
@model.setVerticalScrollbarWidth(verticalScrollbarWidth)
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@@ -933,7 +966,6 @@ class TextEditorPresenter
|
||||
setExplicitHeight: (explicitHeight) ->
|
||||
unless @explicitHeight is explicitHeight
|
||||
@explicitHeight = explicitHeight
|
||||
@model.setHeight(explicitHeight)
|
||||
@updateHeight()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@@ -955,10 +987,10 @@ class TextEditorPresenter
|
||||
@updateEndRow()
|
||||
|
||||
setContentFrameWidth: (contentFrameWidth) ->
|
||||
unless @contentFrameWidth is contentFrameWidth
|
||||
if @contentFrameWidth isnt contentFrameWidth or @editorWidthInChars?
|
||||
oldContentFrameWidth = @contentFrameWidth
|
||||
@contentFrameWidth = contentFrameWidth
|
||||
@model.setWidth(contentFrameWidth)
|
||||
@editorWidthInChars = null
|
||||
@updateScrollbarDimensions()
|
||||
@updateClientWidth()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@@ -1016,6 +1048,9 @@ class TextEditorPresenter
|
||||
@gutterWidth = gutterWidth
|
||||
@updateOverlaysState()
|
||||
|
||||
getGutterWidth: ->
|
||||
@gutterWidth
|
||||
|
||||
setLineHeight: (lineHeight) ->
|
||||
unless @lineHeight is lineHeight
|
||||
@lineHeight = lineHeight
|
||||
@@ -1176,29 +1211,30 @@ class TextEditorPresenter
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
fetchVisibleDecorations: ->
|
||||
@visibleDecorations = []
|
||||
|
||||
for row in @getScreenRows()
|
||||
for markerId, decorations of @model.decorationsForScreenRowRange(row, row)
|
||||
range = @model.getMarker(markerId).getScreenRange()
|
||||
for decoration in decorations
|
||||
@visibleDecorations.push({decoration, range})
|
||||
|
||||
updateLineDecorations: ->
|
||||
@rangesByDecorationId = {}
|
||||
@lineDecorationsByScreenRow = {}
|
||||
@lineNumberDecorationsByScreenRow = {}
|
||||
@customGutterDecorationsByGutterNameAndScreenRow = {}
|
||||
|
||||
return unless 0 <= @startRow <= @endRow <= Infinity
|
||||
|
||||
for row in @getScreenRows()
|
||||
for markerId, decorations of @model.decorationsForScreenRowRange(row, row)
|
||||
range = @model.getMarker(markerId).getScreenRange()
|
||||
for decoration in decorations
|
||||
if decoration.isType('line') or decoration.isType('gutter')
|
||||
@addToLineDecorationCaches(decoration, range)
|
||||
for {decoration, range} in @visibleDecorations
|
||||
if decoration.isType('line') or decoration.isType('gutter')
|
||||
@addToLineDecorationCaches(decoration, range)
|
||||
|
||||
updateHighlightDecorations: ->
|
||||
@visibleHighlights = {}
|
||||
|
||||
return unless 0 <= @startRow <= @endRow <= Infinity
|
||||
|
||||
for markerId, decorations of @model.decorationsForScreenRowRange(@startRow, @endRow - 1)
|
||||
range = @model.getMarker(markerId).getScreenRange()
|
||||
for decoration in decorations when decoration.isType('highlight')
|
||||
for {decoration, range} in @visibleDecorations
|
||||
if decoration.isType('highlight')
|
||||
@updateHighlightState(decoration, range)
|
||||
|
||||
for tileId, tileState of @state.content.tiles
|
||||
@@ -1452,3 +1488,179 @@ class TextEditorPresenter
|
||||
@startBlinkingCursorsAfterDelay ?= _.debounce(@startBlinkingCursors, @getCursorBlinkResumeDelay())
|
||||
@startBlinkingCursorsAfterDelay()
|
||||
@emitDidUpdateState()
|
||||
|
||||
requestAutoscroll: (position) ->
|
||||
@pendingScrollLogicalPosition = position
|
||||
@pendingScrollTop = null
|
||||
@pendingScrollLeft = null
|
||||
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateCustomGutterDecorationState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@shouldUpdateLinesState = true
|
||||
@shouldUpdateLineNumbersState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@shouldUpdateScrollPosition = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
getVerticalScrollMarginInPixels: ->
|
||||
@model.getVerticalScrollMargin() * @lineHeight
|
||||
|
||||
getHorizontalScrollMarginInPixels: ->
|
||||
@model.getHorizontalScrollMargin() * @baseCharacterWidth
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@verticalScrollbarWidth
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
@horizontalScrollbarHeight
|
||||
|
||||
commitPendingLogicalScrollPosition: ->
|
||||
return unless @pendingScrollLogicalPosition?
|
||||
|
||||
{screenRange, options} = @pendingScrollLogicalPosition
|
||||
|
||||
verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels()
|
||||
horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels()
|
||||
|
||||
{top, left} = @pixelRectForScreenRange(new Range(screenRange.start, screenRange.start))
|
||||
{top: endTop, left: endLeft, height: endHeight} = @pixelRectForScreenRange(new Range(screenRange.end, screenRange.end))
|
||||
bottom = endTop + endHeight
|
||||
right = endLeft
|
||||
|
||||
top += @scrollTop
|
||||
bottom += @scrollTop
|
||||
left += @scrollLeft
|
||||
right += @scrollLeft
|
||||
|
||||
if options?.center
|
||||
desiredScrollCenter = (top + bottom) / 2
|
||||
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
|
||||
desiredScrollTop = desiredScrollCenter - @getClientHeight() / 2
|
||||
desiredScrollBottom = desiredScrollCenter + @getClientHeight() / 2
|
||||
else
|
||||
desiredScrollTop = top - verticalScrollMarginInPixels
|
||||
desiredScrollBottom = bottom + verticalScrollMarginInPixels
|
||||
|
||||
desiredScrollLeft = left - horizontalScrollMarginInPixels
|
||||
desiredScrollRight = right + horizontalScrollMarginInPixels
|
||||
|
||||
if options?.reversed ? true
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
else
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
|
||||
@pendingScrollLogicalPosition = null
|
||||
|
||||
commitPendingScrollLeftPosition: ->
|
||||
return unless @pendingScrollLeft?
|
||||
|
||||
scrollLeft = @constrainScrollLeft(@pendingScrollLeft)
|
||||
if scrollLeft isnt @scrollLeft and not Number.isNaN(scrollLeft)
|
||||
@realScrollLeft = scrollLeft
|
||||
@scrollLeft = Math.round(scrollLeft)
|
||||
@scrollColumn = Math.round(@scrollLeft / @baseCharacterWidth)
|
||||
@model.setScrollColumn(@scrollColumn)
|
||||
|
||||
@emitter.emit 'did-change-scroll-left', @scrollLeft
|
||||
|
||||
@pendingScrollLeft = null
|
||||
|
||||
commitPendingScrollTopPosition: ->
|
||||
return unless @pendingScrollTop?
|
||||
|
||||
scrollTop = @constrainScrollTop(@pendingScrollTop)
|
||||
if scrollTop isnt @scrollTop and not Number.isNaN(scrollTop)
|
||||
@realScrollTop = scrollTop
|
||||
@scrollTop = Math.round(scrollTop)
|
||||
@scrollRow = Math.round(@scrollTop / @lineHeight)
|
||||
@model.setScrollRow(@scrollRow)
|
||||
|
||||
@didStartScrolling()
|
||||
@emitter.emit 'did-change-scroll-top', @scrollTop
|
||||
|
||||
@pendingScrollTop = null
|
||||
|
||||
restoreScrollPosition: ->
|
||||
return if @hasRestoredScrollPosition or not @hasPixelPositionRequirements()
|
||||
|
||||
@setScrollTop(@scrollRow * @lineHeight) if @scrollRow?
|
||||
@setScrollLeft(@scrollColumn * @baseCharacterWidth) if @scrollColumn?
|
||||
|
||||
@hasRestoredScrollPosition = true
|
||||
|
||||
updateScrollPosition: ->
|
||||
@restoreScrollPosition()
|
||||
@commitPendingLogicalScrollPosition()
|
||||
@commitPendingScrollLeftPosition()
|
||||
@commitPendingScrollTopPosition()
|
||||
|
||||
canScrollLeftTo: (scrollLeft) ->
|
||||
@scrollLeft isnt @constrainScrollLeft(scrollLeft)
|
||||
|
||||
canScrollTopTo: (scrollTop) ->
|
||||
@scrollTop isnt @constrainScrollTop(scrollTop)
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@emitter.on 'did-change-scroll-top', callback
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@emitter.on 'did-change-scroll-left', callback
|
||||
|
||||
getVisibleRowRange: ->
|
||||
[@startRow, @endRow]
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
targetTop = pixelPosition.top
|
||||
targetLeft = pixelPosition.left
|
||||
defaultCharWidth = @baseCharacterWidth
|
||||
row = Math.floor(targetTop / @lineHeight)
|
||||
targetLeft = 0 if row < 0
|
||||
targetLeft = Infinity if row > @model.getLastScreenRow()
|
||||
row = Math.min(row, @model.getLastScreenRow())
|
||||
row = Math.max(0, row)
|
||||
|
||||
left = 0
|
||||
column = 0
|
||||
|
||||
iterator = @model.tokenizedLineForScreenRow(row).getTokenIterator()
|
||||
while iterator.next()
|
||||
charWidths = @getScopedCharacterWidths(iterator.getScopes())
|
||||
value = iterator.getText()
|
||||
valueIndex = 0
|
||||
while valueIndex < value.length
|
||||
if iterator.isPairedCharacter()
|
||||
char = value
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
charWidth = charWidths[char] ? defaultCharWidth
|
||||
break if targetLeft <= left + (charWidth / 2)
|
||||
left += charWidth
|
||||
column += charLength
|
||||
|
||||
new Point(row, column)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
_ = require 'underscore-plus'
|
||||
path = require 'path'
|
||||
Serializable = require 'serializable'
|
||||
Delegator = require 'delegato'
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
Grim = require 'grim'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
{Point, Range} = TextBuffer = require 'text-buffer'
|
||||
LanguageMode = require './language-mode'
|
||||
@@ -56,11 +54,8 @@ GutterContainer = require './gutter-container'
|
||||
# soft wraps and folds to ensure your code interacts with them correctly.
|
||||
module.exports =
|
||||
class TextEditor extends Model
|
||||
Serializable.includeInto(this)
|
||||
atom.deserializers.add(this)
|
||||
Delegator.includeInto(this)
|
||||
|
||||
deserializing: false
|
||||
callDisplayBufferCreatedHook: false
|
||||
registerEditor: false
|
||||
buffer: null
|
||||
@@ -72,11 +67,20 @@ class TextEditor extends Model
|
||||
selectionFlashDuration: 500
|
||||
gutterContainer: null
|
||||
|
||||
@delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows',
|
||||
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
|
||||
toProperty: 'languageMode'
|
||||
@deserialize: (state) ->
|
||||
try
|
||||
displayBuffer = DisplayBuffer.deserialize(state.displayBuffer)
|
||||
catch error
|
||||
if error.syscall is 'read'
|
||||
return # Error reading the file, don't deserialize an editor for it
|
||||
else
|
||||
throw error
|
||||
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) ->
|
||||
state.displayBuffer = displayBuffer
|
||||
state.registerEditor = true
|
||||
new this(state)
|
||||
|
||||
constructor: ({@softTabs, @scrollRow, @scrollColumn, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) ->
|
||||
super
|
||||
|
||||
@emitter = new Emitter
|
||||
@@ -105,14 +109,6 @@ class TextEditor extends Model
|
||||
|
||||
@setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor()))
|
||||
|
||||
@disposables.add @displayBuffer.onDidChangeScrollTop (scrollTop) =>
|
||||
@emit 'scroll-top-changed', scrollTop if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-scroll-top', scrollTop
|
||||
|
||||
@disposables.add @displayBuffer.onDidChangeScrollLeft (scrollLeft) =>
|
||||
@emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-scroll-left', scrollLeft
|
||||
|
||||
@gutterContainer = new GutterContainer(this)
|
||||
@lineNumberGutter = @gutterContainer.addGutter
|
||||
name: 'line-number'
|
||||
@@ -121,45 +117,25 @@ class TextEditor extends Model
|
||||
|
||||
atom.workspace?.editorAdded(this) if registerEditor
|
||||
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
deserializer: 'TextEditor'
|
||||
id: @id
|
||||
softTabs: @softTabs
|
||||
scrollTop: @scrollTop
|
||||
scrollLeft: @scrollLeft
|
||||
scrollRow: @getScrollRow()
|
||||
scrollColumn: @getScrollColumn()
|
||||
displayBuffer: @displayBuffer.serialize()
|
||||
|
||||
deserializeParams: (params) ->
|
||||
try
|
||||
displayBuffer = DisplayBuffer.deserialize(params.displayBuffer)
|
||||
catch error
|
||||
if error.syscall is 'read'
|
||||
return # Error reading the file, don't deserialize an editor for it
|
||||
else
|
||||
throw error
|
||||
|
||||
params.displayBuffer = displayBuffer
|
||||
params.registerEditor = true
|
||||
params
|
||||
|
||||
subscribeToBuffer: ->
|
||||
@buffer.retain()
|
||||
@disposables.add @buffer.onDidChangePath =>
|
||||
unless atom.project.getPaths().length > 0
|
||||
atom.project.setPaths([path.dirname(@getPath())])
|
||||
@emit "title-changed" if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-title', @getTitle()
|
||||
@emit "path-changed" if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-path', @getPath()
|
||||
@disposables.add @buffer.onDidChangeEncoding =>
|
||||
@emitter.emit 'did-change-encoding', @getEncoding()
|
||||
@disposables.add @buffer.onDidDestroy => @destroy()
|
||||
|
||||
# TODO: remove these when we remove the deprecations. They are old events.
|
||||
if includeDeprecatedAPIs
|
||||
@subscribe @buffer.onDidStopChanging => @emit "contents-modified"
|
||||
@subscribe @buffer.onDidConflict => @emit "contents-conflicted"
|
||||
@subscribe @buffer.onDidChangeModified => @emit "modified-status-changed"
|
||||
|
||||
@preserveCursorPositionOnBufferReload()
|
||||
|
||||
subscribeToDisplayBuffer: ->
|
||||
@@ -168,22 +144,14 @@ class TextEditor extends Model
|
||||
@disposables.add @displayBuffer.onDidTokenize => @handleTokenization()
|
||||
@disposables.add @displayBuffer.onDidChange (e) =>
|
||||
@mergeIntersectingSelections()
|
||||
@emit 'screen-lines-changed', e if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change', e
|
||||
|
||||
# TODO: remove these when we remove the deprecations. Though, no one is likely using them
|
||||
if includeDeprecatedAPIs
|
||||
@subscribe @displayBuffer.onDidChangeSoftWrapped (softWrapped) => @emit 'soft-wrap-changed', softWrapped
|
||||
@subscribe @displayBuffer.onDidAddDecoration (decoration) => @emit 'decoration-added', decoration
|
||||
@subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration
|
||||
|
||||
subscribeToTabTypeConfig: ->
|
||||
@tabTypeSubscription?.dispose()
|
||||
@tabTypeSubscription = atom.config.observe 'editor.tabType', scope: @getRootScopeDescriptor(), =>
|
||||
@softTabs = @shouldUseSoftTabs(defaultValue: @softTabs)
|
||||
|
||||
destroyed: ->
|
||||
@unsubscribe() if includeDeprecatedAPIs
|
||||
@disposables.dispose()
|
||||
@tabTypeSubscription.dispose()
|
||||
selection.destroy() for selection in @selections.slice()
|
||||
@@ -459,10 +427,17 @@ class TextEditor extends Model
|
||||
@displayBuffer.onDidChangeCharacterWidths(callback)
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@emitter.on 'did-change-scroll-top', callback
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollTop instead.")
|
||||
|
||||
atom.views.getView(this).onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@emitter.on 'did-change-scroll-left', callback
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).onDidChangeScrollLeft(callback)
|
||||
|
||||
onDidRequestAutoscroll: (callback) ->
|
||||
@displayBuffer.onDidRequestAutoscroll(callback)
|
||||
|
||||
# TODO Remove once the tabs package no longer uses .on subscriptions
|
||||
onDidChangeIcon: (callback) ->
|
||||
@@ -551,6 +526,10 @@ class TextEditor extends Model
|
||||
setEditorWidthInChars: (editorWidthInChars) ->
|
||||
@displayBuffer.setEditorWidthInChars(editorWidthInChars)
|
||||
|
||||
# Returns the editor width in characters.
|
||||
getEditorWidthInChars: ->
|
||||
@displayBuffer.getEditorWidthInChars()
|
||||
|
||||
###
|
||||
Section: File Details
|
||||
###
|
||||
@@ -779,7 +758,6 @@ class TextEditor extends Model
|
||||
(selection) =>
|
||||
range = selection.insertText(text, options)
|
||||
didInsertEvent = {text, range}
|
||||
@emit('did-insert-text', didInsertEvent) if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-insert-text', didInsertEvent
|
||||
range
|
||||
, groupingInterval
|
||||
@@ -1131,10 +1109,14 @@ class TextEditor extends Model
|
||||
@buffer.transact(groupingInterval, fn)
|
||||
|
||||
# Deprecated: Start an open-ended transaction.
|
||||
beginTransaction: (groupingInterval) -> @buffer.beginTransaction(groupingInterval)
|
||||
beginTransaction: (groupingInterval) ->
|
||||
Grim.deprecate('Transactions should be performed via TextEditor::transact only')
|
||||
@buffer.beginTransaction(groupingInterval)
|
||||
|
||||
# Deprecated: Commit an open-ended transaction started with {::beginTransaction}.
|
||||
commitTransaction: -> @buffer.commitTransaction()
|
||||
commitTransaction: ->
|
||||
Grim.deprecate('Transactions should be performed via TextEditor::transact only')
|
||||
@buffer.commitTransaction()
|
||||
|
||||
# Extended: Abort an open transaction, undoing any operations performed so far
|
||||
# within the transaction.
|
||||
@@ -1326,9 +1308,6 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns a {Decoration} object
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
if includeDeprecatedAPIs and decorationParams.type is 'gutter' and not decorationParams.gutterName
|
||||
deprecate("Decorations of `type: 'gutter'` have been renamed to `type: 'line-number'`.")
|
||||
decorationParams.type = 'line-number'
|
||||
@displayBuffer.decorateMarker(marker, decorationParams)
|
||||
|
||||
# Essential: Get all the decorations within a screen row range.
|
||||
@@ -1758,7 +1737,6 @@ class TextEditor extends Model
|
||||
@decorateMarker(marker, type: 'line-number', class: 'cursor-line')
|
||||
@decorateMarker(marker, type: 'line-number', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
|
||||
@decorateMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
|
||||
@emit 'cursor-added', cursor if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-cursor', cursor
|
||||
cursor
|
||||
|
||||
@@ -2247,7 +2225,6 @@ class TextEditor extends Model
|
||||
if selection.intersectsBufferRange(selectionBufferRange)
|
||||
return selection
|
||||
else
|
||||
@emit 'selection-added', selection if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-selection', selection
|
||||
selection
|
||||
|
||||
@@ -2264,11 +2241,11 @@ class TextEditor extends Model
|
||||
@consolidateSelections()
|
||||
@getLastSelection().clear(options)
|
||||
|
||||
# Reduce multiple selections to the most recently added selection.
|
||||
# Reduce multiple selections to the least recently added selection.
|
||||
consolidateSelections: ->
|
||||
selections = @getSelections()
|
||||
if selections.length > 1
|
||||
selection.destroy() for selection in selections[0...-1]
|
||||
selection.destroy() for selection in selections[1...(selections.length)]
|
||||
true
|
||||
else
|
||||
false
|
||||
@@ -2367,10 +2344,6 @@ class TextEditor extends Model
|
||||
# Returns a {Boolean} or undefined if no non-comment lines had leading
|
||||
# whitespace.
|
||||
usesSoftTabs: ->
|
||||
# FIXME Remove once this can be specified as a scoped setting in the
|
||||
# language-make package
|
||||
return false if @getGrammar()?.scopeName is 'source.makefile'
|
||||
|
||||
for bufferRow in [0..@buffer.getLastRow()]
|
||||
continue if @displayBuffer.tokenizedBuffer.tokenizedLineForRow(bufferRow).isComment()
|
||||
|
||||
@@ -2661,7 +2634,6 @@ class TextEditor extends Model
|
||||
range = selection.insertText(text, options)
|
||||
|
||||
didInsertEvent = {text, range}
|
||||
@emit('did-insert-text', didInsertEvent) if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-insert-text', didInsertEvent
|
||||
|
||||
# Essential: For each selection, if the selection is empty, cut all characters
|
||||
@@ -2881,25 +2853,27 @@ class TextEditor extends Model
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
@displayBuffer.scrollToScreenPosition(screenPosition, options)
|
||||
|
||||
# Essential: Scrolls the editor to the top
|
||||
scrollToTop: ->
|
||||
@setScrollTop(0)
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")
|
||||
|
||||
atom.views.getView(this).scrollToTop()
|
||||
|
||||
# Essential: Scrolls the editor to the bottom
|
||||
scrollToBottom: ->
|
||||
@setScrollBottom(Infinity)
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")
|
||||
|
||||
atom.views.getView(this).scrollToBottom()
|
||||
|
||||
scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options)
|
||||
|
||||
horizontallyScrollable: -> @displayBuffer.horizontallyScrollable()
|
||||
getHorizontalScrollbarHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.")
|
||||
|
||||
verticallyScrollable: -> @displayBuffer.verticallyScrollable()
|
||||
atom.views.getView(this).getHorizontalScrollbarHeight()
|
||||
|
||||
getHorizontalScrollbarHeight: -> @displayBuffer.getHorizontalScrollbarHeight()
|
||||
setHorizontalScrollbarHeight: (height) -> @displayBuffer.setHorizontalScrollbarHeight(height)
|
||||
getVerticalScrollbarWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getVerticalScrollbarWidth instead.")
|
||||
|
||||
getVerticalScrollbarWidth: -> @displayBuffer.getVerticalScrollbarWidth()
|
||||
setVerticalScrollbarWidth: (width) -> @displayBuffer.setVerticalScrollbarWidth(width)
|
||||
atom.views.getView(this).getVerticalScrollbarWidth()
|
||||
|
||||
pageUp: ->
|
||||
@moveUp(@getRowsPerPage())
|
||||
@@ -2962,25 +2936,21 @@ class TextEditor extends Model
|
||||
@placeholderText = placeholderText
|
||||
@emitter.emit 'did-change-placeholder-text', @placeholderText
|
||||
|
||||
getFirstVisibleScreenRow: (suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.")
|
||||
@getVisibleRowRange()[0]
|
||||
getFirstVisibleScreenRow: ->
|
||||
deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.")
|
||||
atom.views.getView(this).getVisibleRowRange()[0]
|
||||
|
||||
getLastVisibleScreenRow: (suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.")
|
||||
@getVisibleRowRange()[1]
|
||||
getLastVisibleScreenRow: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.")
|
||||
atom.views.getView(this).getVisibleRowRange()[1]
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition, suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
|
||||
@displayBuffer.pixelPositionForBufferPosition(bufferPosition)
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
|
||||
atom.views.getView(this).pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition, suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead")
|
||||
@displayBuffer.pixelPositionForScreenPosition(screenPosition)
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead")
|
||||
atom.views.getView(this).pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
getSelectionMarkerAttributes: ->
|
||||
{type: 'selection', editorId: @id, invalidate: 'never', maintainHistory: true}
|
||||
@@ -3006,38 +2976,110 @@ class TextEditor extends Model
|
||||
getDefaultCharWidth: -> @displayBuffer.getDefaultCharWidth()
|
||||
setDefaultCharWidth: (defaultCharWidth) -> @displayBuffer.setDefaultCharWidth(defaultCharWidth)
|
||||
|
||||
setHeight: (height) -> @displayBuffer.setHeight(height)
|
||||
getHeight: -> @displayBuffer.getHeight()
|
||||
setHeight: (height, reentrant=false) ->
|
||||
if reentrant
|
||||
@displayBuffer.setHeight(height)
|
||||
else
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setHeight instead.")
|
||||
atom.views.getView(this).setHeight(height)
|
||||
|
||||
getHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getHeight instead.")
|
||||
@displayBuffer.getHeight()
|
||||
|
||||
getClientHeight: -> @displayBuffer.getClientHeight()
|
||||
|
||||
setWidth: (width) -> @displayBuffer.setWidth(width)
|
||||
getWidth: -> @displayBuffer.getWidth()
|
||||
setWidth: (width, reentrant=false) ->
|
||||
if reentrant
|
||||
@displayBuffer.setWidth(width)
|
||||
else
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setWidth instead.")
|
||||
atom.views.getView(this).setWidth(width)
|
||||
|
||||
getScrollTop: -> @displayBuffer.getScrollTop()
|
||||
setScrollTop: (scrollTop) -> @displayBuffer.setScrollTop(scrollTop)
|
||||
getWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.")
|
||||
@displayBuffer.getWidth()
|
||||
|
||||
getScrollBottom: -> @displayBuffer.getScrollBottom()
|
||||
setScrollBottom: (scrollBottom) -> @displayBuffer.setScrollBottom(scrollBottom)
|
||||
getScrollRow: -> @scrollRow
|
||||
setScrollRow: (@scrollRow) ->
|
||||
|
||||
getScrollLeft: -> @displayBuffer.getScrollLeft()
|
||||
setScrollLeft: (scrollLeft) -> @displayBuffer.setScrollLeft(scrollLeft)
|
||||
getScrollColumn: -> @scrollColumn
|
||||
setScrollColumn: (@scrollColumn) ->
|
||||
|
||||
getScrollRight: -> @displayBuffer.getScrollRight()
|
||||
setScrollRight: (scrollRight) -> @displayBuffer.setScrollRight(scrollRight)
|
||||
getScrollTop: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.")
|
||||
|
||||
getScrollHeight: -> @displayBuffer.getScrollHeight()
|
||||
getScrollWidth: -> @displayBuffer.getScrollWidth()
|
||||
atom.views.getView(this).getScrollTop()
|
||||
|
||||
getVisibleRowRange: -> @displayBuffer.getVisibleRowRange()
|
||||
setScrollTop: (scrollTop) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollTop instead.")
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) -> @displayBuffer.intersectsVisibleRowRange(startRow, endRow)
|
||||
atom.views.getView(this).setScrollTop(scrollTop)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) -> @displayBuffer.selectionIntersectsVisibleRowRange(selection)
|
||||
getScrollBottom: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollBottom instead.")
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) -> @displayBuffer.screenPositionForPixelPosition(pixelPosition)
|
||||
atom.views.getView(this).getScrollBottom()
|
||||
|
||||
pixelRectForScreenRange: (screenRange) -> @displayBuffer.pixelRectForScreenRange(screenRange)
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollBottom instead.")
|
||||
|
||||
atom.views.getView(this).setScrollBottom(scrollBottom)
|
||||
|
||||
getScrollLeft: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).getScrollLeft()
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).setScrollLeft(scrollLeft)
|
||||
|
||||
getScrollRight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollRight instead.")
|
||||
|
||||
atom.views.getView(this).getScrollRight()
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollRight instead.")
|
||||
|
||||
atom.views.getView(this).setScrollRight(scrollRight)
|
||||
|
||||
getScrollHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollHeight instead.")
|
||||
|
||||
atom.views.getView(this).getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollWidth instead.")
|
||||
|
||||
atom.views.getView(this).getScrollWidth()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).getVisibleRowRange()
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).intersectsVisibleRowRange(startRow, endRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::selectionIntersectsVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).selectionIntersectsVisibleRowRange(selection)
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::screenPositionForPixelPosition instead.")
|
||||
|
||||
atom.views.getView(this).screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::pixelRectForScreenRange instead.")
|
||||
|
||||
atom.views.getView(this).pixelRectForScreenRange(screenRange)
|
||||
|
||||
###
|
||||
Section: Utility
|
||||
@@ -3052,232 +3094,21 @@ class TextEditor extends Model
|
||||
result = true
|
||||
cancel = -> result = false
|
||||
willInsertEvent = {cancel, text}
|
||||
@emit('will-insert-text', willInsertEvent) if includeDeprecatedAPIs
|
||||
@emitter.emit 'will-insert-text', willInsertEvent
|
||||
result
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
TextEditor.delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
|
||||
'$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft',
|
||||
toProperty: 'displayBuffer'
|
||||
###
|
||||
Section: Language Mode Delegated Methods
|
||||
###
|
||||
|
||||
TextEditor::joinLine = ->
|
||||
deprecate("Use TextEditor::joinLines() instead")
|
||||
@joinLines()
|
||||
suggestedIndentForBufferRow: (bufferRow, options) -> @languageMode.suggestedIndentForBufferRow(bufferRow, options)
|
||||
|
||||
TextEditor::scopesAtCursor = ->
|
||||
deprecate 'Use editor.getLastCursor().getScopeDescriptor() instead'
|
||||
@getLastCursor().getScopeDescriptor().getScopesArray()
|
||||
autoIndentBufferRow: (bufferRow, options) -> @languageMode.autoIndentBufferRow(bufferRow, options)
|
||||
|
||||
TextEditor::getCursorScopes = ->
|
||||
deprecate 'Use editor.getLastCursor().getScopeDescriptor() instead'
|
||||
@scopesAtCursor()
|
||||
autoIndentBufferRows: (startRow, endRow) -> @languageMode.autoIndentBufferRows(startRow, endRow)
|
||||
|
||||
TextEditor::getUri = ->
|
||||
deprecate("Use `::getURI` instead")
|
||||
@getURI()
|
||||
autoDecreaseIndentForBufferRow: (bufferRow) -> @languageMode.autoDecreaseIndentForBufferRow(bufferRow)
|
||||
|
||||
TextEditor::lineForBufferRow = (bufferRow) ->
|
||||
deprecate 'Use TextEditor::lineTextForBufferRow(bufferRow) instead'
|
||||
@lineTextForBufferRow(bufferRow)
|
||||
toggleLineCommentForBufferRow: (row) -> @languageMode.toggleLineCommentsForBufferRow(row)
|
||||
|
||||
TextEditor::lineForScreenRow = (screenRow) ->
|
||||
deprecate "TextEditor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use TextEditor::lineTextForScreenRow instead"
|
||||
@tokenizedLineForScreenRow(screenRow)
|
||||
|
||||
TextEditor::linesForScreenRows = (start, end) ->
|
||||
deprecate "Use TextEditor::tokenizedLinesForScreenRows instead"
|
||||
@tokenizedLinesForScreenRows(start, end)
|
||||
|
||||
TextEditor::lineLengthForBufferRow = (row) ->
|
||||
deprecate "Use editor.lineTextForBufferRow(row).length instead"
|
||||
@lineTextForBufferRow(row).length
|
||||
|
||||
TextEditor::duplicateLine = ->
|
||||
deprecate("Use TextEditor::duplicateLines() instead")
|
||||
@duplicateLines()
|
||||
|
||||
TextEditor::scopesForBufferPosition = (bufferPosition) ->
|
||||
deprecate 'Use ::scopeDescriptorForBufferPosition instead. The return value has changed! It now returns a `ScopeDescriptor`'
|
||||
@scopeDescriptorForBufferPosition(bufferPosition).getScopesArray()
|
||||
|
||||
TextEditor::toggleSoftWrap = ->
|
||||
deprecate("Use TextEditor::toggleSoftWrapped instead")
|
||||
@toggleSoftWrapped()
|
||||
|
||||
TextEditor::setSoftWrap = (softWrapped) ->
|
||||
deprecate("Use TextEditor::setSoftWrapped instead")
|
||||
@setSoftWrapped(softWrapped)
|
||||
|
||||
TextEditor::backspaceToBeginningOfWord = ->
|
||||
deprecate("Use TextEditor::deleteToBeginningOfWord() instead")
|
||||
@deleteToBeginningOfWord()
|
||||
|
||||
TextEditor::backspaceToBeginningOfLine = ->
|
||||
deprecate("Use TextEditor::deleteToBeginningOfLine() instead")
|
||||
@deleteToBeginningOfLine()
|
||||
|
||||
TextEditor::getGutterDecorations = (propertyFilter) ->
|
||||
deprecate("Use ::getLineNumberDecorations instead")
|
||||
@getLineNumberDecorations(propertyFilter)
|
||||
|
||||
TextEditor::getCursorScreenRow = ->
|
||||
deprecate('Use `editor.getCursorScreenPosition().row` instead')
|
||||
@getCursorScreenPosition().row
|
||||
|
||||
TextEditor::moveCursorUp = (lineCount) ->
|
||||
deprecate("Use TextEditor::moveUp() instead")
|
||||
@moveUp(lineCount)
|
||||
|
||||
TextEditor::moveCursorDown = (lineCount) ->
|
||||
deprecate("Use TextEditor::moveDown() instead")
|
||||
@moveDown(lineCount)
|
||||
|
||||
TextEditor::moveCursorLeft = ->
|
||||
deprecate("Use TextEditor::moveLeft() instead")
|
||||
@moveLeft()
|
||||
|
||||
TextEditor::moveCursorRight = ->
|
||||
deprecate("Use TextEditor::moveRight() instead")
|
||||
@moveRight()
|
||||
|
||||
TextEditor::moveCursorToBeginningOfLine = ->
|
||||
deprecate("Use TextEditor::moveToBeginningOfLine() instead")
|
||||
@moveToBeginningOfLine()
|
||||
|
||||
TextEditor::moveCursorToBeginningOfScreenLine = ->
|
||||
deprecate("Use TextEditor::moveToBeginningOfScreenLine() instead")
|
||||
@moveToBeginningOfScreenLine()
|
||||
|
||||
TextEditor::moveCursorToFirstCharacterOfLine = ->
|
||||
deprecate("Use TextEditor::moveToFirstCharacterOfLine() instead")
|
||||
@moveToFirstCharacterOfLine()
|
||||
|
||||
TextEditor::moveCursorToEndOfLine = ->
|
||||
deprecate("Use TextEditor::moveToEndOfLine() instead")
|
||||
@moveToEndOfLine()
|
||||
|
||||
TextEditor::moveCursorToEndOfScreenLine = ->
|
||||
deprecate("Use TextEditor::moveToEndOfScreenLine() instead")
|
||||
@moveToEndOfScreenLine()
|
||||
|
||||
TextEditor::moveCursorToBeginningOfWord = ->
|
||||
deprecate("Use TextEditor::moveToBeginningOfWord() instead")
|
||||
@moveToBeginningOfWord()
|
||||
|
||||
TextEditor::moveCursorToEndOfWord = ->
|
||||
deprecate("Use TextEditor::moveToEndOfWord() instead")
|
||||
@moveToEndOfWord()
|
||||
|
||||
TextEditor::moveCursorToTop = ->
|
||||
deprecate("Use TextEditor::moveToTop() instead")
|
||||
@moveToTop()
|
||||
|
||||
TextEditor::moveCursorToBottom = ->
|
||||
deprecate("Use TextEditor::moveToBottom() instead")
|
||||
@moveToBottom()
|
||||
|
||||
TextEditor::moveCursorToBeginningOfNextWord = ->
|
||||
deprecate("Use TextEditor::moveToBeginningOfNextWord() instead")
|
||||
@moveToBeginningOfNextWord()
|
||||
|
||||
TextEditor::moveCursorToPreviousWordBoundary = ->
|
||||
deprecate("Use TextEditor::moveToPreviousWordBoundary() instead")
|
||||
@moveToPreviousWordBoundary()
|
||||
|
||||
TextEditor::moveCursorToNextWordBoundary = ->
|
||||
deprecate("Use TextEditor::moveToNextWordBoundary() instead")
|
||||
@moveToNextWordBoundary()
|
||||
|
||||
TextEditor::moveCursorToBeginningOfNextParagraph = ->
|
||||
deprecate("Use TextEditor::moveToBeginningOfNextParagraph() instead")
|
||||
@moveToBeginningOfNextParagraph()
|
||||
|
||||
TextEditor::moveCursorToBeginningOfPreviousParagraph = ->
|
||||
deprecate("Use TextEditor::moveToBeginningOfPreviousParagraph() instead")
|
||||
@moveToBeginningOfPreviousParagraph()
|
||||
|
||||
TextEditor::getCursor = ->
|
||||
deprecate("Use TextEditor::getLastCursor() instead")
|
||||
@getLastCursor()
|
||||
|
||||
TextEditor::selectLine = ->
|
||||
deprecate('Use TextEditor::selectLinesContainingCursors instead')
|
||||
@selectLinesContainingCursors()
|
||||
|
||||
TextEditor::selectWord = ->
|
||||
deprecate('Use TextEditor::selectWordsContainingCursors instead')
|
||||
@selectWordsContainingCursors()
|
||||
|
||||
TextEditor::getSelection = (index) ->
|
||||
if index?
|
||||
deprecate("Use TextEditor::getSelections()[index] instead when getting a specific selection")
|
||||
@getSelections()[index]
|
||||
else
|
||||
deprecate("Use TextEditor::getLastSelection() instead")
|
||||
@getLastSelection()
|
||||
|
||||
TextEditor::getSoftWrapped = ->
|
||||
deprecate("Use TextEditor::isSoftWrapped instead")
|
||||
@displayBuffer.isSoftWrapped()
|
||||
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
TextEditor::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'title-changed'
|
||||
deprecate("Use TextEditor::onDidChangeTitle instead")
|
||||
when 'path-changed'
|
||||
deprecate("Use TextEditor::onDidChangePath instead")
|
||||
when 'modified-status-changed'
|
||||
deprecate("Use TextEditor::onDidChangeModified instead")
|
||||
when 'soft-wrap-changed'
|
||||
deprecate("Use TextEditor::onDidChangeSoftWrapped instead")
|
||||
when 'grammar-changed'
|
||||
deprecate("Use TextEditor::onDidChangeGrammar instead")
|
||||
when 'character-widths-changed'
|
||||
deprecate("Use TextEditor::onDidChangeCharacterWidths instead")
|
||||
when 'contents-modified'
|
||||
deprecate("Use TextEditor::onDidStopChanging instead")
|
||||
when 'contents-conflicted'
|
||||
deprecate("Use TextEditor::onDidConflict instead")
|
||||
|
||||
when 'will-insert-text'
|
||||
deprecate("Use TextEditor::onWillInsertText instead")
|
||||
when 'did-insert-text'
|
||||
deprecate("Use TextEditor::onDidInsertText instead")
|
||||
|
||||
when 'cursor-added'
|
||||
deprecate("Use TextEditor::onDidAddCursor instead")
|
||||
when 'cursor-removed'
|
||||
deprecate("Use TextEditor::onDidRemoveCursor instead")
|
||||
when 'cursor-moved'
|
||||
deprecate("Use TextEditor::onDidChangeCursorPosition instead")
|
||||
|
||||
when 'selection-added'
|
||||
deprecate("Use TextEditor::onDidAddSelection instead")
|
||||
when 'selection-removed'
|
||||
deprecate("Use TextEditor::onDidRemoveSelection instead")
|
||||
when 'selection-screen-range-changed'
|
||||
deprecate("Use TextEditor::onDidChangeSelectionRange instead")
|
||||
|
||||
when 'decoration-added'
|
||||
deprecate("Use TextEditor::onDidAddDecoration instead")
|
||||
when 'decoration-removed'
|
||||
deprecate("Use TextEditor::onDidRemoveDecoration instead")
|
||||
when 'decoration-updated'
|
||||
deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `TextEditor::decorateMarker()`")
|
||||
when 'decoration-changed'
|
||||
deprecate("Use Marker::onDidChange instead. e.g. `editor::decorateMarker(...).getMarker().onDidChange()`")
|
||||
|
||||
when 'screen-lines-changed'
|
||||
deprecate("Use TextEditor::onDidChange instead")
|
||||
|
||||
when 'scroll-top-changed'
|
||||
deprecate("Use TextEditor::onDidChangeScrollTop instead")
|
||||
when 'scroll-left-changed'
|
||||
deprecate("Use TextEditor::onDidChangeScrollLeft instead")
|
||||
|
||||
else
|
||||
deprecate("TextEditor::on is deprecated. Use documented event subscription methods instead.")
|
||||
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
toggleLineCommentsForBufferRows: (start, end) -> @languageMode.toggleLineCommentsForBufferRows(start, end)
|
||||
|
||||
@@ -3,7 +3,6 @@ _ = require 'underscore-plus'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
{File} = require 'pathwatcher'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
|
||||
# Extended: Handles loading and activating available themes.
|
||||
#
|
||||
@@ -16,35 +15,6 @@ class ThemeManager
|
||||
@lessCache = null
|
||||
@initialLoadComplete = false
|
||||
@packageManager.registerPackageActivator(this, ['theme'])
|
||||
@sheetsByStyleElement = new WeakMap
|
||||
|
||||
stylesElement = document.head.querySelector('atom-styles')
|
||||
stylesElement.onDidAddStyleElement @styleElementAdded.bind(this)
|
||||
stylesElement.onDidRemoveStyleElement @styleElementRemoved.bind(this)
|
||||
stylesElement.onDidUpdateStyleElement @styleElementUpdated.bind(this)
|
||||
|
||||
styleElementAdded: (styleElement) ->
|
||||
{sheet} = styleElement
|
||||
@sheetsByStyleElement.set(styleElement, sheet)
|
||||
@emit 'stylesheet-added', sheet if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-stylesheet', sheet
|
||||
@emit 'stylesheets-changed' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-stylesheets'
|
||||
|
||||
styleElementRemoved: (styleElement) ->
|
||||
sheet = @sheetsByStyleElement.get(styleElement)
|
||||
@emit 'stylesheet-removed', sheet if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-remove-stylesheet', sheet
|
||||
@emit 'stylesheets-changed' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-stylesheets'
|
||||
|
||||
styleElementUpdated: ({sheet}) ->
|
||||
@emit 'stylesheet-removed', sheet if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-remove-stylesheet', sheet
|
||||
@emit 'stylesheet-added', sheet if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-add-stylesheet', sheet
|
||||
@emit 'stylesheets-changed' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-stylesheets'
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
@@ -56,7 +26,6 @@ class ThemeManager
|
||||
# * `callback` {Function}
|
||||
onDidChangeActiveThemes: (callback) ->
|
||||
@emitter.on 'did-change-active-themes', callback
|
||||
@emitter.on 'did-reload-all', callback # TODO: Remove once deprecated pre-1.0 APIs are gone
|
||||
|
||||
###
|
||||
Section: Accessing Available Themes
|
||||
@@ -96,6 +65,13 @@ class ThemeManager
|
||||
Section: Managing Enabled Themes
|
||||
###
|
||||
|
||||
warnForNonExistentThemes: ->
|
||||
themeNames = atom.config.get('core.themes') ? []
|
||||
themeNames = [themeNames] unless _.isArray(themeNames)
|
||||
for themeName in themeNames
|
||||
unless themeName and typeof themeName is 'string' and atom.packages.resolvePackagePath(themeName)
|
||||
console.warn("Enabled theme '#{themeName}' is not installed.")
|
||||
|
||||
# Public: Get the enabled theme names from the config.
|
||||
#
|
||||
# Returns an array of theme names in the order that they should be activated.
|
||||
@@ -105,7 +81,6 @@ class ThemeManager
|
||||
themeNames = themeNames.filter (themeName) ->
|
||||
if themeName and typeof themeName is 'string'
|
||||
return true if atom.packages.resolvePackagePath(themeName)
|
||||
console.warn("Enabled theme '#{themeName}' is not installed.")
|
||||
false
|
||||
|
||||
# Use a built-in syntax and UI theme any time the configured themes are not
|
||||
@@ -264,6 +239,8 @@ class ThemeManager
|
||||
atom.config.observe 'core.themes', =>
|
||||
@deactivateThemes()
|
||||
|
||||
@warnForNonExistentThemes()
|
||||
|
||||
@refreshLessCache() # Update cache for packages in core.themes config
|
||||
|
||||
promises = []
|
||||
@@ -279,7 +256,6 @@ class ThemeManager
|
||||
@loadUserStylesheet()
|
||||
@reloadBaseStylesheets()
|
||||
@initialLoadComplete = true
|
||||
@emit 'reloaded' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change-active-themes'
|
||||
resolve()
|
||||
|
||||
@@ -292,10 +268,10 @@ class ThemeManager
|
||||
isInitialLoadComplete: -> @initialLoadComplete
|
||||
|
||||
addActiveThemeClasses: ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.add("theme-#{pack.name}")
|
||||
return
|
||||
if workspaceElement = atom.views.getView(atom.workspace)
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.add("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
removeActiveThemeClasses: ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
@@ -321,59 +297,3 @@ class ThemeManager
|
||||
themePaths.push(path.join(themePath, 'styles'))
|
||||
|
||||
themePaths.filter (themePath) -> fs.isDirectorySync(themePath)
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
EmitterMixin.includeInto(ThemeManager)
|
||||
|
||||
ThemeManager::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'reloaded'
|
||||
Grim.deprecate 'Use ThemeManager::onDidChangeActiveThemes instead'
|
||||
when 'stylesheet-added'
|
||||
Grim.deprecate 'Use ThemeManager::onDidAddStylesheet instead'
|
||||
when 'stylesheet-removed'
|
||||
Grim.deprecate 'Use ThemeManager::onDidRemoveStylesheet instead'
|
||||
when 'stylesheet-updated'
|
||||
Grim.deprecate 'Use ThemeManager::onDidUpdateStylesheet instead'
|
||||
when 'stylesheets-changed'
|
||||
Grim.deprecate 'Use ThemeManager::onDidChangeStylesheets instead'
|
||||
else
|
||||
Grim.deprecate 'ThemeManager::on is deprecated. Use event subscription methods instead.'
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
ThemeManager::onDidReloadAll = (callback) ->
|
||||
Grim.deprecate("Use `::onDidChangeActiveThemes` instead.")
|
||||
@onDidChangeActiveThemes(callback)
|
||||
|
||||
ThemeManager::onDidAddStylesheet = (callback) ->
|
||||
Grim.deprecate("Use atom.styles.onDidAddStyleElement instead")
|
||||
@emitter.on 'did-add-stylesheet', callback
|
||||
|
||||
ThemeManager::onDidRemoveStylesheet = (callback) ->
|
||||
Grim.deprecate("Use atom.styles.onDidRemoveStyleElement instead")
|
||||
@emitter.on 'did-remove-stylesheet', callback
|
||||
|
||||
ThemeManager::onDidUpdateStylesheet = (callback) ->
|
||||
Grim.deprecate("Use atom.styles.onDidUpdateStyleElement instead")
|
||||
@emitter.on 'did-update-stylesheet', callback
|
||||
|
||||
ThemeManager::onDidChangeStylesheets = (callback) ->
|
||||
Grim.deprecate("Use atom.styles.onDidAdd/RemoveStyleElement instead")
|
||||
@emitter.on 'did-change-stylesheets', callback
|
||||
|
||||
ThemeManager::getUserStylesheetPath = ->
|
||||
Grim.deprecate("Call atom.styles.getUserStyleSheetPath() instead")
|
||||
atom.styles.getUserStyleSheetPath()
|
||||
|
||||
ThemeManager::getLoadedNames = ->
|
||||
Grim.deprecate("Use `::getLoadedThemeNames` instead.")
|
||||
@getLoadedThemeNames()
|
||||
|
||||
ThemeManager::getActiveNames = ->
|
||||
Grim.deprecate("Use `::getActiveThemeNames` instead.")
|
||||
@getActiveThemeNames()
|
||||
|
||||
ThemeManager::setEnabledThemes = (enabledThemeNames) ->
|
||||
Grim.deprecate("Use `atom.config.set('core.themes', arrayOfThemeNames)` instead")
|
||||
atom.config.set('core.themes', enabledThemeNames)
|
||||
|
||||
@@ -2,18 +2,14 @@ _ = require 'underscore-plus'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{ScopeSelector} = require 'first-mate'
|
||||
Serializable = require 'serializable'
|
||||
Model = require './model'
|
||||
TokenizedLine = require './tokenized-line'
|
||||
TokenIterator = require './token-iterator'
|
||||
Token = require './token'
|
||||
ScopeDescriptor = require './scope-descriptor'
|
||||
Grim = require 'grim'
|
||||
|
||||
module.exports =
|
||||
class TokenizedBuffer extends Model
|
||||
Serializable.includeInto(this)
|
||||
|
||||
grammar: null
|
||||
currentGrammarScore: null
|
||||
buffer: null
|
||||
@@ -25,6 +21,10 @@ class TokenizedBuffer extends Model
|
||||
configSettings: null
|
||||
changeCount: 0
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.buffer = atom.project.bufferForPathSync(state.bufferPath)
|
||||
new this(state)
|
||||
|
||||
constructor: ({@buffer, @tabLength, @ignoreInvisibles, @largeFileMode}) ->
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
@@ -41,16 +41,13 @@ class TokenizedBuffer extends Model
|
||||
destroyed: ->
|
||||
@disposables.dispose()
|
||||
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
deserializer: 'TokenizedBuffer'
|
||||
bufferPath: @buffer.getPath()
|
||||
tabLength: @tabLength
|
||||
ignoreInvisibles: @ignoreInvisibles
|
||||
largeFileMode: @largeFileMode
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.buffer = atom.project.bufferForPathSync(params.bufferPath)
|
||||
params
|
||||
|
||||
observeGrammar: (callback) ->
|
||||
callback(@grammar)
|
||||
@onDidChangeGrammar(callback)
|
||||
@@ -128,7 +125,6 @@ class TokenizedBuffer extends Model
|
||||
@invalidateRow(0)
|
||||
@fullyTokenized = false
|
||||
event = {start: 0, end: lastRow, delta: 0}
|
||||
@emit 'changed', event if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change', event
|
||||
|
||||
setVisible: (@visible) ->
|
||||
@@ -191,7 +187,6 @@ class TokenizedBuffer extends Model
|
||||
[startRow, endRow] = @updateFoldableStatus(startRow, endRow)
|
||||
|
||||
event = {start: startRow, end: endRow, delta: 0}
|
||||
@emit 'changed', event if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change', event
|
||||
|
||||
if @firstInvalidRow()?
|
||||
@@ -201,7 +196,6 @@ class TokenizedBuffer extends Model
|
||||
|
||||
markTokenizationComplete: ->
|
||||
unless @fullyTokenized
|
||||
@emit 'tokenized' if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-tokenize'
|
||||
@fullyTokenized = true
|
||||
|
||||
@@ -255,7 +249,6 @@ class TokenizedBuffer extends Model
|
||||
end -= delta
|
||||
|
||||
event = {start, end, delta, bufferChange: e}
|
||||
@emit 'changed', event if Grim.includeDeprecatedAPIs
|
||||
@emitter.emit 'did-change', event
|
||||
|
||||
retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) ->
|
||||
@@ -539,22 +532,6 @@ class TokenizedBuffer extends Model
|
||||
console.log row, line, line.length
|
||||
return
|
||||
|
||||
if Grim.includeDeprecatedAPIs
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
|
||||
TokenizedBuffer::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'changed'
|
||||
Grim.deprecate("Use TokenizedBuffer::onDidChange instead")
|
||||
when 'grammar-changed'
|
||||
Grim.deprecate("Use TokenizedBuffer::onDidChangeGrammar instead")
|
||||
when 'tokenized'
|
||||
Grim.deprecate("Use TokenizedBuffer::onDidTokenize instead")
|
||||
else
|
||||
Grim.deprecate("TokenizedBuffer::on is deprecated. Use event subscription methods instead.")
|
||||
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
selectorMatchesAnyScope = (selector, scopes) ->
|
||||
targetClasses = selector.replace(/^\./, '').split('.')
|
||||
_.any scopes, (scope) ->
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
{includeDeprecatedAPIs, deprecate} = require 'grim'
|
||||
_ = require 'underscore-plus'
|
||||
path = require 'path'
|
||||
{join} = path
|
||||
Serializable = require 'serializable'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
fs = require 'fs-plus'
|
||||
DefaultDirectorySearcher = require './default-directory-searcher'
|
||||
Model = require './model'
|
||||
@@ -30,15 +27,22 @@ Task = require './task'
|
||||
module.exports =
|
||||
class Workspace extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
@deserialize: (state) ->
|
||||
return unless state?
|
||||
|
||||
for packageName in state.packagesWithActiveGrammars ? []
|
||||
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
|
||||
|
||||
state.paneContainer = PaneContainer.deserialize(state.paneContainer)
|
||||
new this(state)
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
unless Grim.includeDeprecatedAPIs
|
||||
@paneContainer = params?.paneContainer
|
||||
@fullScreen = params?.fullScreen ? false
|
||||
@destroyedItemURIs = params?.destroyedItemURIs ? []
|
||||
@paneContainer = params?.paneContainer
|
||||
@fullScreen = params?.fullScreen ? false
|
||||
@destroyedItemURIs = params?.destroyedItemURIs ? []
|
||||
|
||||
@emitter = new Emitter
|
||||
@openers = []
|
||||
@@ -84,16 +88,9 @@ class Workspace extends Model
|
||||
|
||||
@subscribeToFontSize()
|
||||
|
||||
# Called by the Serializable mixin during deserialization
|
||||
deserializeParams: (params) ->
|
||||
for packageName in params.packagesWithActiveGrammars ? []
|
||||
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
|
||||
|
||||
params.paneContainer = PaneContainer.deserialize(params.paneContainer)
|
||||
params
|
||||
|
||||
# Called by the Serializable mixin during serialization.
|
||||
serializeParams: ->
|
||||
serialize: ->
|
||||
deserializer: 'Workspace'
|
||||
paneContainer: @paneContainer.serialize()
|
||||
fullScreen: atom.isFullScreen()
|
||||
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
|
||||
@@ -120,10 +117,11 @@ class Workspace extends Model
|
||||
_.uniq(packageNames)
|
||||
|
||||
editorAdded: (editor) ->
|
||||
@emit 'editor-created', editor if includeDeprecatedAPIs
|
||||
|
||||
installShellCommands: ->
|
||||
require('./command-installer').installShellCommandsInteractively()
|
||||
CommandInstaller = require('./command-installer')
|
||||
commandInstaller = new CommandInstaller(atom.getVersion())
|
||||
commandInstaller.installShellCommandsInteractively()
|
||||
|
||||
subscribeToActiveItem: ->
|
||||
@updateWindowTitle()
|
||||
@@ -409,12 +407,6 @@ class Workspace extends Model
|
||||
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# the containing pane. Defaults to `true`.
|
||||
openSync: (uri='', options={}) ->
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
if includeDeprecatedAPIs and options.changeFocus?
|
||||
deprecate("The `changeFocus` option has been renamed to `activatePane`")
|
||||
options.activatePane = options.changeFocus
|
||||
delete options.changeFocus
|
||||
|
||||
{initialLine, initialColumn} = options
|
||||
activatePane = options.activatePane ? true
|
||||
|
||||
@@ -430,12 +422,6 @@ class Workspace extends Model
|
||||
item
|
||||
|
||||
openURIInPane: (uri, pane, options={}) ->
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
if includeDeprecatedAPIs and options.changeFocus?
|
||||
deprecate("The `changeFocus` option has been renamed to `activatePane`")
|
||||
options.activatePane = options.changeFocus
|
||||
delete options.changeFocus
|
||||
|
||||
activatePane = options.activatePane ? true
|
||||
|
||||
if uri?
|
||||
@@ -475,7 +461,6 @@ class Workspace extends Model
|
||||
item.setCursorBufferPosition?([initialLine, initialColumn])
|
||||
|
||||
index = pane.getActiveItemIndex()
|
||||
@emit "uri-opened" if includeDeprecatedAPIs
|
||||
@emitter.emit 'did-open', {uri, pane, item, index}
|
||||
item
|
||||
|
||||
@@ -515,24 +500,8 @@ class Workspace extends Model
|
||||
# {Workspace::open} on the URI `quux-preview://foo/bar/baz.quux`. Then your opener
|
||||
# can check the protocol for quux-preview and only handle those URIs that match.
|
||||
addOpener: (opener) ->
|
||||
if includeDeprecatedAPIs
|
||||
packageName = @getCallingPackageName()
|
||||
|
||||
wrappedOpener = (uri, options) ->
|
||||
item = opener(uri, options)
|
||||
if item? and typeof item.getUri is 'function' and typeof item.getURI isnt 'function'
|
||||
Grim.deprecate("Pane item with class `#{item.constructor.name}` should implement `::getURI` instead of `::getUri`.", {packageName})
|
||||
if item? and typeof item.on is 'function' and typeof item.onDidChangeTitle isnt 'function'
|
||||
Grim.deprecate("If you would like your pane item with class `#{item.constructor.name}` to support title change behavior, please implement a `::onDidChangeTitle()` method. `::on` methods for items are no longer supported. If not, ignore this message.", {packageName})
|
||||
if item? and typeof item.on is 'function' and typeof item.onDidChangeModified isnt 'function'
|
||||
Grim.deprecate("If you would like your pane item with class `#{item.constructor.name}` to support modified behavior, please implement a `::onDidChangeModified()` method. If not, ignore this message. `::on` methods for items are no longer supported.", {packageName})
|
||||
item
|
||||
|
||||
@openers.push(wrappedOpener)
|
||||
new Disposable => _.remove(@openers, wrappedOpener)
|
||||
else
|
||||
@openers.push(opener)
|
||||
new Disposable => _.remove(@openers, opener)
|
||||
@openers.push(opener)
|
||||
new Disposable => _.remove(@openers, opener)
|
||||
|
||||
getOpeners: ->
|
||||
@openers
|
||||
@@ -933,7 +902,7 @@ class Workspace extends Model
|
||||
#
|
||||
# Returns a `Promise`.
|
||||
replace: (regex, replacementText, filePaths, iterator) ->
|
||||
new Promise (resolve, reject) =>
|
||||
new Promise (resolve, reject) ->
|
||||
openPaths = (buffer.getPath() for buffer in atom.project.getBuffers())
|
||||
outOfProcessPaths = _.difference(filePaths, openPaths)
|
||||
|
||||
@@ -960,96 +929,3 @@ class Workspace extends Model
|
||||
|
||||
inProcessFinished = true
|
||||
checkFinished()
|
||||
|
||||
if includeDeprecatedAPIs
|
||||
Workspace.properties
|
||||
paneContainer: null
|
||||
fullScreen: false
|
||||
destroyedItemURIs: -> []
|
||||
|
||||
Object.defineProperty Workspace::, 'activePaneItem',
|
||||
get: ->
|
||||
Grim.deprecate "Use ::getActivePaneItem() instead of the ::activePaneItem property"
|
||||
@getActivePaneItem()
|
||||
|
||||
Object.defineProperty Workspace::, 'activePane',
|
||||
get: ->
|
||||
Grim.deprecate "Use ::getActivePane() instead of the ::activePane property"
|
||||
@getActivePane()
|
||||
|
||||
StackTraceParser = require 'stacktrace-parser'
|
||||
|
||||
Workspace::getCallingPackageName = ->
|
||||
error = new Error
|
||||
Error.captureStackTrace(error)
|
||||
stack = StackTraceParser.parse(error.stack)
|
||||
|
||||
packagePaths = @getPackagePathsByPackageName()
|
||||
|
||||
for i in [0...stack.length]
|
||||
stackFramePath = stack[i].file
|
||||
|
||||
# Empty when it was run from the dev console
|
||||
return unless stackFramePath
|
||||
|
||||
for packageName, packagePath of packagePaths
|
||||
continue if stackFramePath is 'node.js'
|
||||
relativePath = path.relative(packagePath, stackFramePath)
|
||||
return packageName unless /^\.\./.test(relativePath)
|
||||
return
|
||||
|
||||
Workspace::getPackagePathsByPackageName = ->
|
||||
packagePathsByPackageName = {}
|
||||
for pack in atom.packages.getLoadedPackages()
|
||||
packagePath = pack.path
|
||||
if packagePath.indexOf('.atom/dev/packages') > -1 or packagePath.indexOf('.atom/packages') > -1
|
||||
packagePath = fs.realpathSync(packagePath)
|
||||
packagePathsByPackageName[pack.name] = packagePath
|
||||
packagePathsByPackageName
|
||||
|
||||
Workspace::eachEditor = (callback) ->
|
||||
deprecate("Use Workspace::observeTextEditors instead")
|
||||
|
||||
callback(editor) for editor in @getEditors()
|
||||
@subscribe this, 'editor-created', (editor) -> callback(editor)
|
||||
|
||||
Workspace::getEditors = ->
|
||||
deprecate("Use Workspace::getTextEditors instead")
|
||||
|
||||
editors = []
|
||||
for pane in @paneContainer.getPanes()
|
||||
editors.push(item) for item in pane.getItems() when item instanceof TextEditor
|
||||
|
||||
editors
|
||||
|
||||
Workspace::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'editor-created'
|
||||
deprecate("Use Workspace::onDidAddTextEditor or Workspace::observeTextEditors instead.")
|
||||
when 'uri-opened'
|
||||
deprecate("Use Workspace::onDidOpen or Workspace::onDidAddPaneItem instead. https://atom.io/docs/api/latest/Workspace#instance-onDidOpen")
|
||||
else
|
||||
deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.")
|
||||
|
||||
super
|
||||
|
||||
Workspace::reopenItemSync = ->
|
||||
deprecate("Use Workspace::reopenItem instead")
|
||||
if uri = @destroyedItemURIs.pop()
|
||||
@openSync(uri)
|
||||
|
||||
Workspace::registerOpener = (opener) ->
|
||||
Grim.deprecate("Call Workspace::addOpener instead")
|
||||
@addOpener(opener)
|
||||
|
||||
Workspace::unregisterOpener = (opener) ->
|
||||
Grim.deprecate("Call .dispose() on the Disposable returned from ::addOpener instead")
|
||||
_.remove(@openers, opener)
|
||||
|
||||
Workspace::getActiveEditor = ->
|
||||
Grim.deprecate "Call ::getActiveTextEditor instead"
|
||||
@getActivePane()?.getActiveEditor()
|
||||
|
||||
Workspace::paneForUri = (uri) ->
|
||||
deprecate("Use ::paneForURI instead.")
|
||||
@paneForURI(uri)
|
||||
|
||||
@@ -64,9 +64,6 @@
|
||||
ModuleCache.register(loadSettings)
|
||||
ModuleCache.add(loadSettings.resourcePath)
|
||||
|
||||
// Only include deprecated APIs when running core spec
|
||||
require('grim').includeDeprecatedAPIs = isRunningCoreSpecs(loadSettings)
|
||||
|
||||
// Start the crash reporter before anything else.
|
||||
require('crash-reporter').start({
|
||||
productName: 'Atom',
|
||||
@@ -184,14 +181,6 @@
|
||||
}, false)
|
||||
}
|
||||
|
||||
function isRunningCoreSpecs (loadSettings) {
|
||||
return !!(loadSettings &&
|
||||
loadSettings.isSpec &&
|
||||
loadSettings.specDirectory &&
|
||||
loadSettings.resourcePath &&
|
||||
path.dirname(loadSettings.specDirectory) === loadSettings.resourcePath)
|
||||
}
|
||||
|
||||
parseLoadSettings()
|
||||
setupWindowBackground()
|
||||
})()
|
||||
|
||||
Reference in New Issue
Block a user