Merge branch 'master' into mb-fix-undo-stack-on-reload-again

This commit is contained in:
Max Brunsfeld
2015-09-15 14:33:28 -07:00
22 changed files with 282 additions and 119 deletions

View File

@@ -234,6 +234,7 @@ Please open an issue on `atom/atom` if you have suggestions for new labels, and
| `installer` | [search][search-atom-repo-label-installer] | [search][search-atom-org-label-installer] | Related to the Atom installers for different OSes. |
| `auto-updater` | [search][search-atom-repo-label-auto-updater] | [search][search-atom-org-label-auto-updater] | Related to the auto-updater for different OSes. |
| `deprecation-help` | [search][search-atom-repo-label-deprecation-help] | [search][search-atom-org-label-deprecation-help] | Issues for helping package authors remove usage of deprecated APIs in packages. |
| `electron` | [search][search-atom-repo-label-electron] | [search][search-atom-org-label-electron] | Issues that require changes to [Electron](https://electron.atom.io) to fix or implement. |
#### Core Team Project Management
@@ -329,6 +330,8 @@ Please open an issue on `atom/atom` if you have suggestions for new labels, and
[search-atom-org-label-auto-updater]: https://github.com/issues?q=is%3Aopen+is%3Aissue+user%3Aatom+label%3Aauto-updater
[search-atom-repo-label-deprecation-help]: https://github.com/issues?q=is%3Aopen+is%3Aissue+repo%3Aatom%2Fatom+label%3Adeprecation-help
[search-atom-org-label-deprecation-help]: https://github.com/issues?q=is%3Aopen+is%3Aissue+user%3Aatom+label%3Adeprecation-help
[search-atom-repo-label-electron]: https://github.com/issues?q=is%3Aissue+repo%3Aatom%2Fatom+is%3Aopen+label%3Aelectron
[search-atom-org-label-electron]: https://github.com/issues?q=is%3Aopen+is%3Aissue+user%3Aatom+label%3Aelectron
[search-atom-repo-label-on-deck]: https://github.com/issues?q=is%3Aopen+is%3Aissue+repo%3Aatom%2Fatom+label%3Aon-deck
[search-atom-org-label-on-deck]: https://github.com/issues?q=is%3Aopen+is%3Aissue+user%3Aatom+label%3Aon-deck
[search-atom-repo-label-in-progress]: https://github.com/issues?q=is%3Aopen+is%3Aissue+repo%3Aatom%2Fatom+label%3Ain-progress

View File

@@ -11,7 +11,7 @@
"donna": "1.0.10",
"formidable": "~1.0.14",
"fs-plus": "2.x",
"github-releases": "~0.2.0",
"github-releases": "~0.3.0",
"glob": "^5.0.14",
"grunt": "~0.4.1",
"grunt-babel": "^5.0.1",
@@ -22,7 +22,7 @@
"grunt-contrib-less": "~0.8.0",
"grunt-cson": "0.15.0",
"grunt-download-electron": "^2.1.1",
"grunt-electron-installer": "1.0.0",
"grunt-electron-installer": "1.0.3-0",
"grunt-lesslint": "0.17.0",
"grunt-peg": "~1.1.0",
"grunt-shell": "~0.3.1",

View File

@@ -24,6 +24,13 @@ module.exports = (grunt) ->
return done("Unsupported arch #{process.arch}")
{name, version, description} = grunt.file.readJSON('package.json')
# RPM versions can't have dashes in them.
# * http://www.rpm.org/max-rpm/ch-rpm-file-format.html
# * https://github.com/mojombo/semver/issues/145
version = version.replace(/-beta$/, "~beta")
version = version.replace(/-dev$/, "~dev")
buildDir = grunt.config.get('atom.buildDir')
rpmDir = path.join(buildDir, 'rpm')

View File

@@ -22,7 +22,7 @@ module.exports = (gruntObject) ->
grunt.registerTask 'publish-build', 'Publish the built app', ->
tasks = []
tasks.push('build-docs', 'prepare-docs') if process.platform is 'darwin'
tasks.push('upload-assets') if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH is 'master'
tasks.push('upload-assets')
grunt.task.run(tasks)
grunt.registerTask 'prepare-docs', 'Move api.json to atom-api.json', ->
@@ -31,6 +31,14 @@ 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
when 'stable'
isPrerelease = false
when 'beta'
isPrerelease = true
else
return
doneCallback = @async()
startTime = Date.now()
done = (args...) ->
@@ -46,7 +54,7 @@ module.exports = (gruntObject) ->
zipAssets buildDir, assets, (error) ->
return done(error) if error?
getAtomDraftRelease (error, release) ->
getAtomDraftRelease isPrerelease, (error, release) ->
return done(error) if error?
assetNames = (asset.assetName for asset in assets)
deleteExistingAssets release, assetNames, (error) ->
@@ -120,9 +128,9 @@ zipAssets = (buildDir, assets, callback) ->
tasks.push(zip.bind(this, buildDir, sourcePath, assetName))
async.parallel(tasks, callback)
getAtomDraftRelease = (callback) ->
getAtomDraftRelease = (isPrerelease, callback) ->
atomRepo = new GitHub({repo: 'atom/atom', token})
atomRepo.getReleases (error, releases=[]) ->
atomRepo.getReleases {prerelease: isPrerelease}, (error, releases=[]) ->
if error?
logError('Fetching atom/atom releases failed', error, releases)
callback(error)
@@ -142,9 +150,9 @@ getAtomDraftRelease = (callback) ->
firstDraft.assets = assets
callback(null, firstDraft)
else
createAtomDraftRelease(callback)
createAtomDraftRelease(isPrerelease, callback)
createAtomDraftRelease = (callback) ->
createAtomDraftRelease = (isPrerelease, callback) ->
{version} = require('../../package.json')
options =
uri: 'https://api.github.com/repos/atom/atom/releases'
@@ -152,6 +160,7 @@ createAtomDraftRelease = (callback) ->
headers: defaultHeaders
json:
tag_name: "v#{version}"
prerelease: isPrerelease
name: version
draft: true
body: """

View File

@@ -5,7 +5,7 @@ module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
getVersion = (callback) ->
onBuildMachine = process.env.JANKY_SHA1 and process.env.JANKY_BRANCH is 'master'
onBuildMachine = process.env.JANKY_SHA1 and process.env.JANKY_BRANCH in ['stable', 'beta']
inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git'))
{version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json'))
if onBuildMachine or not inRepository

View File

@@ -14,19 +14,19 @@
If it is installed elsewhere, you can create a symbolic link to the
directory containing the python.exe using:
`mklink /d %SystemDrive%\Python27 D:\elsewhere\Python27`
* [GitHub for Windows](http://windows.github.com/)
* [GitHub Desktop](http://desktop.github.com/)
### 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)
* [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 for Windows](http://windows.github.com/)
* [GitHub Desktop](http://desktop.github.com/)
## Instructions
```bash
# Use the `Git Shell` program which was installed by GitHub for Windows.
# Also make sure that you are logged into GitHub for Windows.
# Use the `Git Shell` program which was installed by GitHub Desktop.
# Also make sure that you are logged into GitHub Desktop.
cd C:\
git clone https://github.com/atom/atom/
cd atom
@@ -40,15 +40,14 @@ We will assume the git shell for these instructions.
* `--build-dir` - Build the application in this directory.
* `--verbose` - Verbose mode. A lot more information output.
## Why do I have to use GitHub for Windows?
## Why do I have to use GitHub Desktop?
You don't. You can use your existing Git! GitHub for Windows's Git Shell is just
easier to set up.
You don't. You can use your existing Git! GitHub Desktop's Git Shell is just easier to set up.
If you _prefer_ using your existing Git installation, make sure git's cmd directory is in your PATH env variable (e.g. `C:\Program Files (x86)\Git\cmd`) before you open your powershell or command window.
Note that you may have to open your command window as administrator. For powershell that doesn't seem to always be the case, though.
If none of this works, do install Github for Windows and use its Git shell. Makes life easier.
If none of this works, do install Github Desktop and use its Git shell. Makes life easier.
## Troubleshooting
@@ -59,7 +58,6 @@ If none of this works, do install Github for Windows and use its Git shell. Make
* If you just installed node, you'll need to restart your computer before node is
available on your Path.
* `script/build` outputs only the Node and Python versions before returning
* Try moving the repository to `C:\atom`. Most likely, the path is too long.
@@ -73,7 +71,7 @@ If none of this works, do install Github for Windows and use its Git shell. Make
* https://github.com/TooTallNate/node-gyp/issues/297
* https://code.google.com/p/gyp/issues/detail?id=393
* `script/build` stops at installing runas with 'Failed at the runas@0.5.4 install script.'
* `script/build` stops at installing runas with 'Failed at the runas@x.y.z install script.'
See the next item.

View File

@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "1.0.12",
"version": "1.0.12-dev",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -92,7 +92,7 @@
"dev-live-reload": "0.46.0",
"encoding-selector": "0.21.0",
"exception-reporting": "0.36.0",
"find-and-replace": "0.180.0",
"find-and-replace": "0.181.0",
"fuzzy-finder": "0.88.0",
"git-diff": "0.56.0",
"go-to-line": "0.30.0",
@@ -124,7 +124,7 @@
"language-c": "0.47.1",
"language-clojure": "0.16.0",
"language-coffee-script": "0.41.0",
"language-csharp": "0.9.0",
"language-csharp": "0.10.0",
"language-css": "0.34.0",
"language-gfm": "0.81.0",
"language-git": "0.10.0",
@@ -132,20 +132,20 @@
"language-html": "0.41.2",
"language-hyperlink": "0.14.0",
"language-java": "0.16.0",
"language-javascript": "0.93.0",
"language-javascript": "0.94.0",
"language-json": "0.16.0",
"language-less": "0.28.2",
"language-make": "0.17.0",
"language-mustache": "0.12.0",
"language-objective-c": "0.15.0",
"language-perl": "0.28.0",
"language-php": "0.29.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.57.0",
"language-ruby": "0.58.0",
"language-ruby-on-rails": "0.22.0",
"language-sass": "0.41.0",
"language-shellscript": "0.16.0",
"language-shellscript": "0.17.0",
"language-source": "0.9.0",
"language-sql": "0.17.0",
"language-text": "0.7.0",

89
script/railcar Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env node
var fs = require('fs')
var exec = require('child_process').exec
var series = require('async').series
var semver = require('semver')
series([
section('Preparing to roll the railcars'),
checkCleanWorkingTree,
run('git fetch origin master:master beta:beta stable:stable'),
run('git fetch origin --tags'),
section('Updating stable branch'),
run('git checkout stable'),
run('git merge --ff-only origin/stable'),
run('git merge --ff-only origin/beta'),
bumpStableVersion,
section('Updating beta branch'),
run('git checkout beta'),
run('git merge --ff-only origin/beta'),
run('git merge --ff-only origin/master'),
run('git merge --strategy ours origin/stable'),
bumpBetaVersion,
section('Updating master branch'),
run('git checkout master'),
run('git merge --ff-only origin/master'),
run('git merge --strategy ours origin/beta'),
bumpDevVersion,
section('Pushing changes upstream'),
run('git push origin master:master beta:beta stable:stable'),
run('git push origin --tags')
], finish)
function checkCleanWorkingTree (next) {
run('git status --porcelain')(function (error, output) {
if (error) return next(error)
if (output.trim().length > 0) return next(new Error('Cannot run the railcars with a dirty working tree'))
next()
})
}
function bumpStableVersion (next) {
run('npm version patch')(next)
}
function bumpBetaVersion (next) {
var newVersion = semver.inc(getCurrentVersion(), 'prerelease', 'beta')
run('npm version ' + newVersion)(next)
}
function bumpDevVersion (next) {
var newVersion = semver.inc(getCurrentVersion(), 'preminor', 'dev')
series([
run('npm --no-git-tag-version version ' + newVersion),
run('git commit -am "' + newVersion + '"')
], next)
}
function finish (error) {
if (error) {
console.log('Error: ' + error.message)
process.exit(1)
}
console.log('OK, now just wait for all CI builds to pass on beta and stable')
}
function getCurrentVersion () {
return JSON.parse(fs.readFileSync(require.resolve('../package.json'))).version
}
function run (command) {
return function (next) {
console.log('>', command)
exec(command, next)
}
}
function section (message) {
return function (next) {
console.log()
console.log(message)
next()
}
}

View File

@@ -108,7 +108,7 @@ describe "TextEditorComponent", ->
component.measureDimensions()
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
expect(tilesNodes[0].style.zIndex).toBe("2")
expect(tilesNodes[1].style.zIndex).toBe("1")
@@ -118,7 +118,7 @@ describe "TextEditorComponent", ->
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
expect(tilesNodes[0].style.zIndex).toBe("3")
expect(tilesNodes[1].style.zIndex).toBe("2")
@@ -130,7 +130,7 @@ describe "TextEditorComponent", ->
component.measureDimensions()
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
expect(tilesNodes.length).toBe(3)
@@ -158,7 +158,7 @@ describe "TextEditorComponent", ->
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
expect(component.lineNodeForScreenRow(2)).toBeUndefined()
expect(tilesNodes.length).toBe(3)
@@ -187,7 +187,7 @@ describe "TextEditorComponent", ->
editor.getBuffer().deleteRows(0, 1)
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels)
@@ -202,7 +202,7 @@ describe "TextEditorComponent", ->
editor.getBuffer().insert([0, 0], '\n\n')
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels)
@@ -294,7 +294,7 @@ describe "TextEditorComponent", ->
editorFullWidth = editor.getScrollWidth() + editor.getVerticalScrollbarWidth()
for lineNode in lineNodes
expect(lineNode.style.width).toBe editorFullWidth + 'px'
expect(lineNode.getBoundingClientRect().width).toBe(editorFullWidth)
componentNode.style.width = gutterWidth + editor.getScrollWidth() + 100 + 'px'
component.measureDimensions()
@@ -302,7 +302,7 @@ describe "TextEditorComponent", ->
scrollViewWidth = scrollViewNode.offsetWidth
for lineNode in lineNodes
expect(lineNode.style.width).toBe scrollViewWidth + 'px'
expect(lineNode.getBoundingClientRect().width).toBe(scrollViewWidth)
it "renders an nbsp on empty lines when no line-ending character is defined", ->
atom.config.set("editor.showInvisibles", false)
@@ -313,7 +313,7 @@ describe "TextEditorComponent", ->
backgroundColor = getComputedStyle(wrapperNode).backgroundColor
expect(linesNode.style.backgroundColor).toBe backgroundColor
for tileNode in linesNode.querySelectorAll(".tile")
for tileNode in component.tileNodesForLines()
expect(tileNode.style.backgroundColor).toBe(backgroundColor)
wrapperNode.style.backgroundColor = 'rgb(255, 0, 0)'
@@ -322,7 +322,7 @@ describe "TextEditorComponent", ->
advanceClock(atom.views.documentPollingInterval)
nextAnimationFrame()
expect(linesNode.style.backgroundColor).toBe 'rgb(255, 0, 0)'
for tileNode in linesNode.querySelectorAll(".tile")
for tileNode in component.tileNodesForLines()
expect(tileNode.style.backgroundColor).toBe("rgb(255, 0, 0)")
@@ -606,7 +606,7 @@ describe "TextEditorComponent", ->
component.measureDimensions()
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".line-numbers").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLineNumbers()
expect(tilesNodes[0].style.zIndex).toBe("2")
expect(tilesNodes[1].style.zIndex).toBe("1")
@@ -616,33 +616,13 @@ describe "TextEditorComponent", ->
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".line-numbers").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLineNumbers()
expect(tilesNodes[0].style.zIndex).toBe("3")
expect(tilesNodes[1].style.zIndex).toBe("2")
expect(tilesNodes[2].style.zIndex).toBe("1")
expect(tilesNodes[3].style.zIndex).toBe("0")
it "renders higher line numbers in front of lower ones", ->
wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px'
component.measureDimensions()
nextAnimationFrame()
# Tile 0
expect(component.lineNumberNodeForScreenRow(0).style.zIndex).toBe("2")
expect(component.lineNumberNodeForScreenRow(1).style.zIndex).toBe("1")
expect(component.lineNumberNodeForScreenRow(2).style.zIndex).toBe("0")
# Tile 1
expect(component.lineNumberNodeForScreenRow(3).style.zIndex).toBe("2")
expect(component.lineNumberNodeForScreenRow(4).style.zIndex).toBe("1")
expect(component.lineNumberNodeForScreenRow(5).style.zIndex).toBe("0")
# Tile 2
expect(component.lineNumberNodeForScreenRow(6).style.zIndex).toBe("2")
expect(component.lineNumberNodeForScreenRow(7).style.zIndex).toBe("1")
expect(component.lineNumberNodeForScreenRow(8).style.zIndex).toBe("0")
it "gives the line numbers container the same height as the wrapper node", ->
linesNode = componentNode.querySelector(".line-numbers")
@@ -663,7 +643,7 @@ describe "TextEditorComponent", ->
component.measureDimensions()
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".line-numbers").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLineNumbers()
expect(tilesNodes.length).toBe(3)
expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
@@ -689,7 +669,7 @@ describe "TextEditorComponent", ->
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".line-numbers").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLineNumbers()
expect(component.lineNumberNodeForScreenRow(2)).toBeUndefined()
expect(tilesNodes.length).toBe(3)
@@ -791,7 +771,7 @@ describe "TextEditorComponent", ->
lineNumbersNode = gutterNode.querySelector('.line-numbers')
{backgroundColor} = getComputedStyle(wrapperNode)
expect(lineNumbersNode.style.backgroundColor).toBe backgroundColor
for tileNode in lineNumbersNode.querySelectorAll(".tile")
for tileNode in component.tileNodesForLineNumbers()
expect(tileNode.style.backgroundColor).toBe(backgroundColor)
# favor gutter color if it's assigned
@@ -800,7 +780,7 @@ describe "TextEditorComponent", ->
nextAnimationFrame()
expect(lineNumbersNode.style.backgroundColor).toBe 'rgb(255, 0, 0)'
for tileNode in lineNumbersNode.querySelectorAll(".tile")
for tileNode in component.tileNodesForLineNumbers()
expect(tileNode.style.backgroundColor).toBe("rgb(255, 0, 0)")
it "hides or shows the gutter based on the '::isLineNumberGutterVisible' property on the model and the global 'editor.showLineNumbers' config setting", ->
@@ -1133,7 +1113,7 @@ describe "TextEditorComponent", ->
it "renders 2 regions for 2-line selections", ->
editor.setSelectedScreenRange([[1, 6], [2, 10]])
nextAnimationFrame()
tileNode = componentNode.querySelector(".lines").querySelectorAll(".tile")[0]
tileNode = component.tileNodesForLines()[0]
regions = tileNode.querySelectorAll('.selection .region')
expect(regions.length).toBe 2
@@ -1154,7 +1134,7 @@ describe "TextEditorComponent", ->
nextAnimationFrame()
# Tile 0
tileNode = componentNode.querySelector(".lines").querySelectorAll(".tile")[0]
tileNode = component.tileNodesForLines()[0]
regions = tileNode.querySelectorAll('.selection .region')
expect(regions.length).toBe(3)
@@ -1177,7 +1157,7 @@ describe "TextEditorComponent", ->
expect(region3Rect.right).toBe tileNode.getBoundingClientRect().right
# Tile 3
tileNode = componentNode.querySelector(".lines").querySelectorAll(".tile")[1]
tileNode = component.tileNodesForLines()[1]
regions = tileNode.querySelectorAll('.selection .region')
expect(regions.length).toBe(3)
@@ -2408,7 +2388,7 @@ describe "TextEditorComponent", ->
component.measureDimensions()
nextAnimationFrame()
tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile")
tilesNodes = component.tileNodesForLines()
top = 0
for tileNode in tilesNodes

View File

@@ -2035,15 +2035,10 @@ describe "TextEditorPresenter", ->
lineNumberStateForScreenRow = (presenter, screenRow) ->
editor = presenter.model
tileRow = presenter.tileForRow(screenRow)
bufferRow = editor.bufferRowForScreenRow(screenRow)
wrapCount = screenRow - editor.screenRowForBufferRow(bufferRow)
if wrapCount > 0
key = bufferRow + '-' + wrapCount
else
key = bufferRow
line = editor.tokenizedLineForScreenRow(screenRow)
gutterState = getLineNumberGutterState(presenter)
gutterState.content.tiles[tileRow]?.lineNumbers[key]
gutterState.content.tiles[tileRow]?.lineNumbers[line?.id]
tiledContentContract (presenter) -> getLineNumberGutterState(presenter).content

View File

@@ -0,0 +1,35 @@
TextBuffer = require 'text-buffer'
TokenizedBuffer = require '../src/tokenized-buffer'
describe "TokenIterator", ->
it "correctly terminates scopes at the beginning of the line (regression)", ->
grammar = atom.grammars.createGrammar('test', {
'scopeName': 'text.broken'
'name': 'Broken grammar'
'patterns': [
{
'begin': 'start'
'end': '(?=end)'
'name': 'blue.broken'
}
{
'match': '.'
'name': 'yellow.broken'
}
]
})
buffer = new TextBuffer(text: """
start x
end x
x
""")
tokenizedBuffer = new TokenizedBuffer({buffer})
tokenizedBuffer.setGrammar(grammar)
tokenIterator = tokenizedBuffer.tokenizedLineForRow(1).getTokenIterator()
tokenIterator.next()
expect(tokenIterator.getBufferStart()).toBe 0
expect(tokenIterator.getScopeEnds()).toEqual []
expect(tokenIterator.getScopeStarts()).toEqual ['text.broken', 'yellow.broken']

View File

@@ -9,7 +9,6 @@ class LineNumbersTileComponent
constructor: ({@id}) ->
@lineNumberNodesById = {}
@domNode = document.createElement("div")
@domNode.classList.add("tile")
@domNode.style.position = "absolute"
@domNode.style.display = "block"
@domNode.style.top = 0 # Cover the space occupied by a dummy lineNumber
@@ -75,28 +74,32 @@ class LineNumbersTileComponent
newLineNumbersHTML += @buildLineNumberHTML(lineNumberState)
@oldTileState.lineNumbers[id] = _.clone(lineNumberState)
if newLineNumberIds?
WrapperDiv.innerHTML = newLineNumbersHTML
newLineNumberNodes = _.toArray(WrapperDiv.children)
return unless newLineNumberIds?
node = @domNode
for id, i in newLineNumberIds
lineNumberNode = newLineNumberNodes[i]
@lineNumberNodesById[id] = lineNumberNode
node.appendChild(lineNumberNode)
WrapperDiv.innerHTML = newLineNumbersHTML
newLineNumberNodes = _.toArray(WrapperDiv.children)
for id, i in newLineNumberIds
lineNumberNode = newLineNumberNodes[i]
@lineNumberNodesById[id] = lineNumberNode
if nextNode = @findNodeNextTo(lineNumberNode)
@domNode.insertBefore(lineNumberNode, nextNode)
else
@domNode.appendChild(lineNumberNode)
findNodeNextTo: (node) ->
for nextNode in @domNode.children
return nextNode if @screenRowForNode(node) < @screenRowForNode(nextNode)
return
screenRowForNode: (node) -> parseInt(node.dataset.screenRow)
buildLineNumberHTML: (lineNumberState) ->
{screenRow, bufferRow, softWrapped, top, decorationClasses, zIndex} = lineNumberState
if screenRow?
style = "position: absolute; top: #{top}px; z-index: #{zIndex};"
else
style = "visibility: hidden;"
{screenRow, bufferRow, softWrapped, top, decorationClasses} = lineNumberState
className = @buildLineNumberClassName(lineNumberState)
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped)
"<div class=\"#{className}\" style=\"#{style}\" data-buffer-row=\"#{bufferRow}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
"<div class=\"#{className}\" data-buffer-row=\"#{bufferRow}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
buildLineNumberInnerHTML: (bufferRow, softWrapped) ->
{maxLineNumberDigits} = @newState
@@ -119,18 +122,15 @@ class LineNumbersTileComponent
oldLineNumberState.foldable = newLineNumberState.foldable
oldLineNumberState.decorationClasses = _.clone(newLineNumberState.decorationClasses)
unless oldLineNumberState.top is newLineNumberState.top
node.style.top = newLineNumberState.top + 'px'
unless oldLineNumberState.screenRow is newLineNumberState.screenRow and oldLineNumberState.bufferRow is newLineNumberState.bufferRow
node.innerHTML = @buildLineNumberInnerHTML(newLineNumberState.bufferRow, newLineNumberState.softWrapped)
node.dataset.screenRow = newLineNumberState.screenRow
oldLineNumberState.top = newLineNumberState.top
node.dataset.bufferRow = newLineNumberState.bufferRow
oldLineNumberState.screenRow = newLineNumberState.screenRow
unless oldLineNumberState.zIndex is newLineNumberState.zIndex
node.style.zIndex = newLineNumberState.zIndex
oldLineNumberState.zIndex = newLineNumberState.zIndex
oldLineNumberState.bufferRow = newLineNumberState.bufferRow
buildLineNumberClassName: ({bufferRow, foldable, decorationClasses, softWrapped}) ->
className = "line-number line-number-#{bufferRow}"
className = "line-number"
className += " " + decorationClasses.join(' ') if decorationClasses?
className += " foldable" if foldable and not softWrapped
className

View File

@@ -21,7 +21,6 @@ class LinesTileComponent
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
@domNode = document.createElement("div")
@domNode.classList.add("tile")
@domNode.style.position = "absolute"
@domNode.style.display = "block"
@@ -110,10 +109,19 @@ class LinesTileComponent
for id, i in newLineIds
lineNode = newLineNodes[i]
@lineNodesByLineId[id] = lineNode
@domNode.appendChild(lineNode)
if nextNode = @findNodeNextTo(lineNode)
@domNode.insertBefore(lineNode, nextNode)
else
@domNode.appendChild(lineNode)
findNodeNextTo: (node) ->
for nextNode, index in @domNode.children
continue if index is 0 # skips highlights node
return nextNode if @screenRowForNode(node) < @screenRowForNode(nextNode)
return
screenRowForNode: (node) -> parseInt(node.dataset.screenRow)
buildLineHTML: (id) ->
{width} = @newState
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id]
@@ -124,7 +132,7 @@ class LinesTileComponent
classes += decorationClass + ' '
classes += 'line'
lineHTML = "<div class=\"#{classes}\" style=\"position: absolute; top: #{top}px; width: #{width}px;\" data-screen-row=\"#{screenRow}\">"
lineHTML = "<div class=\"#{classes}\" data-screen-row=\"#{screenRow}\">"
if text is ""
lineHTML += @buildEmptyLineInnerHTML(id)
@@ -284,9 +292,6 @@ class LinesTileComponent
lineNode = @lineNodesByLineId[id]
if @newState.width isnt @oldState.width
lineNode.style.width = @newState.width + 'px'
newDecorationClasses = newLineState.decorationClasses
oldDecorationClasses = oldLineState.decorationClasses
@@ -302,10 +307,6 @@ class LinesTileComponent
oldLineState.decorationClasses = newLineState.decorationClasses
if newLineState.top isnt oldLineState.top
lineNode.style.top = newLineState.top + 'px'
oldLineState.top = newLineState.top
if newLineState.screenRow isnt oldLineState.screenRow
lineNode.dataset.screenRow = newLineState.screenRow
oldLineState.screenRow = newLineState.screenRow

View File

@@ -749,6 +749,13 @@ class TextEditorComponent
tileComponent?.lineNumberNodeForScreenRow(screenRow)
tileNodesForLines: ->
@linesComponent.getTiles()
tileNodesForLineNumbers: ->
gutterComponent = @gutterContainerComponent.getLineNumberGutterComponent()
gutterComponent.getTiles()
screenRowForNode: (node) ->
while node?
if screenRow = node.dataset.screenRow

View File

@@ -20,7 +20,7 @@ class TextEditorPresenter
@measuredHorizontalScrollbarHeight = horizontalScrollbarHeight
@measuredVerticalScrollbarWidth = verticalScrollbarWidth
@gutterWidth ?= 0
@tileSize ?= 12
@tileSize ?= 6
@disposables = new CompositeDisposable
@emitter = new Emitter
@@ -584,22 +584,15 @@ class TextEditorPresenter
if startRow > 0
rowBeforeStartRow = startRow - 1
lastBufferRow = @model.bufferRowForScreenRow(rowBeforeStartRow)
wrapCount = rowBeforeStartRow - @model.screenRowForBufferRow(lastBufferRow)
else
lastBufferRow = null
wrapCount = 0
if endRow > startRow
bufferRows = @model.bufferRowsForScreenRows(startRow, endRow - 1)
zIndex = bufferRows.length - 1
for bufferRow, i in bufferRows
if bufferRow is lastBufferRow
wrapCount++
id = bufferRow + '-' + wrapCount
softWrapped = true
else
id = bufferRow
wrapCount = 0
lastBufferRow = bufferRow
softWrapped = false
@@ -607,10 +600,10 @@ class TextEditorPresenter
top = (screenRow - startRow) * @lineHeight
decorationClasses = @lineNumberDecorationClassesForRow(screenRow)
foldable = @model.isFoldableAtScreenRow(screenRow)
id = @model.tokenizedLineForScreenRow(screenRow).id
tileState.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable, zIndex}
tileState.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable}
visibleLineNumberIds[id] = true
zIndex--
for id of tileState.lineNumbers
delete tileState.lineNumbers[id] unless visibleLineNumberIds[id]

View File

@@ -1,3 +1,5 @@
{values} = require 'underscore-plus'
cloneObject = (object) ->
clone = {}
clone[key] = value for key, value of object
@@ -49,3 +51,6 @@ class TiledComponent
getComponentForTile: (tileRow) ->
@componentsByTileId[tileRow]
getTiles: ->
values(@componentsByTileId).map (component) -> component.getDomNode()

View File

@@ -31,11 +31,14 @@ class TokenIterator
while @index < tags.length
tag = tags[@index]
if tag < 0
scope = atom.grammars.scopeForId(tag)
if tag % 2 is 0
@scopeEnds.push(atom.grammars.scopeForId(tag + 1))
if @scopeStarts[@scopeStarts.length - 1] is scope
@scopeStarts.pop()
else
@scopeEnds.push(scope)
@scopes.pop()
else
scope = atom.grammars.scopeForId(tag)
@scopeStarts.push(scope)
@scopes.push(scope)
@index++

View File

@@ -506,6 +506,15 @@ class Workspace extends Model
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# opener.
#
# Note that the opener will be called if and only if the URI is not already open
# in the current pane. The searchAllPanes flag expands the search from the
# current pane to all panes. If you wish to open a view of a different type for
# a file that is already open, consider changing the protocol of the URI. For
# example, perhaps you wish to preview a rendered version of the file `/foo/bar/baz.quux`
# that is already open in a text editor view. You could signal this by calling
# {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()

View File

@@ -28,3 +28,4 @@
@import "text";
@import "utilities";
@import "octicons";
@import "cursors";

26
static/cursors.less Normal file
View File

@@ -0,0 +1,26 @@
@import "./variables/syntax-variables";
@import "syntax-variables";
@import "./variables/ui-variables";
@import "ui-variables";
@ibeam-1x: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=');
@ibeam-2x: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAz0lEQVRIx2NgYGBY/R8I/vx5eelX3n82IJ9FxGf6tksvf/8FiTMQAcAGQMDvSwu09abffY8QYSAScNk45G198eX//yev73/4///701eh//kZSARckrNBRvz//+8+6ZohwCzjGNjdgQxkAg7B9WADeBjIBqtJCbhRA0YNoIkBSNmaPEMoNmA0FkYNoFKhapJ6FGyAH3nauaSmPfwI0v/3OukVi0CIZ+F25KrtYcx/CTIy0e+rC7R1Z4KMICVTQQ14feVXIbR695u14+Ir4gwAAD49E54wc1kWAAAAAElFTkSuQmCC');
.cursor-white() {
cursor: -webkit-image-set(@ibeam-1x 1x, @ibeam-2x 2x) 5 8, text;
}
// Editors
& when ( lightness(@syntax-background-color) < 50% ) {
.platform-darwin atom-text-editor:not([mini])::shadow .editor-contents--private {
.cursor-white();
}
}
// Mini Editors
& when ( lightness(@input-background-color) < 50% ) {
.platform-darwin atom-text-editor[mini]::shadow .editor-contents--private {
.cursor-white();
}
}

View File

@@ -46,6 +46,7 @@ atom-text-editor {
}
.line-number {
position: relative;
white-space: nowrap;
padding-left: .5em;
opacity: 0.6;

View File

@@ -29,6 +29,7 @@
}
.line-number {
position: relative;
white-space: nowrap;
padding-left: .5em;
opacity: 0.6;