Merge remote-tracking branch 'refs/remotes/origin/master' into wl-electron-35

This commit is contained in:
Wliu
2015-12-18 20:02:22 -05:00
17 changed files with 345 additions and 337 deletions

View File

@@ -21,7 +21,12 @@
# * https://atom.io/docs/latest/using-atom-basic-customization#customizing-key-bindings
# * https://atom.io/docs/latest/behind-atom-keymaps-in-depth
#
# If you're having trouble with your keybindings not working, try the
# Keybinding Resolver: `Cmd+.` on OS X and `Ctrl+.` on other platforms. See the
# Debugging Guide for more information:
# * https://atom.io/docs/latest/hacking-atom-debugging#check-the-keybindings
#
# This file uses CoffeeScript Object Notation (CSON).
# If you are unfamiliar with CSON, you can read more about it in the
# If you are unfamiliar with CSON, you can read more about it in the
# Atom Flight Manual:
# https://atom.io/docs/latest/using-atom-basic-customization#cson

View File

@@ -18,7 +18,7 @@
"atom-keymap": "^6.2.0",
"babel-core": "^5.8.21",
"bootstrap": "^3.3.4",
"cached-run-in-this-context": "0.4.0",
"cached-run-in-this-context": "0.4.1",
"clear-cut": "^2.0.1",
"coffee-script": "1.8.0",
"color": "^0.7.3",
@@ -52,7 +52,7 @@
"service-hub": "^0.7.0",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "8.1.1",
"text-buffer": "8.1.3",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"yargs": "^3.23.0"
@@ -62,8 +62,8 @@
"atom-dark-ui": "0.51.0",
"atom-light-syntax": "0.28.0",
"atom-light-ui": "0.43.0",
"base16-tomorrow-dark-theme": "1.0.0",
"base16-tomorrow-light-theme": "1.0.0",
"base16-tomorrow-dark-theme": "1.1.0",
"base16-tomorrow-light-theme": "1.1.1",
"one-dark-ui": "1.1.9",
"one-dark-syntax": "1.1.1",
"one-light-syntax": "1.1.1",
@@ -75,20 +75,20 @@
"autocomplete-atom-api": "0.9.2",
"autocomplete-css": "0.11.0",
"autocomplete-html": "0.7.2",
"autocomplete-plus": "2.24.0",
"autocomplete-plus": "2.25.0",
"autocomplete-snippets": "1.9.0",
"autoflow": "0.26.0",
"autosave": "0.23.0",
"background-tips": "0.26.0",
"bookmarks": "0.38.0",
"bracket-matcher": "0.79.0",
"command-palette": "0.37.0",
"command-palette": "0.38.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.194.0",
"fuzzy-finder": "0.93.0",
"find-and-replace": "0.195.0",
"fuzzy-finder": "0.94.0",
"git-diff": "0.57.0",
"go-to-line": "0.30.0",
"grammar-selector": "0.48.0",
@@ -97,7 +97,7 @@
"keybinding-resolver": "0.33.0",
"line-ending-selector": "0.3.0",
"link": "0.31.0",
"markdown-preview": "0.157.0",
"markdown-preview": "0.157.1",
"metrics": "0.53.1",
"notifications": "0.62.1",
"open-on-github": "0.40.0",

View File

@@ -88,13 +88,13 @@ describe "DisplayBuffer", ->
describe "when there are korean characters", ->
it "takes them into account when finding the soft wrap column", ->
displayBuffer.setDefaultCharWidth(1, 0, 0, 10)
buffer.setText("1234세계를 향한 대화, 유니코 제10회유니코드국제")
buffer.setText("1234세계를향한대화,유니코제10회유니코드국제")
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("1234세계를 ")
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe("향한 대화, ")
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("니코 ")
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe("제10회유니")
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe("코드국")
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("1234세계를")
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe("대화,")
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("니코제10회")
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe("유니코드국")
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe("")
describe "when editor.softWrapAtPreferredLineLength is set", ->
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
@@ -130,8 +130,25 @@ describe "DisplayBuffer", ->
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe ' sort(left).concat(pivot).concat(sort(right));'
it "wraps the line at the first CJK character before the boundary", ->
displayBuffer.setEditorWidthInChars(10)
buffer.setTextInRange([[0, 0], [1, 0]], 'abcd efg유私フ业余爱\n')
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcd efg유私'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'フ业余爱'
buffer.setTextInRange([[0, 0], [1, 0]], 'abcd ef유gef业余爱\n')
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcd ef유'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'gef业余爱'
describe "when there is no whitespace before the boundary", ->
it "wraps the line exactly at the boundary since there's no more graceful place to wrap it", ->
it "wraps the line at the first CJK character before the boundary", ->
buffer.setTextInRange([[0, 0], [1, 0]], '私たちのabcdefghij\n')
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe '私たちの'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'abcdefghij'
it "wraps the line exactly at the boundary when no CJK character is found, since there's no more graceful place to wrap it", ->
buffer.setTextInRange([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n')
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcdefghij'

View File

@@ -9,61 +9,71 @@ describe "FileSystemBlobStore", ->
blobStore = FileSystemBlobStore.load(storageDirectory)
it "is empty when the file doesn't exist", ->
expect(blobStore.get("foo")).toBeUndefined()
expect(blobStore.get("bar")).toBeUndefined()
expect(blobStore.get("foo", "invalidation-key-1")).toBeUndefined()
expect(blobStore.get("bar", "invalidation-key-2")).toBeUndefined()
it "allows to read and write buffers from/to memory without persisting them", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.set("foo", "invalidation-key-1", new Buffer("foo"))
blobStore.set("bar", "invalidation-key-2", new Buffer("bar"))
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "invalidation-key-1")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar", "invalidation-key-2")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "unexisting-key")).toBeUndefined()
expect(blobStore.get("bar", "unexisting-key")).toBeUndefined()
it "persists buffers when saved and retrieves them on load, giving priority to in-memory ones", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.set("foo", "invalidation-key-1", new Buffer("foo"))
blobStore.set("bar", "invalidation-key-2", new Buffer("bar"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "invalidation-key-1")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar", "invalidation-key-2")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "unexisting-key")).toBeUndefined()
expect(blobStore.get("bar", "unexisting-key")).toBeUndefined()
blobStore.set("foo", new Buffer("changed"))
blobStore.set("foo", "new-key", new Buffer("changed"))
expect(blobStore.get("foo")).toEqual(new Buffer("changed"))
expect(blobStore.get("foo", "new-key")).toEqual(new Buffer("changed"))
expect(blobStore.get("foo", "invalidation-key-1")).toBeUndefined()
it "persists both in-memory and previously stored buffers when saved", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.set("foo", "invalidation-key-1", new Buffer("foo"))
blobStore.set("bar", "invalidation-key-2", new Buffer("bar"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
blobStore.set("bar", new Buffer("changed"))
blobStore.set("qux", new Buffer("qux"))
blobStore.set("bar", "invalidation-key-3", new Buffer("changed"))
blobStore.set("qux", "invalidation-key-4", new Buffer("qux"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("changed"))
expect(blobStore.get("qux")).toEqual(new Buffer("qux"))
expect(blobStore.get("foo", "invalidation-key-1")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar", "invalidation-key-3")).toEqual(new Buffer("changed"))
expect(blobStore.get("qux", "invalidation-key-4")).toEqual(new Buffer("qux"))
expect(blobStore.get("foo", "unexisting-key")).toBeUndefined()
expect(blobStore.get("bar", "invalidation-key-2")).toBeUndefined()
expect(blobStore.get("qux", "unexisting-key")).toBeUndefined()
it "allows to delete keys from both memory and stored buffers", ->
blobStore.set("a", new Buffer("a"))
blobStore.set("b", new Buffer("b"))
blobStore.set("a", "invalidation-key-1", new Buffer("a"))
blobStore.set("b", "invalidation-key-2", new Buffer("b"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
blobStore.set("b", new Buffer("b"))
blobStore.set("c", new Buffer("c"))
blobStore.set("b", "invalidation-key-3", new Buffer("b"))
blobStore.set("c", "invalidation-key-4", new Buffer("c"))
blobStore.delete("b")
blobStore.delete("c")
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("a")).toEqual(new Buffer("a"))
expect(blobStore.get("b")).toBeUndefined()
expect(blobStore.get("c")).toBeUndefined()
expect(blobStore.get("a", "invalidation-key-1")).toEqual(new Buffer("a"))
expect(blobStore.get("b", "invalidation-key-2")).toBeUndefined()
expect(blobStore.get("b", "invalidation-key-3")).toBeUndefined()
expect(blobStore.get("c", "invalidation-key-4")).toBeUndefined()

1
spec/fixtures/native-cache/file-4.js vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = function () { return "file-4" }

View File

@@ -1,3 +1,7 @@
fs = require 'fs'
path = require 'path'
Module = require 'module'
describe "NativeCompileCache", ->
nativeCompileCache = require '../src/native-compile-cache'
[fakeCacheStore, cachedFiles] = []
@@ -5,39 +9,92 @@ describe "NativeCompileCache", ->
beforeEach ->
cachedFiles = []
fakeCacheStore = jasmine.createSpyObj("cache store", ["set", "get", "has", "delete"])
fakeCacheStore.has.andCallFake (cacheKey, invalidationKey) ->
fakeCacheStore.get(cacheKey, invalidationKey)?
fakeCacheStore.get.andCallFake (cacheKey, invalidationKey) ->
for entry in cachedFiles by -1
continue if entry.cacheKey isnt cacheKey
continue if entry.invalidationKey isnt invalidationKey
return entry.cacheBuffer
return
fakeCacheStore.set.andCallFake (cacheKey, invalidationKey, cacheBuffer) ->
cachedFiles.push({cacheKey, invalidationKey, cacheBuffer})
nativeCompileCache.setCacheStore(fakeCacheStore)
nativeCompileCache.setV8Version("a-v8-version")
nativeCompileCache.install()
it "writes and reads from the cache storage when requiring files", ->
fakeCacheStore.has.andReturn(false)
fakeCacheStore.set.andCallFake (filename, cacheBuffer) ->
cachedFiles.push({filename, cacheBuffer})
fn1 = require('./fixtures/native-cache/file-1')
fn2 = require('./fixtures/native-cache/file-2')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[0].filename).toBe(require.resolve('./fixtures/native-cache/file-1'))
expect(cachedFiles[0].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-1'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn1()).toBe(1)
expect(cachedFiles[1].filename).toBe(require.resolve('./fixtures/native-cache/file-2'))
expect(cachedFiles[1].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-2'))
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
expect(fn2()).toBe(2)
fakeCacheStore.has.andReturn(true)
fakeCacheStore.get.andReturn(cachedFiles[0].cacheBuffer)
fakeCacheStore.set.reset()
delete Module._cache[require.resolve('./fixtures/native-cache/file-1')]
fn1 = require('./fixtures/native-cache/file-1')
expect(fakeCacheStore.set).not.toHaveBeenCalled()
expect(cachedFiles.length).toBe(2)
expect(fn1()).toBe(1)
it "deletes previously cached code when the cache is not valid", ->
describe "when v8 version changes", ->
it "updates the cache of previously required files", ->
nativeCompileCache.setV8Version("version-1")
fn4 = require('./fixtures/native-cache/file-4')
expect(cachedFiles.length).toBe(1)
expect(cachedFiles[0].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-4'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn4()).toBe("file-4")
nativeCompileCache.setV8Version("version-2")
delete Module._cache[require.resolve('./fixtures/native-cache/file-4')]
fn4 = require('./fixtures/native-cache/file-4')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[1].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-4'))
expect(cachedFiles[1].invalidationKey).not.toBe(cachedFiles[0].invalidationKey)
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
describe "when a previously required and cached file changes", ->
beforeEach ->
fs.writeFileSync path.resolve('./spec/fixtures/native-cache/file-5'), """
module.exports = function () { return "file-5" }
"""
afterEach ->
fs.unlinkSync path.resolve('./spec/fixtures/native-cache/file-5')
it "removes it from the store and re-inserts it with the new cache", ->
fn5 = require('./fixtures/native-cache/file-5')
expect(cachedFiles.length).toBe(1)
expect(cachedFiles[0].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-5'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn5()).toBe("file-5")
delete Module._cache[require.resolve('./fixtures/native-cache/file-5')]
fs.appendFileSync(require.resolve('./fixtures/native-cache/file-5'), "\n\n")
fn5 = require('./fixtures/native-cache/file-5')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[1].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-5'))
expect(cachedFiles[1].invalidationKey).not.toBe(cachedFiles[0].invalidationKey)
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
it "deletes previously cached code when the cache is an invalid file", ->
fakeCacheStore.has.andReturn(true)
fakeCacheStore.get.andCallFake -> new Buffer("an invalid cache")

View File

@@ -136,14 +136,6 @@ describe "TextEditorPresenter", ->
# clearing additional rows won't trigger a state update
expectNoStateUpdate presenter, -> presenter.clearScreenRowsToMeasure()
expect(stateFn(presenter).tiles[0]).toBeDefined()
expect(stateFn(presenter).tiles[2]).toBeDefined()
expect(stateFn(presenter).tiles[4]).toBeDefined()
expect(stateFn(presenter).tiles[6]).toBeDefined()
expect(stateFn(presenter).tiles[8]).toBeUndefined()
expect(stateFn(presenter).tiles[10]).toBeDefined()
expect(stateFn(presenter).tiles[12]).toBeDefined()
# when another change triggers a state update we remove useless lines
expectStateUpdate presenter, -> presenter.setScrollTop(1)
@@ -625,23 +617,6 @@ describe "TextEditorPresenter", ->
expect(getState(presenter).hiddenInput.width).toBe 2
describe ".content", ->
describe ".scrollingVertically", ->
it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", ->
presenter = buildPresenter(scrollTop: 10, stoppedScrollingDelay: 200, explicitHeight: 100)
expect(getState(presenter).content.scrollingVertically).toBe true
advanceClock(300)
expect(getState(presenter).content.scrollingVertically).toBe false
expectStateUpdate presenter, -> presenter.setScrollTop(0)
expect(getState(presenter).content.scrollingVertically).toBe true
advanceClock(100)
expect(getState(presenter).content.scrollingVertically).toBe true
presenter.setScrollTop(10)
getState(presenter) # commits scroll position
advanceClock(100)
expect(getState(presenter).content.scrollingVertically).toBe true
expectStateUpdate presenter, -> advanceClock(100)
expect(getState(presenter).content.scrollingVertically).toBe false
describe ".maxHeight", ->
it "changes based on boundingClientRect", ->
presenter = buildPresenter(scrollTop: 0, lineHeight: 10)
@@ -807,6 +782,11 @@ describe "TextEditorPresenter", ->
getState(presenter) # commits scroll position
expect(editor.getFirstVisibleScreenRow()).toBe 6
it "updates when the model's scroll position is changed directly", ->
presenter = buildPresenter(scrollTop: 0, explicitHeight: 20, horizontalScrollbarHeight: 10, lineHeight: 10)
expectStateUpdate presenter, -> editor.setFirstVisibleScreenRow(1)
expect(getState(presenter).content.scrollTop).toBe 10
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(getState(presenter).content.scrollTop).toBe(80)

View File

@@ -74,3 +74,23 @@ describe 'text utilities', ->
expect(textUtils.isKoreanCharacter("")).toBe(true)
expect(textUtils.isKoreanCharacter("O")).toBe(false)
describe ".isCJKCharacter(character)", ->
it "returns true when the character is either a korean, half-width or double-width character", ->
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isDoubleWidthCharacter("a")).toBe(false)
expect(textUtils.isDoubleWidthCharacter("O")).toBe(false)
expect(textUtils.isDoubleWidthCharacter("z")).toBe(false)

View File

@@ -26,8 +26,13 @@ describe "TokenizedBuffer", ->
describe "serialization", ->
describe "when the underlying buffer has a path", ->
it "deserializes it searching among the buffers in the current project", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
it "deserializes it searching among the buffers in the current project", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
@@ -38,10 +43,25 @@ describe "TokenizedBuffer", ->
expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer)
it "does not serialize / deserialize the current grammar", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
autoSelectedGrammar = tokenizedBufferA.grammar
tokenizedBufferA.setGrammar(atom.grammars.grammarForScopeName('source.coffee'))
tokenizedBufferB = TokenizedBuffer.deserialize(
JSON.parse(JSON.stringify(tokenizedBufferA.serialize())),
atom
)
expect(tokenizedBufferB.grammar).toBe(atom.grammars.grammarForScopeName('source.js'))
describe "when the underlying buffer has no path", ->
it "deserializes it searching among the buffers in the current project", ->
beforeEach ->
buffer = atom.project.bufferForPathSync(null)
it "deserializes it searching among the buffers in the current project", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
@@ -52,6 +72,38 @@ describe "TokenizedBuffer", ->
expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer)
it "deserializes the previously selected grammar as soon as it's added when not available in the grammar registry", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
tokenizedBufferA.setGrammar(atom.grammars.grammarForScopeName("source.js"))
atom.grammars.removeGrammarForScopeName(tokenizedBufferA.grammar.scopeName)
tokenizedBufferB = TokenizedBuffer.deserialize(
JSON.parse(JSON.stringify(tokenizedBufferA.serialize())),
atom
)
expect(tokenizedBufferB.grammar).not.toBeFalsy()
expect(tokenizedBufferB.grammar).not.toBe(tokenizedBufferA.grammar)
atom.grammars.addGrammar(tokenizedBufferA.grammar)
expect(tokenizedBufferB.grammar).toBe(tokenizedBufferA.grammar)
it "deserializes the previously selected grammar on construction when available in the grammar registry", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
tokenizedBufferA.setGrammar(atom.grammars.grammarForScopeName("source.js"))
tokenizedBufferB = TokenizedBuffer.deserialize(
JSON.parse(JSON.stringify(tokenizedBufferA.serialize())),
atom
)
expect(tokenizedBufferB.grammar).toBe(tokenizedBufferA.grammar)
describe "when the buffer is destroyed", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')

View File

@@ -1,5 +1,10 @@
'use strict'
// For now, we're not using babel or ES6 features like `let` and `const` in
// this file, because `apm` requires this file directly in order to pre-warm
// Atom's compile-cache when installing or updating packages, using an older
// version of node.js
var path = require('path')
var fs = require('fs-plus')
var CSON = null
@@ -159,8 +164,7 @@ require('source-map-support').install({
})
var prepareStackTraceWithSourceMapping = Error.prepareStackTrace
let prepareStackTrace = prepareStackTraceWithSourceMapping
var prepareStackTrace = prepareStackTraceWithSourceMapping
function prepareStackTraceWithRawStackAssignment (error, frames) {
if (error.rawStack) { // avoid infinite recursion

View File

@@ -13,8 +13,10 @@ class FileSystemBlobStore {
constructor (directory) {
this.inMemoryBlobs = new Map()
this.invalidationKeys = {}
this.blobFilename = path.join(directory, 'BLOB')
this.blobMapFilename = path.join(directory, 'MAP')
this.invalidationKeysFilename = path.join(directory, 'INVKEYS')
this.lockFilename = path.join(directory, 'LOCK')
this.storedBlob = new Buffer(0)
this.storedBlobMap = {}
@@ -27,14 +29,19 @@ class FileSystemBlobStore {
if (!fs.existsSync(this.blobFilename)) {
return
}
if (!fs.existsSync(this.invalidationKeysFilename)) {
return
}
this.storedBlob = fs.readFileSync(this.blobFilename)
this.storedBlobMap = JSON.parse(fs.readFileSync(this.blobMapFilename))
this.invalidationKeys = JSON.parse(fs.readFileSync(this.invalidationKeysFilename))
}
save () {
let dump = this.getDump()
let blobToStore = Buffer.concat(dump[0])
let mapToStore = JSON.stringify(dump[1])
let invalidationKeysToStore = JSON.stringify(this.invalidationKeys)
let acquiredLock = false
try {
@@ -43,6 +50,7 @@ class FileSystemBlobStore {
fs.writeFileSync(this.blobFilename, blobToStore)
fs.writeFileSync(this.blobMapFilename, mapToStore)
fs.writeFileSync(this.invalidationKeysFilename, invalidationKeysToStore)
} catch (error) {
// Swallow the exception silently only if we fail to acquire the lock.
if (error.code !== 'EEXIST') {
@@ -55,15 +63,20 @@ class FileSystemBlobStore {
}
}
has (key) {
return this.inMemoryBlobs.hasOwnProperty(key) || this.storedBlobMap.hasOwnProperty(key)
has (key, invalidationKey) {
let containsKey = this.inMemoryBlobs.has(key) || this.storedBlobMap.hasOwnProperty(key)
let isValid = this.invalidationKeys[key] === invalidationKey
return containsKey && isValid
}
get (key) {
return this.getFromMemory(key) || this.getFromStorage(key)
get (key, invalidationKey) {
if (this.has(key, invalidationKey)) {
return this.getFromMemory(key) || this.getFromStorage(key)
}
}
set (key, buffer) {
set (key, invalidationKey, buffer) {
this.invalidationKeys[key] = invalidationKey
return this.inMemoryBlobs.set(key, buffer)
}

View File

@@ -3,6 +3,11 @@
const Module = require('module')
const path = require('path')
const cachedVm = require('cached-run-in-this-context')
const crypto = require('crypto')
function computeHash (contents) {
return crypto.createHash('sha1').update(contents, 'utf8').digest('hex')
}
class NativeCompileCache {
constructor () {
@@ -14,6 +19,10 @@ class NativeCompileCache {
this.cacheStore = store
}
setV8Version (v8Version) {
this.v8Version = v8Version.toString()
}
install () {
this.savePreviousModuleCompile()
this.overrideModuleCompile()
@@ -28,20 +37,20 @@ class NativeCompileCache {
}
overrideModuleCompile () {
let cacheStore = this.cacheStore
let self = this
let resolvedArgv = null
// Here we override Node's module.js
// (https://github.com/atom/node/blob/atom/lib/module.js#L378), changing
// only the bits that affect compilation in order to use the cached one.
Module.prototype._compile = function (content, filename) {
let self = this
let moduleSelf = this
// remove shebang
content = content.replace(/^\#\!.*/, '')
function require (path) {
return self.require(path)
return moduleSelf.require(path)
}
require.resolve = function (request) {
return Module._resolveFilename(request, self)
return Module._resolveFilename(request, moduleSelf)
}
require.main = process.mainModule
@@ -54,18 +63,20 @@ class NativeCompileCache {
// create wrapper function
let wrapper = Module.wrap(content)
let cacheKey = filename
let invalidationKey = computeHash(wrapper + self.v8Version)
let compiledWrapper = null
if (cacheStore.has(filename)) {
let buffer = cacheStore.get(filename)
if (self.cacheStore.has(cacheKey, invalidationKey)) {
let buffer = self.cacheStore.get(cacheKey, invalidationKey)
let compilationResult = cachedVm.runInThisContextCached(wrapper, filename, buffer)
compiledWrapper = compilationResult.result
if (compilationResult.wasRejected) {
cacheStore.delete(filename)
self.cacheStore.delete(cacheKey)
}
} else {
let compilationResult = cachedVm.runInThisContext(wrapper, filename)
if (compilationResult.cacheBuffer) {
cacheStore.set(filename, compilationResult.cacheBuffer)
self.cacheStore.set(cacheKey, invalidationKey, compilationResult.cacheBuffer)
}
compiledWrapper = compilationResult.result
}
@@ -88,8 +99,8 @@ class NativeCompileCache {
global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0)
}
}
let args = [self.exports, require, self, filename, dirname, process, global]
return compiledWrapper.apply(self.exports, args)
let args = [moduleSelf.exports, require, moduleSelf, filename, dirname, process, global]
return compiledWrapper.apply(moduleSelf.exports, args)
}
}

View File

@@ -86,11 +86,7 @@ class TextEditorPresenter
@fetchDecorations()
@updateLineDecorations()
if @shouldUpdateLinesState or @shouldUpdateLineNumbersState
@updateTilesState()
@shouldUpdateLinesState = false
@shouldUpdateLineNumbersState = false
@shouldUpdateTilesState = true
@updateTilesState()
@updating = false
@state
@@ -104,105 +100,47 @@ class TextEditorPresenter
@clearPendingScrollPosition()
@updateRowsPerPage()
@updateFocusedState() if @shouldUpdateFocusedState
@updateHeightState() if @shouldUpdateHeightState
@updateVerticalScrollState() if @shouldUpdateVerticalScrollState
@updateHorizontalScrollState() if @shouldUpdateHorizontalScrollState
@updateScrollbarsState() if @shouldUpdateScrollbarsState
@updateHiddenInputState() if @shouldUpdateHiddenInputState
@updateContentState() if @shouldUpdateContentState
@updateFocusedState()
@updateHeightState()
@updateVerticalScrollState()
@updateHorizontalScrollState()
@updateScrollbarsState()
@updateHiddenInputState()
@updateContentState()
@updateHighlightDecorations() if @shouldUpdateDecorations
@updateTilesState() if @shouldUpdateTilesState
@updateCursorsState() if @shouldUpdateCursorsState
@updateOverlaysState() if @shouldUpdateOverlaysState
@updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState
@updateGutterOrderState() if @shouldUpdateGutterOrderState
@updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState
@updateTilesState()
@updateCursorsState()
@updateOverlaysState()
@updateLineNumberGutterState()
@updateGutterOrderState()
@updateCustomGutterDecorationState()
@updating = false
@resetTrackedUpdates()
@state
resetTrackedUpdates: ->
@shouldUpdateFocusedState = false
@shouldUpdateHeightState = false
@shouldUpdateVerticalScrollState = false
@shouldUpdateHorizontalScrollState = false
@shouldUpdateScrollbarsState = false
@shouldUpdateHiddenInputState = false
@shouldUpdateContentState = false
@shouldUpdateDecorations = false
@shouldUpdateLinesState = false
@shouldUpdateTilesState = false
@shouldUpdateCursorsState = false
@shouldUpdateOverlaysState = false
@shouldUpdateLineNumberGutterState = false
@shouldUpdateLineNumbersState = false
@shouldUpdateGutterOrderState = false
@shouldUpdateCustomGutterDecorationState = false
invalidateState: ->
@shouldUpdateFocusedState = true
@shouldUpdateHeightState = true
@shouldUpdateVerticalScrollState = true
@shouldUpdateHorizontalScrollState = true
@shouldUpdateScrollbarsState = true
@shouldUpdateHiddenInputState = true
@shouldUpdateContentState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateTilesState = true
@shouldUpdateCursorsState = true
@shouldUpdateOverlaysState = true
@shouldUpdateLineNumberGutterState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateGutterOrderState = true
@shouldUpdateCustomGutterDecorationState = true
observeModel: ->
@disposables.add @model.onDidChange =>
@shouldUpdateHeightState = true
@shouldUpdateVerticalScrollState = true
@shouldUpdateHorizontalScrollState = true
@shouldUpdateScrollbarsState = true
@shouldUpdateContentState = true
@shouldUpdateDecorations = true
@shouldUpdateCursorsState = true
@shouldUpdateLinesState = true
@shouldUpdateLineNumberGutterState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateGutterOrderState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
@disposables.add @model.onDidUpdateDecorations =>
@shouldUpdateLinesState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateDecorations = true
@shouldUpdateOverlaysState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
@disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this))
@disposables.add @model.onDidChangePlaceholderText =>
@shouldUpdateContentState = true
@emitDidUpdateState()
@disposables.add @model.onDidChangePlaceholderText(@emitDidUpdateState.bind(this))
@disposables.add @model.onDidChangeMini =>
@shouldUpdateScrollbarsState = true
@shouldUpdateContentState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateLineNumberGutterState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateGutterOrderState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
@disposables.add @model.onDidChangeLineNumberGutterVisible =>
@shouldUpdateLineNumberGutterState = true
@shouldUpdateGutterOrderState = true
@emitDidUpdateState()
@disposables.add @model.onDidChangeLineNumberGutterVisible(@emitDidUpdateState.bind(this))
@disposables.add @model.onDidAddCursor(@didAddCursor.bind(this))
@disposables.add @model.onDidRequestAutoscroll(@requestAutoscroll.bind(this))
@@ -227,29 +165,19 @@ class TextEditorPresenter
@configDisposables.add @config.onDidChange 'editor.showIndentGuide', configParams, ({newValue}) =>
@showIndentGuide = newValue
@shouldUpdateContentState = true
@emitDidUpdateState()
@configDisposables.add @config.onDidChange 'editor.scrollPastEnd', configParams, ({newValue}) =>
@scrollPastEnd = newValue
@shouldUpdateVerticalScrollState = true
@shouldUpdateScrollbarsState = true
@updateScrollHeight()
@emitDidUpdateState()
@configDisposables.add @config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) =>
@showLineNumbers = newValue
@shouldUpdateLineNumberGutterState = true
@shouldUpdateGutterOrderState = true
@emitDidUpdateState()
didChangeGrammar: ->
@observeConfig()
@shouldUpdateContentState = true
@shouldUpdateLineNumberGutterState = true
@shouldUpdateGutterOrderState = true
@emitDidUpdateState()
buildState: ->
@@ -383,8 +311,6 @@ class TextEditorPresenter
return if not screenRows? or screenRows.length is 0
@screenRowsToMeasure = screenRows
@shouldUpdateLinesState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateDecorations = true
clearScreenRowsToMeasure: ->
@@ -425,8 +351,8 @@ class TextEditorPresenter
gutterTile.display = "block"
gutterTile.zIndex = zIndex
@updateLinesState(tile, rowsWithinTile) if @shouldUpdateLinesState
@updateLineNumbersState(gutterTile, rowsWithinTile) if @shouldUpdateLineNumbersState
@updateLinesState(tile, rowsWithinTile)
@updateLineNumbersState(gutterTile, rowsWithinTile)
visibleTiles[tileStartRow] = true
zIndex++
@@ -551,24 +477,15 @@ class TextEditorPresenter
didAddGutter: (gutter) ->
gutterDisposables = new CompositeDisposable
gutterDisposables.add gutter.onDidChangeVisible =>
@shouldUpdateGutterOrderState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
gutterDisposables.add gutter.onDidChangeVisible => @emitDidUpdateState()
gutterDisposables.add gutter.onDidDestroy =>
@disposables.remove(gutterDisposables)
gutterDisposables.dispose()
@shouldUpdateGutterOrderState = true
@emitDidUpdateState()
# It is not necessary to @updateCustomGutterDecorationState here.
# The destroyed gutter will be removed from the list of gutters in @state,
# and thus will be removed from the DOM.
@disposables.add(gutterDisposables)
@shouldUpdateGutterOrderState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
updateGutterOrderState: ->
@@ -861,26 +778,15 @@ class TextEditorPresenter
@startBlinkingCursors()
else
@stopBlinkingCursors(false)
@shouldUpdateFocusedState = true
@shouldUpdateHiddenInputState = true
@emitDidUpdateState()
setScrollTop: (scrollTop, overrideScroll=true) ->
setScrollTop: (scrollTop) ->
return unless scrollTop?
@pendingScrollLogicalPosition = null if overrideScroll
@pendingScrollLogicalPosition = null
@pendingScrollTop = scrollTop
@shouldUpdateVerticalScrollState = true
@shouldUpdateHiddenInputState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateCursorsState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateCustomGutterDecorationState = true
@shouldUpdateOverlaysState = true
@emitDidUpdateState()
getScrollTop: ->
@@ -894,32 +800,19 @@ class TextEditorPresenter
clearTimeout(@stoppedScrollingTimeoutId)
@stoppedScrollingTimeoutId = null
@stoppedScrollingTimeoutId = setTimeout(@didStopScrolling.bind(this), @stoppedScrollingDelay)
@state.content.scrollingVertically = true
@emitDidUpdateState()
didStopScrolling: ->
@state.content.scrollingVertically = false
if @mouseWheelScreenRow?
@mouseWheelScreenRow = null
@shouldUpdateLinesState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
setScrollLeft: (scrollLeft, overrideScroll=true) ->
setScrollLeft: (scrollLeft) ->
return unless scrollLeft?
@pendingScrollLogicalPosition = null if overrideScroll
@pendingScrollLogicalPosition = null
@pendingScrollLeft = scrollLeft
@shouldUpdateHorizontalScrollState = true
@shouldUpdateHiddenInputState = true
@shouldUpdateCursorsState = true
@shouldUpdateOverlaysState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@emitDidUpdateState()
getScrollLeft: ->
@@ -941,13 +834,13 @@ class TextEditorPresenter
@contentFrameWidth - @verticalScrollbarWidth
getScrollBottom: -> @getScrollTop() + @getClientHeight()
setScrollBottom: (scrollBottom, overrideScroll) ->
@setScrollTop(scrollBottom - @getClientHeight(), overrideScroll)
setScrollBottom: (scrollBottom) ->
@setScrollTop(scrollBottom - @getClientHeight())
@getScrollBottom()
getScrollRight: -> @getScrollLeft() + @getClientWidth()
setScrollRight: (scrollRight, overrideScroll) ->
@setScrollLeft(scrollRight - @getClientWidth(), overrideScroll)
setScrollRight: (scrollRight) ->
@setScrollLeft(scrollRight - @getClientWidth())
@getScrollRight()
getScrollHeight: ->
@@ -967,43 +860,24 @@ class TextEditorPresenter
unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight
oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight
@measuredHorizontalScrollbarHeight = horizontalScrollbarHeight
@shouldUpdateScrollbarsState = true
@shouldUpdateVerticalScrollState = true
@shouldUpdateHorizontalScrollState = true
@shouldUpdateCursorsState = true unless oldHorizontalScrollbarHeight?
@emitDidUpdateState()
setVerticalScrollbarWidth: (verticalScrollbarWidth) ->
unless @measuredVerticalScrollbarWidth is verticalScrollbarWidth
oldVerticalScrollbarWidth = @measuredVerticalScrollbarWidth
@measuredVerticalScrollbarWidth = verticalScrollbarWidth
@shouldUpdateScrollbarsState = true
@shouldUpdateVerticalScrollState = true
@shouldUpdateHorizontalScrollState = true
@shouldUpdateCursorsState = true unless oldVerticalScrollbarWidth?
@emitDidUpdateState()
setAutoHeight: (autoHeight) ->
unless @autoHeight is autoHeight
@autoHeight = autoHeight
@shouldUpdateHeightState = true
@emitDidUpdateState()
setExplicitHeight: (explicitHeight) ->
unless @explicitHeight is explicitHeight
@explicitHeight = explicitHeight
@updateHeight()
@shouldUpdateVerticalScrollState = true
@shouldUpdateScrollbarsState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateCursorsState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
updateHeight: ->
@@ -1022,22 +896,12 @@ class TextEditorPresenter
@editorWidthInChars = null
@updateScrollbarDimensions()
@updateClientWidth()
@shouldUpdateVerticalScrollState = true
@shouldUpdateHorizontalScrollState = true
@shouldUpdateScrollbarsState = true
@shouldUpdateContentState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateCursorsState = true unless oldContentFrameWidth?
@emitDidUpdateState()
setBoundingClientRect: (boundingClientRect) ->
unless @clientRectsEqual(@boundingClientRect, boundingClientRect)
@boundingClientRect = boundingClientRect
@shouldUpdateOverlaysState = true
@shouldUpdateContentState = true
@emitDidUpdateState()
clientRectsEqual: (clientRectA, clientRectB) ->
@@ -1051,25 +915,17 @@ class TextEditorPresenter
if @windowWidth isnt width or @windowHeight isnt height
@windowWidth = width
@windowHeight = height
@shouldUpdateOverlaysState = true
@emitDidUpdateState()
setBackgroundColor: (backgroundColor) ->
unless @backgroundColor is backgroundColor
@backgroundColor = backgroundColor
@shouldUpdateContentState = true
@shouldUpdateLineNumberGutterState = true
@shouldUpdateGutterOrderState = true
@emitDidUpdateState()
setGutterBackgroundColor: (gutterBackgroundColor) ->
unless @gutterBackgroundColor is gutterBackgroundColor
@gutterBackgroundColor = gutterBackgroundColor
@shouldUpdateLineNumberGutterState = true
@shouldUpdateGutterOrderState = true
@emitDidUpdateState()
setGutterWidth: (gutterWidth) ->
@@ -1085,18 +941,7 @@ class TextEditorPresenter
@lineHeight = lineHeight
@restoreScrollTopIfNeeded()
@model.setLineHeightInPixels(lineHeight)
@shouldUpdateHeightState = true
@shouldUpdateHorizontalScrollState = true
@shouldUpdateVerticalScrollState = true
@shouldUpdateScrollbarsState = true
@shouldUpdateHiddenInputState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateCursorsState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateCustomGutterDecorationState = true
@shouldUpdateOverlaysState = true
@emitDidUpdateState()
setMouseWheelScreenRow: (screenRow) ->
@@ -1115,16 +960,7 @@ class TextEditorPresenter
@characterWidthsChanged()
characterWidthsChanged: ->
@shouldUpdateHorizontalScrollState = true
@shouldUpdateVerticalScrollState = true
@shouldUpdateScrollbarsState = true
@shouldUpdateHiddenInputState = true
@shouldUpdateContentState = true
@shouldUpdateDecorations = true
@shouldUpdateLinesState = true
@shouldUpdateCursorsState = true
@shouldUpdateOverlaysState = true
@emitDidUpdateState()
hasPixelPositionRequirements: ->
@@ -1365,20 +1201,16 @@ class TextEditorPresenter
overlayState.itemWidth = itemWidth
overlayState.itemHeight = itemHeight
overlayState.contentMargin = contentMargin
@shouldUpdateOverlaysState = true
@emitDidUpdateState()
observeCursor: (cursor) ->
didChangePositionDisposable = cursor.onDidChangePosition =>
@shouldUpdateHiddenInputState = true if cursor.isLastCursor()
@shouldUpdateCursorsState = true
@pauseCursorBlinking()
@emitDidUpdateState()
didChangeVisibilityDisposable = cursor.onDidChangeVisibility =>
@shouldUpdateCursorsState = true
@emitDidUpdateState()
@@ -1386,8 +1218,6 @@ class TextEditorPresenter
@disposables.remove(didChangePositionDisposable)
@disposables.remove(didChangeVisibilityDisposable)
@disposables.remove(didDestroyDisposable)
@shouldUpdateHiddenInputState = true
@shouldUpdateCursorsState = true
@emitDidUpdateState()
@@ -1397,8 +1227,6 @@ class TextEditorPresenter
didAddCursor: (cursor) ->
@observeCursor(cursor)
@shouldUpdateHiddenInputState = true
@shouldUpdateCursorsState = true
@pauseCursorBlinking()
@emitDidUpdateState()
@@ -1432,22 +1260,11 @@ class TextEditorPresenter
@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()
didChangeFirstVisibleScreenRow: (screenRow) ->
@updateScrollTop(screenRow * @lineHeight)
@setScrollTop(screenRow * @lineHeight)
getVerticalScrollMarginInPixels: ->
Math.round(@model.getVerticalScrollMargin() * @lineHeight)
@@ -1482,14 +1299,14 @@ class TextEditorPresenter
if options?.reversed ? true
if desiredScrollBottom > @getScrollBottom()
@setScrollBottom(desiredScrollBottom, false)
@updateScrollTop(desiredScrollBottom - @getClientHeight())
if desiredScrollTop < @getScrollTop()
@setScrollTop(desiredScrollTop, false)
@updateScrollTop(desiredScrollTop)
else
if desiredScrollTop < @getScrollTop()
@setScrollTop(desiredScrollTop, false)
@updateScrollTop(desiredScrollTop)
if desiredScrollBottom > @getScrollBottom()
@setScrollBottom(desiredScrollBottom, false)
@updateScrollTop(desiredScrollBottom - @getClientHeight())
commitPendingLogicalScrollLeftPosition: ->
return unless @pendingScrollLogicalPosition?
@@ -1509,14 +1326,14 @@ class TextEditorPresenter
if options?.reversed ? true
if desiredScrollRight > @getScrollRight()
@setScrollRight(desiredScrollRight, false)
@updateScrollLeft(desiredScrollRight - @getClientWidth())
if desiredScrollLeft < @getScrollLeft()
@setScrollLeft(desiredScrollLeft, false)
@updateScrollLeft(desiredScrollLeft)
else
if desiredScrollLeft < @getScrollLeft()
@setScrollLeft(desiredScrollLeft, false)
@updateScrollLeft(desiredScrollLeft)
if desiredScrollRight > @getScrollRight()
@setScrollRight(desiredScrollRight, false)
@updateScrollLeft(desiredScrollRight - @getClientWidth())
commitPendingScrollLeftPosition: ->
if @pendingScrollLeft?

View File

@@ -57,11 +57,11 @@ isPairedCharacter = (string, index=0) ->
isVariationSequence(charCodeA, charCodeB) or
isCombinedCharacter(charCodeA, charCodeB)
isJapaneseCharacter = (charCode) ->
IsJapaneseKanaCharacter = (charCode) ->
0x3000 <= charCode <= 0x30FF
isCjkUnifiedIdeograph = (charCode) ->
0x4E00 <= charCode <= 0x9FAF
isCJKUnifiedIdeograph = (charCode) ->
0x4E00 <= charCode <= 0x9FFF
isFullWidthForm = (charCode) ->
0xFF01 <= charCode <= 0xFF5E or
@@ -70,8 +70,8 @@ isFullWidthForm = (charCode) ->
isDoubleWidthCharacter = (character) ->
charCode = character.charCodeAt(0)
isJapaneseCharacter(charCode) or
isCjkUnifiedIdeograph(charCode) or
IsJapaneseKanaCharacter(charCode) or
isCJKUnifiedIdeograph(charCode) or
isFullWidthForm(charCode)
isHalfWidthCharacter = (character) ->
@@ -89,6 +89,11 @@ isKoreanCharacter = (character) ->
0xA960 <= charCode <= 0xA97F or
0xD7B0 <= charCode <= 0xD7FF
isCJKCharacter = (character) ->
isDoubleWidthCharacter(character) or
isHalfWidthCharacter(character) or
isKoreanCharacter(character)
# Does the given string contain at least surrogate pair, variation sequence,
# or combined character?
#
@@ -102,4 +107,4 @@ hasPairedCharacter = (string) ->
index++
false
module.exports = {isPairedCharacter, hasPairedCharacter, isDoubleWidthCharacter, isHalfWidthCharacter, isKoreanCharacter}
module.exports = {isPairedCharacter, hasPairedCharacter, isDoubleWidthCharacter, isHalfWidthCharacter, isKoreanCharacter, isCJKCharacter}

View File

@@ -36,7 +36,7 @@ class TokenizedBuffer extends Model
constructor: (params) ->
{
@buffer, @tabLength, @ignoreInvisibles, @largeFileMode, @config,
@grammarRegistry, @packageManager, @assert
@grammarRegistry, @packageManager, @assert, grammarScopeName
} = params
@emitter = new Emitter
@@ -49,18 +49,26 @@ class TokenizedBuffer extends Model
@disposables.add @buffer.preemptDidChange (e) => @handleBufferChange(e)
@disposables.add @buffer.onDidChangePath (@bufferPath) => @reloadGrammar()
@reloadGrammar()
if grammar = @grammarRegistry.grammarForScopeName(grammarScopeName)
@setGrammar(grammar)
else
@reloadGrammar()
@grammarToRestoreScopeName = grammarScopeName
destroyed: ->
@disposables.dispose()
serialize: ->
deserializer: 'TokenizedBuffer'
bufferPath: @buffer.getPath()
bufferId: @buffer.getId()
tabLength: @tabLength
ignoreInvisibles: @ignoreInvisibles
largeFileMode: @largeFileMode
state = {
deserializer: 'TokenizedBuffer'
bufferPath: @buffer.getPath()
bufferId: @buffer.getId()
tabLength: @tabLength
ignoreInvisibles: @ignoreInvisibles
largeFileMode: @largeFileMode
}
state.grammarScopeName = @grammar?.scopeName unless @buffer.getPath()
state
observeGrammar: (callback) ->
callback(@grammar)
@@ -76,7 +84,9 @@ class TokenizedBuffer extends Model
@emitter.on 'did-tokenize', callback
grammarAddedOrUpdated: (grammar) =>
if grammar.injectionSelector?
if @grammarToRestoreScopeName is grammar.scopeName
@setGrammar(grammar)
else if grammar.injectionSelector?
@retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector)
else
newScore = @grammarRegistry.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent())
@@ -89,6 +99,8 @@ class TokenizedBuffer extends Model
@rootScopeDescriptor = new ScopeDescriptor(scopes: [@grammar.scopeName])
@currentGrammarScore = score ? @grammarRegistry.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent())
@grammarToRestoreScopeName = null
@grammarUpdateDisposable?.dispose()
@grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines()
@disposables.add(@grammarUpdateDisposable)

View File

@@ -1,5 +1,5 @@
_ = require 'underscore-plus'
{isPairedCharacter} = require './text-utils'
{isPairedCharacter, isCJKCharacter} = require './text-utils'
Token = require './token'
{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols'
@@ -322,15 +322,18 @@ class TokenizedLine
return unless @text.length > maxColumn
if /\s/.test(@text[maxColumn])
# search forward for the start of a word past the boundary
# search forward for the start of a word past the boundary
for column in [maxColumn..@text.length]
return column if /\S/.test(@text[column])
return @text.length
else if isCJKCharacter(@text[maxColumn])
maxColumn
else
# search backward for the start of the word on the boundary
for column in [maxColumn..@firstNonWhitespaceIndex]
return column + 1 if /\s/.test(@text[column])
if /\s/.test(@text[column]) or isCJKCharacter(@text[column])
return column + 1
return maxColumn

View File

@@ -19,6 +19,7 @@
path.join(process.env.ATOM_HOME, 'blob-store/')
)
NativeCompileCache.setCacheStore(blobStore)
NativeCompileCache.setV8Version(process.versions.v8)
NativeCompileCache.install()
// Normalize to make sure drive letter case is consistent on Windows