Merge branch 'master' into aw/custom-line-number-gutter

This commit is contained in:
Ash Wilson
2018-07-30 09:07:20 -04:00
16 changed files with 24345 additions and 64 deletions

6563
apm/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "1.19.0"
"atom-package-manager": "2.0.0"
}
}

View File

@@ -79,8 +79,8 @@
'ctrl-shift-tab ^ctrl': 'pane:move-active-item-to-top-of-stack'
'cmd-=': 'window:increase-font-size'
'cmd-+': 'window:increase-font-size'
'cmd--': 'window:decrease-font-size'
'cmd-_': 'window:decrease-font-size'
'cmd--': 'window:decrease-font-size'
'cmd-0': 'window:reset-font-size'
'cmd-k up': 'pane:split-up-and-copy-active-item' # Atom Specific

5971
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "1.30.0-dev",
"version": "1.31.0-dev",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/main-process/main.js",
"repository": {
@@ -15,23 +15,48 @@
"electronVersion": "2.0.5",
"dependencies": {
"@atom/nsfw": "^1.0.18",
"@atom/watcher": "1.0.3",
"@atom/source-map-support": "^0.3.4",
"@atom/watcher": "1.0.3",
"about": "https://www.atom.io/api/packages/about/versions/1.10.0/tarball",
"archive-view": "https://www.atom.io/api/packages/archive-view/versions/0.65.1/tarball",
"async": "0.2.6",
"atom-dark-syntax": "https://www.atom.io/api/packages/atom-dark-syntax/versions/0.29.0/tarball",
"atom-dark-ui": "https://www.atom.io/api/packages/atom-dark-ui/versions/0.53.2/tarball",
"atom-keymap": "8.2.10",
"atom-light-syntax": "https://www.atom.io/api/packages/atom-light-syntax/versions/0.29.0/tarball",
"atom-light-ui": "https://www.atom.io/api/packages/atom-light-ui/versions/0.46.2/tarball",
"atom-select-list": "^0.7.0",
"atom-ui": "0.4.1",
"autocomplete-atom-api": "https://www.atom.io/api/packages/autocomplete-atom-api/versions/0.10.7/tarball",
"autocomplete-css": "https://www.atom.io/api/packages/autocomplete-css/versions/0.17.5/tarball",
"autocomplete-html": "https://www.atom.io/api/packages/autocomplete-html/versions/0.8.4/tarball",
"autocomplete-plus": "https://www.atom.io/api/packages/autocomplete-plus/versions/2.40.6/tarball",
"autocomplete-snippets": "https://www.atom.io/api/packages/autocomplete-snippets/versions/1.12.0/tarball",
"autoflow": "https://www.atom.io/api/packages/autoflow/versions/0.29.4/tarball",
"autosave": "https://www.atom.io/api/packages/autosave/versions/0.24.6/tarball",
"babel-core": "5.8.38",
"background-tips": "https://www.atom.io/api/packages/background-tips/versions/0.28.0/tarball",
"base16-tomorrow-dark-theme": "https://www.atom.io/api/packages/base16-tomorrow-dark-theme/versions/1.5.0/tarball",
"base16-tomorrow-light-theme": "https://www.atom.io/api/packages/base16-tomorrow-light-theme/versions/1.5.0/tarball",
"bookmarks": "https://www.atom.io/api/packages/bookmarks/versions/0.45.1/tarball",
"bracket-matcher": "https://www.atom.io/api/packages/bracket-matcher/versions/0.89.2/tarball",
"cached-run-in-this-context": "0.4.1",
"chai": "3.5.0",
"chart.js": "^2.3.0",
"clear-cut": "^2.0.2",
"coffee-script": "1.12.7",
"color": "^0.7.3",
"command-palette": "https://www.atom.io/api/packages/command-palette/versions/0.43.5/tarball",
"dalek": "https://www.atom.io/api/packages/dalek/versions/0.2.2/tarball",
"dedent": "^0.7.0",
"deprecation-cop": "https://www.atom.io/api/packages/deprecation-cop/versions/0.56.9/tarball",
"dev-live-reload": "https://www.atom.io/api/packages/dev-live-reload/versions/0.48.1/tarball",
"devtron": "1.3.0",
"encoding-selector": "https://www.atom.io/api/packages/encoding-selector/versions/0.23.9/tarball",
"etch": "^0.12.6",
"event-kit": "^2.5.0",
"exception-reporting": "https://www.atom.io/api/packages/exception-reporting/versions/0.43.1/tarball",
"find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.215.11/tarball",
"find-parent-dir": "^0.3.0",
"first-mate": "7.1.1",
"focus-trap": "2.4.5",
@@ -39,24 +64,76 @@
"fs-plus": "^3.0.1",
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
"fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.8.2/tarball",
"git-diff": "https://www.atom.io/api/packages/git-diff/versions/1.3.9/tarball",
"git-utils": "5.4.0",
"github": "https://www.atom.io/api/packages/github/versions/0.18.2/tarball",
"glob": "^7.1.1",
"go-to-line": "https://www.atom.io/api/packages/go-to-line/versions/0.33.0/tarball",
"grammar-selector": "https://www.atom.io/api/packages/grammar-selector/versions/0.50.1/tarball",
"grim": "1.5.0",
"image-view": "https://www.atom.io/api/packages/image-view/versions/0.63.0/tarball",
"incompatible-packages": "https://www.atom.io/api/packages/incompatible-packages/versions/0.27.3/tarball",
"jasmine-json": "~0.0",
"jasmine-reporters": "1.1.0",
"jasmine-tagged": "^1.1.4",
"key-path-helpers": "^0.4.0",
"keybinding-resolver": "https://www.atom.io/api/packages/keybinding-resolver/versions/0.38.2/tarball",
"language-c": "https://www.atom.io/api/packages/language-c/versions/0.60.0/tarball",
"language-clojure": "https://www.atom.io/api/packages/language-clojure/versions/0.22.7/tarball",
"language-coffee-script": "https://www.atom.io/api/packages/language-coffee-script/versions/0.49.3/tarball",
"language-csharp": "https://www.atom.io/api/packages/language-csharp/versions/1.0.4/tarball",
"language-css": "https://www.atom.io/api/packages/language-css/versions/0.42.11/tarball",
"language-gfm": "https://www.atom.io/api/packages/language-gfm/versions/0.90.5/tarball",
"language-git": "https://www.atom.io/api/packages/language-git/versions/0.19.1/tarball",
"language-go": "https://www.atom.io/api/packages/language-go/versions/0.46.0/tarball",
"language-html": "https://www.atom.io/api/packages/language-html/versions/0.51.1/tarball",
"language-hyperlink": "https://www.atom.io/api/packages/language-hyperlink/versions/0.16.3/tarball",
"language-java": "https://www.atom.io/api/packages/language-java/versions/0.30.0/tarball",
"language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.129.1/tarball",
"language-json": "https://www.atom.io/api/packages/language-json/versions/0.19.2/tarball",
"language-less": "https://www.atom.io/api/packages/language-less/versions/0.34.2/tarball",
"language-make": "https://www.atom.io/api/packages/language-make/versions/0.22.3/tarball",
"language-mustache": "https://www.atom.io/api/packages/language-mustache/versions/0.14.5/tarball",
"language-objective-c": "https://www.atom.io/api/packages/language-objective-c/versions/0.15.1/tarball",
"language-perl": "https://www.atom.io/api/packages/language-perl/versions/0.38.1/tarball",
"language-php": "https://www.atom.io/api/packages/language-php/versions/0.44.0/tarball",
"language-property-list": "https://www.atom.io/api/packages/language-property-list/versions/0.9.1/tarball",
"language-python": "https://www.atom.io/api/packages/language-python/versions/0.51.0/tarball",
"language-ruby": "https://www.atom.io/api/packages/language-ruby/versions/0.72.2/tarball",
"language-ruby-on-rails": "https://www.atom.io/api/packages/language-ruby-on-rails/versions/0.25.3/tarball",
"language-sass": "https://www.atom.io/api/packages/language-sass/versions/0.62.0/tarball",
"language-shellscript": "https://www.atom.io/api/packages/language-shellscript/versions/0.27.0/tarball",
"language-source": "https://www.atom.io/api/packages/language-source/versions/0.9.0/tarball",
"language-sql": "https://www.atom.io/api/packages/language-sql/versions/0.25.10/tarball",
"language-text": "https://www.atom.io/api/packages/language-text/versions/0.7.4/tarball",
"language-todo": "https://www.atom.io/api/packages/language-todo/versions/0.29.4/tarball",
"language-toml": "https://www.atom.io/api/packages/language-toml/versions/0.18.2/tarball",
"language-typescript": "https://www.atom.io/api/packages/language-typescript/versions/0.4.0/tarball",
"language-xml": "https://www.atom.io/api/packages/language-xml/versions/0.35.2/tarball",
"language-yaml": "https://www.atom.io/api/packages/language-yaml/versions/0.32.0/tarball",
"less-cache": "1.1.0",
"line-ending-selector": "https://www.atom.io/api/packages/line-ending-selector/versions/0.7.7/tarball",
"line-top-index": "0.3.1",
"link": "https://www.atom.io/api/packages/link/versions/0.31.4/tarball",
"markdown-preview": "https://www.atom.io/api/packages/markdown-preview/versions/0.159.20/tarball",
"marked": "^0.3.12",
"metrics": "https://www.atom.io/api/packages/metrics/versions/1.6.0/tarball",
"minimatch": "^3.0.3",
"mocha": "2.5.1",
"mocha-junit-reporter": "^1.13.0",
"mocha-multi-reporters": "^1.1.4",
"mock-spawn": "^0.2.6",
"normalize-package-data": "^2.0.0",
"notifications": "https://www.atom.io/api/packages/notifications/versions/0.70.5/tarball",
"nslog": "^3",
"one-dark-syntax": "https://www.atom.io/api/packages/one-dark-syntax/versions/1.8.4/tarball",
"one-dark-ui": "https://www.atom.io/api/packages/one-dark-ui/versions/1.12.4/tarball",
"one-light-syntax": "https://www.atom.io/api/packages/one-light-syntax/versions/1.8.4/tarball",
"one-light-ui": "https://www.atom.io/api/packages/one-light-ui/versions/1.12.4/tarball",
"oniguruma": "6.2.1",
"open-on-github": "https://www.atom.io/api/packages/open-on-github/versions/1.3.1/tarball",
"package-generator": "https://www.atom.io/api/packages/package-generator/versions/1.3.0/tarball",
"pathwatcher": "8.0.1",
"postcss": "5.2.4",
"postcss-selector-parser": "2.2.1",
@@ -69,13 +146,28 @@
"season": "^6.0.2",
"semver": "^4.3.3",
"service-hub": "^0.7.4",
"settings-view": "https://www.atom.io/api/packages/settings-view/versions/0.255.0/tarball",
"sinon": "1.17.4",
"snippets": "https://www.atom.io/api/packages/snippets/versions/1.3.3/tarball",
"solarized-dark-syntax": "https://www.atom.io/api/packages/solarized-dark-syntax/versions/1.1.5/tarball",
"solarized-light-syntax": "https://www.atom.io/api/packages/solarized-light-syntax/versions/1.1.5/tarball",
"spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.0/tarball",
"status-bar": "https://www.atom.io/api/packages/status-bar/versions/1.8.15/tarball",
"styleguide": "https://www.atom.io/api/packages/styleguide/versions/0.49.11/tarball",
"symbols-view": "https://www.atom.io/api/packages/symbols-view/versions/0.118.2/tarball",
"tabs": "https://www.atom.io/api/packages/tabs/versions/0.109.2/tarball",
"temp": "^0.8.3",
"text-buffer": "13.14.5",
"timecop": "https://www.atom.io/api/packages/timecop/versions/0.36.2/tarball",
"tree-sitter": "0.13.0",
"tree-view": "https://www.atom.io/api/packages/tree-view/versions/0.222.0/tarball",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.8",
"update-package-dependencies": "https://www.atom.io/api/packages/update-package-dependencies/versions/0.13.1/tarball",
"welcome": "https://www.atom.io/api/packages/welcome/versions/0.36.6/tarball",
"whitespace": "https://www.atom.io/api/packages/whitespace/versions/0.37.6/tarball",
"winreg": "^1.2.1",
"wrap-guide": "https://www.atom.io/api/packages/wrap-guide/versions/0.40.3/tarball",
"yargs": "^3.23.0"
},
"packageDependencies": {
@@ -96,7 +188,7 @@
"autocomplete-atom-api": "0.10.7",
"autocomplete-css": "0.17.5",
"autocomplete-html": "0.8.4",
"autocomplete-plus": "2.40.6",
"autocomplete-plus": "2.40.7",
"autocomplete-snippets": "1.12.0",
"autoflow": "0.29.4",
"autosave": "0.24.6",
@@ -109,7 +201,7 @@
"dev-live-reload": "0.48.1",
"encoding-selector": "0.23.9",
"exception-reporting": "0.43.1",
"find-and-replace": "0.215.11",
"find-and-replace": "0.215.12",
"fuzzy-finder": "1.8.2",
"github": "0.18.2",
"git-diff": "1.3.9",
@@ -158,7 +250,7 @@
"language-perl": "0.38.1",
"language-php": "0.44.0",
"language-property-list": "0.9.1",
"language-python": "0.51.0",
"language-python": "0.51.1",
"language-ruby": "0.72.2",
"language-ruby-on-rails": "0.25.3",
"language-sass": "0.62.0",

View File

@@ -29,7 +29,6 @@ const argv = yargs
const checkChromedriverVersion = require('./lib/check-chromedriver-version')
const cleanOutputDirectory = require('./lib/clean-output-directory')
const cleanPackageLock = require('./lib/clean-package-lock')
const codeSignOnMac = require('./lib/code-sign-on-mac')
const codeSignOnWindows = require('./lib/code-sign-on-windows')
const compressArtifacts = require('./lib/compress-artifacts')
@@ -60,7 +59,6 @@ const CONFIG = require('./config')
let binariesPromise = Promise.resolve()
if (!argv.existingBinaries) {
cleanPackageLock()
checkChromedriverVersion()
cleanOutputDirectory()
copyAssets()

View File

@@ -1,18 +0,0 @@
// This module exports a function that deletes all `package-lock.json` files that do
// not exist under a `node_modules` directory.
'use strict'
const CONFIG = require('../config')
const fs = require('fs-extra')
const glob = require('glob')
const path = require('path')
module.exports = function () {
console.log('Deleting problematic package-lock.json files')
let paths = glob.sync(path.join(CONFIG.repositoryRootPath, '**', 'package-lock.json'), {ignore: [path.join('**', 'node_modules', '**'), path.join('**', 'vsts', '**')]})
for (let path of paths) {
fs.unlinkSync(path)
}
}

11381
script/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,3 +4,6 @@
bare = false
logallrefupdates = true
ignorecase = true
[remote "origin"]
url = https://github.com/example-user/example-repo.git
fetch = +refs/heads/*:refs/remotes/origin/*

View File

@@ -219,6 +219,34 @@ describe('Pane', () => {
runs(() => expect(eventOrder).toEqual(['add', 'remove']))
})
it('subscribes to be notified when item terminates its pending state', () => {
const fakeDisposable = { dispose: () => {} }
const spy = jasmine.createSpy('onDidTerminatePendingState').andReturn((fakeDisposable))
const pane = new Pane(paneParams({items: []}))
const item = {
getTitle: () => '',
onDidTerminatePendingState: spy
}
pane.addItem(item)
expect(spy).toHaveBeenCalled()
})
it('subscribes to be notified when item is destroyed', () => {
const fakeDisposable = { dispose: () => {} }
const spy = jasmine.createSpy('onDidDestroy').andReturn((fakeDisposable))
const pane = new Pane(paneParams({items: []}))
const item = {
getTitle: () => '',
onDidDestroy: spy
}
pane.addItem(item)
expect(spy).toHaveBeenCalled()
})
describe('when using the old API of ::addItem(item, index)', () => {
beforeEach(() => spyOn(Grim, 'deprecate'))

View File

@@ -1000,10 +1000,13 @@ describe('Project', () => {
const observed = []
const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo))
const repositoryPath = path.join(__dirname, '..')
atom.project.addPath(repositoryPath)
const projectRootPath = temp.mkdirSync()
const fixtureRepoPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git'))
fs.copySync(fixtureRepoPath, path.join(projectRootPath, '.git'))
atom.project.addPath(projectRootPath)
expect(observed.length).toBe(1)
expect(observed[0].getOriginURL()).toContain('atom/atom')
expect(observed[0].getOriginURL()).toEqual('https://github.com/example-user/example-repo.git')
disposable.dispose()
})
@@ -1012,9 +1015,16 @@ describe('Project', () => {
const observed = []
const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo))
atom.project.addPath(__dirname)
const projectRootPath = temp.mkdirSync()
const fixtureRepoPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git'))
fs.copySync(fixtureRepoPath, path.join(projectRootPath, '.git'))
const projectSubDirPath = path.join(projectRootPath, 'sub-dir')
fs.mkdirSync(projectSubDirPath)
atom.project.addPath(projectSubDirPath)
expect(observed.length).toBe(1)
expect(observed[0].getOriginURL()).toContain('atom/atom')
expect(observed[0].getOriginURL()).toEqual('https://github.com/example-user/example-repo.git')
disposable.dispose()
})

View File

@@ -1304,6 +1304,206 @@ describe('TreeSitterLanguageMode', () => {
})
})
describe('.bufferRangeForScopeAtPosition(selector?, position)', () => {
describe('when selector = null', () => {
it('returns the range of the smallest node at position', async () => {
const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
id: 'javascript',
parser: 'tree-sitter-javascript'
})
buffer.setText('foo({bar: baz});')
buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar}))
await nextHighlightingUpdate(buffer.getLanguageMode())
expect(editor.bufferRangeForScopeAtPosition(null, [0, 6])).toEqual(
[[0, 5], [0, 8]]
)
expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual(
[[0, 8], [0, 9]]
)
})
it('includes nodes in injected syntax trees', async () => {
const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
id: 'javascript',
parser: 'tree-sitter-javascript',
scopes: {},
injectionRegExp: 'javascript',
injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT]
})
const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, {
id: 'html',
parser: 'tree-sitter-html',
scopes: {},
injectionRegExp: 'html',
injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
})
atom.grammars.addGrammar(jsGrammar)
atom.grammars.addGrammar(htmlGrammar)
buffer.setText(`
<div>
<script>
html \`
<span>\${person.name}</span>
\`
</script>
</div>
`)
const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars})
buffer.setLanguageMode(languageMode)
await nextHighlightingUpdate(languageMode)
await nextHighlightingUpdate(languageMode)
await nextHighlightingUpdate(languageMode)
const nameProperty = buffer.findSync('name')
const {start} = nameProperty
const position = Object.assign({}, start, {column: start.column + 2})
expect(languageMode.bufferRangeForScopeAtPosition(null, position))
.toEqual(nameProperty)
})
})
describe('with a selector', () => {
it('returns the range of the smallest matching node at position', async () => {
const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
id: 'javascript',
parser: 'tree-sitter-javascript'
})
buffer.setText('foo({bar: baz});')
buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar}))
await nextHighlightingUpdate(buffer.getLanguageMode())
expect(editor.bufferRangeForScopeAtPosition('.property_identifier', [0, 6])).toEqual(
buffer.findSync('bar')
)
expect(editor.bufferRangeForScopeAtPosition('.call_expression', [0, 6])).toEqual(
[[0, 0], [0, buffer.getText().length - 1]]
)
expect(editor.bufferRangeForScopeAtPosition('.object', [0, 9])).toEqual(
buffer.findSync('{bar: baz}')
)
})
it('includes nodes in injected syntax trees', async () => {
const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
id: 'javascript',
parser: 'tree-sitter-javascript',
scopes: {},
injectionRegExp: 'javascript',
injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT]
})
const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, {
id: 'html',
parser: 'tree-sitter-html',
scopes: {},
injectionRegExp: 'html',
injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
})
atom.grammars.addGrammar(jsGrammar)
atom.grammars.addGrammar(htmlGrammar)
buffer.setText(`
<div>
<script>
html \`
<span>\${person.name}</span>
\`
</script>
</div>
`)
const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars})
buffer.setLanguageMode(languageMode)
await nextHighlightingUpdate(languageMode)
await nextHighlightingUpdate(languageMode)
await nextHighlightingUpdate(languageMode)
const nameProperty = buffer.findSync('name')
const {start} = nameProperty
const position = Object.assign({}, start, {column: start.column + 2})
expect(languageMode.bufferRangeForScopeAtPosition('.property_identifier', position))
.toEqual(nameProperty)
expect(languageMode.bufferRangeForScopeAtPosition('.element', position))
.toEqual(buffer.findSync('<span>\\${person\\.name}</span>'))
})
it('accepts node-matching functions as selectors', async () => {
const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
id: 'javascript',
parser: 'tree-sitter-javascript',
scopes: {},
injectionRegExp: 'javascript',
injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT]
})
const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, {
id: 'html',
parser: 'tree-sitter-html',
scopes: {},
injectionRegExp: 'html',
injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
})
atom.grammars.addGrammar(jsGrammar)
atom.grammars.addGrammar(htmlGrammar)
buffer.setText(`
<div>
<script>
html \`
<span>\${person.name}</span>
\`
</script>
</div>
`)
const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars})
buffer.setLanguageMode(languageMode)
await nextHighlightingUpdate(languageMode)
await nextHighlightingUpdate(languageMode)
await nextHighlightingUpdate(languageMode)
const nameProperty = buffer.findSync('name')
const {start} = nameProperty
const position = Object.assign({}, start, {column: start.column + 2})
const templateStringInCallExpression = node =>
node.type === 'template_string' && node.parent.type === 'call_expression'
expect(languageMode.bufferRangeForScopeAtPosition(templateStringInCallExpression, position))
.toEqual([[3, 19], [5, 15]])
})
})
})
describe('.getSyntaxNodeAtPosition(position, where?)', () => {
it('returns the range of the smallest matching node at position', async () => {
const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
id: 'javascript',
parser: 'tree-sitter-javascript'
})
buffer.setText('foo(bar({x: 2}));')
const languageMode = new TreeSitterLanguageMode({buffer, grammar})
buffer.setLanguageMode(languageMode)
await nextHighlightingUpdate(languageMode)
expect(languageMode.getSyntaxNodeAtPosition([0, 6]).range).toEqual(
buffer.findSync('bar')
)
const findFoo = node =>
node.type === 'call_expression' && node.firstChild.text === 'foo'
expect(languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range).toEqual(
[[0, 0], [0, buffer.getText().length - 1]]
)
})
})
describe('TextEditor.selectLargerSyntaxNode and .selectSmallerSyntaxNode', () => {
it('expands and contracts the selection based on the syntax tree', async () => {
const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {

View File

@@ -614,15 +614,15 @@ class Pane {
if (this.items.includes(item)) return
const itemSubscriptions = new CompositeDisposable()
this.subscriptionsPerItem.set(item, itemSubscriptions)
if (typeof item.onDidDestroy === 'function') {
const itemSubscriptions = new CompositeDisposable()
itemSubscriptions.add(item.onDidDestroy(() => this.removeItem(item, false)))
if (typeof item.onDidTerminatePendingState === 'function') {
itemSubscriptions.add(item.onDidTerminatePendingState(() => {
if (this.getPendingItem() === item) this.clearPendingItem()
}))
}
this.subscriptionsPerItem.set(item, itemSubscriptions)
}
if (typeof item.onDidTerminatePendingState === 'function') {
itemSubscriptions.add(item.onDidTerminatePendingState(() => {
if (this.getPendingItem() === item) this.clearPendingItem()
}))
}
this.items.splice(index, 0, item)

38
src/selectors.js Normal file
View File

@@ -0,0 +1,38 @@
module.exports = {selectorMatchesAnyScope, matcherForSelector}
const {isSubset} = require('underscore-plus')
// Private: Parse a selector into parts.
// If already parsed, returns the selector unmodified.
//
// * `selector` a {String|Array<String>} specifying what to match
// Returns selector parts, an {Array<String>}.
function parse (selector) {
return typeof selector === 'string'
? selector.replace(/^\./, '').split('.')
: selector
}
const always = scope => true
// Essential: Return a matcher function for a selector.
//
// * selector, a {String} selector
// Returns {(scope: String) -> Boolean}, a matcher function returning
// true iff the scope matches the selector.
function matcherForSelector (selector) {
const parts = parse(selector)
if (typeof parts === 'function') return parts
return selector
? scope => isSubset(parts, parse(scope))
: always
}
// Essential: Return true iff the selector matches any provided scope.
//
// * {String} selector
// * {Array<String>} scopes
// Returns {Boolean} true if any scope matches the selector.
function selectorMatchesAnyScope (selector, scopes) {
return !selector || scopes.some(matcherForSelector(selector))
}

View File

@@ -7,6 +7,7 @@ const ScopeDescriptor = require('./scope-descriptor')
const NullGrammar = require('./null-grammar')
const {OnigRegExp} = require('oniguruma')
const {toFirstMateScopeId, fromFirstMateScopeId} = require('./first-mate-helpers')
const {selectorMatchesAnyScope} = require('./selectors')
const NON_WHITESPACE_REGEX = /\S/
@@ -726,14 +727,6 @@ class TextMateLanguageMode {
TextMateLanguageMode.prototype.chunkSize = 50
function selectorMatchesAnyScope (selector, scopes) {
const targetClasses = selector.replace(/^\./, '').split('.')
return scopes.some((scope) => {
const scopeClasses = scope.split('.')
return _.isSubset(targetClasses, scopeClasses)
})
}
class TextMateHighlightIterator {
constructor (languageMode) {
this.languageMode = languageMode

View File

@@ -5,6 +5,7 @@ const {Emitter, Disposable} = require('event-kit')
const ScopeDescriptor = require('./scope-descriptor')
const TokenizedLine = require('./tokenized-line')
const TextMateLanguageMode = require('./text-mate-language-mode')
const {matcherForSelector} = require('./selectors')
let nextId = 0
const MAX_RANGE = new Range(Point.ZERO, Point.INFINITY).freeze()
@@ -20,6 +21,13 @@ class TreeSitterLanguageMode {
}
})
}
if (!Parser.SyntaxNode.prototype.hasOwnProperty('range')) {
Object.defineProperty(Parser.SyntaxNode.prototype, 'range', {
get () {
return rangeForNode(this)
}
})
}
}
constructor ({buffer, grammar, config, grammars}) {
@@ -334,7 +342,7 @@ class TreeSitterLanguageMode {
Section - Syntax Tree APIs
*/
getRangeForSyntaxNodeContainingRange (range) {
getSyntaxNodeContainingRange (range, where = _ => true) {
const startIndex = this.buffer.characterIndexForPosition(range.start)
const endIndex = this.buffer.characterIndexForPosition(range.end)
const searchEndIndex = Math.max(0, endIndex - 1)
@@ -342,17 +350,35 @@ class TreeSitterLanguageMode {
let smallestNode
this._forEachTreeWithRange(range, tree => {
let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex)
while (node && !nodeContainsIndices(node, startIndex, endIndex)) {
while (node) {
if (nodeContainsIndices(node, startIndex, endIndex) && where(node)) {
if (nodeIsSmaller(node, smallestNode)) smallestNode = node
break
}
node = node.parent
}
if (nodeIsSmaller(node, smallestNode)) smallestNode = node
})
if (smallestNode) return rangeForNode(smallestNode)
return smallestNode
}
bufferRangeForScopeAtPosition (position) {
return this.getRangeForSyntaxNodeContainingRange(new Range(position, position))
getRangeForSyntaxNodeContainingRange (range, where) {
const node = this.getSyntaxNodeContainingRange(range, where)
return node && node.range
}
getSyntaxNodeAtPosition (position, where) {
return this.getSyntaxNodeContainingRange(new Range(position, position), where)
}
bufferRangeForScopeAtPosition (selector, position) {
if (typeof selector === 'string') {
const match = matcherForSelector(selector)
selector = ({type}) => match(type)
}
if (selector === null) selector = undefined
const node = this.getSyntaxNodeAtPosition(position, selector)
return node && node.range
}
/*
@@ -849,15 +875,10 @@ class LayerHighlightIterator {
let result = false
const {endIndex} = this.treeCursor
let depth = this.containingNodeEndIndices.length
while (depth > 1) {
// Once the iterator has found a scope boundary, it needs to stay at the same
// position, so it should not move up if the parent node ends later than the
// current node.
if ((!atLastChild || this.openTags.length || this.closeTags.length) &&
this.containingNodeEndIndices[depth - 2] > endIndex) {
break
}
// The iterator should not move up until it has visited all of the children of this node.
while (depth > 1 && (atLastChild || this.containingNodeEndIndices[depth - 2] === endIndex)) {
atLastChild = false
result = true
this.treeCursor.gotoParent()
this.containingNodeTypes.pop()
@@ -873,10 +894,11 @@ class LayerHighlightIterator {
_moveDown () {
let result = false
const {startIndex} = this.treeCursor
// Once the iterator has found a scope boundary, it needs to stay at the same
// position, so it should not move down if the first child node starts later than the
// current node.
while (this.treeCursor.gotoFirstChild()) {
// Once the iterator has found a scope boundary, it needs to stay at the same
// position, so it should not move down if the first child node starts later than the
// current node.
if ((this.closeTags.length || this.openTags.length) &&
this.treeCursor.startIndex > startIndex) {
this.treeCursor.gotoParent()