diff --git a/apm/package.json b/apm/package.json
index 31162dcafb8..73f860586d6 100644
--- a/apm/package.json
+++ b/apm/package.json
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
- "atom-package-manager": "1.12.5"
+ "atom-package-manager": "1.13.0"
}
}
diff --git a/dot-atom/styles.less b/dot-atom/styles.less
index a321469e7a7..e4fad4f3119 100644
--- a/dot-atom/styles.less
+++ b/dot-atom/styles.less
@@ -26,7 +26,7 @@ atom-text-editor {
// background-color: hsl(180, 24%, 12%);
}
-// To style other content in the text editor's shadow DOM, use the ::shadow expression
-atom-text-editor::shadow .cursor {
+// style UI elements inside atom-text-editor
+atom-text-editor .cursor {
// border-color: red;
}
diff --git a/package.json b/package.json
index 46f7d6e5f66..f4ab1375c33 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,8 @@
"nslog": "^3",
"oniguruma": "6.1.0",
"pathwatcher": "~6.5",
+ "postcss": "5.2.4",
+ "postcss-selector-parser": "2.2.1",
"property-accessors": "^1.1.3",
"random-words": "0.0.1",
"resolve": "^1.1.6",
@@ -67,18 +69,18 @@
"yargs": "^3.23.0"
},
"packageDependencies": {
- "atom-dark-syntax": "0.27.0",
- "atom-dark-ui": "0.52.0",
- "atom-light-syntax": "0.28.0",
- "atom-light-ui": "0.45.0",
- "base16-tomorrow-dark-theme": "1.3.0",
- "base16-tomorrow-light-theme": "1.3.0",
- "one-dark-ui": "1.6.2",
- "one-light-ui": "1.6.2",
- "one-dark-syntax": "1.5.0",
- "one-light-syntax": "1.5.0",
- "solarized-dark-syntax": "1.0.5",
- "solarized-light-syntax": "1.0.5",
+ "atom-dark-syntax": "0.28.0",
+ "atom-dark-ui": "0.53.0",
+ "atom-light-syntax": "0.29.0",
+ "atom-light-ui": "0.46.0",
+ "base16-tomorrow-dark-theme": "1.4.0",
+ "base16-tomorrow-light-theme": "1.4.0",
+ "one-dark-ui": "1.7.0",
+ "one-light-ui": "1.7.0",
+ "one-dark-syntax": "1.6.0",
+ "one-light-syntax": "1.6.0",
+ "solarized-dark-syntax": "1.1.0",
+ "solarized-light-syntax": "1.1.0",
"about": "1.7.0",
"archive-view": "0.62.0",
"autocomplete-atom-api": "0.10.0",
@@ -87,18 +89,18 @@
"autocomplete-plus": "2.33.1",
"autocomplete-snippets": "1.11.0",
"autoflow": "0.27.0",
- "autosave": "0.23.1",
+ "autosave": "0.23.2",
"background-tips": "0.26.1",
- "bookmarks": "0.42.0",
+ "bookmarks": "0.43.1",
"bracket-matcher": "0.82.2",
- "command-palette": "0.39.0",
- "deprecation-cop": "0.54.1",
+ "command-palette": "0.39.1",
+ "deprecation-cop": "0.55.1",
"dev-live-reload": "0.47.0",
"encoding-selector": "0.22.0",
"exception-reporting": "0.40.0",
- "find-and-replace": "0.202.1",
+ "find-and-replace": "0.203.0",
"fuzzy-finder": "1.4.0",
- "git-diff": "1.1.0",
+ "git-diff": "1.2.0",
"go-to-line": "0.31.0",
"grammar-selector": "0.48.2",
"image-view": "0.60.0",
@@ -106,16 +108,16 @@
"keybinding-resolver": "0.35.0",
"line-ending-selector": "0.5.0",
"link": "0.31.2",
- "markdown-preview": "0.158.8",
+ "markdown-preview": "0.159.0",
"metrics": "1.0.0",
"notifications": "0.65.1",
"open-on-github": "1.2.1",
- "package-generator": "1.0.1",
- "settings-view": "0.243.1",
+ "package-generator": "1.0.2",
+ "settings-view": "0.244.0",
"snippets": "1.0.3",
- "spell-check": "0.68.4",
+ "spell-check": "0.68.5",
"status-bar": "1.6.0",
- "styleguide": "0.47.2",
+ "styleguide": "0.47.3",
"symbols-view": "0.113.1",
"tabs": "0.103.0",
"timecop": "0.33.2",
@@ -123,7 +125,7 @@
"update-package-dependencies": "0.10.0",
"welcome": "0.35.1",
"whitespace": "0.35.0",
- "wrap-guide": "0.38.2",
+ "wrap-guide": "0.39.0",
"language-c": "0.54.0",
"language-clojure": "0.22.1",
"language-coffee-script": "0.48.0",
diff --git a/spec/atom-reporter.coffee b/spec/atom-reporter.coffee
index ef46b09c550..1600da9d78e 100644
--- a/spec/atom-reporter.coffee
+++ b/spec/atom-reporter.coffee
@@ -97,7 +97,7 @@ class AtomReporter
if @failedCount is 1
@message.textContent = "#{@failedCount} failure"
else
- @message.textConent = "#{@failedCount} failures"
+ @message.textContent = "#{@failedCount} failures"
reportSuiteResults: (suite) ->
@@ -110,42 +110,6 @@ class AtomReporter
reportSpecStarting: (spec) ->
@specStarted(spec)
- addDeprecations: (spec) ->
- deprecations = grim.getDeprecations()
- @deprecationCount += deprecations.length
- @deprecations.style.display = '' if @deprecationCount > 0
- if @deprecationCount is 1
- @deprecationStatus.textContent = "1 deprecation"
- else
- @deprecationStatus.textContent = "#{@deprecationCount} deprecations"
-
- for deprecation in deprecations
- @deprecationList.appendChild(@buildDeprecationElement(spec, deprecation))
-
- grim.clearDeprecations()
-
- buildDeprecationElement: (spec, deprecation) ->
- div = document.createElement('div')
- div.className = 'padded'
- div.innerHTML = """
-
- #{marked(deprecation.message)}
-
- """
-
- for stack in deprecation.getStacks()
- fullStack = stack.map ({functionName, location}) ->
- if functionName is ''
- " at #{location}"
- else
- " at #{functionName} (#{location})"
- pre = document.createElement('pre')
- pre.className = 'stack-trace padded'
- pre.textContent = formatStackTrace(spec, deprecation.message, fullStack.join('\n'))
- div.appendChild(pre)
-
- div
-
handleEvents: ->
listen document, 'click', '.spec-toggle', (event) ->
specFailures = event.currentTarget.parentElement.querySelector('.spec-failures')
@@ -273,7 +237,6 @@ class AtomReporter
specView = new SpecResultView(spec)
specView.attach()
@failedCount++
- @addDeprecations(spec)
class SuiteResultView
constructor: (@suite) ->
diff --git a/spec/lines-yardstick-spec.coffee b/spec/lines-yardstick-spec.coffee
index 483a7767568..2172267db28 100644
--- a/spec/lines-yardstick-spec.coffee
+++ b/spec/lines-yardstick-spec.coffee
@@ -70,7 +70,7 @@ describe "LinesYardstick", ->
font-size: 12px;
font-family: monospace;
}
- .function {
+ .syntax--function {
font-size: 16px
}
"""
@@ -144,7 +144,7 @@ describe "LinesYardstick", ->
font-size: 12px;
font-family: monospace;
}
- .function {
+ .syntax--function {
font-size: 16px
}
"""
diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee
index 7dbd6a4e5da..44d8b4460b1 100644
--- a/spec/spec-helper.coffee
+++ b/spec/spec-helper.coffee
@@ -105,10 +105,10 @@ beforeEach ->
addCustomMatchers(this)
afterEach ->
+ ensureNoDeprecatedFunctionCalls()
+ ensureNoDeprecatedStylesheets()
atom.reset()
-
document.getElementById('jasmine-content').innerHTML = '' unless window.debugContent
-
warnIfLeakingPathSubscriptions()
waits(0) # yield to ui thread to make screen update more frequently
@@ -118,8 +118,9 @@ warnIfLeakingPathSubscriptions = ->
console.error("WARNING: Leaking subscriptions for paths: " + watchedPaths.join(", "))
pathwatcher.closeAllWatchers()
-ensureNoDeprecatedFunctionsCalled = ->
- deprecations = Grim.getDeprecations()
+ensureNoDeprecatedFunctionCalls = ->
+ deprecations = _.clone(Grim.getDeprecations())
+ Grim.clearDeprecations()
if deprecations.length > 0
originalPrepareStackTrace = Error.prepareStackTrace
Error.prepareStackTrace = (error, stack) ->
@@ -136,9 +137,19 @@ ensureNoDeprecatedFunctionsCalled = ->
error = new Error("Deprecated function(s) #{deprecations.map(({originName}) -> originName).join ', '}) were called.")
error.stack
Error.prepareStackTrace = originalPrepareStackTrace
-
throw error
+ensureNoDeprecatedStylesheets = ->
+ deprecations = _.clone(atom.styles.getDeprecations())
+ atom.styles.clearDeprecations()
+ for sourcePath, deprecation of deprecations
+ title =
+ if sourcePath isnt 'undefined'
+ "Deprecated stylesheet at '#{sourcePath}':"
+ else
+ "Deprecated stylesheet:"
+ throw new Error("#{title}\n#{deprecation.message}")
+
emitObject = jasmine.StringPrettyPrinter.prototype.emitObject
jasmine.StringPrettyPrinter.prototype.emitObject = (obj) ->
if obj.inspect
@@ -154,12 +165,15 @@ jasmine.attachToDOM = (element) ->
jasmineContent = document.querySelector('#jasmine-content')
jasmineContent.appendChild(element) unless jasmineContent.contains(element)
-deprecationsSnapshot = null
+grimDeprecationsSnapshot = null
+stylesDeprecationsSnapshot = null
jasmine.snapshotDeprecations = ->
- deprecationsSnapshot = _.clone(Grim.deprecations)
+ grimDeprecationsSnapshot = _.clone(Grim.deprecations)
+ stylesDeprecationsSnapshot = _.clone(atom.styles.deprecationsBySourcePath)
jasmine.restoreDeprecationsSnapshot = ->
- Grim.deprecations = deprecationsSnapshot
+ Grim.deprecations = grimDeprecationsSnapshot
+ atom.styles.deprecationsBySourcePath = stylesDeprecationsSnapshot
jasmine.useRealClock = ->
jasmine.unspy(window, 'setTimeout')
diff --git a/spec/style-manager-spec.coffee b/spec/style-manager-spec.coffee
deleted file mode 100644
index d0a1cfe13f4..00000000000
--- a/spec/style-manager-spec.coffee
+++ /dev/null
@@ -1,68 +0,0 @@
-StyleManager = require '../src/style-manager'
-
-describe "StyleManager", ->
- [manager, addEvents, removeEvents, updateEvents] = []
-
- beforeEach ->
- manager = new StyleManager(configDirPath: atom.getConfigDirPath())
- addEvents = []
- removeEvents = []
- updateEvents = []
-
- manager.onDidAddStyleElement (event) -> addEvents.push(event)
- manager.onDidRemoveStyleElement (event) -> removeEvents.push(event)
- manager.onDidUpdateStyleElement (event) -> updateEvents.push(event)
-
- describe "::addStyleSheet(source, params)", ->
- it "adds a stylesheet based on the given source and returns a disposable allowing it to be removed", ->
- disposable = manager.addStyleSheet("a {color: red;}")
-
- expect(addEvents.length).toBe 1
- expect(addEvents[0].textContent).toBe "a {color: red;}"
-
- styleElements = manager.getStyleElements()
- expect(styleElements.length).toBe 1
- expect(styleElements[0].textContent).toBe "a {color: red;}"
-
- disposable.dispose()
-
- expect(removeEvents.length).toBe 1
- expect(removeEvents[0].textContent).toBe "a {color: red;}"
- expect(manager.getStyleElements().length).toBe 0
-
- describe "when a sourcePath parameter is specified", ->
- it "ensures a maximum of one style element for the given source path, updating a previous if it exists", ->
- disposable1 = manager.addStyleSheet("a {color: red;}", sourcePath: '/foo/bar')
-
- expect(addEvents.length).toBe 1
- expect(addEvents[0].getAttribute('source-path')).toBe '/foo/bar'
-
- disposable2 = manager.addStyleSheet("a {color: blue;}", sourcePath: '/foo/bar')
-
- expect(addEvents.length).toBe 1
- expect(updateEvents.length).toBe 1
- expect(updateEvents[0].getAttribute('source-path')).toBe '/foo/bar'
- expect(updateEvents[0].textContent).toBe "a {color: blue;}"
-
- disposable2.dispose()
- addEvents = []
-
- manager.addStyleSheet("a {color: yellow;}", sourcePath: '/foo/bar')
-
- expect(addEvents.length).toBe 1
- expect(addEvents[0].getAttribute('source-path')).toBe '/foo/bar'
- expect(addEvents[0].textContent).toBe "a {color: yellow;}"
-
- describe "when a priority parameter is specified", ->
- it "inserts the style sheet based on the priority", ->
- manager.addStyleSheet("a {color: red}", priority: 1)
- manager.addStyleSheet("a {color: blue}", priority: 0)
- manager.addStyleSheet("a {color: green}", priority: 2)
- manager.addStyleSheet("a {color: yellow}", priority: 1)
-
- expect(manager.getStyleElements().map (elt) -> elt.textContent).toEqual [
- "a {color: blue}"
- "a {color: red}"
- "a {color: yellow}"
- "a {color: green}"
- ]
diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js
new file mode 100644
index 00000000000..898e855877c
--- /dev/null
+++ b/spec/style-manager-spec.js
@@ -0,0 +1,137 @@
+const StyleManager = require('../src/style-manager')
+
+describe('StyleManager', () => {
+ let [styleManager, addEvents, removeEvents, updateEvents] = []
+
+ beforeEach(() => {
+ styleManager = new StyleManager({configDirPath: atom.getConfigDirPath()})
+ addEvents = []
+ removeEvents = []
+ updateEvents = []
+ styleManager.onDidAddStyleElement((event) => { addEvents.push(event) })
+ styleManager.onDidRemoveStyleElement((event) => { removeEvents.push(event) })
+ styleManager.onDidUpdateStyleElement((event) => { updateEvents.push(event) })
+ })
+
+ describe('::addStyleSheet(source, params)', () => {
+ it('adds a style sheet based on the given source and returns a disposable allowing it to be removed', () => {
+ const disposable = styleManager.addStyleSheet('a {color: red}')
+ expect(addEvents.length).toBe(1)
+ expect(addEvents[0].textContent).toBe('a {color: red}')
+ const styleElements = styleManager.getStyleElements()
+ expect(styleElements.length).toBe(1)
+ expect(styleElements[0].textContent).toBe('a {color: red}')
+ disposable.dispose()
+ expect(removeEvents.length).toBe(1)
+ expect(removeEvents[0].textContent).toBe('a {color: red}')
+ expect(styleManager.getStyleElements().length).toBe(0)
+ })
+
+ describe('atom-text-editor shadow DOM selectors upgrades', () => {
+ beforeEach(() => {
+ // attach styles element to the DOM to parse CSS rules
+ styleManager.onDidAddStyleElement((styleElement) => { jasmine.attachToDOM(styleElement) })
+ })
+
+ it('removes the ::shadow pseudo-element from atom-text-editor selectors', () => {
+ styleManager.addStyleSheet(`
+ atom-text-editor::shadow .class-1, atom-text-editor::shadow .class-2 { color: red }
+ atom-text-editor::shadow > .class-3 { color: yellow }
+ atom-text-editor .class-4 { color: blue }
+ another-element::shadow .class-5 { color: white }
+ atom-text-editor[data-grammar*=\"js\"]::shadow .class-6 { color: green; }
+ atom-text-editor[mini].is-focused::shadow .class-7 { color: green; }
+ `)
+ expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([
+ 'atom-text-editor .class-1, atom-text-editor .class-2',
+ 'atom-text-editor > .class-3',
+ 'atom-text-editor .class-4',
+ 'another-element::shadow .class-5',
+ 'atom-text-editor[data-grammar*=\"js\"] .class-6',
+ 'atom-text-editor[mini].is-focused .class-7'
+ ])
+ })
+
+ describe('when a selector targets the atom-text-editor shadow DOM', () => {
+ it('prepends "--syntax" to class selectors matching a grammar scope name and not already starting with "syntax--"', () => {
+ styleManager.addStyleSheet(`
+ .class-1 { color: red }
+ .source > .js, .source.coffee { color: green }
+ .syntax--source { color: gray }
+ #id-1 { color: blue }
+ `, {context: 'atom-text-editor'})
+ expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([
+ '.class-1',
+ '.syntax--source > .syntax--js, .syntax--source.syntax--coffee',
+ '.syntax--source',
+ '#id-1'
+ ])
+
+ styleManager.addStyleSheet(`
+ .source > .js, .source.coffee { color: green }
+ atom-text-editor::shadow .source > .js { color: yellow }
+ atom-text-editor[mini].is-focused::shadow .source > .js { color: gray }
+ atom-text-editor .source > .js { color: red }
+ `)
+ expect(Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map((r) => r.selectorText)).toEqual([
+ '.source > .js, .source.coffee',
+ 'atom-text-editor .syntax--source > .syntax--js',
+ 'atom-text-editor[mini].is-focused .syntax--source > .syntax--js',
+ 'atom-text-editor .source > .js'
+ ])
+ })
+ })
+
+ it('replaces ":host" with "atom-text-editor" only when the context of a style sheet is "atom-text-editor"', () => {
+ styleManager.addStyleSheet(':host .class-1, :host .class-2 { color: red; }')
+ expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([
+ ':host .class-1, :host .class-2'
+ ])
+ styleManager.addStyleSheet(':host .class-1, :host .class-2 { color: red; }', {context: 'atom-text-editor'})
+ expect(Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map((r) => r.selectorText)).toEqual([
+ 'atom-text-editor .class-1, atom-text-editor .class-2'
+ ])
+ })
+
+ it('does not throw exceptions on rules with no selectors', () => {
+ styleManager.addStyleSheet('@media screen {font-size: 10px}', {context: 'atom-text-editor'})
+ })
+ })
+
+ describe('when a sourcePath parameter is specified', () => {
+ it('ensures a maximum of one style element for the given source path, updating a previous if it exists', () => {
+ const disposable1 = styleManager.addStyleSheet('a {color: red}', {sourcePath: '/foo/bar'})
+ expect(addEvents.length).toBe(1)
+ expect(addEvents[0].getAttribute('source-path')).toBe('/foo/bar')
+
+ const disposable2 = styleManager.addStyleSheet('a {color: blue}', {sourcePath: '/foo/bar'})
+ expect(addEvents.length).toBe(1)
+ expect(updateEvents.length).toBe(1)
+ expect(updateEvents[0].getAttribute('source-path')).toBe('/foo/bar')
+ expect(updateEvents[0].textContent).toBe('a {color: blue}')
+ disposable2.dispose()
+
+ addEvents = []
+ styleManager.addStyleSheet('a {color: yellow}', {sourcePath: '/foo/bar'})
+ expect(addEvents.length).toBe(1)
+ expect(addEvents[0].getAttribute('source-path')).toBe('/foo/bar')
+ expect(addEvents[0].textContent).toBe('a {color: yellow}')
+ })
+ })
+
+ describe('when a priority parameter is specified', () => {
+ it('inserts the style sheet based on the priority', () => {
+ styleManager.addStyleSheet('a {color: red}', {priority: 1})
+ styleManager.addStyleSheet('a {color: blue}', {priority: 0})
+ styleManager.addStyleSheet('a {color: green}', {priority: 2})
+ styleManager.addStyleSheet('a {color: yellow}', {priority: 1})
+ expect(styleManager.getStyleElements().map((elt) => elt.textContent)).toEqual([
+ 'a {color: blue}',
+ 'a {color: red}',
+ 'a {color: yellow}',
+ 'a {color: green}'
+ ])
+ })
+ })
+ })
+})
diff --git a/spec/styles-element-spec.coffee b/spec/styles-element-spec.coffee
index b1a57938c4e..0889b0d43ad 100644
--- a/spec/styles-element-spec.coffee
+++ b/spec/styles-element-spec.coffee
@@ -77,39 +77,3 @@ describe "StylesElement", ->
expect(element.children.length).toBe 2
expect(element.children[0].textContent).toBe "a {color: red;}"
expect(element.children[1].textContent).toBe "a {color: blue;}"
-
- describe "atom-text-editor shadow DOM selector upgrades", ->
- beforeEach ->
- element.setAttribute('context', 'atom-text-editor')
- spyOn(console, 'warn')
-
- it "upgrades selectors containing .editor-colors", ->
- atom.styles.addStyleSheet(".editor-colors {background: black;}", context: 'atom-text-editor')
- expect(element.firstChild.sheet.cssRules[0].selectorText).toBe ':host'
-
- it "upgrades selectors containing .editor", ->
- atom.styles.addStyleSheet """
- .editor {background: black;}
- .editor.mini {background: black;}
- .editor:focus {background: black;}
- """, context: 'atom-text-editor'
-
- expect(element.firstChild.sheet.cssRules[0].selectorText).toBe ':host'
- expect(element.firstChild.sheet.cssRules[1].selectorText).toBe ':host(.mini)'
- expect(element.firstChild.sheet.cssRules[2].selectorText).toBe ':host(:focus)'
-
- it "defers selector upgrade until the element is attached", ->
- element = new StylesElement
- element.initialize(atom.styles)
- element.setAttribute('context', 'atom-text-editor')
-
- atom.styles.addStyleSheet ".editor {background: black;}", context: 'atom-text-editor'
- expect(element.firstChild.sheet).toBeNull()
-
- document.querySelector('#jasmine-content').appendChild(element)
- expect(element.firstChild.sheet.cssRules[0].selectorText).toBe ':host'
-
- it "does not throw exceptions on rules with no selectors", ->
- atom.styles.addStyleSheet """
- @media screen {font-size: 10px;}
- """, context: 'atom-text-editor'
diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js
index 7de1c6ccd7e..4478df5322d 100644
--- a/spec/text-editor-component-spec.js
+++ b/spec/text-editor-component-spec.js
@@ -509,7 +509,7 @@ describe('TextEditorComponent', function () {
it('displays newlines as their own token outside of the other tokens\' scopeDescriptor', function () {
editor.setText('let\n')
runAnimationFrames()
- expect(component.lineNodeForScreenRow(0).innerHTML).toBe('let' + invisibles.eol + '')
+ expect(component.lineNodeForScreenRow(0).innerHTML).toBe('let' + invisibles.eol + '')
})
it('displays trailing carriage returns using a visible, non-empty value', function () {
@@ -544,20 +544,20 @@ describe('TextEditorComponent', function () {
normalizeLineEndings: false
})
runAnimationFrames()
- expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
+ expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
editor.setTabLength(3)
runAnimationFrames()
- expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
+ expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
editor.setTabLength(1)
runAnimationFrames()
- expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
+ expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
editor.setTextInBufferRange([[9, 0], [9, Infinity]], ' ')
editor.setTextInBufferRange([[11, 0], [11, Infinity]], ' ')
runAnimationFrames()
- expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
+ expect(component.lineNodeForScreenRow(10).innerHTML).toBe('CE')
})
describe('when soft wrapping is enabled', function () {
@@ -1252,7 +1252,7 @@ describe('TextEditorComponent', function () {
let cursor = componentNode.querySelector('.cursor')
let cursorRect = cursor.getBoundingClientRect()
- let cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.storage.type.function.js').firstChild
+ let cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.syntax--storage.syntax--type.syntax--function.syntax--js').firstChild
let range = document.createRange()
range.setStart(cursorLocationTextNode, 0)
range.setEnd(cursorLocationTextNode, 1)
@@ -1269,7 +1269,7 @@ describe('TextEditorComponent', function () {
let cursor = componentNode.querySelector('.cursor')
let cursorRect = cursor.getBoundingClientRect()
- let cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.source.js').childNodes[2]
+ let cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.syntax--source.syntax--js').childNodes[2]
let range = document.createRange(cursorLocationTextNode)
range.setStart(cursorLocationTextNode, 0)
range.setEnd(cursorLocationTextNode, 1)
@@ -1294,14 +1294,14 @@ describe('TextEditorComponent', function () {
editor.setCursorScreenPosition([0, 16])
runAnimationFrames(true)
- atom.styles.addStyleSheet('.function.js {\n font-weight: bold;\n}', {
+ atom.styles.addStyleSheet('.syntax--function.syntax--js {\n font-weight: bold;\n}', {
context: 'atom-text-editor'
})
runAnimationFrames(true)
let cursor = componentNode.querySelector('.cursor')
let cursorRect = cursor.getBoundingClientRect()
- let cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.storage.type.function.js').firstChild
+ let cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.syntax--storage.syntax--type.syntax--function.syntax--js').firstChild
let range = document.createRange()
range.setStart(cursorLocationTextNode, 0)
range.setEnd(cursorLocationTextNode, 1)
@@ -1772,32 +1772,32 @@ describe('TextEditorComponent', function () {
let [item3, blockDecoration3] = createBlockDecorationBeforeScreenRow(4, {className: "decoration-3"})
let [item4, blockDecoration4] = createBlockDecorationBeforeScreenRow(7, {className: "decoration-4"})
let [item5, blockDecoration5] = createBlockDecorationAfterScreenRow(7, {className: "decoration-5"})
+ let [item6, blockDecoration6] = createBlockDecorationAfterScreenRow(12, {className: "decoration-6"})
atom.styles.addStyleSheet(
`atom-text-editor .decoration-1 { width: 30px; height: 80px; }
atom-text-editor .decoration-2 { width: 30px; height: 40px; }
atom-text-editor .decoration-3 { width: 30px; height: 100px; }
atom-text-editor .decoration-4 { width: 30px; height: 120px; }
- atom-text-editor .decoration-5 { width: 30px; height: 42px; }`,
+ atom-text-editor .decoration-5 { width: 30px; height: 42px; }
+ atom-text-editor .decoration-6 { width: 30px; height: 22px; }`,
{context: 'atom-text-editor'}
)
runAnimationFrames()
-
expect(component.getDomNode().querySelectorAll(".line").length).toBe(7)
-
+ expect(verticalScrollbarNode.scrollHeight).toBe(editor.getScreenLineCount() * editor.getLineHeightInPixels() + 80 + 40 + 100 + 120 + 42 + 22)
expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 80 + 40 + "px")
expect(component.tileNodesForLines()[0].style.webkitTransform).toBe("translate3d(0px, 0px, 0px)")
expect(component.tileNodesForLines()[1].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 100 + "px")
expect(component.tileNodesForLines()[1].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight}px, 0px)`)
expect(component.tileNodesForLines()[2].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 120 + 42 + "px")
expect(component.tileNodesForLines()[2].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight + component.tileNodesForLines()[1].offsetHeight}px, 0px)`)
-
expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBe(item1)
expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2)
expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3)
expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBeNull()
expect(component.getTopmostDOMNode().querySelector(".decoration-5")).toBeNull()
-
+ expect(component.getTopmostDOMNode().querySelector(".decoration-6")).toBeNull()
expect(item1.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 0)
expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 2 + 80)
expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 4 + 80 + 40)
@@ -1805,24 +1805,21 @@ describe('TextEditorComponent', function () {
editor.setCursorScreenPosition([0, 0])
editor.insertNewline()
blockDecoration1.destroy()
-
runAnimationFrames()
-
expect(component.getDomNode().querySelectorAll(".line").length).toBe(7)
-
+ expect(verticalScrollbarNode.scrollHeight).toBe(editor.getScreenLineCount() * editor.getLineHeightInPixels() + 40 + 100 + 120 + 42 + 22)
expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + "px")
expect(component.tileNodesForLines()[0].style.webkitTransform).toBe("translate3d(0px, 0px, 0px)")
expect(component.tileNodesForLines()[1].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 100 + 40 + "px")
expect(component.tileNodesForLines()[1].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight}px, 0px)`)
expect(component.tileNodesForLines()[2].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 120 + 42 + "px")
expect(component.tileNodesForLines()[2].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight + component.tileNodesForLines()[1].offsetHeight}px, 0px)`)
-
expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBeNull()
expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2)
expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3)
expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBeNull()
expect(component.getTopmostDOMNode().querySelector(".decoration-5")).toBeNull()
-
+ expect(component.getTopmostDOMNode().querySelector(".decoration-6")).toBeNull()
expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 3)
expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 5 + 40)
@@ -1833,52 +1830,71 @@ describe('TextEditorComponent', function () {
runAnimationFrames() // causes the DOM to update and to retrieve new styles
runAnimationFrames() // applies the changes
-
expect(component.getDomNode().querySelectorAll(".line").length).toBe(7)
-
+ expect(verticalScrollbarNode.scrollHeight).toBe(editor.getScreenLineCount() * editor.getLineHeightInPixels() + 60 + 100 + 120 + 42 + 22)
expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + "px")
expect(component.tileNodesForLines()[0].style.webkitTransform).toBe("translate3d(0px, 0px, 0px)")
expect(component.tileNodesForLines()[1].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 100 + 60 + "px")
expect(component.tileNodesForLines()[1].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight}px, 0px)`)
expect(component.tileNodesForLines()[2].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 120 + 42 + "px")
expect(component.tileNodesForLines()[2].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight + component.tileNodesForLines()[1].offsetHeight}px, 0px)`)
-
expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBeNull()
expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2)
expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3)
expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBeNull()
expect(component.getTopmostDOMNode().querySelector(".decoration-5")).toBeNull()
-
+ expect(component.getTopmostDOMNode().querySelector(".decoration-6")).toBeNull()
expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 3)
expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 5 + 60)
item2.style.height = "20px"
wrapperNode.invalidateBlockDecorationDimensions(blockDecoration2)
- runAnimationFrames()
- runAnimationFrames()
-
+ runAnimationFrames() // causes the DOM to update and to retrieve new styles
+ runAnimationFrames() // applies the changes
expect(component.getDomNode().querySelectorAll(".line").length).toBe(9)
-
+ expect(verticalScrollbarNode.scrollHeight).toBe(editor.getScreenLineCount() * editor.getLineHeightInPixels() + 20 + 100 + 120 + 42 + 22)
expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + "px")
expect(component.tileNodesForLines()[0].style.webkitTransform).toBe("translate3d(0px, 0px, 0px)")
expect(component.tileNodesForLines()[1].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 100 + 20 + "px")
expect(component.tileNodesForLines()[1].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight}px, 0px)`)
expect(component.tileNodesForLines()[2].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 120 + 42 + "px")
expect(component.tileNodesForLines()[2].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight + component.tileNodesForLines()[1].offsetHeight}px, 0px)`)
-
expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBeNull()
expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2)
expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3)
expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBe(item4)
expect(component.getTopmostDOMNode().querySelector(".decoration-5")).toBe(item5)
+ expect(component.getTopmostDOMNode().querySelector(".decoration-6")).toBeNull()
+ expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 3)
+ expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 5 + 20)
+ expect(item4.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 8 + 20 + 100)
+ expect(item5.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 8 + 20 + 100 + 120 + lineHeightInPixels)
+ item6.style.height = "33px"
+ wrapperNode.invalidateBlockDecorationDimensions(blockDecoration6)
+ runAnimationFrames() // causes the DOM to update and to retrieve new styles
+ runAnimationFrames() // applies the changes
+ expect(component.getDomNode().querySelectorAll(".line").length).toBe(9)
+ expect(verticalScrollbarNode.scrollHeight).toBe(editor.getScreenLineCount() * editor.getLineHeightInPixels() + 20 + 100 + 120 + 42 + 33)
+ expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + "px")
+ expect(component.tileNodesForLines()[0].style.webkitTransform).toBe("translate3d(0px, 0px, 0px)")
+ expect(component.tileNodesForLines()[1].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 100 + 20 + "px")
+ expect(component.tileNodesForLines()[1].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight}px, 0px)`)
+ expect(component.tileNodesForLines()[2].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 120 + 42 + "px")
+ expect(component.tileNodesForLines()[2].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight + component.tileNodesForLines()[1].offsetHeight}px, 0px)`)
+ expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBeNull()
+ expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2)
+ expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3)
+ expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBe(item4)
+ expect(component.getTopmostDOMNode().querySelector(".decoration-5")).toBe(item5)
+ expect(component.getTopmostDOMNode().querySelector(".decoration-6")).toBeNull()
expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 3)
expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 5 + 20)
expect(item4.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 8 + 20 + 100)
expect(item5.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 8 + 20 + 100 + 120 + lineHeightInPixels)
})
- it("correctly sets screen rows on elements, both initially and when decorations move", function () {
+ it("correctly sets screen rows on block decoration and ruler nodes, both initially and when decorations move", function () {
let [item, blockDecoration] = createBlockDecorationBeforeScreenRow(0, {className: "decoration-1"})
atom.styles.addStyleSheet(
'atom-text-editor .decoration-1 { width: 30px; height: 80px; }',
@@ -1886,42 +1902,37 @@ describe('TextEditorComponent', function () {
)
runAnimationFrames()
-
- let tileNode, contentElements
-
- tileNode = component.tileNodesForLines()[0]
- contentElements = tileNode.querySelectorAll("content")
-
- expect(contentElements.length).toBe(1)
- expect(contentElements[0].dataset.screenRow).toBe("0")
- expect(component.lineNodeForScreenRow(0).dataset.screenRow).toBe("0")
- expect(component.lineNodeForScreenRow(1).dataset.screenRow).toBe("1")
- expect(component.lineNodeForScreenRow(2).dataset.screenRow).toBe("2")
+ const line0 = component.lineNodeForScreenRow(0)
+ expect(item.previousSibling.dataset.screenRow).toBe("0")
+ expect(item.dataset.screenRow).toBe("0")
+ expect(item.nextSibling.dataset.screenRow).toBe("0")
+ expect(line0.previousSibling).toBe(item.nextSibling)
editor.setCursorBufferPosition([0, 0])
editor.insertNewline()
runAnimationFrames()
+ const line1 = component.lineNodeForScreenRow(1)
+ expect(item.previousSibling.dataset.screenRow).toBe("1")
+ expect(item.dataset.screenRow).toBe("1")
+ expect(item.nextSibling.dataset.screenRow).toBe("1")
+ expect(line1.previousSibling).toBe(item.nextSibling)
- tileNode = component.tileNodesForLines()[0]
- contentElements = tileNode.querySelectorAll("content")
-
- expect(contentElements.length).toBe(1)
- expect(contentElements[0].dataset.screenRow).toBe("1")
- expect(component.lineNodeForScreenRow(0).dataset.screenRow).toBe("0")
- expect(component.lineNodeForScreenRow(1).dataset.screenRow).toBe("1")
- expect(component.lineNodeForScreenRow(2).dataset.screenRow).toBe("2")
-
- blockDecoration.getMarker().setHeadBufferPosition([2, 0])
+ editor.setCursorBufferPosition([0, 0])
+ editor.insertNewline()
runAnimationFrames()
+ const line2 = component.lineNodeForScreenRow(2)
+ expect(item.previousSibling.dataset.screenRow).toBe("2")
+ expect(item.dataset.screenRow).toBe("2")
+ expect(item.nextSibling.dataset.screenRow).toBe("2")
+ expect(line2.previousSibling).toBe(item.nextSibling)
- tileNode = component.tileNodesForLines()[0]
- contentElements = tileNode.querySelectorAll("content")
-
- expect(contentElements.length).toBe(1)
- expect(contentElements[0].dataset.screenRow).toBe("2")
- expect(component.lineNodeForScreenRow(0).dataset.screenRow).toBe("0")
- expect(component.lineNodeForScreenRow(1).dataset.screenRow).toBe("1")
- expect(component.lineNodeForScreenRow(2).dataset.screenRow).toBe("2")
+ blockDecoration.getMarker().setHeadBufferPosition([4, 0])
+ runAnimationFrames()
+ const line4 = component.lineNodeForScreenRow(4)
+ expect(item.previousSibling.dataset.screenRow).toBe("4")
+ expect(item.dataset.screenRow).toBe("4")
+ expect(item.nextSibling.dataset.screenRow).toBe("4")
+ expect(line4.previousSibling).toBe(item.nextSibling)
})
it('measures block decorations taking into account both top and bottom margins of the element and its children', function () {
@@ -1946,6 +1957,18 @@ describe('TextEditorComponent', function () {
expect(component.tileNodesForLines()[2].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + "px")
expect(component.tileNodesForLines()[2].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight + component.tileNodesForLines()[1].offsetHeight}px, 0px)`)
})
+
+ it('allows the same block decoration item to be moved from one tile to another in the same animation frame', function () {
+ let [item, blockDecoration] = createBlockDecorationBeforeScreenRow(5, {className: "decoration-1"})
+ runAnimationFrames()
+ expect(component.tileNodesForLines()[0].querySelector('.decoration-1')).toBeNull()
+ expect(component.tileNodesForLines()[1].querySelector('.decoration-1')).toBe(item)
+
+ blockDecoration.getMarker().setHeadBufferPosition([0, 0])
+ runAnimationFrames()
+ expect(component.tileNodesForLines()[0].querySelector('.decoration-1')).toBe(item)
+ expect(component.tileNodesForLines()[1].querySelector('.decoration-1')).toBeNull()
+ })
})
describe('highlight decoration rendering', function () {
@@ -2873,6 +2896,7 @@ describe('TextEditorComponent', function () {
editor.foldBufferRange([[4, 6], [4, 10]])
editor.foldBufferRange([[4, 15], [4, 20]])
runAnimationFrames()
+
let foldMarkers = component.lineNodeForScreenRow(4).querySelectorAll('.fold-marker')
expect(foldMarkers.length).toBe(2)
expect(editor.isFoldedAtBufferRow(4)).toBe(true)
@@ -3409,8 +3433,7 @@ describe('TextEditorComponent', function () {
it('transfers focus to the hidden input', function () {
expect(document.activeElement).toBe(document.body)
wrapperNode.focus()
- expect(document.activeElement).toBe(wrapperNode)
- expect(wrapperNode.shadowRoot.activeElement).toBe(inputNode)
+ expect(document.activeElement).toBe(inputNode)
})
it('adds the "is-focused" class to the editor when the hidden input is focused', function () {
@@ -4294,7 +4317,7 @@ describe('TextEditorComponent', function () {
atom.config.set('editor.fontFamily', 'sans-serif')
wrapperNode.style.display = 'none'
component.checkForVisibilityChange()
- atom.themes.applyStylesheet('test', '.function.js {\n font-weight: bold;\n}')
+ atom.themes.applyStylesheet('test', '.syntax--function.syntax--js {\n font-weight: bold;\n}')
wrapperNode.style.display = ''
component.checkForVisibilityChange()
editor.setCursorBufferPosition([0, Infinity])
@@ -4429,7 +4452,7 @@ describe('TextEditorComponent', function () {
jasmine.attachToDOM(element)
expect(element.offsetHeight).toBe(200)
- expect(element.shadowRoot.querySelector('.editor-contents--private').offsetHeight).toBe(200)
+ expect(element.querySelector('.editor-contents--private').offsetHeight).toBe(200)
expect(Grim.deprecate.callCount).toBe(1)
expect(Grim.deprecate.argsForCall[0][0]).toMatch(/inline style/)
})
@@ -4452,7 +4475,7 @@ describe('TextEditorComponent', function () {
element.component.measureDimensions()
expect(element.offsetHeight).toBe(200)
- expect(element.shadowRoot.querySelector('.editor-contents--private').offsetHeight).toBe(200)
+ expect(element.querySelector('.editor-contents--private').offsetHeight).toBe(200)
expect(Grim.deprecate.callCount).toBe(1)
expect(Grim.deprecate.argsForCall[0][0]).toMatch(/absolute/)
})
diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee
index 22b92164767..7ed4a106feb 100644
--- a/spec/text-editor-element-spec.coffee
+++ b/spec/text-editor-element-spec.coffee
@@ -2,8 +2,6 @@ TextEditor = require '../src/text-editor'
TextEditorElement = require '../src/text-editor-element'
{Disposable} = require 'event-kit'
-# The rest of text-editor-component-spec will be moved to this file when React
-# is eliminated. This covers only concerns related to the wrapper element for now
describe "TextEditorElement", ->
jasmineContent = null
@@ -59,11 +57,11 @@ describe "TextEditorElement", ->
jasmine.attachToDOM(element)
- initialCount = element.shadowRoot.querySelectorAll('.line-number').length
+ initialCount = element.querySelectorAll('.line-number').length
element.remove()
jasmine.attachToDOM(element)
- expect(element.shadowRoot.querySelectorAll('.line-number').length).toBe initialCount
+ expect(element.querySelectorAll('.line-number').length).toBe initialCount
it "does not render duplicate decorations in custom gutters", ->
editor = new TextEditor
@@ -74,14 +72,14 @@ describe "TextEditorElement", ->
element = atom.views.getView(editor)
jasmine.attachToDOM(element)
- initialDecorationCount = element.shadowRoot.querySelectorAll('.decoration').length
+ initialDecorationCount = element.querySelectorAll('.decoration').length
element.remove()
jasmine.attachToDOM(element)
- expect(element.shadowRoot.querySelectorAll('.decoration').length).toBe initialDecorationCount
+ expect(element.querySelectorAll('.decoration').length).toBe initialDecorationCount
describe "focus and blur handling", ->
- it "proxies focus/blur events to/from the hidden input inside the shadow root", ->
+ it "proxies focus/blur events to/from the hidden input", ->
element = new TextEditorElement
jasmineContent.appendChild(element)
@@ -91,12 +89,28 @@ describe "TextEditorElement", ->
element.focus()
expect(blurCalled).toBe false
expect(element.hasFocus()).toBe true
- expect(document.activeElement).toBe element
- expect(element.shadowRoot.activeElement).toBe element.shadowRoot.querySelector('input')
+ expect(document.activeElement).toBe element.querySelector('input')
document.body.focus()
expect(blurCalled).toBe true
+ it "doesn't trigger a blur event on the editor element when focusing an already focused editor element", ->
+ blurCalled = false
+ element = new TextEditorElement
+ element.addEventListener 'blur', -> blurCalled = true
+
+ jasmineContent.appendChild(element)
+ expect(document.activeElement).toBe(document.body)
+ expect(blurCalled).toBe(false)
+
+ element.focus()
+ expect(document.activeElement).toBe(element.querySelector('input'))
+ expect(blurCalled).toBe(false)
+
+ element.focus()
+ expect(document.activeElement).toBe(element.querySelector('input'))
+ expect(blurCalled).toBe(false)
+
describe "when focused while a parent node is being attached to the DOM", ->
class ElementThatFocusesChild extends HTMLDivElement
attachedCallback: ->
@@ -111,7 +125,7 @@ describe "TextEditorElement", ->
parentElement = document.createElement("element-that-focuses-child")
parentElement.appendChild(element)
jasmineContent.appendChild(parentElement)
- expect(element.shadowRoot.activeElement).toBe element.shadowRoot.querySelector('input')
+ expect(document.activeElement).toBe element.querySelector('input')
describe "when the themes finish loading", ->
[themeReloadCallback, initialThemeLoadComplete, element] = []
@@ -143,7 +157,7 @@ describe "TextEditorElement", ->
initialThemeLoadComplete = true
themeReloadCallback()
- verticalScrollbarNode = element.shadowRoot.querySelector(".vertical-scrollbar")
+ verticalScrollbarNode = element.querySelector(".vertical-scrollbar")
scrollbarWidth = verticalScrollbarNode.offsetWidth - verticalScrollbarNode.clientWidth
expect(scrollbarWidth).toEqual(8)
@@ -181,13 +195,13 @@ describe "TextEditorElement", ->
element.getModel().setText("hello")
expect(window.requestAnimationFrame).toHaveBeenCalled()
- expect(element.shadowRoot.textContent).toContain "hello"
+ expect(element.textContent).toContain "hello"
window.requestAnimationFrame.reset()
element.setUpdatedSynchronously(true)
element.getModel().setText("goodbye")
expect(window.requestAnimationFrame).not.toHaveBeenCalled()
- expect(element.shadowRoot.textContent).toContain "goodbye"
+ expect(element.textContent).toContain "goodbye"
describe "::getDefaultCharacterWidth", ->
it "returns null before the element is attached", ->
diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee
index f4760ece1b8..8af2f9abd44 100644
--- a/spec/text-editor-presenter-spec.coffee
+++ b/spec/text-editor-presenter-spec.coffee
@@ -481,7 +481,7 @@ describe "TextEditorPresenter", ->
expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1
expectStateUpdate presenter, ->
- presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'meta.method-call.js', 'support.function.js'], 'p', 20)
+ presenter.getLinesYardstick().setScopedCharacterWidth(['syntax--source.syntax--js', 'syntax--meta.syntax--method-call.syntax--js', 'syntax--support.syntax--function.syntax--js'], 'p', 20)
presenter.measurementsChanged()
expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide
@@ -769,7 +769,7 @@ describe "TextEditorPresenter", ->
expect(getState(presenter).hiddenInput.width).toBe 15
expectStateUpdate presenter, ->
- presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'r', 20)
+ presenter.getLinesYardstick().setScopedCharacterWidth(['syntax--source.syntax--js', 'syntax--storage.syntax--type.syntax--var.syntax--js'], 'r', 20)
presenter.measurementsChanged()
expect(getState(presenter).hiddenInput.width).toBe 20
@@ -926,7 +926,7 @@ describe "TextEditorPresenter", ->
expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1
expectStateUpdate presenter, ->
- presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'meta.method-call.js', 'support.function.js'], 'p', 20)
+ presenter.getLinesYardstick().setScopedCharacterWidth(['syntax--source.syntax--js', 'syntax--meta.syntax--method-call.syntax--js', 'syntax--support.syntax--function.syntax--js'], 'p', 20)
presenter.measurementsChanged()
expect(getState(presenter).content.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide
@@ -1280,7 +1280,16 @@ describe "TextEditorPresenter", ->
expect(tagsForCodes(presenter, lineStateForScreenRow(presenter, 0).tagCodes).openTags).toContain('invisible-character eol')
expect(tagsForCodes(presenter, lineStateForScreenRow(presenter, 1).tagCodes).openTags).toContain('invisible-character eol')
- describe ".blockDecorations", ->
+ describe ".{preceding,following}BlockDecorations", ->
+ stateForBlockDecorations = (blockDecorations) ->
+ state = {}
+ for blockDecoration in blockDecorations
+ state[blockDecoration.id] = {
+ decoration: blockDecoration,
+ screenRow: blockDecoration.getMarker().getHeadScreenPosition().row
+ }
+ state
+
it "contains all block decorations that are present before/after a line, both initially and when decorations change", ->
blockDecoration1 = addBlockDecorationBeforeScreenRow(0)
presenter = buildPresenter()
@@ -1292,32 +1301,32 @@ describe "TextEditorPresenter", ->
blockDecoration4 = addBlockDecorationAfterScreenRow(7)
runs ->
- expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual([blockDecoration1])
- expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual([blockDecoration2])
- expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual([blockDecoration3])
- expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual([blockDecoration4])
- expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual([])
+ expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration1]))
+ expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration2]))
+ expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration3]))
+ expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration4]))
+ expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual({})
waitsForStateToUpdate presenter, ->
blockDecoration1.getMarker().setHeadBufferPosition([1, 0])
@@ -1326,32 +1335,32 @@ describe "TextEditorPresenter", ->
blockDecoration4.getMarker().setHeadBufferPosition([8, 0])
runs ->
- expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual([blockDecoration1])
- expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual([blockDecoration4])
- expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual([blockDecoration2, blockDecoration3])
- expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual([])
+ expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration1]))
+ expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration4]))
+ expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration2, blockDecoration3]))
+ expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual({})
waitsForStateToUpdate presenter, ->
blockDecoration4.destroy()
@@ -1359,71 +1368,85 @@ describe "TextEditorPresenter", ->
blockDecoration1.getMarker().setHeadBufferPosition([0, 0])
runs ->
- expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual([blockDecoration1])
- expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual([blockDecoration2])
- expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual([])
+ expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration1]))
+ expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration2]))
+ expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual({})
waitsForStateToUpdate presenter, ->
editor.setCursorBufferPosition([0, 0])
editor.insertNewline()
runs ->
- expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual([blockDecoration1])
- expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual([blockDecoration2])
- expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual([])
- expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual([])
-
- it "inserts block decorations before the line if not specified otherwise", ->
+ expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 1).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration1]))
+ expect(lineStateForScreenRow(presenter, 1).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 2).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 3).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 5).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 6).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 7).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 8).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 9).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 9).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 10).precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration2]))
+ expect(lineStateForScreenRow(presenter, 10).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 11).followingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).precedingBlockDecorations).toEqual({})
+ expect(lineStateForScreenRow(presenter, 12).followingBlockDecorations).toEqual({})
+
+ it "contains block decorations located in ::mouseWheelScreenRow even if they are off screen", ->
+ blockDecoration = addBlockDecorationBeforeScreenRow(0)
+ presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200)
+ lineId = presenter.displayLayer.getScreenLines(0, 1)[0].id
+
+ expect(getState(presenter).content.tiles[0].lines[lineId].precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration]))
+
+ presenter.setMouseWheelScreenRow(0)
+ expectStateUpdate presenter, -> presenter.setScrollTop(4)
+ expect(getState(presenter).content.tiles[0].lines[lineId].precedingBlockDecorations).toEqual(stateForBlockDecorations([blockDecoration]))
+
+ advanceClock(presenter.stoppedScrollingDelay)
+ expect(getState(presenter).content.tiles[0]).toBeUndefined()
+
+ it "inserts block decorations before the line unless otherwise specified", ->
blockDecoration = editor.decorateMarker(editor.markScreenPosition([4, 0]), {type: "block"})
presenter = buildPresenter()
- expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual [blockDecoration]
- expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual []
+ expect(lineStateForScreenRow(presenter, 4).precedingBlockDecorations).toEqual stateForBlockDecorations([blockDecoration])
+ expect(lineStateForScreenRow(presenter, 4).followingBlockDecorations).toEqual {}
describe ".decorationClasses", ->
it "adds decoration classes to the relevant line state objects, both initially and when decorations change", ->
@@ -1741,12 +1764,12 @@ describe "TextEditorPresenter", ->
presenter = buildPresenter(explicitHeight: 20)
expectStateUpdate presenter, ->
- presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'v', 20)
+ presenter.getLinesYardstick().setScopedCharacterWidth(['syntax--source.syntax--js', 'syntax--storage.syntax--type.syntax--var.syntax--js'], 'v', 20)
presenter.measurementsChanged()
expect(stateForCursor(presenter, 0)).toEqual {top: 1 * 10, left: (3 * 10) + 20, width: 10, height: 10}
expectStateUpdate presenter, ->
- presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'r', 20)
+ presenter.getLinesYardstick().setScopedCharacterWidth(['syntax--source.syntax--js', 'syntax--storage.syntax--type.syntax--var.syntax--js'], 'r', 20)
presenter.measurementsChanged()
expect(stateForCursor(presenter, 0)).toEqual {top: 1 * 10, left: (3 * 10) + 20, width: 20, height: 10}
@@ -2093,7 +2116,7 @@ describe "TextEditorPresenter", ->
regions: [{top: 0, left: 4 * 10, width: 2 * 10, height: 10}]
}
expectStateUpdate presenter, ->
- presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'keyword.control.js'], 'i', 20)
+ presenter.getLinesYardstick().setScopedCharacterWidth(['syntax--source.syntax--js', 'syntax--keyword.syntax--control.syntax--js'], 'i', 20)
presenter.measurementsChanged()
expectValues stateForSelectionInTile(presenter, 0, 2), {
regions: [{top: 0, left: 4 * 10, width: 20 + 10, height: 10}]
@@ -2193,11 +2216,13 @@ describe "TextEditorPresenter", ->
highlight.flash('b', 500)
runs ->
expectValues stateForHighlightInTile(presenter, highlight, 2), {
+ needsFlash: true
flashClass: 'b'
flashDuration: 500
flashCount: 1
}
expectValues stateForHighlightInTile(presenter, highlight, 4), {
+ needsFlash: true
flashClass: 'b'
flashDuration: 500
flashCount: 1
@@ -2206,232 +2231,129 @@ describe "TextEditorPresenter", ->
waitsForStateToUpdate presenter, -> highlight.flash('c', 600)
runs ->
expectValues stateForHighlightInTile(presenter, highlight, 2), {
+ needsFlash: true
flashClass: 'c'
flashDuration: 600
flashCount: 2
}
expectValues stateForHighlightInTile(presenter, highlight, 4), {
+ needsFlash: true
flashClass: 'c'
flashDuration: 600
flashCount: 2
}
- describe ".blockDecorations", ->
- stateForBlockDecoration = (presenter, decoration) ->
- getState(presenter).content.blockDecorations[decoration.id]
-
- it "contains state for measured block decorations that are not visible when they are on ::mouseWheelScreenRow", ->
- blockDecoration1 = addBlockDecorationBeforeScreenRow(0)
- presenter = buildPresenter(explicitHeight: 30, lineHeight: 10, tileSize: 2, scrollTop: 0, stoppedScrollingDelay: 200)
- getState(presenter) # flush pending state
- presenter.setBlockDecorationDimensions(blockDecoration1, 0, 0)
+ waitsForStateToUpdate presenter, -> marker.setBufferRange([[2, 2], [6, 2]])
+ runs ->
+ expectValues stateForHighlightInTile(presenter, highlight, 2), {needsFlash: false}
+ expectValues stateForHighlightInTile(presenter, highlight, 4), {needsFlash: false}
- presenter.setScrollTop(100)
- presenter.setMouseWheelScreenRow(0)
+ describe ".offScreenBlockDecorations", ->
+ stateForOffScreenBlockDecoration = (presenter, decoration) ->
+ getState(presenter).content.offScreenBlockDecorations[decoration.id]
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 0
- isVisible: true
- }
-
- advanceClock(presenter.stoppedScrollingDelay)
+ it "contains state for off-screen unmeasured block decorations, both initially and when they are updated or destroyed", ->
+ item = {}
+ blockDecoration1 = addBlockDecorationBeforeScreenRow(0, item)
+ blockDecoration2 = addBlockDecorationBeforeScreenRow(4, item)
+ blockDecoration3 = addBlockDecorationBeforeScreenRow(4, item)
+ blockDecoration4 = addBlockDecorationBeforeScreenRow(10, item)
+ presenter = buildPresenter(explicitHeight: 30, lineHeight: 10, tileSize: 2, scrollTop: 0)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration4)).toBe(blockDecoration4)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ presenter.setBlockDecorationDimensions(blockDecoration1, 0, 10)
+ presenter.setBlockDecorationDimensions(blockDecoration4, 0, 20)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBe(blockDecoration3)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration4)).toBeUndefined()
- it "invalidates block decorations that intersect a change in the buffer", ->
+ presenter.invalidateBlockDecorationDimensions(blockDecoration1)
+ presenter.invalidateBlockDecorationDimensions(blockDecoration4)
+ presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10)
+ presenter.setBlockDecorationDimensions(blockDecoration3, 0, 10)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration4)).toBe(blockDecoration4)
+
+ blockDecoration4.destroy()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration4)).toBeUndefined()
+
+ it "contains state for off-screen block decorations that intersect a buffer change", ->
blockDecoration1 = addBlockDecorationBeforeScreenRow(9)
blockDecoration2 = addBlockDecorationBeforeScreenRow(10)
blockDecoration3 = addBlockDecorationBeforeScreenRow(11)
presenter = buildPresenter(explicitHeight: 30, lineHeight: 10, tileSize: 2, scrollTop: 0)
-
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 9
- isVisible: false
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration2), {
- decoration: blockDecoration2
- screenRow: 10
- isVisible: false
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration3), {
- decoration: blockDecoration3
- screenRow: 11
- isVisible: false
- }
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBe(blockDecoration1)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBe(blockDecoration3)
presenter.setBlockDecorationDimensions(blockDecoration1, 0, 10)
presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10)
presenter.setBlockDecorationDimensions(blockDecoration3, 0, 10)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
- expect(stateForBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
- expect(stateForBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
editor.setSelectedScreenRange([[10, 0], [12, 0]])
editor.delete()
presenter.setScrollTop(0) # deleting the buffer causes the editor to autoscroll
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration3)).toBe(blockDecoration3)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
- expectValues stateForBlockDecoration(presenter, blockDecoration2), {
- decoration: blockDecoration2
- screenRow: 10
- isVisible: false
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration3), {
- decoration: blockDecoration3
- screenRow: 10
- isVisible: false
- }
-
- it "invalidates all block decorations when content frame width, window size or bounding client rect change", ->
- blockDecoration1 = addBlockDecorationBeforeScreenRow(11)
+ it "contains state for all off-screen block decorations when content frame width, window size or bounding client rect change", ->
+ blockDecoration1 = addBlockDecorationBeforeScreenRow(10)
+ blockDecoration2 = addBlockDecorationBeforeScreenRow(11)
presenter = buildPresenter(explicitHeight: 30, lineHeight: 10, tileSize: 2, scrollTop: 0)
-
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 11
- isVisible: false
- }
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBe(blockDecoration1)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
presenter.setBlockDecorationDimensions(blockDecoration1, 0, 10)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
presenter.setBoundingClientRect({top: 0, left: 0, width: 50, height: 30})
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 11
- isVisible: false
- }
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBe(blockDecoration1)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
presenter.setBlockDecorationDimensions(blockDecoration1, 0, 20)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ presenter.setBlockDecorationDimensions(blockDecoration2, 0, 20)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
presenter.setContentFrameWidth(100)
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 11
- isVisible: false
- }
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBe(blockDecoration1)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
presenter.setBlockDecorationDimensions(blockDecoration1, 0, 20)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ presenter.setBlockDecorationDimensions(blockDecoration2, 0, 20)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
presenter.setWindowSize(100, 200)
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 11
- isVisible: false
- }
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBe(blockDecoration1)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBe(blockDecoration2)
presenter.setBlockDecorationDimensions(blockDecoration1, 0, 20)
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
-
- it "contains state for on-screen and unmeasured block decorations, both initially and when they are updated or destroyed", ->
- item = {}
- blockDecoration1 = addBlockDecorationBeforeScreenRow(0, item)
- blockDecoration2 = addBlockDecorationBeforeScreenRow(4, item)
- blockDecoration3 = addBlockDecorationBeforeScreenRow(4, item)
- blockDecoration4 = addBlockDecorationBeforeScreenRow(10, item)
- presenter = buildPresenter(explicitHeight: 30, lineHeight: 10, tileSize: 2, scrollTop: 0)
-
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 0
- isVisible: true
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration2), {
- decoration: blockDecoration2
- screenRow: 4
- isVisible: true
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration3), {
- decoration: blockDecoration3
- screenRow: 4
- isVisible: true
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration4), {
- decoration: blockDecoration4
- screenRow: 10
- isVisible: false
- }
-
- presenter.setBlockDecorationDimensions(blockDecoration1, 0, 10)
- presenter.setBlockDecorationDimensions(blockDecoration4, 0, 20)
-
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 0
- isVisible: true
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration2), {
- decoration: blockDecoration2
- screenRow: 4
- isVisible: false
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration3), {
- decoration: blockDecoration3
- screenRow: 4
- isVisible: false
- }
- expect(stateForBlockDecoration(presenter, blockDecoration4)).toBeUndefined()
-
- blockDecoration3.getMarker().setHeadScreenPosition([5, 0])
- presenter.setScrollTop(90)
-
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
- expectValues stateForBlockDecoration(presenter, blockDecoration2), {
- decoration: blockDecoration2
- screenRow: 4
- isVisible: false
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration3), {
- decoration: blockDecoration3
- screenRow: 5
- isVisible: false
- }
- expectValues stateForBlockDecoration(presenter, blockDecoration4), {
- decoration: blockDecoration4
- screenRow: 10
- isVisible: true
- }
-
- presenter.invalidateBlockDecorationDimensions(blockDecoration1)
- presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10)
- presenter.setBlockDecorationDimensions(blockDecoration3, 0, 10)
-
- expectValues stateForBlockDecoration(presenter, blockDecoration1), {
- decoration: blockDecoration1
- screenRow: 0
- isVisible: false
- }
- expect(stateForBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
- expect(stateForBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
- expectValues stateForBlockDecoration(presenter, blockDecoration4), {
- decoration: blockDecoration4
- screenRow: 10
- isVisible: true
- }
-
- blockDecoration1.destroy()
-
- expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
- expect(stateForBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
- expect(stateForBlockDecoration(presenter, blockDecoration3)).toBeUndefined()
- expectValues stateForBlockDecoration(presenter, blockDecoration4), {
- decoration: blockDecoration4
- screenRow: 10
- isVisible: true
- }
+ presenter.setBlockDecorationDimensions(blockDecoration2, 0, 20)
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration1)).toBeUndefined()
+ expect(stateForOffScreenBlockDecoration(presenter, blockDecoration2)).toBeUndefined()
it "doesn't throw an error when setting the dimensions for a destroyed decoration", ->
blockDecoration = addBlockDecorationBeforeScreenRow(0)
presenter = buildPresenter()
-
blockDecoration.destroy()
presenter.setBlockDecorationDimensions(blockDecoration, 30, 30)
-
- expect(getState(presenter).content.blockDecorations).toEqual({})
+ expect(getState(presenter).content.offScreenBlockDecorations).toEqual({})
describe ".overlays", ->
[item] = []
diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee
index c1c7141c366..1890b0ef798 100644
--- a/spec/text-editor-spec.coffee
+++ b/spec/text-editor-spec.coffee
@@ -5321,8 +5321,8 @@ describe "TextEditor", ->
tokens = editor.tokensForScreenRow(0)
expect(tokens).toEqual [
- {text: '//', scopes: ['source.js', 'comment.line.double-slash.js', 'punctuation.definition.comment.js']},
- {text: ' http://github.com', scopes: ['source.js', 'comment.line.double-slash.js']}
+ {text: '//', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--punctuation.syntax--definition.syntax--comment.syntax--js']},
+ {text: ' http://github.com', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']}
]
waitsForPromise ->
@@ -5331,9 +5331,9 @@ describe "TextEditor", ->
runs ->
tokens = editor.tokensForScreenRow(0)
expect(tokens).toEqual [
- {text: '//', scopes: ['source.js', 'comment.line.double-slash.js', 'punctuation.definition.comment.js']},
- {text: ' ', scopes: ['source.js', 'comment.line.double-slash.js']}
- {text: 'http://github.com', scopes: ['source.js', 'comment.line.double-slash.js', 'markup.underline.link.http.hyperlink']}
+ {text: '//', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--punctuation.syntax--definition.syntax--comment.syntax--js']},
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']}
+ {text: 'http://github.com', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--markup.syntax--underline.syntax--link.syntax--http.syntax--hyperlink']}
]
describe "when the grammar is updated", ->
@@ -5346,8 +5346,8 @@ describe "TextEditor", ->
tokens = editor.tokensForScreenRow(0)
expect(tokens).toEqual [
- {text: '//', scopes: ['source.js', 'comment.line.double-slash.js', 'punctuation.definition.comment.js']},
- {text: ' SELECT * FROM OCTOCATS', scopes: ['source.js', 'comment.line.double-slash.js']}
+ {text: '//', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--punctuation.syntax--definition.syntax--comment.syntax--js']},
+ {text: ' SELECT * FROM OCTOCATS', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']}
]
waitsForPromise ->
@@ -5356,8 +5356,8 @@ describe "TextEditor", ->
runs ->
tokens = editor.tokensForScreenRow(0)
expect(tokens).toEqual [
- {text: '//', scopes: ['source.js', 'comment.line.double-slash.js', 'punctuation.definition.comment.js']},
- {text: ' SELECT * FROM OCTOCATS', scopes: ['source.js', 'comment.line.double-slash.js']}
+ {text: '//', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--punctuation.syntax--definition.syntax--comment.syntax--js']},
+ {text: ' SELECT * FROM OCTOCATS', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']}
]
waitsForPromise ->
@@ -5366,14 +5366,14 @@ describe "TextEditor", ->
runs ->
tokens = editor.tokensForScreenRow(0)
expect(tokens).toEqual [
- {text: '//', scopes: ['source.js', 'comment.line.double-slash.js', 'punctuation.definition.comment.js']},
- {text: ' ', scopes: ['source.js', 'comment.line.double-slash.js']},
- {text: 'SELECT', scopes: ['source.js', 'comment.line.double-slash.js', 'keyword.other.DML.sql']},
- {text: ' ', scopes: ['source.js', 'comment.line.double-slash.js']},
- {text: '*', scopes: ['source.js', 'comment.line.double-slash.js', 'keyword.operator.star.sql']},
- {text: ' ', scopes: ['source.js', 'comment.line.double-slash.js']},
- {text: 'FROM', scopes: ['source.js', 'comment.line.double-slash.js', 'keyword.other.DML.sql']},
- {text: ' OCTOCATS', scopes: ['source.js', 'comment.line.double-slash.js']}
+ {text: '//', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--punctuation.syntax--definition.syntax--comment.syntax--js']},
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']},
+ {text: 'SELECT', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--keyword.syntax--other.syntax--DML.syntax--sql']},
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']},
+ {text: '*', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--keyword.syntax--operator.syntax--star.syntax--sql']},
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']},
+ {text: 'FROM', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js', 'syntax--keyword.syntax--other.syntax--DML.syntax--sql']},
+ {text: ' OCTOCATS', scopes: ['syntax--source.syntax--js', 'syntax--comment.syntax--line.syntax--double-slash.syntax--js']}
]
describe ".normalizeTabsInBufferRange()", ->
@@ -5808,20 +5808,20 @@ describe "TextEditor", ->
editor.update({showIndentGuide: false})
expect(editor.tokensForScreenRow(0)).toEqual [
- {text: ' ', scopes: ['source.js', 'leading-whitespace']},
- {text: 'foo', scopes: ['source.js']}
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'leading-whitespace']},
+ {text: 'foo', scopes: ['syntax--source.syntax--js']}
]
editor.update({showIndentGuide: true})
expect(editor.tokensForScreenRow(0)).toEqual [
- {text: ' ', scopes: ['source.js', 'leading-whitespace indent-guide']},
- {text: 'foo', scopes: ['source.js']}
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'leading-whitespace indent-guide']},
+ {text: 'foo', scopes: ['syntax--source.syntax--js']}
]
editor.setMini(true)
expect(editor.tokensForScreenRow(0)).toEqual [
- {text: ' ', scopes: ['source.js', 'leading-whitespace']},
- {text: 'foo', scopes: ['source.js']}
+ {text: ' ', scopes: ['syntax--source.syntax--js', 'leading-whitespace']},
+ {text: 'foo', scopes: ['syntax--source.syntax--js']}
]
describe "when the editor is constructed with the grammar option set", ->
diff --git a/spec/tokenized-buffer-iterator-spec.js b/spec/tokenized-buffer-iterator-spec.js
index f6764401c4b..cc703bbec5f 100644
--- a/spec/tokenized-buffer-iterator-spec.js
+++ b/spec/tokenized-buffer-iterator-spec.js
@@ -35,40 +35,40 @@ describe('TokenizedBufferIterator', () => {
expect(iterator.seek(Point(0, 0))).toEqual([])
expect(iterator.getPosition()).toEqual(Point(0, 0))
expect(iterator.getCloseTags()).toEqual([])
- expect(iterator.getOpenTags()).toEqual(['foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--foo'])
iterator.moveToSuccessor()
- expect(iterator.getCloseTags()).toEqual(['foo'])
- expect(iterator.getOpenTags()).toEqual(['bar'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--bar'])
- expect(iterator.seek(Point(0, 1))).toEqual(['baz'])
+ expect(iterator.seek(Point(0, 1))).toEqual(['syntax--baz'])
expect(iterator.getPosition()).toEqual(Point(0, 3))
expect(iterator.getCloseTags()).toEqual([])
- expect(iterator.getOpenTags()).toEqual(['bar'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--bar'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 3))
- expect(iterator.getCloseTags()).toEqual(['bar', 'baz'])
- expect(iterator.getOpenTags()).toEqual(['baz'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--bar', 'syntax--baz'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--baz'])
- expect(iterator.seek(Point(0, 3))).toEqual(['baz'])
+ expect(iterator.seek(Point(0, 3))).toEqual(['syntax--baz'])
expect(iterator.getPosition()).toEqual(Point(0, 3))
expect(iterator.getCloseTags()).toEqual([])
- expect(iterator.getOpenTags()).toEqual(['bar'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--bar'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 3))
- expect(iterator.getCloseTags()).toEqual(['bar', 'baz'])
- expect(iterator.getOpenTags()).toEqual(['baz'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--bar', 'syntax--baz'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--baz'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 7))
- expect(iterator.getCloseTags()).toEqual(['baz'])
- expect(iterator.getOpenTags()).toEqual(['bar'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--baz'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--bar'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 7))
- expect(iterator.getCloseTags()).toEqual(['bar'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--bar'])
expect(iterator.getOpenTags()).toEqual([])
iterator.moveToSuccessor()
@@ -76,14 +76,14 @@ describe('TokenizedBufferIterator', () => {
expect(iterator.getCloseTags()).toEqual([])
expect(iterator.getOpenTags()).toEqual([])
- expect(iterator.seek(Point(0, 5))).toEqual(['baz'])
+ expect(iterator.seek(Point(0, 5))).toEqual(['syntax--baz'])
expect(iterator.getPosition()).toEqual(Point(0, 7))
- expect(iterator.getCloseTags()).toEqual(['baz'])
- expect(iterator.getOpenTags()).toEqual(['bar'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--baz'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--bar'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 7))
- expect(iterator.getCloseTags()).toEqual(['bar'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--bar'])
expect(iterator.getOpenTags()).toEqual([])
})
})
@@ -111,15 +111,15 @@ describe('TokenizedBufferIterator', () => {
iterator.seek(Point(0, 0))
expect(iterator.getPosition()).toEqual(Point(0, 0))
expect(iterator.getCloseTags()).toEqual([])
- expect(iterator.getOpenTags()).toEqual(['foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--foo'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 0))
- expect(iterator.getCloseTags()).toEqual(['foo'])
- expect(iterator.getOpenTags()).toEqual(['foo'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--foo'])
iterator.moveToSuccessor()
- expect(iterator.getCloseTags()).toEqual(['foo'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--foo'])
expect(iterator.getOpenTags()).toEqual([])
})
@@ -163,26 +163,26 @@ describe('TokenizedBufferIterator', () => {
iterator.seek(Point(0, 0))
expect(iterator.getPosition()).toEqual(Point(0, 0))
expect(iterator.getCloseTags()).toEqual([])
- expect(iterator.getOpenTags()).toEqual(['foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--foo'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 3))
- expect(iterator.getCloseTags()).toEqual(['foo'])
- expect(iterator.getOpenTags()).toEqual(['qux'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--qux'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(0, 3))
- expect(iterator.getCloseTags()).toEqual(['qux'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--qux'])
expect(iterator.getOpenTags()).toEqual([])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(1, 0))
expect(iterator.getCloseTags()).toEqual([])
- expect(iterator.getOpenTags()).toEqual(['foo'])
+ expect(iterator.getOpenTags()).toEqual(['syntax--foo'])
iterator.moveToSuccessor()
expect(iterator.getPosition()).toEqual(Point(2, 0))
- expect(iterator.getCloseTags()).toEqual(['foo'])
+ expect(iterator.getCloseTags()).toEqual(['syntax--foo'])
expect(iterator.getOpenTags()).toEqual([])
})
})
diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee
index 6558d42b478..eff79ec95a4 100644
--- a/spec/tokenized-buffer-spec.coffee
+++ b/spec/tokenized-buffer-spec.coffee
@@ -590,21 +590,21 @@ describe "TokenizedBuffer", ->
iterator.seek(Point(0, 0))
expectedBoundaries = [
- {position: Point(0, 0), closeTags: [], openTags: ["source.js", "storage.type.var.js"]}
- {position: Point(0, 3), closeTags: ["storage.type.var.js"], openTags: []}
- {position: Point(0, 8), closeTags: [], openTags: ["keyword.operator.assignment.js"]}
- {position: Point(0, 9), closeTags: ["keyword.operator.assignment.js"], openTags: []}
- {position: Point(0, 10), closeTags: [], openTags: ["constant.numeric.decimal.js"]}
- {position: Point(0, 11), closeTags: ["constant.numeric.decimal.js"], openTags: []}
- {position: Point(0, 12), closeTags: [], openTags: ["comment.block.js", "punctuation.definition.comment.js"]}
- {position: Point(0, 14), closeTags: ["punctuation.definition.comment.js"], openTags: []}
- {position: Point(1, 5), closeTags: [], openTags: ["punctuation.definition.comment.js"]}
- {position: Point(1, 7), closeTags: ["punctuation.definition.comment.js", "comment.block.js"], openTags: ["storage.type.var.js"]}
- {position: Point(1, 10), closeTags: ["storage.type.var.js"], openTags: []}
- {position: Point(1, 15), closeTags: [], openTags: ["keyword.operator.assignment.js"]}
- {position: Point(1, 16), closeTags: ["keyword.operator.assignment.js"], openTags: []}
- {position: Point(1, 17), closeTags: [], openTags: ["constant.numeric.decimal.js"]}
- {position: Point(1, 18), closeTags: ["constant.numeric.decimal.js"], openTags: []}
+ {position: Point(0, 0), closeTags: [], openTags: ["syntax--source.syntax--js", "syntax--storage.syntax--type.syntax--var.syntax--js"]}
+ {position: Point(0, 3), closeTags: ["syntax--storage.syntax--type.syntax--var.syntax--js"], openTags: []}
+ {position: Point(0, 8), closeTags: [], openTags: ["syntax--keyword.syntax--operator.syntax--assignment.syntax--js"]}
+ {position: Point(0, 9), closeTags: ["syntax--keyword.syntax--operator.syntax--assignment.syntax--js"], openTags: []}
+ {position: Point(0, 10), closeTags: [], openTags: ["syntax--constant.syntax--numeric.syntax--decimal.syntax--js"]}
+ {position: Point(0, 11), closeTags: ["syntax--constant.syntax--numeric.syntax--decimal.syntax--js"], openTags: []}
+ {position: Point(0, 12), closeTags: [], openTags: ["syntax--comment.syntax--block.syntax--js", "syntax--punctuation.syntax--definition.syntax--comment.syntax--js"]}
+ {position: Point(0, 14), closeTags: ["syntax--punctuation.syntax--definition.syntax--comment.syntax--js"], openTags: []}
+ {position: Point(1, 5), closeTags: [], openTags: ["syntax--punctuation.syntax--definition.syntax--comment.syntax--js"]}
+ {position: Point(1, 7), closeTags: ["syntax--punctuation.syntax--definition.syntax--comment.syntax--js", "syntax--comment.syntax--block.syntax--js"], openTags: ["syntax--storage.syntax--type.syntax--var.syntax--js"]}
+ {position: Point(1, 10), closeTags: ["syntax--storage.syntax--type.syntax--var.syntax--js"], openTags: []}
+ {position: Point(1, 15), closeTags: [], openTags: ["syntax--keyword.syntax--operator.syntax--assignment.syntax--js"]}
+ {position: Point(1, 16), closeTags: ["syntax--keyword.syntax--operator.syntax--assignment.syntax--js"], openTags: []}
+ {position: Point(1, 17), closeTags: [], openTags: ["syntax--constant.syntax--numeric.syntax--decimal.syntax--js"]}
+ {position: Point(1, 18), closeTags: ["syntax--constant.syntax--numeric.syntax--decimal.syntax--js"], openTags: []}
]
loop
@@ -617,16 +617,16 @@ describe "TokenizedBuffer", ->
expect(boundary).toEqual(expectedBoundaries.shift())
break unless iterator.moveToSuccessor()
- expect(iterator.seek(Point(0, 1))).toEqual(["source.js", "storage.type.var.js"])
+ expect(iterator.seek(Point(0, 1))).toEqual(["syntax--source.syntax--js", "syntax--storage.syntax--type.syntax--var.syntax--js"])
expect(iterator.getPosition()).toEqual(Point(0, 3))
- expect(iterator.seek(Point(0, 8))).toEqual(["source.js"])
+ expect(iterator.seek(Point(0, 8))).toEqual(["syntax--source.syntax--js"])
expect(iterator.getPosition()).toEqual(Point(0, 8))
- expect(iterator.seek(Point(1, 0))).toEqual(["source.js", "comment.block.js"])
+ expect(iterator.seek(Point(1, 0))).toEqual(["syntax--source.syntax--js", "syntax--comment.syntax--block.syntax--js"])
expect(iterator.getPosition()).toEqual(Point(1, 0))
- expect(iterator.seek(Point(1, 18))).toEqual(["source.js", "constant.numeric.decimal.js"])
+ expect(iterator.seek(Point(1, 18))).toEqual(["syntax--source.syntax--js", "syntax--constant.syntax--numeric.syntax--decimal.syntax--js"])
expect(iterator.getPosition()).toEqual(Point(1, 18))
- expect(iterator.seek(Point(2, 0))).toEqual(["source.js"])
+ expect(iterator.seek(Point(2, 0))).toEqual(["syntax--source.syntax--js"])
iterator.moveToSuccessor() # ensure we don't infinitely loop (regression test)
it "does not report columns beyond the length of the line", ->
@@ -671,5 +671,5 @@ describe "TokenizedBuffer", ->
iterator.seek(Point(1, 0))
expect(iterator.getPosition()).toEqual([1, 0])
- expect(iterator.getCloseTags()).toEqual ['blue.broken']
- expect(iterator.getOpenTags()).toEqual ['yellow.broken']
+ expect(iterator.getCloseTags()).toEqual ['syntax--blue.syntax--broken']
+ expect(iterator.getOpenTags()).toEqual ['syntax--yellow.syntax--broken']
diff --git a/src/block-decorations-component.coffee b/src/block-decorations-component.coffee
deleted file mode 100644
index 48bbf77f3fe..00000000000
--- a/src/block-decorations-component.coffee
+++ /dev/null
@@ -1,86 +0,0 @@
-cloneObject = (object) ->
- clone = {}
- clone[key] = value for key, value of object
- clone
-
-module.exports =
-class BlockDecorationsComponent
- constructor: (@container, @views, @presenter, @domElementPool) ->
- @newState = null
- @oldState = null
- @blockDecorationNodesById = {}
- @domNode = @domElementPool.buildElement("content")
- @domNode.setAttribute("select", ".atom--invisible-block-decoration")
- @domNode.style.visibility = "hidden"
-
- getDomNode: ->
- @domNode
-
- updateSync: (state) ->
- @newState = state.content
- @oldState ?= {blockDecorations: {}, width: 0}
-
- if @newState.width isnt @oldState.width
- @domNode.style.width = @newState.width + "px"
- @oldState.width = @newState.width
-
- for id of @oldState.blockDecorations
- unless @newState.blockDecorations.hasOwnProperty(id)
- blockDecorationNode = @blockDecorationNodesById[id]
- blockDecorationNode.previousSibling.remove()
- blockDecorationNode.nextSibling.remove()
- blockDecorationNode.remove()
- delete @blockDecorationNodesById[id]
- delete @oldState.blockDecorations[id]
-
- for id of @newState.blockDecorations
- if @oldState.blockDecorations.hasOwnProperty(id)
- @updateBlockDecorationNode(id)
- else
- @oldState.blockDecorations[id] = {}
- @createAndAppendBlockDecorationNode(id)
-
- measureBlockDecorations: ->
- for decorationId, blockDecorationNode of @blockDecorationNodesById
- decoration = @newState.blockDecorations[decorationId].decoration
- topRuler = blockDecorationNode.previousSibling
- bottomRuler = blockDecorationNode.nextSibling
-
- width = blockDecorationNode.offsetWidth
- height = bottomRuler.offsetTop - topRuler.offsetTop
- @presenter.setBlockDecorationDimensions(decoration, width, height)
-
- createAndAppendBlockDecorationNode: (id) ->
- blockDecorationState = @newState.blockDecorations[id]
- blockDecorationClass = "atom--block-decoration-#{id}"
- topRuler = document.createElement("div")
- blockDecorationNode = @views.getView(blockDecorationState.decoration.getProperties().item)
- bottomRuler = document.createElement("div")
- topRuler.classList.add(blockDecorationClass)
- blockDecorationNode.classList.add(blockDecorationClass)
- bottomRuler.classList.add(blockDecorationClass)
-
- @container.appendChild(topRuler)
- @container.appendChild(blockDecorationNode)
- @container.appendChild(bottomRuler)
-
- @blockDecorationNodesById[id] = blockDecorationNode
- @updateBlockDecorationNode(id)
-
- updateBlockDecorationNode: (id) ->
- newBlockDecorationState = @newState.blockDecorations[id]
- oldBlockDecorationState = @oldState.blockDecorations[id]
- blockDecorationNode = @blockDecorationNodesById[id]
-
- if newBlockDecorationState.isVisible
- blockDecorationNode.previousSibling.classList.remove("atom--invisible-block-decoration")
- blockDecorationNode.classList.remove("atom--invisible-block-decoration")
- blockDecorationNode.nextSibling.classList.remove("atom--invisible-block-decoration")
- else
- blockDecorationNode.previousSibling.classList.add("atom--invisible-block-decoration")
- blockDecorationNode.classList.add("atom--invisible-block-decoration")
- blockDecorationNode.nextSibling.classList.add("atom--invisible-block-decoration")
-
- if oldBlockDecorationState.screenRow isnt newBlockDecorationState.screenRow
- blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow
- oldBlockDecorationState.screenRow = newBlockDecorationState.screenRow
diff --git a/src/deprecated-syntax-selectors.js b/src/deprecated-syntax-selectors.js
new file mode 100644
index 00000000000..4f8b9cefc15
--- /dev/null
+++ b/src/deprecated-syntax-selectors.js
@@ -0,0 +1,964 @@
+module.exports = new Set([
+ 'AFDKO', 'AFKDO', 'ASS', 'AVX', 'AVX2', 'AVX512', 'AVX512BW', 'AVX512DQ',
+ 'Alignment', 'Alpha', 'AlphaLevel', 'Angle', 'Animation', 'AnimationGroup',
+ 'ArchaeologyDigSiteFrame', 'Arrow__', 'AtLilyPond', 'AttrBaseType',
+ 'AttrSetVal__', 'BackColour', 'Banner', 'Bold', 'Bonlang', 'BorderStyle',
+ 'Browser', 'Button', 'C99', 'CALCULATE', 'CharacterSet', 'ChatScript',
+ 'Chatscript', 'CheckButton', 'ClipboardFormat', 'ClipboardType',
+ 'Clipboard__', 'CodePage', 'Codepages__', 'Collisions', 'ColorSelect',
+ 'ColourActual', 'ColourLogical', 'ColourReal', 'ColourScheme', 'ColourSize',
+ 'Column', 'Comment', 'ConfCachePolicy', 'ControlPoint', 'Cooldown', 'DBE',
+ 'DDL', 'DML', 'DSC', 'Database__', 'DdcMode', 'Dialogue',
+ 'DiscussionFilterType', 'DiscussionStatus', 'DisplaySchemes',
+ 'Document-Structuring-Comment', 'DressUpModel', 'Edit', 'EditBox', 'Effect',
+ 'Encoding', 'End', 'ExternalLinkBehaviour', 'ExternalLinkDirection', 'F16c',
+ 'FMA', 'FilterType', 'Font', 'FontInstance', 'FontString', 'Fontname',
+ 'Fonts__', 'Fontsize', 'Format', 'Frame', 'GameTooltip', 'GroupList', 'HLE',
+ 'HeaderEvent', 'HistoryType', 'HttpVerb', 'II', 'IO', 'Icon', 'IconID',
+ 'InPlaceBox__', 'InPlaceEditEvent', 'Info', 'Italic', 'JSXEndTagStart',
+ 'JSXStartTagEnd', 'KNC', 'KeyModifier', 'Kotlin', 'LUW', 'Language', 'Layer',
+ 'LayeredRegion', 'LdapItemList', 'LineSpacing', 'LinkFilter', 'LinkLimit',
+ 'ListView', 'Locales__', 'Lock', 'LoginPolicy', 'MA_End__', 'MA_StdCombo__',
+ 'MA_StdItem__', 'MA_StdMenu__', 'MISSING', 'Mapping', 'MarginL', 'MarginR',
+ 'MarginV', 'Marked', 'MessageFrame', 'Minimap', 'MovieFrame', 'Name',
+ 'Outline', 'OutlineColour', 'ParentedObject', 'Path', 'Permission', 'PlayRes',
+ 'PlayerModel', 'PrimaryColour', 'Proof', 'QuestPOIFrame', 'RTM',
+ 'RecentModule__', 'Regexp', 'Region', 'Rotation', 'SCADABasic', 'SSA',
+ 'Scale', 'ScaleX', 'ScaleY', 'ScaledBorderAndShadow', 'ScenarioPOIFrame',
+ 'ScriptObject', 'Script__', 'Scroll', 'ScrollEvent', 'ScrollFrame',
+ 'ScrollSide', 'ScrollingMessageFrame', 'SecondaryColour', 'Sensitivity',
+ 'Shadow', 'SimpleHTML', 'Slider', 'Spacing', 'Start', 'StatusBar', 'Stream',
+ 'StrikeOut', 'Style', 'TIS', 'TODO', 'TabardModel', 'Text', 'Texture',
+ 'Timer', 'ToolType', 'Translation', 'TreeView', 'TriggerStatus', 'UIObject',
+ 'Underline', 'UserClass', 'UserList', 'UserNotifyList', 'VisibleRegion',
+ 'Vplus', 'WrapStyle', 'XHPEndTagStart', 'XHPStartTagEnd', 'ZipType',
+ '__package-name__', '_c', '_function', 'a', 'a10networks', 'aaa', 'abaqus',
+ 'abbrev', 'abbreviated', 'abbreviation', 'abcnotation', 'abl', 'abnf', 'abp',
+ 'absolute', 'abstract', 'academic', 'access', 'access-control',
+ 'access-qualifiers', 'accessed', 'accessor', 'account', 'accumulator', 'ace',
+ 'ace3', 'acl', 'acos', 'act', 'action', 'action-map', 'actionhandler',
+ 'actionpack', 'actions', 'actionscript', 'activerecord', 'activesupport',
+ 'actual', 'acute-accent', 'ada', 'add', 'adddon', 'added', 'addition',
+ 'additional-character', 'additive', 'addon', 'address', 'address-of',
+ 'address-space', 'addrfam', 'adjustment', 'admonition', 'adr', 'adverb',
+ 'adx', 'ael', 'aem', 'aerospace', 'aes', 'aes_functions', 'aesni',
+ 'aexLightGreen', 'af', 'afii', 'aflex', 'after', 'after-expression', 'agc',
+ 'agda', 'agentspeak', 'aggregate', 'aggregation', 'ahk', 'ai-connection',
+ 'ai-player', 'ai-wheeled-vehicle', 'aif', 'alabel', 'alarms', 'alda', 'alert',
+ 'algebraic-type', 'alias', 'aliases', 'align', 'align-attribute', 'alignment',
+ 'alignment-cue-setting', 'alignment-mode', 'all', 'all-once', 'all-solutions',
+ 'allocate', 'alloy', 'alloyglobals', 'alloyxml', 'alog', 'alpha',
+ 'alphabeticalllt', 'alphabeticallyge', 'alphabeticallygt', 'alphabeticallyle',
+ 'alt', 'alter', 'alternate-wysiwyg-string', 'alternates', 'alternation',
+ 'alternatives', 'am', 'ambient-audio-manager', 'ambient-reflectivity', 'amd',
+ 'amd3DNow', 'amdnops', 'ameter', 'amount', 'amp', 'ampersand', 'ampl',
+ 'ampscript', 'an', 'analysis', 'analytics', 'anb', 'anchor', 'and', 'andop',
+ 'angelscript', 'angle', 'angle-brackets', 'angular', 'animation', 'annot',
+ 'annotated', 'annotation', 'annotation-arguments', 'anon', 'anonymous',
+ 'another', 'ansi', 'ansi-c', 'ansi-colored', 'ansi-escape-code',
+ 'ansi-formatted', 'ansi2', 'ansible', 'answer', 'antialiasing', 'antl',
+ 'antlr', 'antlr4', 'anubis', 'any', 'any-method', 'anyclass', 'aolserver',
+ 'apa', 'apache', 'apache-config', 'apc', 'apdl', 'apex', 'api',
+ 'api-notation', 'apiary', 'apib', 'apl', 'apostrophe', 'appcache',
+ 'applescript', 'application', 'application-name', 'application-process',
+ 'approx-equal', 'aql', 'aqua', 'ar', 'arbitrary-radix',
+ 'arbitrary-repetition', 'arbitrary-repitition', 'arch', 'arch_specification',
+ 'architecture', 'archive', 'archives', 'arduino', 'area-code', 'arendelle',
+ 'argcount', 'args', 'argument', 'argument-label', 'argument-separator',
+ 'argument-seperator', 'argument-type', 'arguments', 'arith', 'arithmetic',
+ 'arithmetical', 'arithmeticcql', 'ark', 'arm', 'arma', 'armaConfig',
+ 'arnoldc', 'arp', 'arpop', 'arr', 'array', 'array-expression',
+ 'array-literal', 'arrays', 'arrow', 'articulation', 'artihmetic', 'arvo',
+ 'aryop', 'as', 'as4', 'ascii', 'asciidoc', 'asdoc', 'ash', 'ashx', 'asl',
+ 'asm', 'asm-instruction', 'asm-type-prefix', 'asn', 'asp', 'asp-core-2',
+ 'aspx', 'ass', 'assembly', 'assert', 'assertion', 'assigment', 'assign',
+ 'assign-class', 'assigned', 'assigned-class', 'assigned-value', 'assignee',
+ 'assignement', 'assignment', 'assignmentforge-config', 'associate',
+ 'association', 'associativity', 'assocs', 'asterisk', 'async', 'at-marker',
+ 'at-root', 'at-rule', 'at-sign', 'atmark', 'atml3', 'atoemp', 'atom',
+ 'atom-term-processing', 'atomic', 'atomscript', 'att', 'attachment', 'attr',
+ 'attribute', 'attribute-entry', 'attribute-expression', 'attribute-key-value',
+ 'attribute-list', 'attribute-lookup', 'attribute-name', 'attribute-reference',
+ 'attribute-selector', 'attribute-value', 'attribute-values',
+ 'attribute-with-value', 'attribute_list', 'attribute_value',
+ 'attribute_value2', 'attributelist', 'attributes', 'attrset',
+ 'attrset-or-function', 'audio', 'audio-file', 'auditor', 'augmented', 'auth',
+ 'auth_basic', 'author', 'author-names', 'authorization', 'auto', 'auto-event',
+ 'autoconf', 'autoindex', 'autoit', 'automake', 'automatic', 'autotools',
+ 'autovar', 'aux', 'auxiliary', 'avdl', 'avra', 'avrasm', 'avrdisasm', 'avs',
+ 'avx', 'avx2', 'avx512', 'awk', 'axes_group', 'axis', 'axl', 'b',
+ 'b-spline-patch', 'babel', 'back', 'back-from', 'back-reference',
+ 'back-slash', 'backend', 'background', 'backreference', 'backslash',
+ 'backslash-bar', 'backslash-g', 'backspace', 'backtick', 'bad-ampersand',
+ 'bad-angle-bracket', 'bad-assignment', 'bad-comments-or-CDATA', 'bad-escape',
+ 'bad-octal', 'bad-var', 'bang', 'banner', 'bar', 'bareword', 'barline',
+ 'base', 'base-11', 'base-12', 'base-13', 'base-14', 'base-15', 'base-16',
+ 'base-17', 'base-18', 'base-19', 'base-20', 'base-21', 'base-22', 'base-23',
+ 'base-24', 'base-25', 'base-26', 'base-27', 'base-28', 'base-29', 'base-3',
+ 'base-30', 'base-31', 'base-32', 'base-33', 'base-34', 'base-35', 'base-36',
+ 'base-4', 'base-5', 'base-6', 'base-7', 'base-9', 'base-call', 'base-integer',
+ 'base64', 'base85', 'base_pound_number_pound', 'basetype', 'basic',
+ 'basic-arithmetic', 'basic-type', 'basic_functions', 'basicblock',
+ 'basis-matrix', 'bat', 'batch', 'batchfile', 'battlesim', 'bb', 'bbcode',
+ 'bcmath', 'be', 'beam', 'beamer', 'beancount', 'before', 'begin',
+ 'begin-document', 'begin-emphasis', 'begin-end', 'begin-end-group',
+ 'begin-literal', 'begin-symbolic', 'begintimeblock', 'behaviour', 'bem',
+ 'between-tag-pair', 'bevel', 'bezier-patch', 'bfeac', 'bff', 'bg', 'bg-black',
+ 'bg-blue', 'bg-cyan', 'bg-green', 'bg-normal', 'bg-purple', 'bg-red',
+ 'bg-white', 'bg-yellow', 'bhtml', 'bhv', 'bibitem', 'bibliography-anchor',
+ 'biblioref', 'bibpaper', 'bibtex', 'bif', 'big-arrow', 'big-arrow-left',
+ 'bigdecimal', 'bigint', 'biicode', 'biiconf', 'bin', 'binOp', 'binary',
+ 'binary-arithmetic', 'bind', 'binder', 'binding', 'binding-prefix',
+ 'bindings', 'binop', 'bioinformatics', 'biosphere', 'bird-track', 'bis',
+ 'bison', 'bit', 'bit-and-byte', 'bit-range', 'bit-wise', 'bitarray', 'bitop',
+ 'bits-mov', 'bitvector', 'bitwise', 'black', 'blade', 'blanks', 'blaze',
+ 'blenc', 'blend', 'blending', 'blendtype', 'blendu', 'blendv', 'blip',
+ 'block', 'block-attribute', 'block-dartdoc', 'block-data', 'block-level',
+ 'blockid', 'blockname', 'blockquote', 'blocktitle', 'blue', 'blueprint',
+ 'bluespec', 'blur', 'bm', 'bmi', 'bmi1', 'bmi2', 'bnd', 'bnf', 'body',
+ 'body-statement', 'bold', 'bold-italic-text', 'bold-text', 'bolt', 'bond',
+ 'bonlang', 'boo', 'boogie', 'bool', 'boolean', 'boolean-test', 'boost',
+ 'boot', 'bord', 'border', 'botml', 'bottom', 'boundary', 'bounded', 'bounds',
+ 'bow', 'box', 'bpl', 'bpr', 'bqparam', 'brace', 'braced', 'braces', 'bracket',
+ 'bracketed', 'brackets', 'brainfuck', 'branch', 'branch-point', 'break',
+ 'breakpoint', 'breakpoints', 'breaks', 'bridle', 'brightscript', 'bro',
+ 'broken', 'browser', 'browsers', 'bs', 'bsl', 'btw', 'buffered', 'buffers',
+ 'bugzilla-number', 'build', 'buildin', 'buildout', 'built-in',
+ 'built-in-variable', 'built-ins', 'builtin', 'builtin-comparison', 'builtins',
+ 'bullet', 'bullet-point', 'bump', 'bump-multiplier', 'bundle', 'but',
+ 'button', 'buttons', 'by', 'by-name', 'by-number', 'byref', 'byte',
+ 'bytearray', 'bz2', 'bzl', 'c', 'c-style', 'c0', 'c1', 'c2hs', 'ca', 'cabal',
+ 'cabal-keyword', 'cache', 'cache-management', 'cacheability-control', 'cake',
+ 'calc', 'calca', 'calendar', 'call', 'callable', 'callback', 'caller',
+ 'calling', 'callmethod', 'callout', 'callparent', 'camera', 'camlp4',
+ 'camlp4-stream', 'canonicalized-program-name', 'canopen', 'capability',
+ 'capnp', 'cappuccino', 'caps', 'caption', 'capture', 'capturename',
+ 'cardinal-curve', 'cardinal-patch', 'cascade', 'case', 'case-block',
+ 'case-body', 'case-class', 'case-clause', 'case-clause-body',
+ 'case-expression', 'case-modifier', 'case-pattern', 'case-statement',
+ 'case-terminator', 'case-value', 'cassius', 'cast', 'catch',
+ 'catch-exception', 'catcode', 'categories', 'categort', 'category', 'cba',
+ 'cbmbasic', 'cbot', 'cbs', 'cc', 'cc65', 'ccml', 'cdata', 'cdef', 'cdtor',
+ 'ceiling', 'cell', 'cellcontents', 'cellwall', 'ceq', 'ces', 'cet', 'cexpr',
+ 'cextern', 'ceylon', 'ceylondoc', 'cf', 'cfdg', 'cfengine', 'cfg', 'cfml',
+ 'cfscript', 'cfunction', 'cg', 'cgi', 'cgx', 'chain', 'chained', 'chaining',
+ 'chainname', 'changed', 'changelogs', 'changes', 'channel', 'chapel',
+ 'chapter', 'char', 'characater', 'character', 'character-class',
+ 'character-data-not-allowed-here', 'character-literal',
+ 'character-literal-too-long', 'character-not-allowed-here', 'character-range',
+ 'character-reference', 'character-token', 'character_not_allowed',
+ 'character_not_allowed_here', 'characters', 'chars', 'chars-and-bytes-io',
+ 'charset', 'check', 'check-identifier', 'checkboxes', 'checker', 'chef',
+ 'chem', 'chemical', 'children', 'choice', 'choicescript', 'chord', 'chorus',
+ 'chuck', 'chunk', 'ciexyz', 'circle', 'circle-jot', 'cirru', 'cisco',
+ 'cisco-ios-config', 'citation', 'cite', 'citrine', 'cjam', 'cjson', 'clamp',
+ 'clamping', 'class', 'class-constraint', 'class-constraints',
+ 'class-declaration', 'class-definition', 'class-fns', 'class-instance',
+ 'class-list', 'class-struct-block', 'class-type', 'class-type-definition',
+ 'classcode', 'classes', 'classic', 'classicalb', 'classmethods', 'classobj',
+ 'classtree', 'clause', 'clause-head-body', 'clauses', 'clear',
+ 'clear-argument', 'cleared', 'clflushopt', 'click', 'client', 'client-server',
+ 'clip', 'clipboard', 'clips', 'clmul', 'clock', 'clojure', 'cloned', 'close',
+ 'closed', 'closing', 'closing-text', 'closure', 'clothes-body', 'cm', 'cmake',
+ 'cmb', 'cmd', 'cnet', 'cns', 'cobject', 'cocoa', 'cocor', 'cod4mp', 'code',
+ 'code-example', 'codeblock', 'codepoint', 'codimension', 'codstr', 'coffee',
+ 'coffeescript', 'coffeescript-preview', 'coil', 'collection', 'collision',
+ 'colon', 'colons', 'color', 'color-adjustment', 'coloring', 'colour',
+ 'colour-correction', 'colour-interpolation', 'colour-name', 'colour-scheme',
+ 'colspan', 'column', 'column-divider', 'column-specials', 'com',
+ 'combinators', 'comboboxes', 'comma', 'comma-bar', 'comma-parenthesis',
+ 'command', 'command-name', 'command-synopsis', 'commandline', 'commands',
+ 'comment', 'comment-ish', 'comment-italic', 'commented-out', 'commit-command',
+ 'commit-message', 'commodity', 'common', 'commonform', 'communications',
+ 'community', 'commute', 'comnd', 'compare', 'compareOp', 'comparison',
+ 'compile', 'compile-only', 'compiled', 'compiled-papyrus', 'compiler',
+ 'compiler-directive', 'compiletime', 'compiling-and-loading', 'complement',
+ 'complete', 'completed', 'complex', 'component', 'component-separator',
+ 'component_instantiation', 'compositor', 'compound', 'compound-assignment',
+ 'compress', 'computer', 'computercraft', 'concat', 'concatenated-arguments',
+ 'concatenation', 'concatenator', 'concatination', 'concealed', 'concise',
+ 'concrete', 'condition', 'conditional', 'conditional-directive',
+ 'conditional-short', 'conditionals', 'conditions', 'conf', 'config',
+ 'configuration', 'configure', 'confluence', 'conftype', 'conjunction',
+ 'conky', 'connect', 'connection-state', 'connectivity', 'connstate', 'cons',
+ 'consecutive-tags', 'considering', 'console', 'const', 'const-data',
+ 'constant', 'constants', 'constrained', 'constraint', 'constraints',
+ 'construct', 'constructor', 'constructor-list', 'constructs', 'consult',
+ 'contacts', 'container', 'containers-raycast', 'contains', 'content',
+ 'content-detective', 'contentSupplying', 'contentitem', 'context',
+ 'context-free', 'context-signature', 'continuation', 'continuations',
+ 'continue', 'continued', 'continuum', 'contol', 'contract', 'contracts',
+ 'contrl', 'control', 'control-char', 'control-handlers', 'control-management',
+ 'control-systems', 'control-transfer', 'controller', 'controlline',
+ 'controls', 'contstant', 'conventional', 'conversion', 'convert-type',
+ 'cookie', 'cool', 'coord1', 'coord2', 'coord3', 'coordinates', 'copy',
+ 'copying', 'coq', 'core', 'core-parse', 'coreutils', 'correct', 'cos',
+ 'counter', 'counters', 'cover', 'cplkg', 'cplusplus', 'cpm', 'cpp',
+ 'cpp-include', 'cpp-type', 'cpp_type', 'cpu12', 'cql', 'cram', 'crc32',
+ 'create', 'creation', 'critic', 'crl', 'crontab', 'crypto', 'crystal', 'cs',
+ 'csharp', 'cshtml', 'csi', 'csjs', 'csound', 'csound-document',
+ 'csound-score', 'cspm', 'css', 'csv', 'csx', 'ct', 'ctkey', 'ctor', 'ctxvar',
+ 'ctxvarbracket', 'ctype', 'cubic-bezier', 'cucumber', 'cuda',
+ 'cue-identifier', 'cue-timings', 'cuesheet', 'cup', 'cupsym', 'curl',
+ 'curley', 'curly', 'currency', 'current', 'current-escape-char',
+ 'curve', 'curve-2d', 'curve-fitting', 'curve-reference', 'curve-technique',
+ 'custom', 'customevent', 'cut', 'cve-number', 'cvs', 'cw', 'cxx', 'cy-GB',
+ 'cyan', 'cyc', 'cycle', 'cypher', 'cyrix', 'cython', 'd', 'da', 'daml',
+ 'dana', 'danger', 'danmakufu', 'dark_aqua', 'dark_blue', 'dark_gray',
+ 'dark_green', 'dark_purple', 'dark_red', 'dart', 'dartdoc', 'dash', 'dasm',
+ 'data', 'data-acquisition', 'data-extension', 'data-integrity', 'data-item',
+ 'data-step', 'data-transfer', 'database', 'database-name', 'datablock',
+ 'datablocks', 'datafeed', 'datatype', 'datatypes', 'date', 'date-time',
+ 'datetime', 'dav', 'day', 'dayofmonth', 'dayofweek', 'db', 'dba', 'dbx', 'dc',
+ 'dcon', 'dd', 'ddp', 'de', 'dealii', 'deallocate', 'deb-control', 'debian',
+ 'debris', 'debug', 'debug-specification', 'debugger', 'debugging',
+ 'debugging-comment', 'dec', 'decal', 'decimal', 'decimal-arithmetic',
+ 'decision', 'decl', 'declaration', 'declaration-expr', 'declaration-prod',
+ 'declarations', 'declarator', 'declaratyion', 'declare', 'decode',
+ 'decoration', 'decorator', 'decreasing', 'decrement', 'def', 'default',
+ 'define', 'define-colour', 'defined', 'definedness', 'definingobj',
+ 'definition', 'definitions', 'defintions', 'deflate', 'delay', 'delegated',
+ 'delete', 'deleted', 'deletion', 'delimeter', 'delimited', 'delimiter',
+ 'delimiter-too-long', 'delimiters', 'dense', 'deprecated', 'depricated',
+ 'dereference', 'derived-type', 'deriving', 'desc', 'describe', 'description',
+ 'descriptors', 'design', 'desktop', 'destination', 'destructor',
+ 'destructured', 'determ', 'developer', 'device', 'device-io', 'dformat', 'dg',
+ 'dhcp', 'diagnostic', 'dialogue', 'diamond', 'dict', 'dictionary',
+ 'dictionaryname', 'diff', 'difference', 'different', 'diffuse-reflectivity',
+ 'digdag', 'digit-width', 'dim', 'dimension', 'dip', 'dir', 'dir-target',
+ 'dircolors', 'direct', 'direction', 'directive', 'directive-option',
+ 'directives', 'directory', 'dirjs', 'dirtyblue', 'dirtygreen', 'disable',
+ 'disable-markdown', 'disable-todo', 'discarded', 'discusson', 'disjunction',
+ 'disk', 'disk-folder-file', 'dism', 'displacement', 'display', 'dissolve',
+ 'dissolve-interpolation', 'distribution', 'diverging-function', 'divert',
+ 'divide', 'divider', 'django', 'dl', 'dlv', 'dm', 'dmf', 'dml', 'do',
+ 'dobody', 'doc', 'doc-comment', 'docRoot', 'dockerfile', 'dockerignore',
+ 'doconce', 'docstring', 'doctest', 'doctree-option', 'doctype', 'document',
+ 'documentation', 'documentroot', 'does', 'dogescript', 'doki', 'dollar',
+ 'dollar-quote', 'dollar_variable', 'dom', 'domain', 'dontcollect', 'doors',
+ 'dop', 'dot', 'dot-access', 'dotenv', 'dotfiles', 'dothandout', 'dotnet',
+ 'dotnote', 'dots', 'dotted', 'dotted-circle', 'dotted-del', 'dotted-greater',
+ 'dotted-tack-up', 'double', 'double-arrow', 'double-colon', 'double-dash',
+ 'double-dash-not-allowed', 'double-dot', 'double-number-sign',
+ 'double-percentage', 'double-qoute', 'double-quote', 'double-quoted',
+ 'double-quoted-string', 'double-semicolon', 'double-slash', 'doublequote',
+ 'doubleslash', 'dougle', 'down', 'download', 'downwards', 'doxyfile',
+ 'doxygen', 'dragdrop', 'drawing', 'drive', 'droiuby', 'drop', 'drop-shadow',
+ 'droplevel', 'drummode', 'drupal', 'dsl', 'dsv', 'dt', 'dtl', 'due', 'dummy',
+ 'dummy-variable', 'dump', 'duration', 'dust', 'dust_Conditional',
+ 'dust_end_section_tag', 'dust_filter', 'dust_partial',
+ 'dust_partial_not_self_closing', 'dust_ref', 'dust_ref_name',
+ 'dust_section_context', 'dust_section_name', 'dust_section_params',
+ 'dust_self_closing_section_tag', 'dust_special', 'dust_start_section_tag',
+ 'dustjs', 'dut', 'dwscript', 'dxl', 'dylan', 'dynamic', 'dyndoc', 'dyon', 'e',
+ 'e3globals', 'each', 'eachin', 'earl-grey', 'ebnf', 'ebuild', 'echo',
+ 'eclass', 'ecmascript', 'eco', 'ecr', 'ect', 'ect2', 'ect3', 'ect4', 'edasm',
+ 'edge', 'edit-manager', 'editfields', 'editors', 'ee', 'eex', 'effect',
+ 'effectgroup', 'effective_routine_body', 'effects', 'eiffel', 'eight', 'eio',
+ 'eiz', 'ejectors', 'el', 'elasticsearch', 'elasticsearch2', 'element',
+ 'elements', 'elemnt', 'elif', 'elipse', 'elision', 'elixir', 'ellipsis',
+ 'elm', 'elmx', 'else', 'else-condition', 'else-if', 'elseif',
+ 'elseif-condition', 'elsewhere', 'eltype', 'elvis', 'em', 'email', 'embed',
+ 'embed-diversion', 'embedded', 'embedded-c', 'embedded-ruby', 'embedded2',
+ 'embeded', 'ember', 'emberscript', 'emblem', 'embperl', 'emissive-colour',
+ 'eml', 'emlist', 'emoji', 'emojicode', 'emp', 'emph', 'emphasis', 'empty',
+ 'empty-dictionary', 'empty-list', 'empty-parenthesis', 'empty-start',
+ 'empty-string', 'empty-tag', 'empty-tuple', 'empty-typing-pair', 'empty_gif',
+ 'emptyelement', 'en', 'en-Scouse', 'en-au', 'en-lol', 'en-old', 'en-pirate',
+ 'enable', 'enc', 'enchant', 'enclose', 'encode', 'encoding', 'encryption',
+ 'end', 'end-block-data', 'end-definition', 'end-document', 'end-enum',
+ 'end-footnote', 'end-of-line', 'end-statement', 'end-value', 'endassociate',
+ 'endcode', 'enddo', 'endfile', 'endforall', 'endfunction', 'endian',
+ 'endianness', 'endif', 'endinfo', 'ending', 'ending-space', 'endinterface',
+ 'endlocaltable', 'endmodule', 'endobject', 'endobjecttable', 'endparamtable',
+ 'endprogram', 'endproperty', 'endpropertygroup', 'endpropertygrouptable',
+ 'endpropertytable', 'endselect', 'endstate', 'endstatetable', 'endstruct',
+ 'endstructtable', 'endsubmodule', 'endsubroutine', 'endtimeblock', 'endtype',
+ 'enduserflagsref', 'endvariable', 'endvariabletable', 'endwhere', 'engine',
+ 'enterprise', 'entity', 'entity-creation-and-abolishing',
+ 'entity_instantiation', 'entry', 'entry-definition', 'entry-key',
+ 'entry-type', 'entrypoint', 'enum', 'enum-block', 'enum-declaration',
+ 'enumeration', 'enumerator', 'enumerator-specification', 'env', 'environment',
+ 'environment-variable', 'eo', 'eof', 'epatch', 'eq', 'eqn', 'eqnarray',
+ 'equal', 'equal-or-greater', 'equal-or-less', 'equalexpr', 'equality',
+ 'equals', 'equals-sign', 'equation', 'equation-label', 'erb', 'ereg',
+ 'erlang', 'error', 'error-control', 'errorfunc', 'errorstop', 'es', 'es6',
+ 'es6import', 'esc', 'escape', 'escape-char', 'escape-code', 'escape-sequence',
+ 'escape-unicode', 'escaped', 'escapes', 'escript', 'eso-lua', 'eso-txt',
+ 'essence', 'et', 'eth', 'ethaddr', 'etml', 'etpl', 'eudoc', 'euler',
+ 'euphoria', 'european', 'evaled', 'evaluable', 'evaluation', 'even-tab',
+ 'event', 'event-call', 'event-handler', 'event-handling', 'event-schedulling',
+ 'eventType', 'eventb', 'eventend', 'events', 'evnd', 'exactly', 'example',
+ 'exampleText', 'examples', 'exceeding-sections', 'excel-link', 'exception',
+ 'exceptions', 'exclaimation-point', 'exclamation', 'exec', 'exec-command',
+ 'execution-context', 'exif', 'existential', 'exit', 'exp', 'expand-register',
+ 'expanded', 'expansion', 'expected-array-separator',
+ 'expected-dictionary-separator', 'expected-extends', 'expected-implements',
+ 'expected-range-separator', 'experimental', 'expires', 'expl3', 'explosion',
+ 'exponent', 'exponential', 'export', 'exports', 'expr', 'expression',
+ 'expression-separator', 'expression-seperator', 'expressions',
+ 'expressions-and-types', 'exprwrap', 'ext', 'extempore', 'extend', 'extended',
+ 'extends', 'extension', 'extension-specification', 'extensions', 'extern',
+ 'extern-block', 'external', 'external-call', 'external-signature', 'extersk',
+ 'extglob', 'extra', 'extra-characters', 'extra-equals-sign', 'extracted',
+ 'extras', 'extrassk', 'exxample', 'eztpl', 'f', 'f5networks', 'fa', 'face',
+ 'fact', 'factor', 'factorial', 'fadeawayheight', 'fadeawaywidth', 'fail',
+ 'fakeroot', 'fallback', 'fallout4', 'false', 'fandoc', 'fann', 'fantom',
+ 'fastcgi', 'fbaccidental', 'fbfigure', 'fbgroupclose', 'fbgroupopen', 'fbp',
+ 'fctn', 'fe', 'feature', 'features', 'feedrate', 'fenced', 'fftwfn', 'fhem',
+ 'fi', 'field', 'field-assignment', 'field-completions', 'field-id',
+ 'field-level-comment', 'field-name', 'field-tag', 'fields', 'figbassmode',
+ 'figure', 'figuregroup', 'filder-design-hdl-coder', 'file', 'file-i-o',
+ 'file-io', 'file-name', 'file-object', 'file-path', 'fileinfo', 'filename',
+ 'filepath', 'filetest', 'filter', 'filter-pipe', 'filteredtranscludeblock',
+ 'filters', 'final', 'final-procedure', 'finally', 'financial',
+ 'financial-derivatives', 'find', 'find-in-files', 'find-m', 'finder',
+ 'finish', 'finn', 'fire', 'firebug', 'first', 'first-class', 'first-line',
+ 'fish', 'fitnesse', 'five', 'fix_this_later', 'fixed', 'fixed-income',
+ 'fixed-point', 'fixme', 'fl', 'flag', 'flag-control', 'flags', 'flash',
+ 'flatbuffers', 'flex-config', 'fload', 'float', 'float-exponent', 'float_exp',
+ 'floating-point', 'floating_point', 'floor', 'flow', 'flow-control',
+ 'flowcontrol', 'flows', 'flowtype', 'flush', 'fma', 'fma4', 'fmod', 'fn',
+ 'fold', 'folder', 'folder-actions', 'following', 'font',
+ 'font-cache', 'font-face', 'font-name', 'font-size', 'fontface', 'fontforge',
+ 'foobar', 'footer', 'footnote', 'for', 'for-in-loop', 'for-loop',
+ 'for-quantity', 'forall', 'force', 'foreach', 'foreign', 'forever',
+ 'forge-config', 'forin', 'form', 'form-feed', 'formal', 'format',
+ 'format-register', 'format-verb', 'formatted', 'formatter', 'formatting',
+ 'forth', 'fortran', 'forward', 'foundation', 'fountain', 'four',
+ 'fourd-command', 'fourd-constant', 'fourd-constant-hex',
+ 'fourd-constant-number', 'fourd-constant-string', 'fourd-control-begin',
+ 'fourd-control-end', 'fourd-declaration', 'fourd-declaration-array',
+ 'fourd-local-variable', 'fourd-parameter', 'fourd-table', 'fourd-tag',
+ 'fourd-variable', 'fpm', 'fpu', 'fpu_x87', 'fr', 'fragment', 'frame',
+ 'frames', 'frametitle', 'framexml', 'free', 'free-form', 'freebasic',
+ 'freefem', 'freespace2', 'from', 'from-file', 'front-matter', 'fs', 'fs2',
+ 'fsc', 'fsgsbase', 'fsharp', 'fsi', 'fsl', 'fsm', 'fsp', 'fsx', 'fth', 'ftl',
+ 'ftl20n', 'full-line', 'full-stop', 'fun', 'funarg', 'func-tag', 'func_call',
+ 'funchand', 'function', 'function-arity', 'function-attribute',
+ 'function-call', 'function-definition', 'function-literal',
+ 'function-parameter', 'function-recursive', 'function-return',
+ 'function-type', 'functionDeclaration', 'functionDefinition',
+ 'function_definition', 'function_prototype', 'functional_test', 'functionend',
+ 'functions', 'functionstart', 'fundimental', 'funk', 'funtion-definition',
+ 'fus', 'future', 'futures', 'fuzzy-logic', 'fx', 'fx-foliage-replicator',
+ 'fx-light', 'fx-shape-replicator', 'fx-sun-light', 'g', 'g-code', 'ga',
+ 'gain', 'galaxy', 'gallery', 'game-base', 'game-connection', 'game-server',
+ 'gamebusk', 'gamescript', 'gams', 'gams-lst', 'gap', 'garch', 'gather',
+ 'gcode', 'gdb', 'gdscript', 'gdx', 'ge', 'geant4-macro', 'geck',
+ 'geck-keyword', 'general', 'general-purpose', 'generate', 'generator',
+ 'generic', 'generic-config', 'generic-spec', 'generic-type', 'generic_list',
+ 'genericcall', 'generics', 'genetic-algorithms', 'geo', 'geometric',
+ 'geometry', 'geometry-adjustment', 'get', 'getproperty', 'getsec', 'getset',
+ 'getter', 'gettext', 'getword', 'gfm', 'gfm-todotxt', 'gfx', 'gh-number',
+ 'gherkin', 'gisdk', 'git', 'git-attributes', 'git-commit', 'git-config',
+ 'git-rebase', 'gitignore', 'given', 'gj', 'gl', 'glob', 'global',
+ 'global-functions', 'globals', 'globalsection', 'glsl', 'glue',
+ 'glyph_class_name', 'glyphname-value', 'gml', 'gmp', 'gmsh', 'gmx', 'gn',
+ 'gnu', 'gnuplot', 'go', 'goal', 'goatee', 'godmode', 'gohtml', 'gold', 'golo',
+ 'google', 'gosub', 'gotemplate', 'goto', 'goto-label', 'gpd', 'gpd_note',
+ 'gpp', 'grace', 'grade-down', 'grade-up', 'gradient', 'gradle', 'grails',
+ 'grammar', 'grammar-rule', 'grammar_production', 'grap', 'grapahql', 'graph',
+ 'graphics', 'graphql', 'grave-accent', 'gray', 'greater', 'greater-equal',
+ 'greater-or-equal', 'greek', 'greek-letter', 'green', 'gremlin', 'grey',
+ 'grg', 'grid-table', 'gridlists', 'grog', 'groovy', 'groovy-properties',
+ 'group', 'group-level-comment', 'group-name', 'group-number',
+ 'group-reference', 'group-title', 'group1', 'group10', 'group11', 'group2',
+ 'group3', 'group4', 'group5', 'group6', 'group7', 'group8', 'group9',
+ 'groupend', 'groupflag', 'grouping-statement', 'groupname', 'groupstart',
+ 'growl', 'grr', 'gs', 'gsc', 'gsp', 'gt', 'guard', 'guards', 'gui',
+ 'gui-bitmap-ctrl', 'gui-button-base-ctrl', 'gui-canvas', 'gui-control',
+ 'gui-filter-ctrl', 'gui-frameset-ctrl', 'gui-menu-bar',
+ 'gui-message-vector-ctrl', 'gui-ml-text-ctrl', 'gui-popup-menu-ctrl',
+ 'gui-scroll-ctrl', 'gui-slider-ctrl', 'gui-text-ctrl', 'gui-text-edit-ctrl',
+ 'gui-text-list-ctrl', 'guid', 'guillemot', 'guis', 'gzip', 'gzip_static', 'h',
+ 'h1', 'hack', 'hackfragment', 'haddock', 'hairpin', 'ham', 'haml', 'hamlbars',
+ 'hamlc', 'hamlet', 'hamlpy', 'handlebar', 'handlebars', 'handler',
+ 'hanging-paragraph', 'haproxy-config', 'harbou', 'harbour', 'hard-break',
+ 'hardlinebreaks', 'hash', 'hash-tick', 'hashbang', 'hashicorp', 'hashkey',
+ 'haskell', 'haxe', 'hbs', 'hcl', 'hdl', 'hdr', 'he', 'header',
+ 'header-continuation', 'header-value', 'headername', 'headers', 'heading',
+ 'heading-0', 'heading-1', 'heading-2', 'heading-3', 'heading-4', 'heading-5',
+ 'heading-6', 'height', 'helen', 'help', 'helper', 'helpers', 'heredoc',
+ 'heredoc-token', 'herestring', 'heritage', 'hex', 'hex-ascii', 'hex-byte',
+ 'hex-literal', 'hex-old', 'hex-string', 'hex-value', 'hex8', 'hexadecimal',
+ 'hexidecimal', 'hexprefix', 'hg-commit', 'hgignore', 'hi', 'hidden', 'hide',
+ 'high-minus', 'highlight-end', 'highlight-group',
+ 'highlight-start', 'hint', 'history', 'hive', 'hive-name', 'hjson', 'hl7',
+ 'hlsl', 'hn', 'hoa', 'hoc', 'hocharacter', 'hocomment', 'hocon', 'hoconstant',
+ 'hocontinuation', 'hocontrol', 'hombrew-formula', 'homebrew', 'homematic',
+ 'hook', 'hoon', 'horizontal-blending', 'horizontal-packed-arithmetic',
+ 'horizontal-rule', 'hostname', 'hosts', 'hour', 'hours', 'hps', 'hql', 'hr',
+ 'hrm', 'hs', 'hsc2hs', 'ht', 'htaccess', 'htl', 'html', 'html_entity',
+ 'htmlbars', 'http', 'hu', 'hungary', 'hxml', 'hy', 'hydrant', 'hydrogen',
+ 'hyperbolic', 'hyperlink', 'hyphen', 'hyphenation', 'hyphenation-char', 'i',
+ 'i-beam', 'i18n', 'iRev', 'ice', 'icinga2', 'icmc', 'icmptype', 'icmpv6type',
+ 'icmpxtype', 'iconv', 'id', 'id-type', 'id-with-protocol', 'idd', 'ideal',
+ 'identical', 'identifer', 'identified', 'identifier', 'identifier-type',
+ 'identifiers-and-DTDs', 'identity', 'idf', 'idl', 'idris', 'ieee', 'if',
+ 'if-block', 'if-branch', 'if-condition', 'if-else', 'if-then', 'ifacespec',
+ 'ifdef', 'ifname', 'ifndef', 'ignore', 'ignore-eol', 'ignore-errors',
+ 'ignorebii', 'ignored', 'ignored-binding', 'ignoring', 'iisfunc', 'ijk',
+ 'ilasm', 'illagal', 'illeagal', 'illegal', 'illumination-model', 'image',
+ 'image-acquisition', 'image-alignment', 'image-option', 'image-processing',
+ 'images', 'imap', 'imba', 'imfchan', 'img', 'immediate',
+ 'immediately-evaluated', 'immutable', 'impex', 'implementation',
+ 'implementation-defined-hooks', 'implemented', 'implements', 'implicit',
+ 'import', 'import-all', 'importall', 'important', 'in', 'in-block',
+ 'in-module', 'in-out', 'inappropriate', 'include', 'include-statement',
+ 'includefile', 'incomplete', 'incomplete-variable-assignment', 'inconsistent',
+ 'increment', 'increment-decrement', 'indent', 'indented',
+ 'indented-paragraph', 'indepimage', 'index', 'index-seperator', 'indexed',
+ 'indexer', 'indexes', 'indicator', 'indices', 'indirect', 'indirection',
+ 'individual-enum-definition', 'individual-rpc-call', 'inet', 'inetprototype',
+ 'inferred', 'infes', 'infinity', 'infix', 'info', 'inform', 'inform6',
+ 'inform7', 'infotype', 'ingore-eol', 'inherit', 'inheritDoc', 'inheritance',
+ 'inherited', 'inherited-class', 'inherited-struct', 'inherits', 'ini', 'init',
+ 'initial-lowercase', 'initial-uppercase', 'initial-value', 'initialization',
+ 'initialize', 'initializer-list', 'ink', 'inline', 'inline-data',
+ 'inlineConditionalBranchSeparator', 'inlineConditionalClause',
+ 'inlineConditionalEnd', 'inlineConditionalStart', 'inlineLogicEnd',
+ 'inlineLogicStart', 'inlineSequenceEnd', 'inlineSequenceSeparator',
+ 'inlineSequenceStart', 'inlineSequenceTypeChar', 'inlineblock', 'inlinecode',
+ 'inlinecomment', 'inlinetag', 'inner', 'inner-class', 'inno', 'ino', 'inout',
+ 'input', 'inquire', 'inserted', 'insertion', 'insertion-and-extraction',
+ 'inside', 'install', 'instance', 'instancemethods', 'instanceof', 'instances',
+ 'instantiation', 'instruction', 'instruction-pointer', 'instructions',
+ 'instrument', 'instrument-block', 'instrument-control',
+ 'instrument-declaration', 'int', 'int32', 'int64', 'integer', 'integer-float',
+ 'intel', 'intel-hex', 'intent', 'intepreted', 'interaction', 'interbase',
+ 'interface', 'interface-block', 'interface-or-protocol', 'interfaces',
+ 'interior-instance', 'interiors', 'interlink', 'internal', 'internet',
+ 'interpolate-argument', 'interpolate-string', 'interpolate-variable',
+ 'interpolated', 'interpolation', 'interrupt', 'intersection', 'interval',
+ 'intervalOrList', 'intl', 'intrinsic', 'intuicio4', 'invalid',
+ 'invalid-character', 'invalid-character-escape', 'invalid-inequality',
+ 'invalid-quote', 'invalid-variable-name', 'invariant', 'invocation', 'invoke',
+ 'invokee', 'io', 'ior', 'iota', 'ip', 'ip-port', 'ip6', 'ipkg', 'ipsec',
+ 'ipv4', 'ipv6', 'ipynb', 'irct', 'irule', 'is', 'isa', 'isc', 'iscexport',
+ 'isclass', 'isml', 'issue', 'it', 'italic', 'italic-text', 'item',
+ 'item-access', 'itemlevel', 'items', 'iteration', 'itunes', 'ivar', 'ja',
+ 'jack', 'jade', 'jakefile', 'jasmin', 'java', 'java-properties', 'java-props',
+ 'javadoc', 'javascript', 'jbeam', 'jekyll', 'jflex', 'jibo-rule', 'jinja',
+ 'jison', 'jisonlex', 'jmp', 'joint', 'joker', 'jolie', 'jot', 'journaling',
+ 'jpl', 'jq', 'jquery', 'js', 'js-label', 'jsdoc', 'jsduck', 'jsim', 'json',
+ 'json5', 'jsoniq', 'jsonnet', 'jsont', 'jsp', 'jsx', 'julia', 'julius',
+ 'jump', 'juniper', 'juniper-junos-config', 'junit-test-report', 'junos',
+ 'juttle', 'jv', 'jxa', 'k', 'kag', 'kagex', 'kb', 'kbd', 'kconfig',
+ 'kerboscript', 'kernel', 'kevs', 'kevscript', 'kewyword', 'key',
+ 'key-assignment', 'key-letter', 'key-pair', 'key-path', 'key-value',
+ 'keyboard', 'keyframe', 'keyframes', 'keygroup', 'keyname', 'keyspace',
+ 'keyspace-name', 'keyvalue', 'keyword', 'keyword-parameter', 'keyword1',
+ 'keyword2', 'keyword3', 'keyword4', 'keyword5', 'keyword6', 'keyword7',
+ 'keyword8', 'keyword_arrays', 'keyword_objects', 'keyword_roots',
+ 'keyword_string', 'keywords', 'keywork', 'kickstart', 'kind', 'kmd', 'kn',
+ 'knitr', 'knockout', 'knot', 'ko', 'ko-virtual', 'kos', 'kotlin', 'krl',
+ 'ksp-cfg', 'kspcfg', 'kurumin', 'kv', 'kxi', 'kxigauge', 'l', 'l20n',
+ 'l4proto', 'label', 'label-expression', 'labeled', 'labeled-parameter',
+ 'labelled-thing', 'lagda', 'lambda', 'lambda-function', 'lammps', 'langref',
+ 'language', 'language-range', 'languagebabel', 'langversion', 'largesk',
+ 'lasso', 'last', 'last-paren-match', 'latex', 'latex2', 'latino', 'latte',
+ 'launch', 'layout', 'layoutbii', 'lbsearch', 'lc', 'lc-3', 'lcb', 'ldap',
+ 'ldif', 'le', 'leader-char', 'leading', 'leading-space', 'leading-tabs',
+ 'leaf', 'lean', 'ledger', 'left', 'left-margin', 'leftshift', 'lefttoright',
+ 'legacy', 'legacy-setting', 'lemon', 'len', 'length', 'leopard', 'less',
+ 'less-equal', 'less-or-equal', 'let', 'letter', 'level', 'level-of-detail',
+ 'level1', 'level2', 'level3', 'level4', 'level5', 'level6', 'levels', 'lex',
+ 'lexc', 'lexical', 'lf-in-string', 'lhs', 'li', 'lib', 'libfile', 'library',
+ 'libs', 'libxml', 'lid', 'lifetime', 'ligature', 'light', 'light_purple',
+ 'lighting', 'lightning', 'lilypond', 'lilypond-drummode',
+ 'lilypond-figbassmode', 'lilypond-figuregroup', 'lilypond-internals',
+ 'lilypond-lyricsmode', 'lilypond-markupmode', 'lilypond-notedrum',
+ 'lilypond-notemode', 'lilypond-notemode-explicit', 'lilypond-notenames',
+ 'lilypond-schememode', 'limit_zone', 'line-block', 'line-break',
+ 'line-continuation', 'line-cue-setting', 'line-statement',
+ 'line-too-long', 'linebreak', 'linenumber', 'link', 'link-label',
+ 'link-text', 'link-url', 'linkage', 'linkage-type', 'linkedin',
+ 'linkedsockets', 'linkplain', 'linkplain-label', 'linq', 'linuxcncgcode',
+ 'liquid', 'liquidhaskell', 'liquidsoap', 'lisp', 'lisp-repl', 'list',
+ 'list-done', 'list-separator', 'list-style-type', 'list-today', 'list_item',
+ 'listing', 'listnum', 'listvalues', 'litaco', 'litcoffee', 'literal',
+ 'literal-string', 'literate', 'litword', 'livecodescript', 'livescript',
+ 'livescriptscript', 'll', 'llvm', 'load-constants', 'load-hint', 'loader',
+ 'local', 'local-variables', 'localhost', 'localizable', 'localized',
+ 'localname', 'locals', 'localtable', 'location', 'lock', 'log', 'log-debug',
+ 'log-error', 'log-failed', 'log-info', 'log-patch', 'log-success',
+ 'log-verbose', 'log-warning', 'logarithm', 'logging', 'logic', 'logicBegin',
+ 'logical', 'logical-expression', 'logicblox', 'logicode', 'logo', 'logstash',
+ 'logtalk', 'lol', 'long', 'look-ahead', 'look-behind', 'lookahead',
+ 'lookaround', 'lookbehind', 'loop', 'loop-control', 'low-high', 'lowercase',
+ 'lowercase_character_not_allowed_here', 'lozenge', 'lparen', 'lsg', 'lsl',
+ 'lst', 'lst-cpu12', 'lstdo', 'lt', 'lt-gt', 'lterat', 'lu', 'lua', 'lucee',
+ 'lucius', 'lury', 'lv', 'lyricsmode', 'm', 'm4', 'm4sh', 'm65816', 'm68k',
+ 'mac-classic', 'mac-fsaa', 'machine', 'machineclause', 'macro', 'macro-usage',
+ 'macro11', 'macrocallblock', 'macrocallinline', 'madoko', 'magenta', 'magic',
+ 'magik', 'mail', 'mailer', 'mailto', 'main', 'makefile', 'makefile2', 'mako',
+ 'mamba', 'man', 'mantissa', 'manualmelisma', 'map', 'map-library', 'map-name',
+ 'mapfile', 'mapkey', 'mapping', 'mapping-type', 'maprange', 'marasm',
+ 'margin', 'marginpar', 'mark', 'mark-input', 'markdown', 'marker', 'marko',
+ 'marko-attribute', 'marko-tag', 'markup', 'markupmode', 'mas2j', 'mask',
+ 'mason', 'mat', 'mata', 'match', 'match-bind', 'match-branch',
+ 'match-condition', 'match-definition', 'match-exception', 'match-option',
+ 'match-pattern', 'material', 'material-library', 'material-name', 'math',
+ 'math-symbol', 'math_complex', 'math_real', 'mathematic', 'mathematica',
+ 'mathematical', 'mathematical-symbols', 'mathematics', 'mathjax', 'mathml',
+ 'matlab', 'matrix', 'maude', 'maven', 'max', 'max-angle', 'max-distance',
+ 'max-length', 'maxscript', 'maybe', 'mb', 'mbstring', 'mc', 'mcc', 'mccolor',
+ 'mch', 'mcn', 'mcode', 'mcq', 'mcr', 'mcrypt', 'mcs', 'md', 'mdash', 'mdoc',
+ 'mdx', 'me', 'measure', 'media', 'media-feature', 'media-property',
+ 'media-type', 'mediawiki', 'mei', 'mel', 'memaddress', 'member',
+ 'member-function-attribute', 'member-of', 'membership', 'memcache',
+ 'memcached', 'memoir', 'memoir-alltt', 'memoir-fbox', 'memoir-verbatim',
+ 'memory', 'memory-management', 'memory-protection', 'memos', 'menhir',
+ 'mention', 'menu', 'mercury', 'merge-group', 'merge-key', 'merlin',
+ 'mesgTrigger', 'mesgType', 'message', 'message-declaration',
+ 'message-forwarding-handler', 'message-sending', 'message-vector', 'messages',
+ 'meta', 'meta-conditional', 'meta-data', 'meta-file', 'meta-info',
+ 'metaclass', 'metacommand', 'metadata', 'metakey', 'metamodel', 'metapost',
+ 'metascript', 'meteor', 'method', 'method-call', 'method-definition',
+ 'method-modification', 'method-mofification', 'method-parameter',
+ 'method-parameters', 'method-restriction', 'methodcalls', 'methods',
+ 'metrics', 'mhash', 'microsites', 'microsoft-dynamics', 'middle',
+ 'midi_processing', 'migration', 'mime', 'min', 'minelua', 'minetweaker',
+ 'minitemplate', 'minitest', 'minus', 'minute', 'mips', 'mirah', 'misc',
+ 'miscellaneous', 'mismatched', 'missing', 'missing-asterisk',
+ 'missing-inheritance', 'missing-parameters', 'missing-section-begin',
+ 'missingend', 'mission-area', 'mixin', 'mixin-name', 'mjml', 'ml', 'mlab',
+ 'mls', 'mm', 'mml', 'mmx', 'mmx_instructions', 'mn', 'mnemonic',
+ 'mobile-messaging', 'mochi', 'mod', 'mod-r', 'mod_perl', 'mod_perl_1',
+ 'modblock', 'modbus', 'mode', 'model', 'model-based-calibration',
+ 'model-predictive-control', 'modelica', 'modelicascript', 'modeline',
+ 'models', 'modern', 'modified', 'modifier', 'modifiers', 'modify',
+ 'modify-range', 'modifytime', 'modl', 'modr', 'modula-2', 'module',
+ 'module-alias', 'module-binding', 'module-definition', 'module-expression',
+ 'module-function', 'module-reference', 'module-rename', 'module-sum',
+ 'module-type', 'module-type-definition', 'modules', 'modulo', 'modx',
+ 'mojolicious', 'mojom', 'moment', 'mond', 'money', 'mongo', 'mongodb',
+ 'monicelli', 'monitor', 'monkberry', 'monkey', 'monospace', 'monospaced',
+ 'monte', 'month', 'moon', 'moonscript', 'moos', 'moose', 'moosecpp', 'motion',
+ 'mouse', 'mov', 'movement', 'movie', 'movie-file', 'mozu', 'mpw', 'mpx',
+ 'mqsc', 'ms', 'mscgen', 'mscript', 'msg', 'msgctxt', 'msgenny', 'msgid',
+ 'msgstr', 'mson', 'mson-block', 'mss', 'mta', 'mtl', 'mucow', 'mult', 'multi',
+ 'multi-line', 'multi-symbol', 'multi-threading', 'multiclet', 'multids-file',
+ 'multiline', 'multiline-cell', 'multiline-text-reference',
+ 'multiline-tiddler-title', 'multimethod', 'multipart', 'multiplication',
+ 'multiplicative', 'multiply', 'multiverse', 'mumps', 'mundosk', 'music',
+ 'must_be', 'mustache', 'mut', 'mutable', 'mutator', 'mx', 'mxml', 'mydsl1',
+ 'mylanguage', 'mysql', 'mysqli', 'mysqlnd-memcache', 'mysqlnd-ms',
+ 'mysqlnd-qc', 'mysqlnd-uh', 'mzn', 'nabla', 'nagios', 'name', 'name-list',
+ 'name-of-parameter', 'named', 'named-char', 'named-key', 'named-tuple',
+ 'nameless-typed', 'namelist', 'names', 'namespace', 'namespace-block',
+ 'namespace-definition', 'namespace-language', 'namespace-prefix',
+ 'namespace-reference', 'namespace-statement', 'namespaces', 'nan', 'nand',
+ 'nant', 'nant-build', 'narration', 'nas', 'nasal', 'nasl', 'nasm', 'nastran',
+ 'nat', 'native', 'nativeint', 'natural', 'navigation', 'nbtkey', 'ncf', 'ncl',
+ 'ndash', 'ne', 'nearley', 'neg-ratio', 'negatable', 'negate', 'negated',
+ 'negation', 'negative', 'negative-look-ahead', 'negative-look-behind',
+ 'negativity', 'nesc', 'nessuskb', 'nested', 'nested_braces',
+ 'nested_brackets', 'nested_ltgt', 'nested_parens', 'nesty', 'net',
+ 'net-object', 'netbios', 'network', 'network-value', 'networking',
+ 'neural-network', 'new', 'new-line', 'new-object', 'newline',
+ 'newline-spacing', 'newlinetext', 'newlisp', 'newobject', 'nez', 'nft',
+ 'ngdoc', 'nginx', 'nickname', 'nil', 'nim', 'nine', 'ninja', 'ninjaforce',
+ 'nit', 'nitro', 'nix', 'nl', 'nlf', 'nm', 'nm7', 'no', 'no-capture',
+ 'no-completions', 'no-content', 'no-default', 'no-indent',
+ 'no-leading-digits', 'no-trailing-digits', 'no-validate-params', 'node',
+ 'nogc', 'noindent', 'nokia-sros-config', 'non', 'non-capturing',
+ 'non-immediate', 'non-null-typehinted', 'non-standard', 'non-terminal',
+ 'nondir-target', 'none', 'none-parameter', 'nonlocal', 'nonterminal', 'noon',
+ 'noop', 'nop', 'noparams', 'nor', 'normal', 'normal_numeric',
+ 'normal_objects', 'normal_text', 'normalised', 'not', 'not-a-number',
+ 'not-equal', 'not-identical', 'notation', 'note', 'notechord', 'notemode',
+ 'notequal', 'notequalexpr', 'notes', 'notidentical', 'notification', 'nowdoc',
+ 'noweb', 'nrtdrv', 'nsapi', 'nscript', 'nse', 'nsis', 'nsl', 'ntriples',
+ 'nul', 'null', 'nullify', 'nullological', 'nulltype', 'num', 'number',
+ 'number-sign', 'number-sign-equals', 'numbered', 'numberic', 'numbers',
+ 'numbersign', 'numeric', 'numeric_std', 'numerical', 'nunjucks', 'nut',
+ 'nvatom', 'nxc', 'o', 'obj', 'objaggregation', 'objc', 'objcpp', 'objdump',
+ 'object', 'object-comments', 'object-definition', 'object-level-comment',
+ 'object-name', 'objects', 'objectset', 'objecttable', 'objectvalues', 'objj',
+ 'obsolete', 'ocaml', 'ocamllex', 'occam', 'oci8', 'ocmal', 'oct', 'octal',
+ 'octave', 'octave-change', 'octave-shift', 'octet', 'octo', 'octobercms',
+ 'octothorpe', 'odd-tab', 'odedsl', 'ods', 'of', 'off', 'offset', 'ofx',
+ 'ogre', 'ok', 'ol', 'old', 'old-style', 'omap', 'omitted', 'on-background',
+ 'on-error', 'once', 'one', 'one-sixth-em', 'one-twelfth-em', 'oniguruma',
+ 'oniguruma-comment', 'only', 'only-in', 'onoff', 'ooc', 'oot', 'op-domain',
+ 'op-range', 'opa', 'opaque', 'opc', 'opcache', 'opcode',
+ 'opcode-argument-types', 'opcode-declaration', 'opcode-definition',
+ 'opcode-details', 'open', 'open-gl', 'openal', 'openbinding', 'opencl',
+ 'opendss', 'opening', 'opening-text', 'openmp', 'openssl', 'opentype',
+ 'operand', 'operands', 'operation', 'operator', 'operator2', 'operator3',
+ 'operators', 'opmask', 'opmaskregs', 'optical-density', 'optimization',
+ 'option', 'option-description', 'option-toggle', 'optional',
+ 'optional-parameter', 'optional-parameter-assignment', 'optionals',
+ 'optionname', 'options', 'optiontype', 'or', 'oracle', 'orbbasic', 'orcam',
+ 'orchestra', 'order', 'ordered', 'ordered-block', 'ordinal', 'organized',
+ 'orgtype', 'origin', 'osiris', 'other', 'other-inherited-class',
+ 'other_buildins', 'other_keywords', 'others', 'otherwise',
+ 'otherwise-expression', 'out', 'outer', 'output', 'overload', 'override',
+ 'owner', 'ownership', 'oz', 'p', 'p4', 'p5', 'p8', 'pa', 'package',
+ 'package-definition', 'package_body', 'packages', 'packed',
+ 'packed-arithmetic', 'packed-blending', 'packed-comparison',
+ 'packed-conversion', 'packed-floating-point', 'packed-integer', 'packed-math',
+ 'packed-mov', 'packed-other', 'packed-shift', 'packed-shuffle', 'packed-test',
+ 'padlock', 'page', 'page-props', 'pagebreak', 'pair', 'pair-programming',
+ 'paket', 'pandoc', 'papyrus', 'papyrus-assembly', 'paragraph', 'parallel',
+ 'param', 'param-list', 'paramater', 'paramerised-type', 'parameter',
+ 'parameter-entity', 'parameter-space', 'parameterless', 'parameters',
+ 'paramless', 'params', 'paramtable', 'paramter', 'paren', 'paren-group',
+ 'parens', 'parent', 'parent-reference', 'parent-selector',
+ 'parent-selector-suffix', 'parenthases', 'parentheses', 'parenthesis',
+ 'parenthetical', 'parenthetical_list', 'parenthetical_pair', 'parfor',
+ 'parfor-quantity', 'parse', 'parsed', 'parser', 'parser-function',
+ 'parser-token', 'parser3', 'part', 'partial', 'particle', 'pascal', 'pass',
+ 'pass-through', 'passive', 'passthrough', 'password', 'password-hash',
+ 'patch', 'path', 'path-camera', 'path-pattern', 'pathoperation', 'paths',
+ 'pathspec', 'patientId', 'pattern', 'pattern-argument', 'pattern-binding',
+ 'pattern-definition', 'pattern-match', 'pattern-offset', 'patterns', 'pause',
+ 'payee', 'payload', 'pbo', 'pbtxt', 'pcdata', 'pcntl', 'pdd', 'pddl', 'ped',
+ 'pegcoffee', 'pegjs', 'pending', 'percentage', 'percentage-sign',
+ 'percussionnote', 'period', 'perl', 'perl-section', 'perl6', 'perl6fe',
+ 'perlfe', 'perlt6e', 'perm', 'permutations', 'personalization', 'pervasive',
+ 'pf', 'pflotran', 'pfm', 'pfx', 'pgn', 'pgsql', 'phone', 'phone-number',
+ 'phonix', 'php', 'php-code-in-comment', 'php_apache', 'php_dom', 'php_ftp',
+ 'php_imap', 'php_mssql', 'php_odbc', 'php_pcre', 'php_spl', 'php_zip',
+ 'phpdoc', 'phrasemodifiers', 'phraslur', 'physical-zone', 'physics', 'pi',
+ 'pic', 'pick', 'pickup', 'picture', 'pig', 'pillar', 'pipe', 'pipe-sign',
+ 'pipeline', 'piratesk', 'pitch', 'pixie', 'pkgbuild', 'pl', 'placeholder',
+ 'placeholder-parts', 'plain', 'plainsimple-emphasize', 'plainsimple-heading',
+ 'plainsimple-number', 'plantuml', 'player', 'playerversion', 'pld_modeling',
+ 'please-build', 'please-build-defs', 'plist', 'plsql', 'plugin', 'plus',
+ 'plztarget', 'pmc', 'pml', 'pmlPhysics-arrangecharacter',
+ 'pmlPhysics-emphasisequote', 'pmlPhysics-graphic', 'pmlPhysics-header',
+ 'pmlPhysics-htmlencoded', 'pmlPhysics-links', 'pmlPhysics-listtable',
+ 'pmlPhysics-physicalquantity', 'pmlPhysics-relationships',
+ 'pmlPhysics-slides', 'pmlPhysics-slidestacks', 'pmlPhysics-speech',
+ 'pmlPhysics-structure', 'pnt', 'po', 'pod', 'poe', 'pogoscript', 'point',
+ 'point-size', 'pointer', 'pointer-arith', 'pointer-following', 'points',
+ 'polarcoord', 'policiesbii', 'policy', 'polydelim', 'polygonal', 'polymer',
+ 'polymorphic', 'polymorphic-variant', 'polynomial-degree', 'polysep', 'pony',
+ 'port', 'port_list', 'pos-ratio', 'position-cue-setting', 'positional',
+ 'positive', 'posix', 'posix-reserved', 'post-match', 'postblit', 'postcss',
+ 'postfix', 'postpone', 'postscript', 'potigol', 'potion', 'pound',
+ 'pound-sign', 'povray', 'power', 'power_set', 'powershell', 'pp', 'ppc',
+ 'ppcasm', 'ppd', 'praat', 'pragma', 'pragma-all-once', 'pragma-mark',
+ 'pragma-message', 'pragma-newline-spacing', 'pragma-newline-spacing-value',
+ 'pragma-once', 'pragma-stg', 'pragma-stg-value', 'pre', 'pre-defined',
+ 'pre-match', 'preamble', 'prec', 'precedence', 'precipitation', 'precision',
+ 'precision-point', 'pred', 'predefined', 'predicate', 'prefetch',
+ 'prefetchwt', 'prefix', 'prefixed-uri', 'prefixes', 'preinst', 'prelude',
+ 'prepare', 'prepocessor', 'preposition', 'prepositional', 'preprocessor',
+ 'prerequisites', 'preset', 'preview', 'previous', 'prg', 'primary',
+ 'primitive', 'primitive-datatypes', 'primitive-field', 'print',
+ 'print-argument', 'priority', 'prism', 'private', 'privileged', 'pro',
+ 'probe', 'proc', 'procedure', 'procedure_definition', 'procedure_prototype',
+ 'process', 'process-id', 'process-substitution', 'processes', 'processing',
+ 'proctitle', 'production', 'profile', 'profiling', 'program', 'program-block',
+ 'program-name', 'progressbars', 'proguard', 'project', 'projectile', 'prolog',
+ 'prolog-flags', 'prologue', 'promoted', 'prompt', 'prompt-prefix', 'prop',
+ 'properties', 'properties_literal', 'property', 'property-flag',
+ 'property-list', 'property-name', 'property-value',
+ 'property-with-attributes', 'propertydef', 'propertyend', 'propertygroup',
+ 'propertygrouptable', 'propertyset', 'propertytable', 'proposition',
+ 'protection', 'protections', 'proto', 'protobuf', 'protobufs', 'protocol',
+ 'protocol-specification', 'prototype', 'provision', 'proxy', 'psci', 'pseudo',
+ 'pseudo-class', 'pseudo-element', 'pseudo-method', 'pseudo-mnemonic',
+ 'pseudo-variable', 'pshdl', 'pspell', 'psql', 'pt', 'ptc-config',
+ 'ptc-config-modelcheck', 'pthread', 'ptr', 'ptx', 'public', 'pug',
+ 'punchcard', 'punctual', 'punctuation', 'punctutation', 'puncuation',
+ 'puncutation', 'puntuation', 'puppet', 'purebasic', 'purescript', 'pweave',
+ 'pwisa', 'pwn', 'py2pml', 'pyj', 'pyjade', 'pymol', 'pyresttest', 'python',
+ 'python-function', 'q', 'q-brace', 'q-bracket', 'q-ltgt', 'q-paren', 'qa',
+ 'qm', 'qml', 'qos', 'qoute', 'qq', 'qq-brace', 'qq-bracket', 'qq-ltgt',
+ 'qq-paren', 'qry', 'qtpro', 'quad', 'quad-arrow-down', 'quad-arrow-left',
+ 'quad-arrow-right', 'quad-arrow-up', 'quad-backslash', 'quad-caret-down',
+ 'quad-caret-up', 'quad-circle', 'quad-colon', 'quad-del-down', 'quad-del-up',
+ 'quad-diamond', 'quad-divide', 'quad-equal', 'quad-jot', 'quad-less',
+ 'quad-not-equal', 'quad-question', 'quad-quote', 'quad-slash', 'quadrigraph',
+ 'qual', 'qualified', 'qualifier', 'quality', 'quant', 'quantifier',
+ 'quantifiers', 'quartz', 'quasi', 'quasiquote', 'quasiquotes', 'query',
+ 'query-dsl', 'question', 'questionmark', 'quicel', 'quicktemplate',
+ 'quicktime-file', 'quotation', 'quote', 'quoted', 'quoted-identifier',
+ 'quoted-object', 'quoted-or-unquoted', 'quotes', 'qx', 'qx-brace',
+ 'qx-bracket', 'qx-ltgt', 'qx-paren', 'r', 'r3', 'rabl', 'racket', 'radar',
+ 'radar-area', 'radiobuttons', 'radix', 'rails', 'rainmeter', 'raml', 'random',
+ 'random_number', 'randomsk', 'range', 'range-2', 'rank', 'rant', 'rapid',
+ 'rarity', 'ratio', 'rational-form', 'raw', 'raw-regex', 'raxe', 'rb', 'rd',
+ 'rdfs-type', 'rdrand', 'rdseed', 'react', 'read', 'readline', 'readonly',
+ 'readwrite', 'real', 'realip', 'rebeca', 'rebol', 'rec', 'receive',
+ 'receive-channel', 'recipe', 'recipient-subscriber-list', 'recode', 'record',
+ 'record-field', 'record-usage', 'recordfield', 'recutils', 'red',
+ 'redbook-audio', 'redirect', 'redirection', 'redprl', 'redundancy', 'ref',
+ 'refer', 'reference', 'referer', 'refinement', 'reflection', 'reg', 'regex',
+ 'regexname', 'regexp', 'regexp-option', 'region-anchor-setting',
+ 'region-cue-setting', 'region-identifier-setting', 'region-lines-setting',
+ 'region-scroll-setting', 'region-viewport-anchor-setting',
+ 'region-width-setting', 'register', 'register-64', 'registers', 'regular',
+ 'reiny', 'reject', 'rejecttype', 'rel', 'related', 'relation', 'relational',
+ 'relations', 'relationship', 'relationship-name', 'relationship-pattern',
+ 'relationship-pattern-end', 'relationship-pattern-start', 'relationship-type',
+ 'relationship-type-or', 'relationship-type-ored', 'relationship-type-start',
+ 'relative', 'rem', 'reminder', 'remote', 'removed', 'rename', 'renamed-from',
+ 'renamed-to', 'renaming', 'render', 'renpy', 'reocrd', 'reparator', 'repeat',
+ 'repl-prompt', 'replace', 'replaceXXX', 'replaced', 'replacement', 'reply',
+ 'repo', 'reporter', 'reporting', 'repository', 'request', 'request-type',
+ 'require', 'required', 'requiredness', 'requirement', 'requirements',
+ 'rescue', 'reserved', 'reset', 'resolution', 'resource', 'resource-manager',
+ 'response', 'response-type', 'rest', 'rest-args', 'rester', 'restriced',
+ 'restructuredtext', 'result', 'result-separator', 'results', 'retro',
+ 'return', 'return-type', 'return-value', 'returns', 'rev', 'reverse',
+ 'reversed', 'review', 'rewrite', 'rewrite-condition', 'rewrite-operator',
+ 'rewrite-pattern', 'rewrite-substitution', 'rewrite-test', 'rewritecond',
+ 'rewriterule', 'rf', 'rfc', 'rgb', 'rgb-percentage', 'rgb-value', 'rhap',
+ 'rho', 'rhs', 'rhtml', 'richtext', 'rid', 'right', 'ring', 'riot',
+ 'rivescript', 'rjs', 'rl', 'rmarkdown', 'rnc', 'rng', 'ro', 'roboconf',
+ 'robot', 'robotc', 'robust-control', 'rockerfile', 'roff', 'role',
+ 'rollout-control', 'root', 'rotate', 'rotate-first', 'rotate-last', 'round',
+ 'round-brackets', 'router', 'routeros', 'routes', 'routine', 'row', 'row2',
+ 'rowspan', 'roxygen', 'rparent', 'rpc', 'rpc-definition', 'rpe', 'rpm-spec',
+ 'rpmspec', 'rpt', 'rq', 'rrd', 'rsl', 'rspec', 'rtemplate', 'ru', 'ruby',
+ 'rubymotion', 'rule', 'rule-identifier', 'rule-name', 'rule-pattern',
+ 'rule-tag', 'ruleDefinition', 'rules', 'run', 'rune', 'runoff', 'runtime',
+ 'rust', 'rviz', 'rx', 's', 'safe-call', 'safe-navigation', 'safe-trap',
+ 'safer', 'safety', 'sage', 'salesforce', 'salt', 'sampler',
+ 'sampler-comparison', 'samplerarg', 'sampling', 'sas', 'sass',
+ 'sass-script-maps', 'satcom', 'satisfies', 'sblock', 'scad', 'scala',
+ 'scaladoc', 'scalar', 'scale', 'scam', 'scan', 'scenario', 'scenario_outline',
+ 'scene', 'scene-object', 'scheduled', 'schelp', 'schem', 'schema', 'scheme',
+ 'schememode', 'scientific', 'scilab', 'sck', 'scl', 'scope', 'scope-name',
+ 'scope-resolution', 'scoping', 'score', 'screen', 'scribble', 'script',
+ 'script-flag', 'script-metadata', 'script-object', 'script-tag', 'scripting',
+ 'scriptlet', 'scriptlocal', 'scriptname', 'scriptname-declaration', 'scripts',
+ 'scroll', 'scrollbars', 'scrollpanes', 'scss', 'scumm', 'sdbl', 'sdl', 'sdo',
+ 'sealed', 'search', 'seawolf', 'second', 'secondary', 'section',
+ 'section-attribute', 'sectionname', 'sections', 'see', 'segment',
+ 'segment-registers', 'segment-resolution', 'select', 'select-block',
+ 'selector', 'self', 'self-binding', 'self-close', 'sem', 'semantic',
+ 'semanticmodel', 'semi-colon', 'semicolon', 'semicoron', 'semireserved',
+ 'send-channel', 'sender', 'senum', 'sep', 'separator', 'separatory',
+ 'sepatator', 'seperator', 'sequence', 'sequences', 'serial', 'serpent',
+ 'server', 'service', 'service-declaration', 'service-rpc', 'services',
+ 'session', 'set', 'set-colour', 'set-size', 'set-variable', 'setbagmix',
+ 'setname', 'setproperty', 'sets', 'setter', 'setting', 'settings', 'settype',
+ 'setword', 'seven', 'severity', 'sexpr', 'sfd', 'sfst', 'sgml', 'sgx1',
+ 'sgx2', 'sha', 'sha256', 'sha512', 'sha_functions', 'shad', 'shade',
+ 'shaderlab', 'shadow-object', 'shape', 'shape-base', 'shape-base-data',
+ 'shared', 'shared-static', 'sharp', 'sharpequal', 'sharpge', 'sharpgt',
+ 'sharple', 'sharplt', 'sharpness', 'shebang', 'shell', 'shell-function',
+ 'shell-session', 'shift', 'shift-and-rotate', 'shift-left', 'shift-right',
+ 'shine', 'shinescript', 'shipflow', 'shmop', 'short', 'shortcut', 'shortcuts',
+ 'shorthand', 'shorthandpropertyname', 'show', 'show-argument',
+ 'shuffle-and-unpack', 'shutdown', 'shy', 'sidebar', 'sifu', 'sigdec', 'sigil',
+ 'sign-line', 'signal', 'signal-processing', 'signature', 'signed',
+ 'signed-int', 'signedness', 'signifier', 'silent', 'sim-group', 'sim-object',
+ 'sim-set', 'simd', 'simd-horizontal', 'simd-integer', 'simple',
+ 'simple-delimiter', 'simple-divider', 'simple-element', 'simple_delimiter',
+ 'simplexml', 'simplez', 'simulate', 'since', 'singe', 'single', 'single-line',
+ 'single-quote', 'single-quoted', 'single_quote', 'singlequote', 'singleton',
+ 'singleword', 'sites', 'six', 'size', 'size-cue-setting', 'sized_integer',
+ 'sizeof', 'sjs', 'sjson', 'sk', 'skaction', 'skdragon', 'skeeland',
+ 'skellett', 'sketchplugin', 'skevolved', 'skew', 'skill', 'skipped',
+ 'skmorkaz', 'skquery', 'skrambled', 'skrayfall', 'skript', 'skrpg', 'sksharp',
+ 'skstuff', 'skutilities', 'skvoice', 'sky', 'skyrim', 'sl', 'slash',
+ 'slash-bar', 'slash-option', 'slash-sign', 'slashes', 'sleet', 'slice',
+ 'slim', 'slm', 'sln', 'slot', 'slugignore', 'sma', 'smali', 'smalltalk',
+ 'smarty', 'smb', 'smbinternal', 'smilebasic', 'sml', 'smoothing-group',
+ 'smpte', 'smtlib', 'smx', 'snakeskin', 'snapshot', 'snlog', 'snmp', 'so',
+ 'soap', 'social', 'socketgroup', 'sockets', 'soft', 'solidity', 'solve',
+ 'soma', 'somearg', 'something', 'soql', 'sort', 'sorting', 'souce', 'sound',
+ 'sound_processing', 'sound_synthesys', 'source', 'source-constant', 'soy',
+ 'sp', 'space', 'space-after-command', 'spacebars', 'spaces', 'sparql',
+ 'spath', 'spec', 'special', 'special-attributes', 'special-character',
+ 'special-curve', 'special-functions', 'special-hook', 'special-keyword',
+ 'special-method', 'special-point', 'special-token-sequence', 'special-tokens',
+ 'special-type', 'specification', 'specifier', 'spectral-curve',
+ 'specular-exponent', 'specular-reflectivity', 'sphinx', 'sphinx-domain',
+ 'spice', 'spider', 'spindlespeed', 'splat', 'spline', 'splunk', 'splunk-conf',
+ 'splus', 'spn', 'spread', 'spread-line', 'spreadmap', 'sprite', 'sproto',
+ 'sproutcore', 'sqf', 'sql', 'sqlbuiltin', 'sqlite', 'sqlsrv', 'sqr', 'sqsp',
+ 'squad', 'square', 'squart', 'squirrel', 'sr-Cyrl', 'sr-Latn', 'src',
+ 'srltext', 'sros', 'srt', 'srv', 'ss', 'ssa', 'sse', 'sse2', 'sse2_simd',
+ 'sse3', 'sse4', 'sse4_simd', 'sse5', 'sse_avx', 'sse_simd', 'ssh-config',
+ 'ssi', 'ssl', 'ssn', 'sstemplate', 'st', 'stable', 'stack', 'stack-effect',
+ 'stackframe', 'stage', 'stan', 'standard', 'standard-key', 'standard-links',
+ 'standard-suite', 'standardadditions', 'standoc', 'star', 'starline', 'start',
+ 'start-block', 'start-condition', 'start-symbol', 'start-value',
+ 'starting-function-params', 'starting-functions', 'starting-functions-point',
+ 'startshape', 'stata', 'statamic', 'state', 'state-flag', 'state-management',
+ 'stateend', 'stategrouparg', 'stategroupval', 'statement',
+ 'statement-separator', 'states', 'statestart', 'statetable', 'static',
+ 'static-assert', 'static-classes', 'static-if', 'static-shape',
+ 'staticimages', 'statistics', 'stats', 'std', 'stdWrap', 'std_logic',
+ 'std_logic_1164', 'stderr-write-file', 'stdint', 'stdlib', 'stdlibcall',
+ 'stdplugin', 'stem', 'step', 'step-size', 'steps', 'stg', 'stile-shoe-left',
+ 'stile-shoe-up', 'stile-tilde', 'stitch', 'stk', 'stmt', 'stochastic', 'stop',
+ 'stopping', 'storage', 'story', 'stp', 'straight-quote', 'stray',
+ 'stray-comment-end', 'stream', 'stream-selection-and-control', 'streamsfuncs',
+ 'streem', 'strict', 'strictness', 'strike', 'strikethrough', 'string',
+ 'string-constant', 'string-format', 'string-interpolation',
+ 'string-long-quote', 'string-long-single-quote', 'string-single-quote',
+ 'stringchar', 'stringize', 'strings', 'strong', 'struc', 'struct',
+ 'struct-union-block', 'structdef', 'structend', 'structs', 'structstart',
+ 'structtable', 'structure', 'stuff', 'stupid-goddamn-hack', 'style',
+ 'styleblock', 'styles', 'stylus', 'sub', 'sub-pattern', 'subchord', 'subckt',
+ 'subcmd', 'subexp', 'subexpression', 'subkey', 'subkeys', 'subl', 'submodule',
+ 'subnet', 'subnet6', 'subpattern', 'subprogram', 'subroutine', 'subscript',
+ 'subsection', 'subsections', 'subset', 'subshell', 'subsort', 'substituted',
+ 'substitution', 'substitution-definition', 'subtitle', 'subtlegradient',
+ 'subtlegray', 'subtract', 'subtraction', 'subtype', 'suffix', 'sugarml',
+ 'sugarss', 'sugly', 'sugly-comparison-operators', 'sugly-control-keywords',
+ 'sugly-declare-function', 'sugly-delcare-operator', 'sugly-delcare-variable',
+ 'sugly-else-in-invalid-position', 'sugly-encode-clause',
+ 'sugly-function-groups', 'sugly-function-recursion',
+ 'sugly-function-variables', 'sugly-general-functions',
+ 'sugly-general-operators', 'sugly-generic-classes', 'sugly-generic-types',
+ 'sugly-global-function', 'sugly-int-constants', 'sugly-invoke-function',
+ 'sugly-json-clause', 'sugly-language-constants', 'sugly-math-clause',
+ 'sugly-math-constants', 'sugly-multiple-parameter-function',
+ 'sugly-number-constants', 'sugly-operator-operands', 'sugly-print-clause',
+ 'sugly-single-parameter-function', 'sugly-subject-or-predicate',
+ 'sugly-type-function', 'sugly-uri-clause', 'summary', 'super', 'superclass',
+ 'supercollider', 'superscript', 'superset', 'supervisor', 'supervisord',
+ 'supplemental', 'supplimental', 'support', 'suppress-image-or-category',
+ 'suppressed', 'surface', 'surface-technique', 'sv', 'svg', 'svm', 'svn',
+ 'swift', 'swig', 'switch', 'switch-block', 'switch-expression',
+ 'switch-statement', 'switchEnd', 'switchStart', 'swizzle', 'sybase',
+ 'syllableseparator', 'symbol', 'symbol-definition', 'symbol-type', 'symbolic',
+ 'symbolic-math', 'symbols', 'symmetry', 'sync-match', 'sync-mode',
+ 'sync-mode-location', 'synchronization', 'synchronize', 'synchronized',
+ 'synergy', 'synopsis', 'syntax', 'syntax-case', 'syntax-cluster',
+ 'syntax-conceal', 'syntax-error', 'syntax-include', 'syntax-item',
+ 'syntax-keywords', 'syntax-match', 'syntax-option', 'syntax-region',
+ 'syntax-rule', 'syntax-spellcheck', 'syntax-sync', 'sys-types', 'sysj',
+ 'syslink', 'syslog-ng', 'system', 'system-events', 'system-identification',
+ 'system-table-pointer', 'systemreference', 'sytem-events', 't',
+ 't3datastructure', 't4', 't5', 't7', 'ta', 'tab', 'table', 'table-name',
+ 'tablename', 'tabpanels', 'tabs', 'tabular', 'tacacs', 'tack-down', 'tack-up',
+ 'taco', 'tads3', 'tag', 'tag-string', 'tag-value', 'tagbraces', 'tagdef',
+ 'tagged', 'tagger_script', 'taglib', 'tagname', 'tagnamedjango', 'tags',
+ 'taint', 'take', 'target', 'targetobj', 'targetprop', 'task', 'tasks',
+ 'tbdfile', 'tbl', 'tbody', 'tcl', 'tcoffee', 'tcp-object', 'td', 'tdl', 'tea',
+ 'team', 'telegram', 'tell', 'telnet', 'temp', 'template', 'template-call',
+ 'template-parameter', 'templatetag', 'tempo', 'temporal', 'term',
+ 'term-comparison', 'term-creation-and-decomposition', 'term-io',
+ 'term-testing', 'term-unification', 'terminal', 'terminate', 'termination',
+ 'terminator', 'terms', 'ternary', 'ternary-if', 'terra', 'terraform',
+ 'terrain-block', 'test', 'testcase', 'testing', 'tests', 'testsuite', 'testx',
+ 'tex', 'texres', 'texshop', 'text', 'text-reference', 'text-suite', 'textbf',
+ 'textcolor', 'textile', 'textio', 'textit', 'textlabels', 'textmate',
+ 'texttt', 'textual', 'texture', 'texture-map', 'texture-option', 'tfoot',
+ 'th', 'thead', 'then', 'therefore', 'thin', 'thing1', 'third', 'this',
+ 'thorn', 'thread', 'three', 'thrift', 'throughput', 'throw', 'throwables',
+ 'throws', 'tick', 'ticket-num', 'ticket-psa', 'tid-file', 'tidal',
+ 'tidalcycles', 'tiddler', 'tiddler-field', 'tiddler-fields', 'tidy', 'tier',
+ 'tieslur', 'tikz', 'tilde', 'time', 'timeblock', 'timehrap', 'timeout',
+ 'timer', 'times', 'timesig', 'timespan', 'timespec', 'timestamp', 'timing',
+ 'titanium', 'title', 'title-page', 'title-text', 'titled-paragraph', 'tjs',
+ 'tl', 'tla', 'tlh', 'tmpl', 'tmsim', 'tmux', 'tnote', 'tnsaudit', 'to',
+ 'to-file', 'to-type', 'toc', 'toc-list', 'todo', 'todo_extra', 'todotxt',
+ 'token', 'token-def', 'token-paste', 'token-type', 'tokenised', 'tokenizer',
+ 'toml', 'too-many-tildes', 'tool', 'toolbox', 'tooltip', 'top', 'top-level',
+ 'top_level', 'topas', 'topic', 'topic-decoration', 'topic-title', 'tornado',
+ 'torque', 'torquescript', 'tosca', 'total-config', 'totaljs', 'tpye', 'tr',
+ 'trace', 'trace-argument', 'trace-object', 'traceback', 'tracing',
+ 'track_processing', 'trader', 'tradersk', 'trail', 'trailing',
+ 'trailing-array-separator', 'trailing-dictionary-separator', 'trailing-match',
+ 'trait', 'traits', 'traits-keyword', 'transaction',
+ 'transcendental', 'transcludeblock', 'transcludeinline', 'transclusion',
+ 'transform', 'transformation', 'transient', 'transition',
+ 'transitionable-property-value', 'translation', 'transmission-filter',
+ 'transparency', 'transparent-line', 'transpose', 'transposed-func',
+ 'transposed-matrix', 'transposed-parens', 'transposed-variable', 'trap',
+ 'tree', 'treetop', 'trenni', 'trigEvent_', 'trigLevelMod_', 'trigLevel_',
+ 'trigger', 'trigger-words', 'triggermodifier', 'trigonometry',
+ 'trimming-loop', 'triple', 'triple-dash', 'triple-slash', 'triple-star',
+ 'true', 'truncate', 'truncation', 'truthgreen', 'try', 'try-catch',
+ 'trycatch', 'ts', 'tsql', 'tss', 'tst', 'tsv', 'tsx', 'tt', 'ttcn3',
+ 'ttlextension', 'ttpmacro', 'tts', 'tubaina', 'tubaina2', 'tul', 'tup',
+ 'tuple', 'turbulence', 'turing', 'turquoise', 'turtle', 'tutch', 'tvml',
+ 'tw5', 'twig', 'twigil', 'twiki', 'two', 'txl', 'txt', 'txt2tags', 'type',
+ 'type-annotation', 'type-cast', 'type-cheat', 'type-checking',
+ 'type-constrained', 'type-constraint', 'type-declaration', 'type-def',
+ 'type-definition', 'type-definition-group', 'type-definitions',
+ 'type-descriptor', 'type-of', 'type-or', 'type-parameter', 'type-parameters',
+ 'type-signature', 'type-spec', 'type-specialization', 'type-specifiers',
+ 'type_2', 'type_trait', 'typeabbrev', 'typeclass', 'typed', 'typed-hole',
+ 'typedblock', 'typedcoffeescript', 'typedecl', 'typedef', 'typeexp',
+ 'typehint', 'typehinted', 'typeid', 'typename', 'types', 'typesbii',
+ 'typescriptish', 'typographic-quotes', 'typoscript', 'typoscript2', 'u',
+ 'u-degree', 'u-end', 'u-offset', 'u-resolution', 'u-scale', 'u-segments',
+ 'u-size', 'u-start', 'u-value', 'uc', 'ucicfg', 'ucicmd', 'udaf', 'udf',
+ 'udl', 'udp', 'udtf', 'ui', 'ui-block', 'ui-group', 'ui-state', 'ui-subgroup',
+ 'uintptr', 'ujm', 'uk', 'ul', 'umbaska', 'unOp', 'unary', 'unbuffered',
+ 'unchecked', 'uncleared', 'unclosed', 'unclosed-string', 'unconstrained',
+ 'undef', 'undefined', 'underbar-circle', 'underbar-diamond', 'underbar-iota',
+ 'underbar-jot', 'underbar-quote', 'underbar-semicolon', 'underline',
+ 'underline-text', 'underlined', 'underscore', 'undocumented',
+ 'unescaped-quote', 'unexpected', 'unexpected-characters',
+ 'unexpected-extends', 'unexpected-extends-character', 'unfiled',
+ 'unformatted', 'unicode', 'unicode-16-bit', 'unicode-32-bit',
+ 'unicode-escape', 'unicode-raw', 'unicode-raw-regex', 'unified', 'unify',
+ 'unimplemented', 'unimportant', 'union', 'union-declaration', 'unique-id',
+ 'unit', 'unit-checking', 'unit-test', 'unit_test', 'unittest', 'unity',
+ 'unityscript', 'universal-match', 'unix', 'unknown', 'unknown-escape',
+ 'unknown-method', 'unknown-property-name', 'unknown-rune', 'unlabeled',
+ 'unless', 'unnecessary', 'unnumbered', 'uno', 'unoconfig', 'unop', 'unoproj',
+ 'unordered', 'unordered-block', 'unosln', 'unpack', 'unpacking', 'unparsed',
+ 'unqualified', 'unquoted', 'unrecognized', 'unrecognized-character',
+ 'unrecognized-character-escape', 'unrecognized-string-escape', 'unsafe',
+ 'unsigned', 'unsigned-int', 'unsized_integer', 'unsupplied', 'until',
+ 'untitled', 'untyped', 'unused', 'uopz', 'update', 'uppercase', 'upstream',
+ 'upwards', 'ur', 'uri', 'url', 'usable', 'usage', 'use', 'use-as', 'use-map',
+ 'use-material', 'usebean', 'usecase', 'usecase-block', 'user', 'user-defined',
+ 'user-defined-property', 'user-defined-type', 'user-interaction',
+ 'userflagsref', 'userid', 'username', 'users', 'using',
+ 'using-namespace-declaration', 'using_animtree', 'util', 'utilities',
+ 'utility', 'utxt', 'uv-resolution', 'uvu', 'uvw', 'ux', 'uxc', 'uxl', 'uz',
+ 'v', 'v-degree', 'v-end', 'v-offset', 'v-resolution', 'v-scale', 'v-segments',
+ 'v-size', 'v-start', 'v-value', 'val', 'vala', 'valgrind', 'valid',
+ 'valid-ampersand', 'valid-bracket', 'valign', 'value', 'value-pair',
+ 'value-signature', 'value-size', 'value-type', 'valuepair', 'vamos', 'vamp',
+ 'vane-down', 'vane-left', 'vane-right', 'vane-up', 'var',
+ 'var-single-variable', 'var1', 'var2', 'variable', 'variable-access',
+ 'variable-assignment', 'variable-declaration', 'variable-definition',
+ 'variable-modifier', 'variable-parameter', 'variable-reference',
+ 'variable-usage', 'variables', 'variabletable', 'variant',
+ 'variant-definition', 'varname', 'varnish', 'vars', 'vb', 'vbnet', 'vbs',
+ 'vc', 'vcard', 'vcd', 'vcl', 'vcs', 'vector', 'vector-load', 'vectors',
+ 'vehicle', 'velocity', 'vendor-prefix', 'verb', 'verbatim', 'verdict',
+ 'verilog', 'version', 'version-number', 'version-specification', 'vertex',
+ 'vertex-reference', 'vertical-blending', 'vertical-span',
+ 'vertical-text-cue-setting', 'vex', 'vhdl', 'vhost', 'vi', 'via',
+ 'video-texturing', 'video_processing', 'view', 'viewhelpers', 'vimAugroupKey',
+ 'vimBehaveModel', 'vimFTCmd', 'vimFTOption', 'vimFuncKey', 'vimGroupSpecial',
+ 'vimHiAttrib', 'vimHiClear', 'vimMapModKey', 'vimPattern', 'vimSynCase',
+ 'vimSynType', 'vimSyncC', 'vimSyncLinecont', 'vimSyncMatch', 'vimSyncNone',
+ 'vimSyncRegion', 'vimUserAttrbCmplt', 'vimUserAttrbKey', 'vimUserCommand',
+ 'viml', 'virtual', 'virtual-host', 'virtual-reality', 'visibility',
+ 'visualforce', 'visualization', 'vlanhdr', 'vle', 'vmap', 'vmx', 'voice',
+ 'void', 'volatile', 'volt', 'volume', 'vpath', 'vplus', 'vrf', 'vtt', 'vue',
+ 'vue-jade', 'vue-stylus', 'w-offset', 'w-scale', 'w-value',
+ 'w3c-extended-color-name', 'w3c-non-standard-color-name',
+ 'w3c-standard-color-name', 'wait', 'waitress', 'waitress-config',
+ 'waitress-rb', 'warn', 'warning', 'warnings', 'wast', 'water', 'watson-todo',
+ 'wavefront', 'wavelet', 'wddx', 'wdiff', 'weapon', 'weave', 'weaveBracket',
+ 'weaveBullet', 'webidl', 'webspeed', 'webvtt', 'weekday', 'weirdland', 'wf',
+ 'wh', 'whatever', 'wheeled-vehicle', 'when', 'where', 'while',
+ 'while-condition', 'while-loop', 'whiskey', 'white', 'whitespace', 'widget',
+ 'width', 'wiki', 'wiki-link', 'wildcard', 'wildsk', 'win', 'window',
+ 'window-classes', 'windows', 'winered', 'with', 'with-arg', 'with-args',
+ 'with-arguments', 'with-params', 'with-prefix', 'with-side-effects',
+ 'with-suffix', 'with-terminator', 'with-value', 'with_colon', 'without-args',
+ 'without-arguments', 'wla-dx', 'word', 'word-op', 'wordnet', 'wordpress',
+ 'words', 'workitem', 'world', 'wow', 'wp', 'write', 'wrong',
+ 'wrong-access-type', 'wrong-division', 'wrong-division-assignment', 'ws',
+ 'www', 'wxml', 'wysiwyg-string', 'x10', 'x86', 'x86_64', 'x86asm', 'xacro',
+ 'xbase', 'xchg', 'xhp', 'xhprof', 'xikij', 'xml', 'xml-attr', 'xmlrpc',
+ 'xmlwriter', 'xop', 'xor', 'xparse', 'xq', 'xquery', 'xref', 'xsave',
+ 'xsd-all', 'xsd_nillable', 'xsd_optional', 'xsl', 'xslt', 'xsse3_simd', 'xst',
+ 'xtend', 'xtoy', 'xtpl', 'xu', 'xvc', 'xve', 'xyzw', 'y', 'y1', 'y2', 'yabb',
+ 'yaml', 'yaml-ext', 'yang', 'yara', 'yate', 'yaws', 'year', 'yellow', 'yield',
+ 'ykk', 'yorick', 'you-forgot-semicolon', 'z', 'z80', 'zap', 'zapper', 'zep',
+ 'zepon', 'zepto', 'zero', 'zero-width-marker', 'zero-width-print', 'zeroop',
+ 'zh-CN', 'zh-TW', 'zig', 'zilde', 'zlib', 'zoomfilter', 'zzz'
+])
diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee
index a6e85b7e5b3..e5c1db60ee8 100644
--- a/src/highlights-component.coffee
+++ b/src/highlights-component.coffee
@@ -97,24 +97,23 @@ class HighlightsComponent
flashHighlightNodeIfRequested: (id, newHighlightState) ->
oldHighlightState = @oldState[id]
- return unless newHighlightState.flashCount > oldHighlightState.flashCount
-
- highlightNode = @highlightNodesById[id]
-
- addFlashClass = =>
- highlightNode.classList.add(newHighlightState.flashClass)
- oldHighlightState.flashClass = newHighlightState.flashClass
- @flashTimeoutId = setTimeout(removeFlashClass, newHighlightState.flashDuration)
-
- removeFlashClass = =>
- highlightNode.classList.remove(oldHighlightState.flashClass)
- oldHighlightState.flashClass = null
- clearTimeout(@flashTimeoutId)
-
- if oldHighlightState.flashClass?
- removeFlashClass()
- requestAnimationFrame(addFlashClass)
- else
- addFlashClass()
+ if newHighlightState.needsFlash and oldHighlightState.flashCount isnt newHighlightState.flashCount
+ highlightNode = @highlightNodesById[id]
+
+ addFlashClass = =>
+ highlightNode.classList.add(newHighlightState.flashClass)
+ oldHighlightState.flashClass = newHighlightState.flashClass
+ @flashTimeoutId = setTimeout(removeFlashClass, newHighlightState.flashDuration)
+
+ removeFlashClass = =>
+ highlightNode.classList.remove(oldHighlightState.flashClass)
+ oldHighlightState.flashClass = null
+ clearTimeout(@flashTimeoutId)
+
+ if oldHighlightState.flashClass?
+ removeFlashClass()
+ requestAnimationFrame(addFlashClass)
+ else
+ addFlashClass()
- oldHighlightState.flashCount = newHighlightState.flashCount
+ oldHighlightState.flashCount = newHighlightState.flashCount
diff --git a/src/lines-component.coffee b/src/lines-component.coffee
index fb9b28b0398..6c92711794b 100644
--- a/src/lines-component.coffee
+++ b/src/lines-component.coffee
@@ -19,7 +19,7 @@ module.exports =
class LinesComponent extends TiledComponent
placeholderTextDiv: null
- constructor: ({@presenter, @domElementPool, @assert}) ->
+ constructor: ({@views, @presenter, @domElementPool, @assert}) ->
@domNode = document.createElement('div')
@domNode.classList.add('lines')
@tilesNode = document.createElement("div")
@@ -32,10 +32,6 @@ class LinesComponent extends TiledComponent
@cursorsComponent = new CursorsComponent
@domNode.appendChild(@cursorsComponent.getDomNode())
- insertionPoint = document.createElement('content')
- insertionPoint.setAttribute('select', '.overlayer')
- @domNode.appendChild(insertionPoint)
-
getDomNode: ->
@domNode
@@ -61,9 +57,17 @@ class LinesComponent extends TiledComponent
@domNode.appendChild(@placeholderTextDiv)
@oldState.placeholderText = @newState.placeholderText
+ # Removing and updating block decorations needs to be done in two different
+ # steps, so that the same decoration node can be moved from one tile to
+ # another in the same animation frame.
+ for component in @getComponents()
+ component.removeDeletedBlockDecorations()
+ for component in @getComponents()
+ component.updateBlockDecorations()
+
@cursorsComponent.updateSync(state)
- buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter, @domElementPool, @assert})
+ buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter, @domElementPool, @assert, @views})
buildEmptyState: ->
{tiles: {}}
@@ -87,6 +91,11 @@ class LinesComponent extends TiledComponent
@presenter.setLineHeight(lineHeightInPixels)
@presenter.setBaseCharacterWidth(defaultCharWidth, doubleWidthCharWidth, halfWidthCharWidth, koreanCharWidth)
+ measureBlockDecorations: ->
+ for component in @getComponents()
+ component.measureBlockDecorations()
+ return
+
lineIdForScreenRow: (screenRow) ->
tile = @presenter.tileForRow(screenRow)
@getComponentForTile(tile)?.lineIdForScreenRow(screenRow)
diff --git a/src/lines-tile-component.coffee b/src/lines-tile-component.coffee
deleted file mode 100644
index c1cb2ba64bf..00000000000
--- a/src/lines-tile-component.coffee
+++ /dev/null
@@ -1,288 +0,0 @@
-HighlightsComponent = require './highlights-component'
-ZERO_WIDTH_NBSP = '\ufeff'
-
-cloneObject = (object) ->
- clone = {}
- clone[key] = value for key, value of object
- clone
-
-module.exports =
-class LinesTileComponent
- constructor: ({@presenter, @id, @domElementPool, @assert}) ->
- @measuredLines = new Set
- @lineNodesByLineId = {}
- @screenRowsByLineId = {}
- @lineIdsByScreenRow = {}
- @textNodesByLineId = {}
- @insertionPointsBeforeLineById = {}
- @insertionPointsAfterLineById = {}
- @domNode = @domElementPool.buildElement("div")
- @domNode.style.position = "absolute"
- @domNode.style.display = "block"
-
- @highlightsComponent = new HighlightsComponent(@domElementPool)
- @domNode.appendChild(@highlightsComponent.getDomNode())
-
- destroy: ->
- @domElementPool.freeElementAndDescendants(@domNode)
-
- getDomNode: ->
- @domNode
-
- updateSync: (state) ->
- @newState = state
- unless @oldState
- @oldState = {tiles: {}}
- @oldState.tiles[@id] = {lines: {}}
-
- @newTileState = @newState.tiles[@id]
- @oldTileState = @oldState.tiles[@id]
-
- if @newState.backgroundColor isnt @oldState.backgroundColor
- @domNode.style.backgroundColor = @newState.backgroundColor
- @oldState.backgroundColor = @newState.backgroundColor
-
- if @newTileState.zIndex isnt @oldTileState.zIndex
- @domNode.style.zIndex = @newTileState.zIndex
- @oldTileState.zIndex = @newTileState.zIndex
-
- if @newTileState.display isnt @oldTileState.display
- @domNode.style.display = @newTileState.display
- @oldTileState.display = @newTileState.display
-
- if @newTileState.height isnt @oldTileState.height
- @domNode.style.height = @newTileState.height + 'px'
- @oldTileState.height = @newTileState.height
-
- if @newState.width isnt @oldState.width
- @domNode.style.width = @newState.width + 'px'
- @oldTileState.width = @newTileState.width
-
- if @newTileState.top isnt @oldTileState.top or @newTileState.left isnt @oldTileState.left
- @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)"
- @oldTileState.top = @newTileState.top
- @oldTileState.left = @newTileState.left
-
- @updateLineNodes()
-
- @highlightsComponent.updateSync(@newTileState)
-
- removeLineNodes: ->
- @removeLineNode(id) for id of @oldTileState.lines
- return
-
- removeLineNode: (id) ->
- @domElementPool.freeElementAndDescendants(@lineNodesByLineId[id])
- @removeBlockDecorationInsertionPointBeforeLine(id)
- @removeBlockDecorationInsertionPointAfterLine(id)
-
- delete @lineNodesByLineId[id]
- delete @textNodesByLineId[id]
- delete @lineIdsByScreenRow[@screenRowsByLineId[id]]
- delete @screenRowsByLineId[id]
- delete @oldTileState.lines[id]
-
- updateLineNodes: ->
- for id of @oldTileState.lines
- unless @newTileState.lines.hasOwnProperty(id)
- @removeLineNode(id)
-
- newLineIds = null
- newLineNodes = null
-
- for id, lineState of @newTileState.lines
- if @oldTileState.lines.hasOwnProperty(id)
- @updateLineNode(id)
- else
- newLineIds ?= []
- newLineNodes ?= []
- newLineIds.push(id)
- newLineNodes.push(@buildLineNode(id))
- @screenRowsByLineId[id] = lineState.screenRow
- @lineIdsByScreenRow[lineState.screenRow] = id
- @oldTileState.lines[id] = cloneObject(lineState)
-
- return unless newLineIds?
-
- for id, i in newLineIds
- lineNode = newLineNodes[i]
- @lineNodesByLineId[id] = lineNode
- if nextNode = @findNodeNextTo(lineNode)
- @domNode.insertBefore(lineNode, nextNode)
- else
- @domNode.appendChild(lineNode)
-
- @insertBlockDecorationInsertionPointBeforeLine(id)
- @insertBlockDecorationInsertionPointAfterLine(id)
-
- removeBlockDecorationInsertionPointBeforeLine: (id) ->
- if insertionPoint = @insertionPointsBeforeLineById[id]
- @domElementPool.freeElementAndDescendants(insertionPoint)
- delete @insertionPointsBeforeLineById[id]
-
- insertBlockDecorationInsertionPointBeforeLine: (id) ->
- {hasPrecedingBlockDecorations, screenRow} = @newTileState.lines[id]
-
- if hasPrecedingBlockDecorations
- lineNode = @lineNodesByLineId[id]
- insertionPoint = @domElementPool.buildElement("content")
- @domNode.insertBefore(insertionPoint, lineNode)
- @insertionPointsBeforeLineById[id] = insertionPoint
- insertionPoint.dataset.screenRow = screenRow
- @updateBlockDecorationInsertionPointBeforeLine(id)
-
- updateBlockDecorationInsertionPointBeforeLine: (id) ->
- oldLineState = @oldTileState.lines[id]
- newLineState = @newTileState.lines[id]
- insertionPoint = @insertionPointsBeforeLineById[id]
- return unless insertionPoint?
-
- if newLineState.screenRow isnt oldLineState.screenRow
- insertionPoint.dataset.screenRow = newLineState.screenRow
-
- precedingBlockDecorationsSelector = newLineState.precedingBlockDecorations.map((d) -> ".atom--block-decoration-#{d.id}").join(',')
-
- if precedingBlockDecorationsSelector isnt oldLineState.precedingBlockDecorationsSelector
- insertionPoint.setAttribute("select", precedingBlockDecorationsSelector)
- oldLineState.precedingBlockDecorationsSelector = precedingBlockDecorationsSelector
-
- removeBlockDecorationInsertionPointAfterLine: (id) ->
- if insertionPoint = @insertionPointsAfterLineById[id]
- @domElementPool.freeElementAndDescendants(insertionPoint)
- delete @insertionPointsAfterLineById[id]
-
- insertBlockDecorationInsertionPointAfterLine: (id) ->
- {hasFollowingBlockDecorations, screenRow} = @newTileState.lines[id]
-
- if hasFollowingBlockDecorations
- lineNode = @lineNodesByLineId[id]
- insertionPoint = @domElementPool.buildElement("content")
- @domNode.insertBefore(insertionPoint, lineNode.nextSibling)
- @insertionPointsAfterLineById[id] = insertionPoint
- insertionPoint.dataset.screenRow = screenRow
- @updateBlockDecorationInsertionPointAfterLine(id)
-
- updateBlockDecorationInsertionPointAfterLine: (id) ->
- oldLineState = @oldTileState.lines[id]
- newLineState = @newTileState.lines[id]
- insertionPoint = @insertionPointsAfterLineById[id]
- return unless insertionPoint?
-
- if newLineState.screenRow isnt oldLineState.screenRow
- insertionPoint.dataset.screenRow = newLineState.screenRow
-
- followingBlockDecorationsSelector = newLineState.followingBlockDecorations.map((d) -> ".atom--block-decoration-#{d.id}").join(',')
-
- if followingBlockDecorationsSelector isnt oldLineState.followingBlockDecorationsSelector
- insertionPoint.setAttribute("select", followingBlockDecorationsSelector)
- oldLineState.followingBlockDecorationsSelector = followingBlockDecorationsSelector
-
- findNodeNextTo: (node) ->
- for nextNode, index in @domNode.children
- continue if index is 0 # skips highlights node
- return nextNode if @screenRowForNode(node) < @screenRowForNode(nextNode)
- return
-
- screenRowForNode: (node) -> parseInt(node.dataset.screenRow)
-
- buildLineNode: (id) ->
- {lineText, tagCodes, screenRow, decorationClasses} = @newTileState.lines[id]
-
- lineNode = @domElementPool.buildElement("div", "line")
- lineNode.dataset.screenRow = screenRow
-
- if decorationClasses?
- for decorationClass in decorationClasses
- lineNode.classList.add(decorationClass)
-
- textNodes = []
- startIndex = 0
- openScopeNode = lineNode
- for tagCode in tagCodes when tagCode isnt 0
- if @presenter.isCloseTagCode(tagCode)
- openScopeNode = openScopeNode.parentElement
- else if @presenter.isOpenTagCode(tagCode)
- scope = @presenter.tagForCode(tagCode)
- newScopeNode = @domElementPool.buildElement("span", scope.replace(/\.+/g, ' '))
- openScopeNode.appendChild(newScopeNode)
- openScopeNode = newScopeNode
- else
- textNode = @domElementPool.buildText(lineText.substr(startIndex, tagCode))
- startIndex += tagCode
- openScopeNode.appendChild(textNode)
- textNodes.push(textNode)
-
- if startIndex is 0
- textNode = @domElementPool.buildText(' ')
- lineNode.appendChild(textNode)
- textNodes.push(textNode)
-
- if lineText.endsWith(@presenter.displayLayer.foldCharacter)
- # Insert a zero-width non-breaking whitespace, so that
- # LinesYardstick can take the fold-marker::after pseudo-element
- # into account during measurements when such marker is the last
- # character on the line.
- textNode = @domElementPool.buildText(ZERO_WIDTH_NBSP)
- lineNode.appendChild(textNode)
- textNodes.push(textNode)
-
- @textNodesByLineId[id] = textNodes
- lineNode
-
- updateLineNode: (id) ->
- oldLineState = @oldTileState.lines[id]
- newLineState = @newTileState.lines[id]
-
- lineNode = @lineNodesByLineId[id]
-
- newDecorationClasses = newLineState.decorationClasses
- oldDecorationClasses = oldLineState.decorationClasses
-
- if oldDecorationClasses?
- for decorationClass in oldDecorationClasses
- unless newDecorationClasses? and decorationClass in newDecorationClasses
- lineNode.classList.remove(decorationClass)
-
- if newDecorationClasses?
- for decorationClass in newDecorationClasses
- unless oldDecorationClasses? and decorationClass in oldDecorationClasses
- lineNode.classList.add(decorationClass)
-
- oldLineState.decorationClasses = newLineState.decorationClasses
-
- if not oldLineState.hasPrecedingBlockDecorations and newLineState.hasPrecedingBlockDecorations
- @insertBlockDecorationInsertionPointBeforeLine(id)
- else if oldLineState.hasPrecedingBlockDecorations and not newLineState.hasPrecedingBlockDecorations
- @removeBlockDecorationInsertionPointBeforeLine(id)
-
- if not oldLineState.hasFollowingBlockDecorations and newLineState.hasFollowingBlockDecorations
- @insertBlockDecorationInsertionPointAfterLine(id)
- else if oldLineState.hasFollowingBlockDecorations and not newLineState.hasFollowingBlockDecorations
- @removeBlockDecorationInsertionPointAfterLine(id)
-
- if newLineState.screenRow isnt oldLineState.screenRow
- lineNode.dataset.screenRow = newLineState.screenRow
- @lineIdsByScreenRow[newLineState.screenRow] = id
- @screenRowsByLineId[id] = newLineState.screenRow
-
- @updateBlockDecorationInsertionPointBeforeLine(id)
- @updateBlockDecorationInsertionPointAfterLine(id)
-
- oldLineState.screenRow = newLineState.screenRow
- oldLineState.hasPrecedingBlockDecorations = newLineState.hasPrecedingBlockDecorations
- oldLineState.hasFollowingBlockDecorations = newLineState.hasFollowingBlockDecorations
-
- lineNodeForScreenRow: (screenRow) ->
- @lineNodesByLineId[@lineIdsByScreenRow[screenRow]]
-
- lineNodeForLineId: (lineId) ->
- @lineNodesByLineId[lineId]
-
- textNodesForLineId: (lineId) ->
- @textNodesByLineId[lineId].slice()
-
- lineIdForScreenRow: (screenRow) ->
- @lineIdsByScreenRow[screenRow]
-
- textNodesForScreenRow: (screenRow) ->
- @textNodesByLineId[@lineIdsByScreenRow[screenRow]]?.slice()
diff --git a/src/lines-tile-component.js b/src/lines-tile-component.js
new file mode 100644
index 00000000000..202e1670870
--- /dev/null
+++ b/src/lines-tile-component.js
@@ -0,0 +1,401 @@
+const HighlightsComponent = require('./highlights-component')
+const ZERO_WIDTH_NBSP = '\ufeff'
+
+module.exports = class LinesTileComponent {
+ constructor ({presenter, id, domElementPool, assert, views}) {
+ this.id = id
+ this.presenter = presenter
+ this.views = views
+ this.domElementPool = domElementPool
+ this.assert = assert
+ this.lineNodesByLineId = {}
+ this.screenRowsByLineId = {}
+ this.lineIdsByScreenRow = {}
+ this.textNodesByLineId = {}
+ this.blockDecorationNodesByLineIdAndDecorationId = {}
+ this.domNode = this.domElementPool.buildElement('div')
+ this.domNode.style.position = 'absolute'
+ this.domNode.style.display = 'block'
+ this.highlightsComponent = new HighlightsComponent(this.domElementPool)
+ this.domNode.appendChild(this.highlightsComponent.getDomNode())
+ }
+
+ destroy () {
+ this.removeLineNodes()
+ this.domElementPool.freeElementAndDescendants(this.domNode)
+ }
+
+ getDomNode () {
+ return this.domNode
+ }
+
+ updateSync (state) {
+ this.newState = state
+ if (this.oldState == null) {
+ this.oldState = {tiles: {}}
+ this.oldState.tiles[this.id] = {lines: {}}
+ }
+
+ this.newTileState = this.newState.tiles[this.id]
+ this.oldTileState = this.oldState.tiles[this.id]
+
+ if (this.newState.backgroundColor !== this.oldState.backgroundColor) {
+ this.domNode.style.backgroundColor = this.newState.backgroundColor
+ this.oldState.backgroundColor = this.newState.backgroundColor
+ }
+
+ if (this.newTileState.zIndex !== this.oldTileState.zIndex) {
+ this.domNode.style.zIndex = this.newTileState.zIndex
+ this.oldTileState.zIndex = this.newTileState.zIndex
+ }
+
+ if (this.newTileState.display !== this.oldTileState.display) {
+ this.domNode.style.display = this.newTileState.display
+ this.oldTileState.display = this.newTileState.display
+ }
+
+ if (this.newTileState.height !== this.oldTileState.height) {
+ this.domNode.style.height = this.newTileState.height + 'px'
+ this.oldTileState.height = this.newTileState.height
+ }
+
+ if (this.newState.width !== this.oldState.width) {
+ this.domNode.style.width = this.newState.width + 'px'
+ this.oldState.width = this.newState.width
+ }
+
+ if (this.newTileState.top !== this.oldTileState.top || this.newTileState.left !== this.oldTileState.left) {
+ this.domNode.style.transform = `translate3d(${this.newTileState.left}px, ${this.newTileState.top}px, 0px)`
+ this.oldTileState.top = this.newTileState.top
+ this.oldTileState.left = this.newTileState.left
+ }
+
+ this.updateLineNodes()
+ this.highlightsComponent.updateSync(this.newTileState)
+ }
+
+ removeLineNodes () {
+ for (const id of Object.keys(this.oldTileState.lines)) {
+ this.removeLineNode(id)
+ }
+ }
+
+ removeLineNode (lineId) {
+ this.domElementPool.freeElementAndDescendants(this.lineNodesByLineId[lineId])
+ for (const decorationId of Object.keys(this.oldTileState.lines[lineId].precedingBlockDecorations)) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ topRulerNode.remove()
+ blockDecorationNode.remove()
+ bottomRulerNode.remove()
+ }
+ for (const decorationId of Object.keys(this.oldTileState.lines[lineId].followingBlockDecorations)) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ topRulerNode.remove()
+ blockDecorationNode.remove()
+ bottomRulerNode.remove()
+ }
+
+ delete this.blockDecorationNodesByLineIdAndDecorationId[lineId]
+ delete this.lineNodesByLineId[lineId]
+ delete this.textNodesByLineId[lineId]
+ delete this.lineIdsByScreenRow[this.screenRowsByLineId[lineId]]
+ delete this.screenRowsByLineId[lineId]
+ delete this.oldTileState.lines[lineId]
+ }
+
+ updateLineNodes () {
+ for (const id of Object.keys(this.oldTileState.lines)) {
+ if (!this.newTileState.lines.hasOwnProperty(id)) {
+ this.removeLineNode(id)
+ }
+ }
+
+ const newLineIds = []
+ const newLineNodes = []
+ for (const id of Object.keys(this.newTileState.lines)) {
+ const lineState = this.newTileState.lines[id]
+ if (this.oldTileState.lines.hasOwnProperty(id)) {
+ this.updateLineNode(id)
+ } else {
+ newLineIds.push(id)
+ newLineNodes.push(this.buildLineNode(id))
+ this.screenRowsByLineId[id] = lineState.screenRow
+ this.lineIdsByScreenRow[lineState.screenRow] = id
+ this.oldTileState.lines[id] = Object.assign({}, lineState)
+ // Avoid assigning state for block decorations, because we need to
+ // process it later when updating the DOM.
+ this.oldTileState.lines[id].precedingBlockDecorations = {}
+ this.oldTileState.lines[id].followingBlockDecorations = {}
+ }
+ }
+
+ while (newLineIds.length > 0) {
+ const id = newLineIds.shift()
+ const lineNode = newLineNodes.shift()
+ this.lineNodesByLineId[id] = lineNode
+ const nextNode = this.findNodeNextTo(lineNode)
+ if (nextNode == null) {
+ this.domNode.appendChild(lineNode)
+ } else {
+ this.domNode.insertBefore(lineNode, nextNode)
+ }
+ }
+ }
+
+ findNodeNextTo (node) {
+ let i = 1 // skip highlights node
+ while (i < this.domNode.children.length) {
+ const nextNode = this.domNode.children[i]
+ if (this.screenRowForNode(node) < this.screenRowForNode(nextNode)) {
+ return nextNode
+ }
+ i++
+ }
+ return null
+ }
+
+ screenRowForNode (node) {
+ return parseInt(node.dataset.screenRow)
+ }
+
+ buildLineNode (id) {
+ const {lineText, tagCodes, screenRow, decorationClasses} = this.newTileState.lines[id]
+
+ const lineNode = this.domElementPool.buildElement('div', 'line')
+ lineNode.dataset.screenRow = screenRow
+ if (decorationClasses != null) {
+ for (const decorationClass of decorationClasses) {
+ lineNode.classList.add(decorationClass)
+ }
+ }
+
+ const textNodes = []
+ let startIndex = 0
+ let openScopeNode = lineNode
+ for (const tagCode of tagCodes) {
+ if (tagCode !== 0) {
+ if (this.presenter.isCloseTagCode(tagCode)) {
+ openScopeNode = openScopeNode.parentElement
+ } else if (this.presenter.isOpenTagCode(tagCode)) {
+ const scope = this.presenter.tagForCode(tagCode)
+ const newScopeNode = this.domElementPool.buildElement('span', scope.replace(/\.+/g, ' '))
+ openScopeNode.appendChild(newScopeNode)
+ openScopeNode = newScopeNode
+ } else {
+ const textNode = this.domElementPool.buildText(lineText.substr(startIndex, tagCode))
+ startIndex += tagCode
+ openScopeNode.appendChild(textNode)
+ textNodes.push(textNode)
+ }
+ }
+ }
+
+ if (startIndex === 0) {
+ const textNode = this.domElementPool.buildText(' ')
+ lineNode.appendChild(textNode)
+ textNodes.push(textNode)
+ }
+
+ if (lineText.endsWith(this.presenter.displayLayer.foldCharacter)) {
+ // Insert a zero-width non-breaking whitespace, so that LinesYardstick can
+ // take the fold-marker::after pseudo-element into account during
+ // measurements when such marker is the last character on the line.
+ const textNode = this.domElementPool.buildText(ZERO_WIDTH_NBSP)
+ lineNode.appendChild(textNode)
+ textNodes.push(textNode)
+ }
+
+ this.textNodesByLineId[id] = textNodes
+ return lineNode
+ }
+
+ updateLineNode (id) {
+ const oldLineState = this.oldTileState.lines[id]
+ const newLineState = this.newTileState.lines[id]
+ const lineNode = this.lineNodesByLineId[id]
+ const newDecorationClasses = newLineState.decorationClasses
+ const oldDecorationClasses = oldLineState.decorationClasses
+
+ if (oldDecorationClasses != null) {
+ for (const decorationClass of oldDecorationClasses) {
+ if (newDecorationClasses == null || !newDecorationClasses.includes(decorationClass)) {
+ lineNode.classList.remove(decorationClass)
+ }
+ }
+ }
+
+ if (newDecorationClasses != null) {
+ for (const decorationClass of newDecorationClasses) {
+ if (oldDecorationClasses == null || !oldDecorationClasses.includes(decorationClass)) {
+ lineNode.classList.add(decorationClass)
+ }
+ }
+ }
+
+ oldLineState.decorationClasses = newLineState.decorationClasses
+
+ if (newLineState.screenRow !== oldLineState.screenRow) {
+ lineNode.dataset.screenRow = newLineState.screenRow
+ this.lineIdsByScreenRow[newLineState.screenRow] = id
+ this.screenRowsByLineId[id] = newLineState.screenRow
+ }
+
+ oldLineState.screenRow = newLineState.screenRow
+ }
+
+ removeDeletedBlockDecorations () {
+ for (const lineId of Object.keys(this.newTileState.lines)) {
+ const oldLineState = this.oldTileState.lines[lineId]
+ const newLineState = this.newTileState.lines[lineId]
+ for (const decorationId of Object.keys(oldLineState.precedingBlockDecorations)) {
+ if (!newLineState.precedingBlockDecorations.hasOwnProperty(decorationId)) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ topRulerNode.remove()
+ blockDecorationNode.remove()
+ bottomRulerNode.remove()
+ delete this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ delete oldLineState.precedingBlockDecorations[decorationId]
+ }
+ }
+ for (const decorationId of Object.keys(oldLineState.followingBlockDecorations)) {
+ if (!newLineState.followingBlockDecorations.hasOwnProperty(decorationId)) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ topRulerNode.remove()
+ blockDecorationNode.remove()
+ bottomRulerNode.remove()
+ delete this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ delete oldLineState.followingBlockDecorations[decorationId]
+ }
+ }
+ }
+ }
+
+ updateBlockDecorations () {
+ for (const lineId of Object.keys(this.newTileState.lines)) {
+ const oldLineState = this.oldTileState.lines[lineId]
+ const newLineState = this.newTileState.lines[lineId]
+ const lineNode = this.lineNodesByLineId[lineId]
+ if (!this.blockDecorationNodesByLineIdAndDecorationId.hasOwnProperty(lineId)) {
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId] = {}
+ }
+ for (const decorationId of Object.keys(newLineState.precedingBlockDecorations)) {
+ const oldBlockDecorationState = oldLineState.precedingBlockDecorations[decorationId]
+ const newBlockDecorationState = newLineState.precedingBlockDecorations[decorationId]
+ if (oldBlockDecorationState != null) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ if (oldBlockDecorationState.screenRow !== newBlockDecorationState.screenRow) {
+ topRulerNode.remove()
+ blockDecorationNode.remove()
+ bottomRulerNode.remove()
+ topRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(topRulerNode, lineNode)
+ blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(blockDecorationNode, lineNode)
+ bottomRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(bottomRulerNode, lineNode)
+ }
+ } else {
+ const topRulerNode = document.createElement('div')
+ topRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(topRulerNode, lineNode)
+ const blockDecorationNode = this.views.getView(newBlockDecorationState.decoration.getProperties().item)
+ blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(blockDecorationNode, lineNode)
+ const bottomRulerNode = document.createElement('div')
+ bottomRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(bottomRulerNode, lineNode)
+
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId] =
+ {topRulerNode, blockDecorationNode, bottomRulerNode}
+ }
+ oldLineState.precedingBlockDecorations[decorationId] = Object.assign({}, newBlockDecorationState)
+ }
+ for (const decorationId of Object.keys(newLineState.followingBlockDecorations)) {
+ const oldBlockDecorationState = oldLineState.followingBlockDecorations[decorationId]
+ const newBlockDecorationState = newLineState.followingBlockDecorations[decorationId]
+ if (oldBlockDecorationState != null) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ if (oldBlockDecorationState.screenRow !== newBlockDecorationState.screenRow) {
+ topRulerNode.remove()
+ blockDecorationNode.remove()
+ bottomRulerNode.remove()
+ bottomRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(bottomRulerNode, lineNode.nextSibling)
+ blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(blockDecorationNode, lineNode.nextSibling)
+ topRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(topRulerNode, lineNode.nextSibling)
+ }
+ } else {
+ const bottomRulerNode = document.createElement('div')
+ bottomRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(bottomRulerNode, lineNode.nextSibling)
+ const blockDecorationNode = this.views.getView(newBlockDecorationState.decoration.getProperties().item)
+ blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(blockDecorationNode, lineNode.nextSibling)
+ const topRulerNode = document.createElement('div')
+ topRulerNode.dataset.screenRow = newBlockDecorationState.screenRow
+ this.domNode.insertBefore(topRulerNode, lineNode.nextSibling)
+
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId] =
+ {topRulerNode, blockDecorationNode, bottomRulerNode}
+ }
+ oldLineState.followingBlockDecorations[decorationId] = Object.assign({}, newBlockDecorationState)
+ }
+ }
+ }
+
+ measureBlockDecorations () {
+ for (const lineId of Object.keys(this.newTileState.lines)) {
+ const newLineState = this.newTileState.lines[lineId]
+
+ for (const decorationId of Object.keys(newLineState.precedingBlockDecorations)) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ const width = blockDecorationNode.offsetWidth
+ const height = bottomRulerNode.offsetTop - topRulerNode.offsetTop
+ const {decoration} = newLineState.precedingBlockDecorations[decorationId]
+ this.presenter.setBlockDecorationDimensions(decoration, width, height)
+ }
+ for (const decorationId of Object.keys(newLineState.followingBlockDecorations)) {
+ const {topRulerNode, blockDecorationNode, bottomRulerNode} =
+ this.blockDecorationNodesByLineIdAndDecorationId[lineId][decorationId]
+ const width = blockDecorationNode.offsetWidth
+ const height = bottomRulerNode.offsetTop - topRulerNode.offsetTop
+ const {decoration} = newLineState.followingBlockDecorations[decorationId]
+ this.presenter.setBlockDecorationDimensions(decoration, width, height)
+ }
+ }
+ }
+
+ lineNodeForScreenRow (screenRow) {
+ return this.lineNodesByLineId[this.lineIdsByScreenRow[screenRow]]
+ }
+
+ lineNodeForLineId (lineId) {
+ return this.lineNodesByLineId[lineId]
+ }
+
+ textNodesForLineId (lineId) {
+ return this.textNodesByLineId[lineId].slice()
+ }
+
+ lineIdForScreenRow (screenRow) {
+ return this.lineIdsByScreenRow[screenRow]
+ }
+
+ textNodesForScreenRow (screenRow) {
+ const textNodes = this.textNodesByLineId[this.lineIdsByScreenRow[screenRow]]
+ if (textNodes == null) {
+ return null
+ } else {
+ return textNodes.slice()
+ }
+ }
+}
diff --git a/src/off-screen-block-decorations-component.js b/src/off-screen-block-decorations-component.js
new file mode 100644
index 00000000000..0460c854e04
--- /dev/null
+++ b/src/off-screen-block-decorations-component.js
@@ -0,0 +1,62 @@
+module.exports = class OffScreenBlockDecorationsComponent {
+ constructor ({presenter, views}) {
+ this.presenter = presenter
+ this.views = views
+ this.newState = {offScreenBlockDecorations: {}, width: 0}
+ this.oldState = {offScreenBlockDecorations: {}, width: 0}
+ this.domNode = document.createElement('div')
+ this.domNode.style.visibility = 'hidden'
+ this.domNode.style.position = 'absolute'
+ this.blockDecorationNodesById = {}
+ }
+
+ getDomNode () {
+ return this.domNode
+ }
+
+ updateSync (state) {
+ this.newState = state.content
+
+ if (this.newState.width !== this.oldState.width) {
+ this.domNode.style.width = `${this.newState.width}px`
+ this.oldState.width = this.newState.width
+ }
+
+ for (const id of Object.keys(this.oldState.offScreenBlockDecorations)) {
+ if (!this.newState.offScreenBlockDecorations.hasOwnProperty(id)) {
+ const {topRuler, blockDecoration, bottomRuler} = this.blockDecorationNodesById[id]
+ topRuler.remove()
+ blockDecoration.remove()
+ bottomRuler.remove()
+ delete this.blockDecorationNodesById[id]
+ delete this.oldState.offScreenBlockDecorations[id]
+ }
+ }
+
+ for (const id of Object.keys(this.newState.offScreenBlockDecorations)) {
+ const decoration = this.newState.offScreenBlockDecorations[id]
+ if (!this.oldState.offScreenBlockDecorations.hasOwnProperty(id)) {
+ const topRuler = document.createElement('div')
+ this.domNode.appendChild(topRuler)
+ const blockDecoration = this.views.getView(decoration.getProperties().item)
+ this.domNode.appendChild(blockDecoration)
+ const bottomRuler = document.createElement('div')
+ this.domNode.appendChild(bottomRuler)
+
+ this.blockDecorationNodesById[id] = {topRuler, blockDecoration, bottomRuler}
+ }
+
+ this.oldState.offScreenBlockDecorations[id] = decoration
+ }
+ }
+
+ measureBlockDecorations () {
+ for (const id of Object.keys(this.blockDecorationNodesById)) {
+ const {topRuler, blockDecoration, bottomRuler} = this.blockDecorationNodesById[id]
+ const width = blockDecoration.offsetWidth
+ const height = bottomRuler.offsetTop - topRuler.offsetTop
+ const decoration = this.newState.offScreenBlockDecorations[id]
+ this.presenter.setBlockDecorationDimensions(decoration, width, height)
+ }
+ }
+}
diff --git a/src/style-manager.coffee b/src/style-manager.coffee
deleted file mode 100644
index 8f932d22995..00000000000
--- a/src/style-manager.coffee
+++ /dev/null
@@ -1,177 +0,0 @@
-fs = require 'fs-plus'
-path = require 'path'
-{Emitter, Disposable} = require 'event-kit'
-StylesElement = require './styles-element'
-
-# Extended: A singleton instance of this class available via `atom.styles`,
-# which you can use to globally query and observe the set of active style
-# sheets. The `StyleManager` doesn't add any style elements to the DOM on its
-# own, but is instead subscribed to by individual `` elements,
-# which clone and attach style elements in different contexts.
-module.exports =
-class StyleManager
- constructor: ({@configDirPath}) ->
- @emitter = new Emitter
- @styleElements = []
- @styleElementsBySourcePath = {}
-
- ###
- Section: Event Subscription
- ###
-
- # Extended: Invoke `callback` for all current and future style elements.
- #
- # * `callback` {Function} that is called with style elements.
- # * `styleElement` An `HTMLStyleElement` instance. The `.sheet` property
- # will be null because this element isn't attached to the DOM. If you want
- # to attach this element to the DOM, be sure to clone it first by calling
- # `.cloneNode(true)` on it. The style element will also have the following
- # non-standard properties:
- # * `sourcePath` A {String} containing the path from which the style
- # element was loaded.
- # * `context` A {String} indicating the target context of the style
- # element.
- #
- # Returns a {Disposable} on which `.dispose()` can be called to cancel the
- # subscription.
- observeStyleElements: (callback) ->
- callback(styleElement) for styleElement in @getStyleElements()
- @onDidAddStyleElement(callback)
-
- # Extended: Invoke `callback` when a style element is added.
- #
- # * `callback` {Function} that is called with style elements.
- # * `styleElement` An `HTMLStyleElement` instance. The `.sheet` property
- # will be null because this element isn't attached to the DOM. If you want
- # to attach this element to the DOM, be sure to clone it first by calling
- # `.cloneNode(true)` on it. The style element will also have the following
- # non-standard properties:
- # * `sourcePath` A {String} containing the path from which the style
- # element was loaded.
- # * `context` A {String} indicating the target context of the style
- # element.
- #
- # Returns a {Disposable} on which `.dispose()` can be called to cancel the
- # subscription.
- onDidAddStyleElement: (callback) ->
- @emitter.on 'did-add-style-element', callback
-
- # Extended: Invoke `callback` when a style element is removed.
- #
- # * `callback` {Function} that is called with style elements.
- # * `styleElement` An `HTMLStyleElement` instance.
- #
- # Returns a {Disposable} on which `.dispose()` can be called to cancel the
- # subscription.
- onDidRemoveStyleElement: (callback) ->
- @emitter.on 'did-remove-style-element', callback
-
- # Extended: Invoke `callback` when an existing style element is updated.
- #
- # * `callback` {Function} that is called with style elements.
- # * `styleElement` An `HTMLStyleElement` instance. The `.sheet` property
- # will be null because this element isn't attached to the DOM. The style
- # element will also have the following non-standard properties:
- # * `sourcePath` A {String} containing the path from which the style
- # element was loaded.
- # * `context` A {String} indicating the target context of the style
- # element.
- #
- # Returns a {Disposable} on which `.dispose()` can be called to cancel the
- # subscription.
- onDidUpdateStyleElement: (callback) ->
- @emitter.on 'did-update-style-element', callback
-
- ###
- Section: Reading Style Elements
- ###
-
- # Extended: Get all loaded style elements.
- getStyleElements: ->
- @styleElements.slice()
-
- addStyleSheet: (source, params) ->
- sourcePath = params?.sourcePath
- context = params?.context
- priority = params?.priority
-
- if sourcePath? and styleElement = @styleElementsBySourcePath[sourcePath]
- updated = true
- else
- styleElement = document.createElement('style')
- if sourcePath?
- styleElement.sourcePath = sourcePath
- styleElement.setAttribute('source-path', sourcePath)
-
- if context?
- styleElement.context = context
- styleElement.setAttribute('context', context)
-
- if priority?
- styleElement.priority = priority
- styleElement.setAttribute('priority', priority)
-
- styleElement.textContent = source
-
- if updated
- @emitter.emit 'did-update-style-element', styleElement
- else
- @addStyleElement(styleElement)
-
- new Disposable => @removeStyleElement(styleElement)
-
- addStyleElement: (styleElement) ->
- {sourcePath, priority} = styleElement
-
- if priority?
- for existingElement, index in @styleElements
- if existingElement.priority > priority
- insertIndex = index
- break
-
- insertIndex ?= @styleElements.length
-
- @styleElements.splice(insertIndex, 0, styleElement)
- @styleElementsBySourcePath[sourcePath] ?= styleElement if sourcePath?
- @emitter.emit 'did-add-style-element', styleElement
-
- removeStyleElement: (styleElement) ->
- index = @styleElements.indexOf(styleElement)
- unless index is -1
- @styleElements.splice(index, 1)
- delete @styleElementsBySourcePath[styleElement.sourcePath] if styleElement.sourcePath?
- @emitter.emit 'did-remove-style-element', styleElement
-
- getSnapshot: ->
- @styleElements.slice()
-
- restoreSnapshot: (styleElementsToRestore) ->
- for styleElement in @getStyleElements()
- @removeStyleElement(styleElement) unless styleElement in styleElementsToRestore
-
- existingStyleElements = @getStyleElements()
- for styleElement in styleElementsToRestore
- @addStyleElement(styleElement) unless styleElement in existingStyleElements
-
- return
-
- buildStylesElement: ->
- stylesElement = new StylesElement
- stylesElement.initialize(this)
- stylesElement
-
- ###
- Section: Paths
- ###
-
- # Extended: Get the path of the user style sheet in `~/.atom`.
- #
- # Returns a {String}.
- getUserStyleSheetPath: ->
- return "" unless @configDirPath?
-
- stylesheetPath = fs.resolve(path.join(@configDirPath, 'styles'), ['css', 'less'])
- if fs.isFileSync(stylesheetPath)
- stylesheetPath
- else
- path.join(@configDirPath, 'styles.less')
diff --git a/src/style-manager.js b/src/style-manager.js
new file mode 100644
index 00000000000..b273f449bf3
--- /dev/null
+++ b/src/style-manager.js
@@ -0,0 +1,307 @@
+const {Emitter, Disposable} = require('event-kit')
+const crypto = require('crypto')
+const fs = require('fs-plus')
+const path = require('path')
+const postcss = require('postcss')
+const selectorParser = require('postcss-selector-parser')
+const StylesElement = require('./styles-element')
+const DEPRECATED_SYNTAX_SELECTORS = require('./deprecated-syntax-selectors')
+
+// Extended: A singleton instance of this class available via `atom.styles`,
+// which you can use to globally query and observe the set of active style
+// sheets. The `StyleManager` doesn't add any style elements to the DOM on its
+// own, but is instead subscribed to by individual `` elements,
+// which clone and attach style elements in different contexts.
+module.exports = class StyleManager {
+ constructor ({configDirPath}) {
+ this.configDirPath = configDirPath
+ if (this.configDirPath != null) {
+ this.cacheDirPath = path.join(this.configDirPath, 'compile-cache', 'style-manager')
+ }
+ this.emitter = new Emitter()
+ this.styleElements = []
+ this.styleElementsBySourcePath = {}
+ this.deprecationsBySourcePath = {}
+ }
+
+ /*
+ Section: Event Subscription
+ */
+
+ // Extended: Invoke `callback` for all current and future style elements.
+ //
+ // * `callback` {Function} that is called with style elements.
+ // * `styleElement` An `HTMLStyleElement` instance. The `.sheet` property
+ // will be null because this element isn't attached to the DOM. If you want
+ // to attach this element to the DOM, be sure to clone it first by calling
+ // `.cloneNode(true)` on it. The style element will also have the following
+ // non-standard properties:
+ // * `sourcePath` A {String} containing the path from which the style
+ // element was loaded.
+ // * `context` A {String} indicating the target context of the style
+ // element.
+ //
+ // Returns a {Disposable} on which `.dispose()` can be called to cancel the
+ // subscription.
+ observeStyleElements (callback) {
+ for (let styleElement of this.getStyleElements()) {
+ callback(styleElement)
+ }
+
+ return this.onDidAddStyleElement(callback)
+ }
+
+ // Extended: Invoke `callback` when a style element is added.
+ //
+ // * `callback` {Function} that is called with style elements.
+ // * `styleElement` An `HTMLStyleElement` instance. The `.sheet` property
+ // will be null because this element isn't attached to the DOM. If you want
+ // to attach this element to the DOM, be sure to clone it first by calling
+ // `.cloneNode(true)` on it. The style element will also have the following
+ // non-standard properties:
+ // * `sourcePath` A {String} containing the path from which the style
+ // element was loaded.
+ // * `context` A {String} indicating the target context of the style
+ // element.
+ //
+ // Returns a {Disposable} on which `.dispose()` can be called to cancel the
+ // subscription.
+ onDidAddStyleElement (callback) {
+ return this.emitter.on('did-add-style-element', callback)
+ }
+
+ // Extended: Invoke `callback` when a style element is removed.
+ //
+ // * `callback` {Function} that is called with style elements.
+ // * `styleElement` An `HTMLStyleElement` instance.
+ //
+ // Returns a {Disposable} on which `.dispose()` can be called to cancel the
+ // subscription.
+ onDidRemoveStyleElement (callback) {
+ return this.emitter.on('did-remove-style-element', callback)
+ }
+
+ // Extended: Invoke `callback` when an existing style element is updated.
+ //
+ // * `callback` {Function} that is called with style elements.
+ // * `styleElement` An `HTMLStyleElement` instance. The `.sheet` property
+ // will be null because this element isn't attached to the DOM. The style
+ // element will also have the following non-standard properties:
+ // * `sourcePath` A {String} containing the path from which the style
+ // element was loaded.
+ // * `context` A {String} indicating the target context of the style
+ // element.
+ //
+ // Returns a {Disposable} on which `.dispose()` can be called to cancel the
+ // subscription.
+ onDidUpdateStyleElement (callback) {
+ return this.emitter.on('did-update-style-element', callback)
+ }
+
+ onDidUpdateDeprecations (callback) {
+ return this.emitter.on('did-update-deprecations', callback)
+ }
+
+ /*
+ Section: Reading Style Elements
+ */
+
+ // Extended: Get all loaded style elements.
+ getStyleElements () {
+ return this.styleElements.slice()
+ }
+
+ addStyleSheet (source, params = {}) {
+ let styleElement
+ let updated
+ if (params.sourcePath != null && this.styleElementsBySourcePath[params.sourcePath] != null) {
+ updated = true
+ styleElement = this.styleElementsBySourcePath[params.sourcePath]
+ } else {
+ updated = false
+ styleElement = document.createElement('style')
+ if (params.sourcePath != null) {
+ styleElement.sourcePath = params.sourcePath
+ styleElement.setAttribute('source-path', params.sourcePath)
+ }
+ if (params.context != null) {
+ styleElement.context = params.context
+ styleElement.setAttribute('context', params.context)
+ }
+ if (params.priority != null) {
+ styleElement.priority = params.priority
+ styleElement.setAttribute('priority', params.priority)
+ }
+ }
+
+ let transformed
+ if (this.cacheDirPath != null) {
+ const hash = crypto.createHash('sha1')
+ if (params.context != null) {
+ hash.update(params.context)
+ }
+ hash.update(source)
+ const cacheFilePath = path.join(this.cacheDirPath, hash.digest('hex'))
+ try {
+ transformed = JSON.parse(fs.readFileSync(cacheFilePath))
+ } catch (e) {
+ transformed = transformDeprecatedShadowDOMSelectors(source, params.context)
+ fs.writeFileSync(cacheFilePath, JSON.stringify(transformed))
+ }
+ } else {
+ transformed = transformDeprecatedShadowDOMSelectors(source, params.context)
+ }
+
+ styleElement.textContent = transformed.source
+ if (transformed.deprecationMessage) {
+ this.deprecationsBySourcePath[params.sourcePath] = {message: transformed.deprecationMessage}
+ this.emitter.emit('did-update-deprecations')
+ }
+ if (updated) {
+ this.emitter.emit('did-update-style-element', styleElement)
+ } else {
+ this.addStyleElement(styleElement)
+ }
+ return new Disposable(() => { this.removeStyleElement(styleElement) })
+ }
+
+ addStyleElement (styleElement) {
+ let insertIndex = this.styleElements.length
+ if (styleElement.priority != null) {
+ for (let [index, existingElement] of this.styleElements.entries()) {
+ if (existingElement.priority > styleElement.priority) {
+ insertIndex = index
+ break
+ }
+ }
+ }
+
+ this.styleElements.splice(insertIndex, 0, styleElement)
+ if (styleElement.sourcePath != null && this.styleElementsBySourcePath[styleElement.sourcePath] == null) {
+ this.styleElementsBySourcePath[styleElement.sourcePath] = styleElement
+ }
+ this.emitter.emit('did-add-style-element', styleElement)
+ }
+
+ removeStyleElement (styleElement) {
+ const index = this.styleElements.indexOf(styleElement)
+ if (index !== -1) {
+ this.styleElements.splice(index, 1)
+ if (styleElement.sourcePath != null) {
+ delete this.styleElementsBySourcePath[styleElement.sourcePath]
+ }
+ this.emitter.emit('did-remove-style-element', styleElement)
+ }
+ }
+
+ getDeprecations () {
+ return this.deprecationsBySourcePath
+ }
+
+ clearDeprecations () {
+ this.deprecationsBySourcePath = {}
+ }
+
+ getSnapshot () {
+ return this.styleElements.slice()
+ }
+
+ restoreSnapshot (styleElementsToRestore) {
+ for (let styleElement of this.getStyleElements()) {
+ if (!styleElementsToRestore.includes(styleElement)) {
+ this.removeStyleElement(styleElement)
+ }
+ }
+
+ const existingStyleElements = this.getStyleElements()
+ for (let styleElement of styleElementsToRestore) {
+ if (!existingStyleElements.includes(styleElement)) {
+ this.addStyleElement(styleElement)
+ }
+ }
+ }
+
+ buildStylesElement () {
+ var stylesElement = new StylesElement()
+ stylesElement.initialize(this)
+ return stylesElement
+ }
+
+ /*
+ Section: Paths
+ */
+
+ // Extended: Get the path of the user style sheet in `~/.atom`.
+ //
+ // Returns a {String}.
+ getUserStyleSheetPath () {
+ if (this.configDirPath == null) {
+ return ''
+ } else {
+ const stylesheetPath = fs.resolve(path.join(this.configDirPath, 'styles'), ['css', 'less'])
+ if (fs.isFileSync(stylesheetPath)) {
+ return stylesheetPath
+ } else {
+ return path.join(this.configDirPath, 'styles.less')
+ }
+ }
+ }
+}
+
+function transformDeprecatedShadowDOMSelectors (css, context) {
+ const transformedSelectors = []
+ const transformedSource = postcss.parse(css)
+ transformedSource.walkRules((rule) => {
+ const transformedSelector = selectorParser((selectors) => {
+ selectors.each((selector) => {
+ const firstNode = selector.nodes[0]
+ if (context === 'atom-text-editor' && firstNode.type === 'pseudo' && firstNode.value === ':host') {
+ const atomTextEditorElementNode = selectorParser.tag({value: 'atom-text-editor'})
+ firstNode.replaceWith(atomTextEditorElementNode)
+ }
+
+ let previousNodeIsAtomTextEditor = false
+ let targetsAtomTextEditorShadow = context === 'atom-text-editor'
+ let previousNode
+ selector.each((node) => {
+ if (targetsAtomTextEditorShadow && node.type === 'class') {
+ if (DEPRECATED_SYNTAX_SELECTORS.has(node.value)) {
+ node.value = `syntax--${node.value}`
+ }
+ } else {
+ if (previousNodeIsAtomTextEditor && node.type === 'pseudo' && node.value === '::shadow') {
+ selector.removeChild(node)
+ targetsAtomTextEditorShadow = true
+ }
+ }
+
+ previousNode = node
+ if (node.type === 'combinator') {
+ previousNodeIsAtomTextEditor = false
+ } else if (previousNode.type === 'tag' && previousNode.value === 'atom-text-editor') {
+ previousNodeIsAtomTextEditor = true
+ }
+ })
+ })
+ }).process(rule.selector, {lossless: true}).result
+ if (transformedSelector !== rule.selector) {
+ transformedSelectors.push({before: rule.selector, after: transformedSelector})
+ rule.selector = transformedSelector
+ }
+ })
+ let deprecationMessage
+ if (transformedSelectors.length > 0) {
+ deprecationMessage = 'Starting from Atom v1.13.0, the contents of `atom-text-editor` elements '
+ deprecationMessage += 'are no longer encapsulated within a shadow DOM boundary. '
+ deprecationMessage += 'This means you should stop using `:host` and `::shadow` '
+ deprecationMessage += 'pseudo-selectors, and prepend all your syntax selectors with `syntax--`. '
+ deprecationMessage += 'To prevent breakage with existing style sheets, Atom will automatically '
+ deprecationMessage += 'upgrade the following selectors:\n\n'
+ deprecationMessage += transformedSelectors
+ .map((selector) => `* \`${selector.before}\` => \`${selector.after}\``)
+ .join('\n\n') + '\n\n'
+ deprecationMessage += 'Automatic translation of selectors will be removed in a few release cycles to minimize startup time. '
+ deprecationMessage += 'Please, make sure to upgrade the above selectors as soon as possible.'
+ }
+ return {source: transformedSource.toString(), deprecationMessage}
+}
diff --git a/src/styles-element.coffee b/src/styles-element.coffee
index d1e6bf3d9c3..2c53300c218 100644
--- a/src/styles-element.coffee
+++ b/src/styles-element.coffee
@@ -19,10 +19,6 @@ class StylesElement extends HTMLElement
@styleElementClonesByOriginalElement = new WeakMap
attachedCallback: ->
- if @context is 'atom-text-editor'
- for styleElement in @children
- @upgradeDeprecatedSelectors(styleElement)
-
@context = @getAttribute('context') ? undefined
detachedCallback: ->
@@ -64,10 +60,6 @@ class StylesElement extends HTMLElement
break
@insertBefore(styleElementClone, insertBefore)
-
- if @context is 'atom-text-editor'
- @upgradeDeprecatedSelectors(styleElementClone)
-
@emitter.emit 'did-add-style-element', styleElementClone
styleElementRemoved: (styleElement) ->
@@ -87,31 +79,4 @@ class StylesElement extends HTMLElement
styleElementMatchesContext: (styleElement) ->
not @context? or styleElement.context is @context
- upgradeDeprecatedSelectors: (styleElement) ->
- return unless styleElement.sheet?
-
- upgradedSelectors = []
-
- for rule in styleElement.sheet.cssRules
- continue unless rule.selectorText?
- continue if /\:host/.test(rule.selectorText)
-
- inputSelector = rule.selectorText
- outputSelector = rule.selectorText
- .replace(/\.editor-colors($|[ >])/g, ':host$1')
- .replace(/\.editor([:.][^ ,>]+)/g, ':host($1)')
- .replace(/\.editor($|[ ,>])/g, ':host$1')
-
- unless inputSelector is outputSelector
- rule.selectorText = outputSelector
- upgradedSelectors.push({inputSelector, outputSelector})
-
- if upgradedSelectors.length > 0
- warning = "Upgraded the following syntax theme selectors in `#{styleElement.sourcePath}` for shadow DOM compatibility:\n\n"
- for {inputSelector, outputSelector} in upgradedSelectors
- warning += "`#{inputSelector}` => `#{outputSelector}`\n"
-
- warning += "\nSee the upgrade guide for information on removing this warning."
- console.warn(warning)
-
module.exports = StylesElement = document.registerElement 'atom-styles', prototype: StylesElement.prototype
diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee
index d2647d767d5..cccd2f4c86f 100644
--- a/src/text-editor-component.coffee
+++ b/src/text-editor-component.coffee
@@ -8,12 +8,12 @@ TextEditorPresenter = require './text-editor-presenter'
GutterContainerComponent = require './gutter-container-component'
InputComponent = require './input-component'
LinesComponent = require './lines-component'
+OffScreenBlockDecorationsComponent = require './off-screen-block-decorations-component'
ScrollbarComponent = require './scrollbar-component'
ScrollbarCornerComponent = require './scrollbar-corner-component'
OverlayManager = require './overlay-manager'
DOMElementPool = require './dom-element-pool'
LinesYardstick = require './lines-yardstick'
-BlockDecorationsComponent = require './block-decorations-component'
LineTopIndex = require 'line-top-index'
module.exports =
@@ -42,7 +42,7 @@ class TextEditorComponent
@assert domNode?, "TextEditorComponent::domNode was set to null."
@domNodeValue = domNode
- constructor: ({@editor, @hostElement, @rootElement, @stylesElement, tileSize, @views, @themes, @assert}) ->
+ constructor: ({@editor, @hostElement, tileSize, @views, @themes, @styles, @assert}) ->
@tileSize = tileSize if tileSize?
@disposables = new CompositeDisposable
@@ -64,11 +64,7 @@ class TextEditorComponent
@domNode = document.createElement('div')
@domNode.classList.add('editor-contents--private')
- insertionPoint = document.createElement('content')
- insertionPoint.setAttribute('select', 'atom-overlay')
- @domNode.appendChild(insertionPoint)
- @overlayManager = new OverlayManager(@presenter, @hostElement, @views)
- @blockDecorationsComponent = new BlockDecorationsComponent(@hostElement, @views, @presenter, @domElementPool)
+ @overlayManager = new OverlayManager(@presenter, @domNode, @views)
@scrollViewNode = document.createElement('div')
@scrollViewNode.classList.add('scroll-view')
@@ -77,11 +73,11 @@ class TextEditorComponent
@hiddenInputComponent = new InputComponent
@scrollViewNode.appendChild(@hiddenInputComponent.getDomNode())
- @linesComponent = new LinesComponent({@presenter, @hostElement, @domElementPool, @assert, @grammars})
+ @linesComponent = new LinesComponent({@presenter, @domElementPool, @assert, @grammars, @views})
@scrollViewNode.appendChild(@linesComponent.getDomNode())
- if @blockDecorationsComponent?
- @linesComponent.getDomNode().appendChild(@blockDecorationsComponent.getDomNode())
+ @offScreenBlockDecorationsComponent = new OffScreenBlockDecorationsComponent({@presenter, @views})
+ @scrollViewNode.appendChild(@offScreenBlockDecorationsComponent.getDomNode())
@linesYardstick = new LinesYardstick(@editor, @linesComponent, lineTopIndex)
@presenter.setLinesYardstick(@linesYardstick)
@@ -98,9 +94,9 @@ class TextEditorComponent
@observeEditor()
@listenForDOMEvents()
- @disposables.add @stylesElement.onDidAddStyleElement @onStylesheetsChanged
- @disposables.add @stylesElement.onDidUpdateStyleElement @onStylesheetsChanged
- @disposables.add @stylesElement.onDidRemoveStyleElement @onStylesheetsChanged
+ @disposables.add @styles.onDidAddStyleElement @onStylesheetsChanged
+ @disposables.add @styles.onDidUpdateStyleElement @onStylesheetsChanged
+ @disposables.add @styles.onDidRemoveStyleElement @onStylesheetsChanged
unless @themes.isInitialLoadComplete()
@disposables.add @themes.onDidChangeActiveThemes @onAllThemesLoaded
@disposables.add scrollbarStyle.onDidChangePreferredScrollbarStyle @refreshScrollbars
@@ -165,8 +161,8 @@ class TextEditorComponent
@gutterContainerComponent = null
@hiddenInputComponent.updateSync(@newState)
+ @offScreenBlockDecorationsComponent.updateSync(@newState)
@linesComponent.updateSync(@newState)
- @blockDecorationsComponent?.updateSync(@newState)
@horizontalScrollbarComponent.updateSync(@newState)
@verticalScrollbarComponent.updateSync(@newState)
@scrollbarCornerComponent.updateSync(@newState)
@@ -186,7 +182,8 @@ class TextEditorComponent
readAfterUpdateSync: =>
@overlayManager?.measureOverlays()
- @blockDecorationsComponent?.measureBlockDecorations() if @isVisible()
+ @linesComponent.measureBlockDecorations()
+ @offScreenBlockDecorationsComponent.measureBlockDecorations()
mountGutterContainerComponent: ->
@gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown, @domElementPool, @views})
@@ -969,9 +966,7 @@ class TextEditorComponent
updateParentViewFocusedClassIfNeeded: ->
if @oldState.focused isnt @newState.focused
@hostElement.classList.toggle('is-focused', @newState.focused)
- @rootElement.classList.toggle('is-focused', @newState.focused)
@oldState.focused = @newState.focused
updateParentViewMiniClass: ->
@hostElement.classList.toggle('mini', @editor.isMini())
- @rootElement.classList.toggle('mini', @editor.isMini())
diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee
index 27a29bed657..4a7d1598dc8 100644
--- a/src/text-editor-element.coffee
+++ b/src/text-editor-element.coffee
@@ -1,9 +1,7 @@
+Grim = require 'grim'
{Emitter, CompositeDisposable} = require 'event-kit'
TextBuffer = require 'text-buffer'
TextEditorComponent = require './text-editor-component'
-StylesElement = require './styles-element'
-
-ShadowStyleSheet = null
class TextEditorElement extends HTMLElement
model: null
@@ -14,6 +12,7 @@ class TextEditorElement extends HTMLElement
focusOnAttach: false
hasTiledRendering: true
logicalDisplayBuffer: true
+ lightDOM: true
createdCallback: ->
# Use globals when the following instance variables aren't set.
@@ -33,22 +32,18 @@ class TextEditorElement extends HTMLElement
@setAttribute('tabindex', -1)
initializeContent: (attributes) ->
- unless ShadowStyleSheet?
- ShadowStyleSheet = document.createElement('style')
- ShadowStyleSheet.textContent = @themes.loadLessStylesheet(require.resolve('../static/text-editor-shadow.less'))
-
- @createShadowRoot()
-
- @shadowRoot.appendChild(ShadowStyleSheet.cloneNode(true))
- @stylesElement = new StylesElement
- @stylesElement.initialize(@styles)
- @stylesElement.setAttribute('context', 'atom-text-editor')
-
+ Object.defineProperty(this, 'shadowRoot', {
+ get: =>
+ Grim.deprecate("""
+ The contents of `atom-text-editor` elements are no longer encapsulated
+ within a shadow DOM boundary. Please, stop using `shadowRoot` and access
+ the editor contents directly instead.
+ """)
+ this
+ })
@rootElement = document.createElement('div')
@rootElement.classList.add('editor--private')
-
- @shadowRoot.appendChild(@stylesElement)
- @shadowRoot.appendChild(@rootElement)
+ @appendChild(@rootElement)
attachedCallback: ->
@buildModel() unless @getModel()?
@@ -56,7 +51,7 @@ class TextEditorElement extends HTMLElement
@mountComponent() unless @component?
@listenForComponentEvents()
@component.checkForVisibilityChange()
- if this is document.activeElement
+ if @hasFocus()
@focused()
@emitter.emit("did-attach")
@@ -116,18 +111,18 @@ class TextEditorElement extends HTMLElement
mountComponent: ->
@component = new TextEditorComponent(
hostElement: this
- rootElement: @rootElement
- stylesElement: @stylesElement
editor: @model
tileSize: @tileSize
views: @views
themes: @themes
+ styles: @styles
workspace: @workspace
assert: @assert
)
@rootElement.appendChild(@component.getDomNode())
-
- @shadowRoot.addEventListener('blur', @shadowRootBlurred.bind(this), true)
+ inputNode = @component.hiddenInputComponent.getDomNode()
+ inputNode.addEventListener 'focus', @focused.bind(this)
+ inputNode.addEventListener 'blur', @inputNodeBlurred.bind(this)
unmountComponent: ->
if @component?
@@ -135,21 +130,18 @@ class TextEditorElement extends HTMLElement
@component.getDomNode().remove()
@component = null
- focused: ->
+ focused: (event) ->
@component?.focused()
blurred: (event) ->
+ if event.relatedTarget is @component?.hiddenInputComponent.getDomNode()
+ event.stopImmediatePropagation()
+ return
@component?.blurred()
- # Work around what seems to be a bug in Chromium. Focus can be stolen from the
- # hidden input when clicking on the gutter and transferred to the
- # already-focused host element. The host element never gets a 'focus' event
- # however, which leaves us in a limbo state where the text editor element is
- # focused but the hidden input isn't focused. This always refocuses the hidden
- # input if a blur event occurs in the shadow DOM that is transferring focus
- # back to the host element.
- shadowRootBlurred: (event) ->
- @component.focused() if event.relatedTarget is this
+ inputNodeBlurred: (event) ->
+ if event.relatedTarget isnt this
+ @dispatchEvent(new FocusEvent('blur', bubbles: false))
addGrammarScopeAttribute: ->
@dataset.grammar = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')
diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee
index bbefc91c04b..22268af183a 100644
--- a/src/text-editor-presenter.coffee
+++ b/src/text-editor-presenter.coffee
@@ -35,7 +35,10 @@ class TextEditorPresenter
@observedBlockDecorations = new Set()
@invalidatedDimensionsByBlockDecoration = new Set()
@invalidateAllBlockDecorationsDimensions = false
+ @precedingBlockDecorationsByScreenRowAndId = {}
+ @followingBlockDecorationsByScreenRowAndId = {}
@screenRowsToMeasure = []
+ @flashCountsByDecorationId = {}
@transferMeasurementsToModel()
@transferMeasurementsFromModel()
@observeModel()
@@ -197,7 +200,7 @@ class TextEditorPresenter
highlights: {}
overlays: {}
cursors: {}
- blockDecorations: {}
+ offScreenBlockDecorations: {}
gutters: []
# Shared state that is copied into ``@state.gutters`.
@sharedGutterStyles = {}
@@ -414,16 +417,14 @@ class TextEditorPresenter
continue unless line?
visibleLineIds[line.id] = true
- precedingBlockDecorations = @precedingBlockDecorationsByScreenRow[screenRow] ? []
- followingBlockDecorations = @followingBlockDecorationsByScreenRow[screenRow] ? []
+ precedingBlockDecorations = @precedingBlockDecorationsByScreenRowAndId[screenRow] ? {}
+ followingBlockDecorations = @followingBlockDecorationsByScreenRowAndId[screenRow] ? {}
if tileState.lines.hasOwnProperty(line.id)
lineState = tileState.lines[line.id]
lineState.screenRow = screenRow
lineState.decorationClasses = @lineDecorationClassesForRow(screenRow)
lineState.precedingBlockDecorations = precedingBlockDecorations
lineState.followingBlockDecorations = followingBlockDecorations
- lineState.hasPrecedingBlockDecorations = precedingBlockDecorations.length > 0
- lineState.hasFollowingBlockDecorations = followingBlockDecorations.length > 0
else
tileState.lines[line.id] =
screenRow: screenRow
@@ -432,8 +433,6 @@ class TextEditorPresenter
decorationClasses: @lineDecorationClassesForRow(screenRow)
precedingBlockDecorations: precedingBlockDecorations
followingBlockDecorations: followingBlockDecorations
- hasPrecedingBlockDecorations: precedingBlockDecorations.length > 0
- hasFollowingBlockDecorations: followingBlockDecorations.length > 0
for id, line of tileState.lines
delete tileState.lines[id] unless visibleLineIds.hasOwnProperty(id)
@@ -1063,41 +1062,42 @@ class TextEditorPresenter
@decorations = @model.decorationsStateForScreenRowRange(@startRow, @endRow - 1)
updateBlockDecorations: ->
- @blockDecorationsToRenderById = {}
- @precedingBlockDecorationsByScreenRow = {}
- @followingBlockDecorationsByScreenRow = {}
- visibleDecorationsByMarkerId = @model.decorationsForScreenRowRange(@getStartTileRow(), @getEndTileRow() + @tileSize - 1)
-
if @invalidateAllBlockDecorationsDimensions
for decoration in @model.getDecorations(type: 'block')
@invalidatedDimensionsByBlockDecoration.add(decoration)
@invalidateAllBlockDecorationsDimensions = false
- for markerId, decorations of visibleDecorationsByMarkerId
+ visibleDecorationsById = {}
+ visibleDecorationsByScreenRowAndId = {}
+ for markerId, decorations of @model.decorationsForScreenRowRange(@getStartTileRow(), @getEndTileRow() + @tileSize - 1)
for decoration in decorations when decoration.isType('block')
- @updateBlockDecorationState(decoration, true)
-
+ screenRow = decoration.getMarker().getHeadScreenPosition().row
+ if decoration.getProperties().position is "after"
+ @followingBlockDecorationsByScreenRowAndId[screenRow] ?= {}
+ @followingBlockDecorationsByScreenRowAndId[screenRow][decoration.id] = {screenRow, decoration}
+ else
+ @precedingBlockDecorationsByScreenRowAndId[screenRow] ?= {}
+ @precedingBlockDecorationsByScreenRowAndId[screenRow][decoration.id] = {screenRow, decoration}
+ visibleDecorationsById[decoration.id] = true
+ visibleDecorationsByScreenRowAndId[screenRow] ?= {}
+ visibleDecorationsByScreenRowAndId[screenRow][decoration.id] = true
+
+ for screenRow, blockDecorations of @precedingBlockDecorationsByScreenRowAndId
+ if Number(screenRow) isnt @mouseWheelScreenRow
+ for id, blockDecoration of blockDecorations
+ unless visibleDecorationsByScreenRowAndId[screenRow]?[id]
+ delete @precedingBlockDecorationsByScreenRowAndId[screenRow][id]
+
+ for screenRow, blockDecorations of @followingBlockDecorationsByScreenRowAndId
+ if Number(screenRow) isnt @mouseWheelScreenRow
+ for id, blockDecoration of blockDecorations
+ unless visibleDecorationsByScreenRowAndId[screenRow]?[id]
+ delete @followingBlockDecorationsByScreenRowAndId[screenRow][id]
+
+ @state.content.offScreenBlockDecorations = {}
@invalidatedDimensionsByBlockDecoration.forEach (decoration) =>
- @updateBlockDecorationState(decoration, false)
-
- for decorationId, decorationState of @state.content.blockDecorations
- continue if @blockDecorationsToRenderById[decorationId]
- continue if decorationState.screenRow is @mouseWheelScreenRow
-
- delete @state.content.blockDecorations[decorationId]
-
- updateBlockDecorationState: (decoration, isVisible) ->
- return if @blockDecorationsToRenderById[decoration.getId()]
-
- screenRow = decoration.getMarker().getHeadScreenPosition().row
- if decoration.getProperties().position is "after"
- @followingBlockDecorationsByScreenRow[screenRow] ?= []
- @followingBlockDecorationsByScreenRow[screenRow].push(decoration)
- else
- @precedingBlockDecorationsByScreenRow[screenRow] ?= []
- @precedingBlockDecorationsByScreenRow[screenRow].push(decoration)
- @state.content.blockDecorations[decoration.getId()] = {decoration, screenRow, isVisible}
- @blockDecorationsToRenderById[decoration.getId()] = true
+ unless visibleDecorationsById[decoration.id]
+ @state.content.offScreenBlockDecorations[decoration.id] = decoration
updateLineDecorations: ->
@lineDecorationsByScreenRow = {}
@@ -1184,6 +1184,9 @@ class TextEditorPresenter
startTile = @tileForRow(screenRange.start.row)
endTile = @tileForRow(screenRange.end.row)
+ needsFlash = properties.flashCount? and @flashCountsByDecorationId[decorationId] isnt properties.flashCount
+ if needsFlash
+ @flashCountsByDecorationId[decorationId] = properties.flashCount
for tileStartRow in [startTile..endTile] by @tileSize
rangeWithinTile = @intersectRangeWithTile(screenRange, tileStartRow)
@@ -1193,6 +1196,7 @@ class TextEditorPresenter
tileState = @state.content.tiles[tileStartRow] ?= {highlights: {}}
highlightState = tileState.highlights[decorationId] ?= {}
+ highlightState.needsFlash = needsFlash
highlightState.flashCount = properties.flashCount
highlightState.flashClass = properties.flashClass
highlightState.flashDuration = properties.flashDuration
@@ -1299,7 +1303,7 @@ class TextEditorPresenter
setBlockDecorationDimensions: (decoration, width, height) ->
return unless @observedBlockDecorations.has(decoration)
- @lineTopIndex.resizeBlock(decoration.getId(), height)
+ @lineTopIndex.resizeBlock(decoration.id, height)
@invalidatedDimensionsByBlockDecoration.delete(decoration)
@shouldUpdateDecorations = true
@@ -1336,7 +1340,7 @@ class TextEditorPresenter
@didDestroyBlockDecoration(decoration)
isAfter = decoration.getProperties().position is "after"
- @lineTopIndex.insertBlock(decoration.getId(), decoration.getMarker().getHeadScreenPosition().row, 0, isAfter)
+ @lineTopIndex.insertBlock(decoration.id, decoration.getMarker().getHeadScreenPosition().row, 0, isAfter)
@observedBlockDecorations.add(decoration)
@invalidateBlockDecorationDimensions(decoration)
@@ -1350,14 +1354,14 @@ class TextEditorPresenter
# change.
return if markerEvent.textChanged
- @lineTopIndex.moveBlock(decoration.getId(), decoration.getMarker().getHeadScreenPosition().row)
+ @lineTopIndex.moveBlock(decoration.id, decoration.getMarker().getHeadScreenPosition().row)
@shouldUpdateDecorations = true
@emitDidUpdateState()
didDestroyBlockDecoration: (decoration) ->
return unless @observedBlockDecorations.has(decoration)
- @lineTopIndex.removeBlock(decoration.getId())
+ @lineTopIndex.removeBlock(decoration.id)
@observedBlockDecorations.delete(decoration)
@invalidatedDimensionsByBlockDecoration.delete(decoration)
@shouldUpdateDecorations = true
diff --git a/src/tiled-component.coffee b/src/tiled-component.coffee
index 2e8dc7149f6..37de27e9b71 100644
--- a/src/tiled-component.coffee
+++ b/src/tiled-component.coffee
@@ -1,10 +1,3 @@
-{values} = require 'underscore-plus'
-
-cloneObject = (object) ->
- clone = {}
- clone[key] = value for key, value of object
- clone
-
module.exports =
class TiledComponent
updateSync: (state) ->
@@ -41,7 +34,7 @@ class TiledComponent
component = @componentsByTileId[tileRow] = @buildComponentForTile(tileRow)
@getTilesNode().appendChild(component.getDomNode())
- @oldState.tiles[tileRow] = cloneObject(tileState)
+ @oldState.tiles[tileRow] = Object.assign({}, tileState)
component.updateSync(@newState)
@@ -50,5 +43,9 @@ class TiledComponent
getComponentForTile: (tileRow) ->
@componentsByTileId[tileRow]
+ getComponents: ->
+ for _, component of @componentsByTileId
+ component
+
getTiles: ->
- values(@componentsByTileId).map (component) -> component.getDomNode()
+ @getComponents().map((component) -> component.getDomNode())
diff --git a/src/tokenized-buffer-iterator.coffee b/src/tokenized-buffer-iterator.coffee
deleted file mode 100644
index 23b72d5a91f..00000000000
--- a/src/tokenized-buffer-iterator.coffee
+++ /dev/null
@@ -1,126 +0,0 @@
-{Point} = require 'text-buffer'
-
-module.exports =
-class TokenizedBufferIterator
- constructor: (@tokenizedBuffer) ->
- @openTags = null
- @closeTags = null
- @containingTags = null
-
- seek: (position) ->
- @openTags = []
- @closeTags = []
- @tagIndex = null
-
- currentLine = @tokenizedBuffer.tokenizedLineForRow(position.row)
- @currentTags = currentLine.tags
- @currentLineOpenTags = currentLine.openScopes
- @currentLineLength = currentLine.text.length
- @containingTags = @currentLineOpenTags.map (id) => @tokenizedBuffer.grammar.scopeForId(id)
- currentColumn = 0
-
- for tag, index in @currentTags
- if tag >= 0
- if currentColumn >= position.column
- @tagIndex = index
- break
- else
- currentColumn += tag
- @containingTags.pop() while @closeTags.shift()
- @containingTags.push(openTag) while openTag = @openTags.shift()
- else
- scopeName = @tokenizedBuffer.grammar.scopeForId(tag)
- if tag % 2 is 0 # close tag
- if @openTags.length > 0
- if currentColumn >= position.column
- @tagIndex = index
- break
- else
- @containingTags.pop() while @closeTags.shift()
- @containingTags.push(openTag) while openTag = @openTags.shift()
- @closeTags.push(scopeName)
- else # open tag
- @openTags.push(scopeName)
-
- @tagIndex ?= @currentTags.length
- @position = Point(position.row, Math.min(@currentLineLength, currentColumn))
- @containingTags.slice()
-
- moveToSuccessor: ->
- @containingTags.pop() for tag in @closeTags
- @containingTags.push(tag) for tag in @openTags
- @openTags = []
- @closeTags = []
-
- loop
- if @tagIndex is @currentTags.length
- if @isAtTagBoundary()
- break
- else
- if @shouldMoveToNextLine
- @moveToNextLine()
- @openTags = @currentLineOpenTags.map (id) => @tokenizedBuffer.grammar.scopeForId(id)
- @shouldMoveToNextLine = false
- else if @nextLineHasMismatchedContainingTags()
- @closeTags = @containingTags.slice().reverse()
- @containingTags = []
- @shouldMoveToNextLine = true
- else
- return false unless @moveToNextLine()
- else
- tag = @currentTags[@tagIndex]
- if tag >= 0
- if @isAtTagBoundary()
- break
- else
- @position = Point(@position.row, Math.min(@currentLineLength, @position.column + @currentTags[@tagIndex]))
- else
- scopeName = @tokenizedBuffer.grammar.scopeForId(tag)
- if tag % 2 is 0
- if @openTags.length > 0
- break
- else
- @closeTags.push(scopeName)
- else
- @openTags.push(scopeName)
- @tagIndex++
-
- true
-
- getPosition: ->
- @position
-
- getCloseTags: ->
- @closeTags.slice()
-
- getOpenTags: ->
- @openTags.slice()
-
- ###
- Section: Private Methods
- ###
-
- nextLineHasMismatchedContainingTags: ->
- if line = @tokenizedBuffer.tokenizedLineForRow(@position.row + 1)
- return true if line.openScopes.length isnt @containingTags.length
-
- for i in [0...@containingTags.length] by 1
- if @containingTags[i] isnt @tokenizedBuffer.grammar.scopeForId(line.openScopes[i])
- return true
- false
- else
- false
-
- moveToNextLine: ->
- @position = Point(@position.row + 1, 0)
- if tokenizedLine = @tokenizedBuffer.tokenizedLineForRow(@position.row)
- @currentTags = tokenizedLine.tags
- @currentLineLength = tokenizedLine.text.length
- @currentLineOpenTags = tokenizedLine.openScopes
- @tagIndex = 0
- true
- else
- false
-
- isAtTagBoundary: ->
- @closeTags.length > 0 or @openTags.length > 0
diff --git a/src/tokenized-buffer-iterator.js b/src/tokenized-buffer-iterator.js
new file mode 100644
index 00000000000..29d2fdf8694
--- /dev/null
+++ b/src/tokenized-buffer-iterator.js
@@ -0,0 +1,174 @@
+const {Point} = require('text-buffer')
+
+module.exports = class TokenizedBufferIterator {
+ constructor (tokenizedBuffer) {
+ this.tokenizedBuffer = tokenizedBuffer
+ this.openTags = null
+ this.closeTags = null
+ this.containingTags = null
+ }
+
+ seek (position) {
+ this.openTags = []
+ this.closeTags = []
+ this.tagIndex = null
+
+ const currentLine = this.tokenizedBuffer.tokenizedLineForRow(position.row)
+ this.currentTags = currentLine.tags
+ this.currentLineOpenTags = currentLine.openScopes
+ this.currentLineLength = currentLine.text.length
+ this.containingTags = this.currentLineOpenTags.map((id) => this.scopeForId(id))
+
+ let currentColumn = 0
+ for (let [index, tag] of this.currentTags.entries()) {
+ if (tag >= 0) {
+ if (currentColumn >= position.column) {
+ this.tagIndex = index
+ break
+ } else {
+ currentColumn += tag
+ while (this.closeTags.length > 0) {
+ this.closeTags.shift()
+ this.containingTags.pop()
+ }
+ while (this.openTags.length > 0) {
+ const openTag = this.openTags.shift()
+ this.containingTags.push(openTag)
+ }
+ }
+ } else {
+ const scopeName = this.scopeForId(tag)
+ if (tag % 2 === 0) {
+ if (this.openTags.length > 0) {
+ if (currentColumn >= position.column) {
+ this.tagIndex = index
+ break
+ } else {
+ while (this.closeTags.length > 0) {
+ this.closeTags.shift()
+ this.containingTags.pop()
+ }
+ while (this.openTags.length > 0) {
+ const openTag = this.openTags.shift()
+ this.containingTags.push(openTag)
+ }
+ }
+ }
+ this.closeTags.push(scopeName)
+ } else {
+ this.openTags.push(scopeName)
+ }
+ }
+ }
+
+ if (this.tagIndex == null) {
+ this.tagIndex = this.currentTags.length
+ }
+ this.position = Point(position.row, Math.min(this.currentLineLength, currentColumn))
+ return this.containingTags.slice()
+ }
+
+ moveToSuccessor () {
+ for (let tag of this.closeTags) { // eslint-disable-line no-unused-vars
+ this.containingTags.pop()
+ }
+ for (let tag of this.openTags) {
+ this.containingTags.push(tag)
+ }
+ this.openTags = []
+ this.closeTags = []
+ while (true) {
+ if (this.tagIndex === this.currentTags.length) {
+ if (this.isAtTagBoundary()) {
+ break
+ } else if (this.shouldMoveToNextLine) {
+ this.moveToNextLine()
+ this.openTags = this.currentLineOpenTags.map((id) => this.scopeForId(id))
+ this.shouldMoveToNextLine = false
+ } else if (this.nextLineHasMismatchedContainingTags()) {
+ this.closeTags = this.containingTags.slice().reverse()
+ this.containingTags = []
+ this.shouldMoveToNextLine = true
+ } else if (!this.moveToNextLine()) {
+ return false
+ }
+ } else {
+ const tag = this.currentTags[this.tagIndex]
+ if (tag >= 0) {
+ if (this.isAtTagBoundary()) {
+ break
+ } else {
+ this.position = Point(this.position.row, Math.min(
+ this.currentLineLength,
+ this.position.column + this.currentTags[this.tagIndex]
+ ))
+ }
+ } else {
+ const scopeName = this.scopeForId(tag)
+ if (tag % 2 === 0) {
+ if (this.openTags.length > 0) {
+ break
+ } else {
+ this.closeTags.push(scopeName)
+ }
+ } else {
+ this.openTags.push(scopeName)
+ }
+ }
+ this.tagIndex++
+ }
+ }
+ return true
+ }
+
+ getPosition () {
+ return this.position
+ }
+
+ getCloseTags () {
+ return this.closeTags.slice()
+ }
+
+ getOpenTags () {
+ return this.openTags.slice()
+ }
+
+ nextLineHasMismatchedContainingTags () {
+ const line = this.tokenizedBuffer.tokenizedLineForRow(this.position.row + 1)
+ if (line == null) {
+ return false
+ } else {
+ return (
+ this.containingTags.length !== line.openScopes.length ||
+ this.containingTags.some((tag, i) => tag !== this.scopeForId(line.openScopes[i]))
+ )
+ }
+ }
+
+ moveToNextLine () {
+ this.position = Point(this.position.row + 1, 0)
+ const tokenizedLine = this.tokenizedBuffer.tokenizedLineForRow(this.position.row)
+ if (tokenizedLine == null) {
+ return false
+ } else {
+ this.currentTags = tokenizedLine.tags
+ this.currentLineLength = tokenizedLine.text.length
+ this.currentLineOpenTags = tokenizedLine.openScopes
+ this.tagIndex = 0
+ return true
+ }
+ }
+
+ isAtTagBoundary () {
+ return this.closeTags.length > 0 || this.openTags.length > 0
+ }
+
+ scopeForId (id) {
+ const scope = this.tokenizedBuffer.grammar.scopeForId(id)
+ if (scope) {
+ return `syntax--${scope.replace(/\./g, '.syntax--')}`
+ } else {
+ return null
+ }
+ }
+}
diff --git a/static/cursors.less b/static/cursors.less
index b2807217e10..0b54c6ea1c5 100644
--- a/static/cursors.less
+++ b/static/cursors.less
@@ -13,14 +13,14 @@
// Editors
& when ( lightness(@syntax-background-color) < 50% ) {
- .platform-darwin atom-text-editor:not([mini])::shadow .editor-contents--private {
+ .platform-darwin atom-text-editor:not([mini]) .editor-contents--private {
.cursor-white();
}
}
// Mini Editors
& when ( lightness(@input-background-color) < 50% ) {
- .platform-darwin atom-text-editor[mini]::shadow .editor-contents--private {
+ .platform-darwin atom-text-editor[mini] .editor-contents--private {
.cursor-white();
}
}
diff --git a/static/text-editor-light.less b/static/text-editor-light.less
index 2082dc715b6..178f62d1d71 100644
--- a/static/text-editor-light.less
+++ b/static/text-editor-light.less
@@ -5,28 +5,14 @@
atom-text-editor {
display: block;
font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace;
-}
-
-atom-text-editor[mini] {
- font-size: @input-font-size;
- line-height: @component-line-height;
- max-height: @component-line-height + 2; // +2 for borders
- overflow: auto;
-}
-atom-overlay {
- position: fixed;
- display: block;
- z-index: 4;
-}
-
-// TODO: Remove the following styles when the editor shadow DOM can no longer be disabled
-atom-text-editor {
- display: flex;
+ .editor--private, .editor-contents--private {
+ height: 100%;
+ width: 100%;
+ }
- .editor-contents {
+ .editor-contents--private {
width: 100%;
- overflow: hidden;
cursor: text;
display: flex;
-webkit-user-select: none;
@@ -35,6 +21,7 @@ atom-text-editor {
.gutter {
overflow: hidden;
+ z-index: 0;
text-align: right;
cursor: default;
min-width: 1em;
@@ -217,3 +204,16 @@ atom-text-editor {
right: 0;
}
}
+
+atom-text-editor[mini] {
+ font-size: @input-font-size;
+ line-height: @component-line-height;
+ max-height: @component-line-height + 2; // +2 for borders
+ overflow: auto;
+}
+
+atom-overlay {
+ position: fixed;
+ display: block;
+ z-index: 4;
+}
diff --git a/static/text-editor-shadow.less b/static/text-editor-shadow.less
deleted file mode 100644
index a3d44f56813..00000000000
--- a/static/text-editor-shadow.less
+++ /dev/null
@@ -1,201 +0,0 @@
-@import "ui-variables";
-@import "octicon-utf-codes";
-@import "octicon-mixins";
-
-.editor--private, .editor-contents--private {
- height: 100%;
- width: 100%;
-}
-
-.editor-contents--private {
- width: 100%;
- cursor: text;
- display: flex;
- -webkit-user-select: none;
- position: relative;
-}
-
-.gutter {
- overflow: hidden;
- z-index: 0;
- text-align: right;
- cursor: default;
- min-width: 1em;
- box-sizing: border-box;
-}
-
-.line-numbers {
- position: relative;
-}
-
-.line-number {
- position: relative;
- white-space: nowrap;
- padding-left: .5em;
- opacity: 0.6;
-
- &.cursor-line {
- opacity: 1;
- }
-
- .icon-right {
- .octicon(chevron-down, 0.8em);
- display: inline-block;
- visibility: hidden;
- opacity: .6;
- padding: 0 .4em;
-
- &::before {
- text-align: center;
- }
- }
-}
-
-.gutter:hover {
- .line-number.foldable .icon-right {
- visibility: visible;
-
- &:hover {
- opacity: 1;
- }
- }
-}
-
-.gutter, .gutter:hover {
- .line-number.folded .icon-right {
- .octicon(chevron-right, 0.8em);
-
- visibility: visible;
-
- &::before {
- position: relative;
- left: -.1em;
- }
- }
-}
-
-.scroll-view {
- position: relative;
- z-index: 0;
-
- overflow: hidden;
- flex: 1;
- min-width: 0;
- min-height: 0;
-}
-
-.highlight {
- background: none;
- padding: 0;
-}
-
-.highlight .region {
- position: absolute;
- pointer-events: none;
- z-index: -1;
-}
-
-.lines {
- min-width: 100%;
- position: relative;
- z-index: 1;
-}
-
-.line {
- white-space: pre;
-
- &.cursor-line .fold-marker::after {
- opacity: 1;
- }
-}
-
-.fold-marker {
- cursor: default;
-
- &::after {
- .icon(0.8em, inline);
-
- content: @ellipsis;
- padding-left: 0.2em;
- }
-}
-
-.placeholder-text {
- position: absolute;
- color: @text-color-subtle;
-}
-
-.invisible-character {
- font-weight: normal !important;
- font-style: normal !important;
-}
-
-.indent-guide {
- display: inline-block;
- box-shadow: inset 1px 0;
-}
-
-.hidden-input {
- padding: 0;
- border: 0;
- position: absolute;
- z-index: -1;
- top: 0;
- left: 0;
- opacity: 0;
- width: 1px;
-}
-
-.cursor {
- z-index: 4;
- pointer-events: none;
- box-sizing: border-box;
- position: absolute;
- border-left: 1px solid;
- opacity: 0;
-}
-
-&.is-focused .cursor {
- opacity: 1;
-}
-
-.cursors.blink-off .cursor {
- opacity: 0;
-}
-
-.horizontal-scrollbar {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
-
- height: 15px;
- overflow-x: auto;
- overflow-y: hidden;
- z-index: 3;
- cursor: default;
-
- .scrollbar-content {
- height: 15px;
- }
-}
-
-.vertical-scrollbar {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
-
- width: 15px;
- overflow-x: hidden;
- overflow-y: auto;
- z-index: 3;
- cursor: default;
-}
-
-.scrollbar-corner {
- position: absolute;
- overflow: auto;
- bottom: 0;
- right: 0;
-}