mirror of
https://github.com/atom/atom.git
synced 2026-01-23 13:58:08 -05:00
Merge remote-tracking branch 'refs/remotes/origin/master' into wl-electron-35
This commit is contained in:
@@ -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
|
||||
|
||||
18
package.json
18
package.json
@@ -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",
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
1
spec/fixtures/native-cache/file-4.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = function () { return "file-4" }
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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("B")).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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user