mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-11 19:17:09 +03:00
Merge branch 'master' into no-request
This commit is contained in:
commit
4eef8250fb
@ -1,5 +1,7 @@
|
||||
env:
|
||||
PYTHON_VERSION: 3.10
|
||||
GITHUB_TOKEN: ENCRYPTED[13da504dc34d1608564d891fb7f456b546019d07d1abb059f9ab4296c56ccc0e6e32c7b313629776eda40ab74a54e95c]
|
||||
# The above token, is a GitHub API Token, that allows us to download RipGrep without concern of API limits
|
||||
|
||||
linux_task:
|
||||
alias: linux
|
||||
|
@ -7,7 +7,7 @@ module.exports = {
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:node/recommended",
|
||||
"plugin:jsdoc/recommended"
|
||||
// "plugin:jsdoc/recommended"
|
||||
],
|
||||
overrides: [],
|
||||
parserOptions: {
|
||||
|
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,3 +1,5 @@
|
||||
CHANGELOG.* merge=union
|
||||
|
||||
# Specs depend on character counts, if we don't specify the line endings the
|
||||
# fixtures will vary depending on platform
|
||||
spec/fixtures/**/*.js text eol=lf
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,6 +8,8 @@ Thumbs.db
|
||||
.nvm-version
|
||||
.vscode
|
||||
.python-version
|
||||
.envrc
|
||||
.tool-versions
|
||||
node_modules
|
||||
*.log
|
||||
/tags
|
||||
|
44
CHANGELOG.md
44
CHANGELOG.md
@ -6,12 +6,56 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Added a modern implementation of Tree-sitter grammars behind an experimental flag. Enable the “Use Modern Tree-Sitter Implementation” in the Core settings to try it out.
|
||||
|
||||
## 1.105.0
|
||||
|
||||
- Rebranded notifications, using our backend to find new versions of package,
|
||||
and our github repository to find issues on Pulsar. Also fixed the "view issue"
|
||||
and "create issue" buttons that were not working
|
||||
- Bumped to latest version of `second-mate`, fixing a memory usage issue in `vscode-oniguruma`
|
||||
- Removed a cache for native modules - fix bugs where an user rebuilds a native
|
||||
module outside of Pulsar, but Pulsar refuses to load anyway
|
||||
- Removed `nslog` dependency
|
||||
- Fixed an error where the GitHub package tried to interact with a diff view after it was closed
|
||||
- Fixed RPM installation failure when Atom was installed on the same machine
|
||||
- Added a new set of Package `activationHooks`, `...:uri-opened` lets a package activate when any URI is opened within Pulsar, and `...:file-name-opened` lets a package activate when any specific filename is opened within Pulsar.
|
||||
|
||||
### Pulsar
|
||||
- Added: Add new `...:uri-opened` && `...:file-name-opened` Package Activation Hook [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/518)
|
||||
- Fixed: Properly localize Download/Stargazer Counts within `settings-view` [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/526)
|
||||
- Added: Add bookmarks service for consumption by other packages [@savetheclocktower](https://github.com/pulsar-edit/pulsar/pull/525)
|
||||
- Added: Bundle notifications [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/529)
|
||||
- Fixed: Fix Ripgrep download issues in CirrusCI [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/530)
|
||||
- Removed: Revert Incorrect Commit [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/528)
|
||||
- Fixed: Making CI green, hopefully [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/523)
|
||||
- Bumped: Bump `second-mate` to 96866771 [@savetheclocktower](https://github.com/pulsar-edit/pulsar/pull/524)
|
||||
- Removed: Remove cache of incompatible native packages [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/493)
|
||||
- Added: Simplify and bundle fuzzy-finder [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/515)
|
||||
- Added: Bundle find and replace [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/517)
|
||||
- Added: Bundle tree view [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/513)
|
||||
- Added: Bundle `autocomplete-atom-api` [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/476)
|
||||
- Added: Add FPM option to stop rpm buildid clash [@Daeraxa](https://github.com/pulsar-edit/pulsar/pull/505)
|
||||
- Bumped: chore(deps): update dependency minimist [security] [@renovate](https://github.com/pulsar-edit/pulsar/pull/502)
|
||||
- Fixed: Disable Failing Tests [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/477)
|
||||
- Bumped: chore(deps): update dependency ajv to 6.12.3 [security] [@renovate](https://github.com/pulsar-edit/pulsar/pull/501)
|
||||
- Bumped: chore(deps): update dependency async to 3.2.2 [security] [@renovate](https://github.com/pulsar-edit/pulsar/pull/495)
|
||||
- Added: Add "icon only" class to settings view icon [@Daeraxa](https://github.com/pulsar-edit/pulsar/pull/456)
|
||||
- Bumped: chore(deps): update dependency minimatch [security] [@renovate](https://github.com/pulsar-edit/pulsar/pull/496)
|
||||
- Removed: Remove `nslog` dependency [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/494)
|
||||
- Added: Setup Renovate [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/469)
|
||||
- Fixed: Don't mark diff ranges on a destroyed buffer [@savetheclocktower](https://github.com/pulsar-edit/pulsar/pull/481)
|
||||
- Added: First Architectural Design Records [@mauricioszabo](https://github.com/pulsar-edit/pulsar/pull/480)
|
||||
- Bumped: use pular's `typscript-simple` fork, which bumps `typescript` to 5.0.3 [@Meadowsys](https://github.com/pulsar-edit/pulsar/pull/458)
|
||||
- Added: CI: cache and restore dependencies, plus skip rebuilding all over the place (saves a lot of time) [@DeeDeeG](https://github.com/pulsar-edit/pulsar/pull/492)
|
||||
|
||||
### notifications
|
||||
- Fixed: Cleanup and rename [@Sertonix](https://github.com/pulsar-edit/notifications/pull/1)
|
||||
- Added: reject promise with Error instance [@Sertonix](https://github.com/pulsar-edit/notifications/pull/2)
|
||||
- Added: Add our Testing Action [@confused-Techie](https://github.com/pulsar-edit/notifications/pull/3)
|
||||
- Fixed: Change atom strings to pulsar [@mdibella-dev](https://github.com/pulsar-edit/notifications/pull/4)
|
||||
- Bumped: Bump to v3.2 of action-pulsar-dependency [@confused-Techie](https://github.com/pulsar-edit/notifications/pull/5)
|
||||
- Fixed: Fix all Tests [@confused-Techie](https://github.com/pulsar-edit/notifications/pull/6)
|
||||
|
||||
## 1.104.0
|
||||
|
||||
|
13
package.json
13
package.json
@ -2,7 +2,7 @@
|
||||
"name": "pulsar",
|
||||
"author": "Pulsar-Edit <admin@pulsar-edit.dev>",
|
||||
"productName": "Pulsar",
|
||||
"version": "1.104.0-dev",
|
||||
"version": "1.105.0-dev",
|
||||
"description": "A Community-led Hyper-Hackable Text Editor",
|
||||
"branding": {
|
||||
"id": "pulsar",
|
||||
@ -19,6 +19,9 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/pulsar-edit/pulsar/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"license": "MIT",
|
||||
"electronVersion": "12.2.3",
|
||||
"dependencies": {
|
||||
@ -66,6 +69,7 @@
|
||||
"fs-admin": "0.19.0",
|
||||
"fs-plus": "^3.1.1",
|
||||
"fstream": "1.0.12",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"fuzzy-finder": "file:packages/fuzzy-finder",
|
||||
"git-diff": "file:packages/git-diff",
|
||||
"git-utils": "5.7.1",
|
||||
@ -126,7 +130,7 @@
|
||||
"mocha-multi-reporters": "^1.1.4",
|
||||
"mock-spawn": "^0.2.6",
|
||||
"normalize-package-data": "3.0.2",
|
||||
"notifications": "https://codeload.github.com/atom/notifications/legacy.tar.gz/refs/tags/v0.72.1",
|
||||
"notifications": "file:./packages/notifications",
|
||||
"nsfw": "2.2.2",
|
||||
"one-dark-syntax": "file:packages/one-dark-syntax",
|
||||
"one-dark-ui": "file:packages/one-dark-ui",
|
||||
@ -135,7 +139,7 @@
|
||||
"open-on-github": "file:packages/open-on-github",
|
||||
"package-generator": "file:packages/package-generator",
|
||||
"pathwatcher": "^8.1.2",
|
||||
"postcss": "8.2.10",
|
||||
"postcss": "8.2.13",
|
||||
"postcss-selector-parser": "6.0.4",
|
||||
"property-accessors": "^1.1.3",
|
||||
"resolve": "1.18.1",
|
||||
@ -166,6 +170,7 @@
|
||||
"underscore-plus": "^1.7.0",
|
||||
"update-package-dependencies": "file:./packages/update-package-dependencies",
|
||||
"vscode-ripgrep": "1.9.0",
|
||||
"web-tree-sitter": "^0.20.7",
|
||||
"welcome": "file:packages/welcome",
|
||||
"whitespace": "file:./packages/whitespace",
|
||||
"winreg": "^1.2.1",
|
||||
@ -215,7 +220,7 @@
|
||||
"line-ending-selector": "file:./packages/line-ending-selector",
|
||||
"link": "file:./packages/link",
|
||||
"markdown-preview": "file:./packages/markdown-preview",
|
||||
"notifications": "0.72.1",
|
||||
"notifications": "file:./packages/notifications",
|
||||
"open-on-github": "file:./packages/open-on-github",
|
||||
"package-generator": "file:./packages/package-generator",
|
||||
"settings-view": "file:./packages/settings-view",
|
||||
|
@ -51,6 +51,7 @@ describe "CSS property name and value autocompletions", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage('autocomplete-css')
|
||||
waitsForPromise -> atom.packages.activatePackage('language-css') # Used in all CSS languages
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
runs ->
|
||||
provider = atom.packages.getActivePackage('autocomplete-css').mainModule.getProvider()
|
||||
|
31
packages/bookmarks/lib/bookmarks-provider.js
Normal file
31
packages/bookmarks/lib/bookmarks-provider.js
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
class BookmarksProvider {
|
||||
constructor(main) {
|
||||
this.main = main
|
||||
}
|
||||
|
||||
// Returns all bookmarks present in the given editor.
|
||||
//
|
||||
// Each bookmark tracks a buffer range and is represented by an instance of
|
||||
// {DisplayMarker}.
|
||||
//
|
||||
// Will return an empty array if there are no bookmarks in the given editor.
|
||||
//
|
||||
// Keep in mind that a single bookmark can span multiple buffer rows and/or
|
||||
// screen rows. Thus there isn't necessarily a 1:1 correlation between the
|
||||
// number of bookmarks in the editor and the number of bookmark icons that
|
||||
// the user will see in the gutter.
|
||||
getBookmarksForEditor(editor) {
|
||||
let instance = this.getInstanceForEditor(editor)
|
||||
if (!instance) return null
|
||||
return instance.getAllBookmarks()
|
||||
}
|
||||
|
||||
// Returns the instance of the `Bookmarks` class that is responsible for
|
||||
// managing bookmarks in the given editor.
|
||||
getInstanceForEditor(editor) {
|
||||
return this.main.editorsBookmarks.find(b => b.editor.id === editor.id)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BookmarksProvider
|
@ -1,12 +1,13 @@
|
||||
const {CompositeDisposable} = require('atom')
|
||||
const {CompositeDisposable, Emitter} = require('atom')
|
||||
|
||||
module.exports =
|
||||
class Bookmarks {
|
||||
static deserialize (editor, state) {
|
||||
static deserialize(editor, state) {
|
||||
return new Bookmarks(editor, editor.getMarkerLayer(state.markerLayerId))
|
||||
}
|
||||
|
||||
constructor (editor, markerLayer) {
|
||||
constructor(editor, markerLayer) {
|
||||
this.emitter = new Emitter()
|
||||
this.editor = editor
|
||||
this.markerLayer = markerLayer || this.editor.addMarkerLayer({persistent: true})
|
||||
this.decorationLayer = this.editor.decorateMarkerLayer(this.markerLayer, {type: 'line-number', class: 'bookmarked'})
|
||||
@ -24,23 +25,23 @@ class Bookmarks {
|
||||
this.disposables.add(this.editor.onDidDestroy(this.destroy.bind(this)))
|
||||
}
|
||||
|
||||
destroy () {
|
||||
destroy() {
|
||||
this.deactivate()
|
||||
this.markerLayer.destroy()
|
||||
}
|
||||
|
||||
deactivate () {
|
||||
deactivate() {
|
||||
this.decorationLayer.destroy()
|
||||
this.decorationLayerLine.destroy()
|
||||
this.decorationLayerHighlight.destroy()
|
||||
this.disposables.dispose()
|
||||
}
|
||||
|
||||
serialize () {
|
||||
serialize() {
|
||||
return {markerLayerId: this.markerLayer.id}
|
||||
}
|
||||
|
||||
toggleBookmark () {
|
||||
toggleBookmark() {
|
||||
for (const range of this.editor.getSelectedBufferRanges()) {
|
||||
const bookmarks = this.markerLayer.findMarkers({intersectsRowRange: [range.start.row, range.end.row]})
|
||||
if (bookmarks && bookmarks.length > 0) {
|
||||
@ -52,19 +53,34 @@ class Bookmarks {
|
||||
this.disposables.add(bookmark.onDidChange(({isValid}) => {
|
||||
if (!isValid) {
|
||||
bookmark.destroy()
|
||||
// TODO: If N bookmarks are affected by a buffer change,
|
||||
// `did-change-bookmarks` will be emitted N times. We could
|
||||
// debounce this if we were willing to go async.
|
||||
this.emitter.emit('did-change-bookmarks', this.getAllBookmarks())
|
||||
}
|
||||
}))
|
||||
}
|
||||
this.emitter.emit('did-change-bookmarks', this.getAllBookmarks())
|
||||
}
|
||||
}
|
||||
|
||||
clearBookmarks () {
|
||||
getAllBookmarks() {
|
||||
let markers = this.markerLayer.getMarkers()
|
||||
return markers
|
||||
}
|
||||
|
||||
onDidChangeBookmarks(callback) {
|
||||
return this.emitter.on('did-change-bookmarks', callback)
|
||||
}
|
||||
|
||||
clearBookmarks() {
|
||||
for (const bookmark of this.markerLayer.getMarkers()) {
|
||||
bookmark.destroy()
|
||||
}
|
||||
this.emitter.emit('did-change-bookmarks', [])
|
||||
}
|
||||
|
||||
jumpToNextBookmark () {
|
||||
jumpToNextBookmark() {
|
||||
if (this.markerLayer.getMarkerCount() > 0) {
|
||||
const bufferRow = this.editor.getLastCursor().getMarker().getStartBufferPosition().row
|
||||
const markers = this.markerLayer.getMarkers().sort((a, b) => a.compare(b))
|
||||
@ -76,7 +92,7 @@ class Bookmarks {
|
||||
}
|
||||
}
|
||||
|
||||
jumpToPreviousBookmark () {
|
||||
jumpToPreviousBookmark() {
|
||||
if (this.markerLayer.getMarkerCount() > 0) {
|
||||
const bufferRow = this.editor.getLastCursor().getMarker().getStartBufferPosition().row
|
||||
const markers = this.markerLayer.getMarkers().sort((a, b) => b.compare(a))
|
||||
@ -88,7 +104,7 @@ class Bookmarks {
|
||||
}
|
||||
}
|
||||
|
||||
selectToNextBookmark () {
|
||||
selectToNextBookmark() {
|
||||
if (this.markerLayer.getMarkerCount() > 0) {
|
||||
const bufferRow = this.editor.getLastCursor().getMarker().getStartBufferPosition().row
|
||||
const markers = this.markerLayer.getMarkers().sort((a, b) => a.compare(b))
|
||||
@ -103,7 +119,7 @@ class Bookmarks {
|
||||
}
|
||||
}
|
||||
|
||||
selectToPreviousBookmark () {
|
||||
selectToPreviousBookmark() {
|
||||
if (this.markerLayer.getMarkerCount() > 0) {
|
||||
const bufferRow = this.editor.getLastCursor().getMarker().getStartBufferPosition().row
|
||||
const markers = this.markerLayer.getMarkers().sort((a, b) => b.compare(a))
|
||||
|
@ -2,9 +2,10 @@ const {CompositeDisposable} = require('atom')
|
||||
|
||||
const Bookmarks = require('./bookmarks')
|
||||
const BookmarksView = require('./bookmarks-view')
|
||||
const BookmarksProvider = require('./bookmarks-provider')
|
||||
|
||||
module.exports = {
|
||||
activate (bookmarksByEditorId) {
|
||||
activate(bookmarksByEditorId) {
|
||||
this.bookmarksView = null
|
||||
this.editorsBookmarks = []
|
||||
this.disposables = new CompositeDisposable()
|
||||
@ -44,7 +45,7 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
deactivate () {
|
||||
deactivate() {
|
||||
if (this.bookmarksView != null) {
|
||||
this.bookmarksView.destroy()
|
||||
this.bookmarksView = null
|
||||
@ -56,11 +57,16 @@ module.exports = {
|
||||
this.disposables.dispose()
|
||||
},
|
||||
|
||||
serialize () {
|
||||
serialize() {
|
||||
const bookmarksByEditorId = {}
|
||||
for (let bookmarks of this.editorsBookmarks) {
|
||||
bookmarksByEditorId[bookmarks.editor.id] = bookmarks.serialize()
|
||||
}
|
||||
return bookmarksByEditorId
|
||||
},
|
||||
|
||||
provideBookmarks() {
|
||||
this.bookmarksProvider ??= new BookmarksProvider(this)
|
||||
return this.bookmarksProvider
|
||||
}
|
||||
}
|
||||
|
@ -10,5 +10,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-select-list": "^0.7.0"
|
||||
},
|
||||
|
||||
"providedServices": {
|
||||
"bookmarks": {
|
||||
"description": "Provides a list of bookmarks to any package that wants to know about them.",
|
||||
"versions": {
|
||||
"1.0.0": "provideBookmarks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
describe('Bookmarks package', () => {
|
||||
let [workspaceElement, editorElement, editor, bookmarks] = []
|
||||
let workspaceElement, editorElement, editor, bookmarks, provider
|
||||
|
||||
const bookmarkedRangesForEditor = editor => {
|
||||
const decorationsById = editor.decorationsStateForScreenRowRange(0, editor.getLastScreenRow())
|
||||
@ -18,6 +18,7 @@ describe('Bookmarks package', () => {
|
||||
await atom.workspace.open('sample.js')
|
||||
|
||||
bookmarks = (await atom.packages.activatePackage('bookmarks')).mainModule
|
||||
provider = bookmarks.bookmarksProvider
|
||||
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
@ -32,17 +33,28 @@ describe('Bookmarks package', () => {
|
||||
expect(bookmarkedRangesForEditor(editor)).toEqual([])
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(bookmarkedRangesForEditor(editor)).toEqual([[[3, 10], [3, 10]]])
|
||||
|
||||
let marks = provider.getBookmarksForEditor(editor)
|
||||
expect(marks.length).toBe(1)
|
||||
expect(marks.map(m => m.getScreenRange())).toEqual(bookmarkedRangesForEditor(editor))
|
||||
})
|
||||
|
||||
it('removes marker when toggled', () => {
|
||||
let callback = jasmine.createSpy()
|
||||
|
||||
let instance = provider.getInstanceForEditor(editor)
|
||||
instance.onDidChangeBookmarks(callback)
|
||||
|
||||
editor.setCursorBufferPosition([3, 10])
|
||||
expect(bookmarkedRangesForEditor(editor).length).toBe(0)
|
||||
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(bookmarkedRangesForEditor(editor).length).toBe(1)
|
||||
expect(callback.callCount).toBe(1)
|
||||
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(bookmarkedRangesForEditor(editor).length).toBe(0)
|
||||
expect(callback.callCount).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
@ -53,6 +65,8 @@ describe('Bookmarks package', () => {
|
||||
expect(bookmarkedRangesForEditor(editor)).toEqual([])
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(bookmarkedRangesForEditor(editor)).toEqual([[[3, 10], [3, 10]], [[6, 11], [6, 11]]])
|
||||
let instance = provider.getInstanceForEditor(editor)
|
||||
expect(instance.getAllBookmarks().length).toBe(2)
|
||||
})
|
||||
|
||||
it('removes multiple markers when toggled', () => {
|
||||
@ -215,27 +229,39 @@ describe('Bookmarks package', () => {
|
||||
})
|
||||
|
||||
it('clears all bookmarks', () => {
|
||||
let callback = jasmine.createSpy()
|
||||
let instance = provider.getInstanceForEditor(editor)
|
||||
instance.onDidChangeBookmarks(callback)
|
||||
|
||||
editor.setCursorBufferPosition([3, 10])
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(callback.callCount).toBe(1)
|
||||
|
||||
editor.setCursorBufferPosition([5, 0])
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(callback.callCount).toBe(2)
|
||||
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:clear-bookmarks')
|
||||
expect(getBookmarkedLineNodes(editorElement).length).toBe(0)
|
||||
expect(callback.callCount).toBe(3)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a bookmark is invalidated', () => {
|
||||
it('creates a marker when toggled', () => {
|
||||
let callback = jasmine.createSpy()
|
||||
let instance = provider.getInstanceForEditor(editor)
|
||||
instance.onDidChangeBookmarks(callback)
|
||||
editor.setCursorBufferPosition([3, 10])
|
||||
expect(bookmarkedRangesForEditor(editor).length).toBe(0)
|
||||
|
||||
atom.commands.dispatch(editorElement, 'bookmarks:toggle-bookmark')
|
||||
expect(bookmarkedRangesForEditor(editor).length).toBe(1)
|
||||
expect(callback.callCount).toBe(1)
|
||||
|
||||
editor.setText('')
|
||||
expect(bookmarkedRangesForEditor(editor).length).toBe(0)
|
||||
expect(callback.callCount).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -3,6 +3,7 @@ const SelectListView = require('atom-select-list');
|
||||
module.exports = class GrammarListView {
|
||||
constructor() {
|
||||
this.autoDetect = { name: 'Auto Detect' };
|
||||
|
||||
this.selectListView = new SelectListView({
|
||||
itemsClassList: ['mark-active'],
|
||||
items: [],
|
||||
@ -21,12 +22,23 @@ module.exports = class GrammarListView {
|
||||
|
||||
if (isTreeSitter(grammar)) {
|
||||
const parser = document.createElement('span');
|
||||
|
||||
let badgeColor = 'badge-success';
|
||||
let badgeText = 'Tree-sitter';
|
||||
|
||||
if (isExperimentalTreeSitterMode()) {
|
||||
badgeColor = isModernTreeSitter(grammar) ?
|
||||
'badge-success' : 'badge-warning';
|
||||
badgeText = isModernTreeSitter(grammar) ?
|
||||
'Tree-sitter' : 'Legacy Tree-sitter';
|
||||
}
|
||||
|
||||
parser.classList.add(
|
||||
'grammar-selector-parser',
|
||||
'badge',
|
||||
'badge-success'
|
||||
badgeColor
|
||||
);
|
||||
parser.textContent = 'Tree-sitter';
|
||||
parser.textContent = badgeText;
|
||||
parser.setAttribute(
|
||||
'title',
|
||||
'(Recommended) A faster parser with improved syntax highlighting & code navigation support.'
|
||||
@ -56,6 +68,7 @@ module.exports = class GrammarListView {
|
||||
this.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
this.selectListView.element.classList.add('grammar-selector');
|
||||
}
|
||||
|
||||
@ -105,6 +118,12 @@ module.exports = class GrammarListView {
|
||||
return grammar !== atom.grammars.nullGrammar && grammar.name;
|
||||
});
|
||||
|
||||
// Don't show modern tree-sitter grammars in the selector unless the user
|
||||
// has opted into it.
|
||||
if (!isExperimentalTreeSitterMode()) {
|
||||
grammars = grammars.filter(grammar => !isModernTreeSitter(grammar));
|
||||
}
|
||||
|
||||
if (atom.config.get('grammar-selector.hideDuplicateTextMateGrammars')) {
|
||||
const blacklist = new Set();
|
||||
grammars.forEach(grammar => {
|
||||
@ -134,15 +153,36 @@ module.exports = class GrammarListView {
|
||||
}
|
||||
};
|
||||
|
||||
function getLanguageModeConfig() {
|
||||
let isTreeSitterMode = atom.config.get('core.useTreeSitterParsers');
|
||||
let isExperimental = atom.config.get('core.useExperimentalModernTreeSitter');
|
||||
if (!isTreeSitterMode) return 'textmate';
|
||||
return isExperimental ? 'wasm-tree-sitter' : 'node-tree-sitter';
|
||||
}
|
||||
|
||||
function isExperimentalTreeSitterMode() {
|
||||
return getLanguageModeConfig() === 'wasm-tree-sitter';
|
||||
}
|
||||
|
||||
function isTreeSitter(grammar) {
|
||||
return isOldTreeSitter(grammar) || isModernTreeSitter(grammar);
|
||||
}
|
||||
|
||||
function isModernTreeSitter(grammar) {
|
||||
return grammar.constructor.name === 'WASMTreeSitterGrammar';
|
||||
}
|
||||
|
||||
function isOldTreeSitter(grammar) {
|
||||
return grammar.constructor.name === 'TreeSitterGrammar';
|
||||
}
|
||||
|
||||
function compareGrammarType(a, b) {
|
||||
if (isTreeSitter(a)) {
|
||||
return -1;
|
||||
} else if (isTreeSitter(b)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return getGrammarScore(a) - getGrammarScore(b);
|
||||
}
|
||||
|
||||
function getGrammarScore(grammar) {
|
||||
let languageParser = getLanguageModeConfig();
|
||||
if (isModernTreeSitter(grammar)) { return -2; }
|
||||
if (isOldTreeSitter(grammar)) { return -1; }
|
||||
return languageParser === 'textmate' ? -3 : 0;
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
const path = require('path');
|
||||
const SelectListView = require('atom-select-list');
|
||||
|
||||
function setConfigForLanguageMode(mode) {
|
||||
let useTreeSitterParsers = mode !== 'textmate';
|
||||
let useExperimentalModernTreeSitter = mode === 'wasm-tree-sitter';
|
||||
atom.config.set('core.useTreeSitterParsers', useTreeSitterParsers);
|
||||
atom.config.set('core.useExperimentalModernTreeSitter', useExperimentalModernTreeSitter);
|
||||
}
|
||||
|
||||
describe('GrammarSelector', () => {
|
||||
let [editor, textGrammar, jsGrammar] = [];
|
||||
|
||||
@ -24,6 +31,8 @@ describe('GrammarSelector', () => {
|
||||
jsGrammar = atom.grammars.grammarForScopeName('source.js');
|
||||
expect(jsGrammar).toBeTruthy();
|
||||
expect(editor.getGrammar()).toBe(jsGrammar);
|
||||
|
||||
setConfigForLanguageMode('textmate');
|
||||
});
|
||||
|
||||
describe('when grammar-selector:show is triggered', () =>
|
||||
@ -56,16 +65,30 @@ describe('GrammarSelector', () => {
|
||||
expect(editor.getGrammar()).toBe(textGrammar);
|
||||
}));
|
||||
|
||||
describe('when auto-detect is selected', () =>
|
||||
it('restores the auto-detected grammar on the editor', async () => {
|
||||
describe('when auto-detect is selected', () => {
|
||||
it('restores the auto-detected grammar on the editor (when language parser is textmate)', async () => {
|
||||
let grammarView = await getGrammarView(editor);
|
||||
grammarView.props.didConfirmSelection(textGrammar);
|
||||
expect(editor.getGrammar()).toBe(textGrammar);
|
||||
|
||||
grammarView = await getGrammarView(editor);
|
||||
grammarView.props.didConfirmSelection(grammarView.items[0]);
|
||||
expect(editor.getGrammar()).toBe(jsGrammar);
|
||||
}));
|
||||
let currentGrammar = editor.getGrammar();
|
||||
expect(currentGrammar.scopeName).toBe('source.js');
|
||||
expect(currentGrammar.constructor.name).toBe('Grammar');
|
||||
});
|
||||
|
||||
it('restores the auto-detected grammar on the editor (when language parser is node-tree-sitter)', async () => {
|
||||
setConfigForLanguageMode('node-tree-sitter');
|
||||
let grammarView = await getGrammarView(editor);
|
||||
grammarView.props.didConfirmSelection(textGrammar);
|
||||
expect(editor.getGrammar()).toBe(textGrammar);
|
||||
grammarView = await getGrammarView(editor);
|
||||
grammarView.props.didConfirmSelection(grammarView.items[0]);
|
||||
let currentGrammar = editor.getGrammar();
|
||||
expect(currentGrammar.scopeName).toBe('source.js');
|
||||
expect(currentGrammar.constructor.name).toBe('TreeSitterGrammar');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the editor's current grammar is the null grammar", () =>
|
||||
it('displays Auto Detect as the selected grammar', async () => {
|
||||
@ -201,7 +224,38 @@ describe('GrammarSelector', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('shows both if false', async () => {
|
||||
it('shows both if false (in proper order when language parser is node-tree-sitter)', async () => {
|
||||
await atom.packages.activatePackage('language-c'); // punctuation making it sort wrong
|
||||
setConfigForLanguageMode('node-tree-sitter');
|
||||
atom.config.set(
|
||||
'grammar-selector.hideDuplicateTextMateGrammars',
|
||||
false
|
||||
);
|
||||
await getGrammarView(editor);
|
||||
let cppCount = 0;
|
||||
|
||||
const listItems = atom.workspace.getModalPanels()[0].item.items;
|
||||
for (let i = 0; i < listItems.length; i++) {
|
||||
const grammar = listItems[i];
|
||||
const name = grammar.name;
|
||||
if (cppCount === 0 && name === 'C++') {
|
||||
// first C++ entry should be Tree-sitter
|
||||
expect(grammar.constructor.name).toBe('TreeSitterGrammar');
|
||||
cppCount++;
|
||||
} else if (cppCount === 1) {
|
||||
// immediate next grammar should be the TextMate version
|
||||
expect(name).toBe('C++');
|
||||
expect(grammar.constructor.name).toBe('Grammar');
|
||||
cppCount++;
|
||||
} else {
|
||||
expect(name).not.toBe('C++'); // there should not be any other C++ grammars
|
||||
}
|
||||
}
|
||||
|
||||
expect(cppCount).toBe(2); // ensure we actually saw both grammars
|
||||
});
|
||||
|
||||
it('shows both if false (in proper order when language parser is textmate)', async () => {
|
||||
await atom.packages.activatePackage('language-c'); // punctuation making it sort wrong
|
||||
atom.config.set(
|
||||
'grammar-selector.hideDuplicateTextMateGrammars',
|
||||
@ -215,11 +269,13 @@ describe('GrammarSelector', () => {
|
||||
const grammar = listItems[i];
|
||||
const name = grammar.name;
|
||||
if (cppCount === 0 && name === 'C++') {
|
||||
expect(grammar.constructor.name).toBe('TreeSitterGrammar'); // first C++ entry should be Tree-sitter
|
||||
// first C++ entry should be TextMate
|
||||
expect(grammar.constructor.name).toBe('Grammar');
|
||||
cppCount++;
|
||||
} else if (cppCount === 1) {
|
||||
// immediate next grammar should be the Tree-sitter version
|
||||
expect(name).toBe('C++');
|
||||
expect(grammar.constructor.name).toBe('Grammar'); // immediate next grammar should be the TextMate version
|
||||
expect(grammar.constructor.name).toBe('TreeSitterGrammar');
|
||||
cppCount++;
|
||||
} else {
|
||||
expect(name).not.toBe('C++'); // there should not be any other C++ grammars
|
||||
@ -228,8 +284,10 @@ describe('GrammarSelector', () => {
|
||||
|
||||
expect(cppCount).toBe(2); // ensure we actually saw both grammars
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('for every Tree-sitter grammar', () => {
|
||||
it('adds a label to identify it as Tree-sitter', async () => {
|
||||
const grammarView = await getGrammarView(editor);
|
||||
@ -266,6 +324,130 @@ describe('GrammarSelector', () => {
|
||||
expect(grammarTile.destroy).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
|
||||
// TODO: These tests will need to be altered when we remove legacy
|
||||
// tree-sitter altogether.
|
||||
describe('when language parser is "wasm-tree-sitter"', () => {
|
||||
beforeEach(() => {
|
||||
setConfigForLanguageMode('wasm-tree-sitter');
|
||||
});
|
||||
|
||||
describe('when grammar-selector:show is triggered', () => {
|
||||
it('displays a list of all the available grammars', async () => {
|
||||
const grammarView = (await getGrammarView(editor)).element;
|
||||
|
||||
// -1 for removing nullGrammar, +1 for adding "Auto Detect"
|
||||
// Tree-sitter names the regex and JSDoc grammars
|
||||
expect(grammarView.querySelectorAll('li').length).toBe(
|
||||
atom.grammars
|
||||
.getGrammars({ includeTreeSitter: true })
|
||||
.filter(g => g.name).length
|
||||
);
|
||||
expect(grammarView.querySelectorAll('li')[0].textContent).toBe(
|
||||
'Auto Detect'
|
||||
);
|
||||
expect(grammarView.textContent.includes('source.a')).toBe(false);
|
||||
grammarView
|
||||
.querySelectorAll('li')
|
||||
.forEach(li =>
|
||||
expect(li.textContent).not.toBe(atom.grammars.nullGrammar.name)
|
||||
);
|
||||
// Ensure we're showing and labelling tree-sitter grammars…
|
||||
expect(grammarView.textContent.includes('Tree-sitter')).toBe(true);
|
||||
// …and old tree-sitter grammars.
|
||||
expect(grammarView.textContent.includes('Legacy Tree-sitter')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when toggling hideDuplicateTextMateGrammars', () => {
|
||||
it('shows only the Tree-sitter if true and both exist', async () => {
|
||||
// the main JS grammar has both a TextMate and Tree-sitter implementation
|
||||
atom.config.set('grammar-selector.hideDuplicateTextMateGrammars', true);
|
||||
const grammarView = await getGrammarView(editor);
|
||||
const observedNames = new Map();
|
||||
// Show a maximum of two different kinds of grammar (both tree-sitter
|
||||
// variants).
|
||||
grammarView.element.querySelectorAll('li').forEach(li => {
|
||||
const name = li.getAttribute('data-grammar');
|
||||
if (!observedNames.has(name)) {
|
||||
observedNames.set(name, 0);
|
||||
}
|
||||
observedNames.set(name, observedNames.get(name) + 1);
|
||||
expect(observedNames.get(name) < 3).toBe(true, `found ${observedNames.get(name)} of ${name}`);
|
||||
});
|
||||
|
||||
// check the seen JS is actually the Tree-sitter one
|
||||
const list = atom.workspace.getModalPanels()[0].item;
|
||||
for (const item of list.items) {
|
||||
if (item.name === 'JavaScript') {
|
||||
expect(item.constructor.name.includes('TreeSitterGrammar'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('shows both if false', async () => {
|
||||
await atom.packages.activatePackage('language-c'); // punctuation making it sort wrong
|
||||
atom.config.set(
|
||||
'grammar-selector.hideDuplicateTextMateGrammars',
|
||||
false
|
||||
);
|
||||
await getGrammarView(editor);
|
||||
let cppCount = 0;
|
||||
|
||||
const listItems = atom.workspace.getModalPanels()[0].item.items;
|
||||
for (let i = 0; i < listItems.length; i++) {
|
||||
const grammar = listItems[i];
|
||||
const name = grammar.name;
|
||||
if (cppCount === 0 && name === 'C++') {
|
||||
expect(grammar.constructor.name).toBe('WASMTreeSitterGrammar'); // first C++ entry should be Modern Tree-sitter
|
||||
cppCount++;
|
||||
} else if (cppCount === 1) {
|
||||
expect(name).toBe('C++');
|
||||
expect(grammar.constructor.name).toBe('TreeSitterGrammar'); // second C++ entry should be Legacy Tree-sitter
|
||||
cppCount++;
|
||||
} else if (cppCount === 2) {
|
||||
expect(name).toBe('C++');
|
||||
expect(grammar.constructor.name).toBe('Grammar'); // immediate next grammar should be the TextMate version
|
||||
cppCount++;
|
||||
} else {
|
||||
expect(name).not.toBe('C++'); // there should not be any other C++ grammars
|
||||
}
|
||||
}
|
||||
|
||||
expect(cppCount).toBe(3); // ensure we actually saw three grammars
|
||||
});
|
||||
});
|
||||
|
||||
describe('for every Tree-sitter grammar', () => {
|
||||
it('adds a label to identify it as Tree-sitter', async () => {
|
||||
const grammarView = await getGrammarView(editor);
|
||||
const elements = grammarView.element.querySelectorAll('li');
|
||||
const listItems = atom.workspace.getModalPanels()[0].item.items;
|
||||
for (let i = 0; i < listItems.length; i++) {
|
||||
let item = listItems[i];
|
||||
let element = elements[i];
|
||||
if (item.constructor.name.includes('TreeSitterGrammar')) {
|
||||
expect(
|
||||
element.childNodes[1].childNodes[0].className.startsWith(
|
||||
'grammar-selector-parser'
|
||||
)
|
||||
).toBe(true);
|
||||
}
|
||||
if (item.constructor.name === 'TreeSitterGrammar') {
|
||||
expect(
|
||||
element.childNodes[1].childNodes[0].classList.contains('badge-warning')
|
||||
).toBe(true);
|
||||
} else if (item.constructor.name === 'WASMTreeSitterGrammar') {
|
||||
expect(
|
||||
element.childNodes[1].childNodes[0].classList.contains('badge-success')
|
||||
).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function getTooltipText(element) {
|
||||
@ -274,7 +456,11 @@ function getTooltipText(element) {
|
||||
}
|
||||
|
||||
async function getGrammarView(editor) {
|
||||
let timeout = setTimeout(() => {
|
||||
throw new Error('Timeout');
|
||||
}, 5000);
|
||||
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show');
|
||||
await SelectListView.getScheduler().getNextUpdatePromise();
|
||||
clearTimeout(timeout);
|
||||
return atom.workspace.getModalPanels()[0].getItem();
|
||||
}
|
||||
|
1
packages/language-c/.envrc
Normal file
1
packages/language-c/.envrc
Normal file
@ -0,0 +1 @@
|
||||
source "/Users/andrew/Code/JavaScript/emsdk/emsdk_env.sh"
|
1
packages/language-c/.tool-versions
Normal file
1
packages/language-c/.tool-versions
Normal file
@ -0,0 +1 @@
|
||||
nodejs 18.14.0
|
13
packages/language-c/grammars/modern-tree-sitter-c.cson
Normal file
13
packages/language-c/grammars/modern-tree-sitter-c.cson
Normal file
@ -0,0 +1,13 @@
|
||||
name: 'C'
|
||||
scopeName: 'source.c'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-c'
|
||||
|
||||
injectionRegex: '^(c|C)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-c/tree-sitter-c.wasm'
|
||||
highlightsQuery: 'tree-sitter-c/highlights.scm'
|
||||
localsQuery: 'tree-sitter-c/locals.scm'
|
||||
foldsQuery: 'tree-sitter-c/folds.scm'
|
||||
indentsQuery: 'tree-sitter-c/indents.scm'
|
13
packages/language-c/grammars/modern-tree-sitter-cpp.cson
Normal file
13
packages/language-c/grammars/modern-tree-sitter-cpp.cson
Normal file
@ -0,0 +1,13 @@
|
||||
name: 'C++'
|
||||
scopeName: 'source.cpp'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-cpp'
|
||||
|
||||
injectionRegex: '^(cpp|CPP|cc|CC)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-cpp/tree-sitter-cpp.wasm'
|
||||
highlightsQuery: 'tree-sitter-cpp/highlights.scm'
|
||||
localsQuery: 'tree-sitter-cpp/locals.scm'
|
||||
foldsQuery: 'tree-sitter-cpp/folds.scm'
|
||||
indentsQuery: 'tree-sitter-cpp/indents.scm'
|
24
packages/language-c/grammars/tree-sitter-c/folds.scm
Normal file
24
packages/language-c/grammars/tree-sitter-c/folds.scm
Normal file
@ -0,0 +1,24 @@
|
||||
; When we've got
|
||||
;
|
||||
; if (foo) {
|
||||
; // something
|
||||
; } else {
|
||||
; // something else
|
||||
; }
|
||||
;
|
||||
; we want the folds to work a little differently so that collapsing the `if`
|
||||
; fold doesn't interfere with our ability to collapse the `else` fold.
|
||||
(if_statement
|
||||
consequence: (compound_statement) @fold
|
||||
(#set! fold.adjustToEndOfPreviousRow true))
|
||||
|
||||
[
|
||||
(field_declaration_list)
|
||||
(enumerator_list)
|
||||
(compound_statement)
|
||||
] @fold
|
||||
|
||||
; Divided folds for preprocessor statements because they can't reliably be
|
||||
; expressed with simple folds.
|
||||
["#ifndef" "#ifdef" "#elif" "#else" "#if"] @fold.start
|
||||
["#elif" "#else" "#endif"] @fold.end
|
328
packages/language-c/grammars/tree-sitter-c/highlights.scm
Normal file
328
packages/language-c/grammars/tree-sitter-c/highlights.scm
Normal file
@ -0,0 +1,328 @@
|
||||
; PREPROCESSOR
|
||||
; ============
|
||||
|
||||
[
|
||||
"#if"
|
||||
"#ifdef"
|
||||
"#ifndef"
|
||||
"#endif"
|
||||
"#elif"
|
||||
"#else"
|
||||
] @keyword.control.directive.conditional.c
|
||||
|
||||
"#define" @keyword.control.directive.define.c
|
||||
"#include" @keyword.control.directive.include.c
|
||||
|
||||
; This will match if the more specific rules above haven't matched. The
|
||||
; anonymous nodes will match under ideal conditions, but might not be present
|
||||
; if the parser is flummoxed.
|
||||
((preproc_directive) @keyword.control.directive.c
|
||||
(#set! test.shy true))
|
||||
|
||||
((preproc_ifdef
|
||||
(identifier) @entity.name.function.preprocessor.c
|
||||
(#match? @entity.name.function.preprocessor.c "[a-zA-Z_$][\\w$]*")))
|
||||
|
||||
(preproc_function_def
|
||||
(identifier) @entity.name.function.preprocessor.c
|
||||
(#set! test.final true))
|
||||
|
||||
(system_lib_string) @string.quoted.other.lt-gt.include.c
|
||||
((system_lib_string) @punctuation.definition.string.begin.c
|
||||
(#set! adjust.endAfterFirstMatchOf "^<"))
|
||||
((system_lib_string) @punctuation.definition.string.end.c
|
||||
(#set! adjust.startBeforeFirstMatchOf ">$"))
|
||||
|
||||
|
||||
; TYPES
|
||||
; =====
|
||||
|
||||
; WORKAROUND: If we're in an error state, don't trust the parser's designation
|
||||
; of `type_identifier`. Someone's probably just typing on a new line.
|
||||
(ERROR
|
||||
(type_identifier) @_IGNORE_
|
||||
(#set! test.final true))
|
||||
|
||||
(primitive_type) @storage.type.builtin.c
|
||||
(type_identifier) @storage.type.other.c
|
||||
|
||||
[
|
||||
"enum"
|
||||
"long"
|
||||
"short"
|
||||
"signed"
|
||||
"struct"
|
||||
"typedef"
|
||||
"union"
|
||||
"unsigned"
|
||||
] @storage.type.c
|
||||
|
||||
[
|
||||
"const"
|
||||
"extern"
|
||||
"inline"
|
||||
"register"
|
||||
"restrict"
|
||||
"static"
|
||||
"volatile"
|
||||
] @storage.modifier.c
|
||||
|
||||
((primitive_type) @support.type.stdint.c
|
||||
(#match? @support.type.stdint.c "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$"))
|
||||
|
||||
|
||||
; CAVEAT: tree-sitter-c doesn't identify placeholders like `%c` in strings.
|
||||
; Candidate for an injection grammar.
|
||||
(string_literal "\"") @string.quoted.double.c
|
||||
|
||||
(string_literal
|
||||
"\"" @punctuation.definition.string.begin.c
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(string_literal
|
||||
"\"" @punctuation.definition.string.end.c
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
(char_literal "'") @string.quoted.single.c
|
||||
|
||||
(char_literal
|
||||
"'" @punctuation.definition.string.begin.c
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(char_literal
|
||||
"'" @punctuation.definition.string.end.c
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
(string_literal (escape_sequence) @constant.character.escape.c)
|
||||
(char_literal (escape_sequence) @constant.character.escape.c)
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
; Declarations and assignments
|
||||
; ----------------------------
|
||||
|
||||
; The "x" in `int x`;
|
||||
(declaration
|
||||
declarator: (identifier) @variable.declaration.c)
|
||||
|
||||
; The "x" in `int x = y`;
|
||||
(init_declarator
|
||||
declarator: (identifier) @variable.declaration.c)
|
||||
|
||||
(field_declaration
|
||||
(field_identifier) @variable.declaration.c)
|
||||
|
||||
(field_declaration
|
||||
(pointer_declarator
|
||||
(field_identifier) @variable.declaration.c))
|
||||
|
||||
(field_declaration
|
||||
(array_declarator
|
||||
(field_identifier) @variable.declaration.c))
|
||||
|
||||
(init_declarator
|
||||
(pointer_declarator
|
||||
(identifier) @variable.declaration.c))
|
||||
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.c)
|
||||
|
||||
|
||||
; Function parameters
|
||||
; -------------------
|
||||
|
||||
(preproc_params
|
||||
(identifier) @variable.parameter.preprocessor.c)
|
||||
|
||||
; The "foo" in `const char foo` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (identifier) @variable.parameter.c)
|
||||
|
||||
; The "foo" in `const char *foo` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator
|
||||
declarator: (identifier) @variable.parameter.c))
|
||||
|
||||
; The "foo" in `const char foo[]` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (array_declarator
|
||||
declarator: (identifier) @variable.parameter.c))
|
||||
|
||||
; The "argv" in `char* argv[]` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator
|
||||
declarator: (array_declarator
|
||||
declarator: (identifier) @variable.parameter.c)))
|
||||
|
||||
; The "size" in `finfo->size`.
|
||||
(field_expression
|
||||
"->"
|
||||
field: (field_identifier) @variable.other.member.c)
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
; =========
|
||||
|
||||
(function_declarator
|
||||
(identifier) @entity.name.function.c)
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.function.c99.c
|
||||
; Regex copied from the TM grammar.
|
||||
(#match? @support.function.c99.c "^(_Exit|(?:nearbyint|nextafter|nexttoward|netoward|nan)[fl]?|a(?:cos|sin)h?[fl]?|abort|abs|asctime|assert|atan(?:[h2]?[fl]?)?|atexit|ato[ifl]|atoll|bsearch|btowc|cabs[fl]?|cacos|cacos[fl]|cacosh[fl]?|calloc|carg[fl]?|casinh?[fl]?|catanh?[fl]?|cbrt[fl]?|ccosh?[fl]?|ceil[fl]?|cexp[fl]?|cimag[fl]?|clearerr|clock|clog[fl]?|conj[fl]?|copysign[fl]?|cosh?[fl]?|cpow[fl]?|cproj[fl]?|creal[fl]?|csinh?[fl]?|csqrt[fl]?|ctanh?[fl]?|ctime|difftime|div|erfc?[fl]?|exit|fabs[fl]?|exp(?:2[fl]?|[fl]|m1[fl]?)?|fclose|fdim[fl]?|fe[gs]et(?:env|exceptflag|round)|feclearexcept|feholdexcept|feof|feraiseexcept|ferror|fetestexcept|feupdateenv|fflush|fgetpos|fgetw?[sc]|floor[fl]?|fmax?[fl]?|fmin[fl]?|fmod[fl]?|fopen|fpclassify|fprintf|fputw?[sc]|fread|free|freopen|frexp[fl]?|fscanf|fseek|fsetpos|ftell|fwide|fwprintf|fwrite|fwscanf|genv|get[sc]|getchar|gmtime|gwc|gwchar|hypot[fl]?|ilogb[fl]?|imaxabs|imaxdiv|isalnum|isalpha|isblank|iscntrl|isdigit|isfinite|isgraph|isgreater|isgreaterequal|isinf|isless(?:equal|greater)?|isw?lower|isnan|isnormal|isw?print|isw?punct|isw?space|isunordered|isw?upper|iswalnum|iswalpha|iswblank|iswcntrl|iswctype|iswdigit|iswgraph|isw?xdigit|labs|ldexp[fl]?|ldiv|lgamma[fl]?|llabs|lldiv|llrint[fl]?|llround[fl]?|localeconv|localtime|log[2b]?[fl]?|log1[p0][fl]?|longjmp|lrint[fl]?|lround[fl]?|malloc|mbr?len|mbr?towc|mbsinit|mbsrtowcs|mbstowcs|memchr|memcmp|memcpy|memmove|memset|mktime|modf[fl]?|perror|pow[fl]?|printf|puts|putw?c(?:har)?|qsort|raise|rand|remainder[fl]?|realloc|remove|remquo[fl]?|rename|rewind|rint[fl]?|round[fl]?|scalbl?n[fl]?|scanf|setbuf|setjmp|setlocale|setvbuf|signal|signbit|sinh?[fl]?|snprintf|sprintf|sqrt[fl]?|srand|sscanf|strcat|strchr|strcmp|strcoll|strcpy|strcspn|strerror|strftime|strlen|strncat|strncmp|strncpy|strpbrk|strrchr|strspn|strstr|strto[kdf]|strtoimax|strtol[dl]?|strtoull?|strtoumax|strxfrm|swprintf|swscanf|system|tan|tan[fl]|tanh[fl]?|tgamma[fl]?|time|tmpfile|tmpnam|tolower|toupper|trunc[fl]?|ungetw?c|va_arg|va_copy|va_end|va_start|vfw?printf|vfw?scanf|vprintf|vscanf|vsnprintf|vsprintf|vsscanf|vswprintf|vswscanf|vwprintf|vwscanf|wcrtomb|wcscat|wcschr|wcscmp|wcscoll|wcscpy|wcscspn|wcsftime|wcslen|wcsncat|wcsncmp|wcsncpy|wcspbrk|wcsrchr|wcsrtombs|wcsspn|wcsstr|wcsto[dkf]|wcstoimax|wcstol[dl]?|wcstombs|wcstoull?|wcstoumax|wcsxfrm|wctom?b|wmem(?:set|chr|cpy|cmp|move)|wprintf|wscanf)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; The "foo" in `thing->troz->foo(...)`.
|
||||
(call_expression
|
||||
(field_expression
|
||||
field: (field_identifier) @support.other.function.c)
|
||||
(#set! test.final true))
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.other.function.c
|
||||
(#set! test.final true))
|
||||
|
||||
; NUMBERS
|
||||
; =======
|
||||
|
||||
(number_literal) @constant.numeric.c
|
||||
|
||||
|
||||
; CONSTANTS
|
||||
; =========
|
||||
|
||||
[
|
||||
(null)
|
||||
(true)
|
||||
(false)
|
||||
] @constant.language._TYPE_.c
|
||||
|
||||
((identifier) @constant.c
|
||||
(#match? @constant.c "[_A-Z][_A-Z0-9]*$"))
|
||||
|
||||
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
; Match // comments.
|
||||
((comment) @comment.line.double-slash.c
|
||||
(#match? @comment.line.double-slash.c "^\\s*//"))
|
||||
|
||||
((comment) @punctuation.definition.comment.c
|
||||
(#match? @comment.line.double-slash.c "^\\s*//")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "//"))
|
||||
|
||||
; Match /* */ comments.
|
||||
((comment) @comment.block.c
|
||||
(#match? @comment.block.c "^/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.begin.c
|
||||
(#match? @punctuation.definition.comment.begin.c "^/\\*")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.end.c
|
||||
(#match? @punctuation.definition.comment.end.c "\\*/$")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\*/$"))
|
||||
|
||||
|
||||
[
|
||||
"break"
|
||||
"case"
|
||||
"continue"
|
||||
"default"
|
||||
"do"
|
||||
"else"
|
||||
"for"
|
||||
"goto"
|
||||
"if"
|
||||
"return"
|
||||
"switch"
|
||||
"while"
|
||||
] @keyword.control._TYPE_.c
|
||||
|
||||
; OPERATORS
|
||||
; =========
|
||||
|
||||
(pointer_declarator "*" @keyword.operator.pointer.c)
|
||||
(abstract_pointer_declarator "*" @keyword.operator.pointer.c)
|
||||
(pointer_expression "*" @keyword.operator.pointer.c)
|
||||
|
||||
"sizeof" @keyword.operator.sizeof.c
|
||||
(pointer_expression "&" @keyword.operator.pointer.c)
|
||||
|
||||
"=" @keyword.operator.assignment.c
|
||||
|
||||
[
|
||||
"%="
|
||||
"+="
|
||||
"-="
|
||||
"*="
|
||||
"/="
|
||||
"&="
|
||||
"^="
|
||||
"<<="
|
||||
">>="
|
||||
"|="
|
||||
] @keyword.operator.assignment.compound.c
|
||||
|
||||
|
||||
(binary_expression
|
||||
["==" "!=" ">" "<" ">=" "<="] @keyword.operator.comparison.c)
|
||||
|
||||
(binary_expression
|
||||
["&" "|" "^" "~" "<<" ">>"]
|
||||
@keyword.operator.bitwise.c)
|
||||
|
||||
"++" @keyword.operator.increment.c
|
||||
"--" @keyword.operator.decrement.c
|
||||
|
||||
(binary_expression ["+" "-" "*" "/" "%"] @keyword.operator.arithmetic.c)
|
||||
(unary_expression ["+" "-" "!"] @keyword.operator.unary.c)
|
||||
|
||||
(conditional_expression
|
||||
["?" ":"] @keyword.operator.ternary.c)
|
||||
|
||||
|
||||
["||" "&&"] @keyword.operator.logical.c
|
||||
|
||||
(field_expression "." @keyword.operator.accessor.dot.c)
|
||||
(preproc_params "..." @keyword.operator.ellipsis.c)
|
||||
|
||||
; PUNCTUATION
|
||||
; ===========
|
||||
|
||||
";" @punctuation.terminator.statement.c
|
||||
|
||||
"," @punctuation.separator.comma.c
|
||||
"->" @punctuation.separator.pointer-access.c
|
||||
|
||||
(parameter_list
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.c
|
||||
")" @punctuation.definition.parameters.end.bracket.round.c
|
||||
(#set! test.final true))
|
||||
|
||||
(parenthesized_expression
|
||||
"(" @punctuation.definition.expression.begin.bracket.round.c
|
||||
")" @punctuation.definition.expression.end.bracket.round.c
|
||||
(#set! test.final true))
|
||||
|
||||
(if_statement
|
||||
condition: (parenthesized_expression
|
||||
"(" @punctuation.definition.expression.begin.bracket.round.c
|
||||
")" @punctuation.definition.expression.end.bracket.round.c
|
||||
(#set! test.final true)))
|
||||
|
||||
"{" @punctuation.definition.block.begin.bracket.curly.c
|
||||
"}" @punctuation.definition.block.end.bracket.curly.c
|
||||
"(" @punctuation.definition.begin.bracket.round.c
|
||||
")" @punctuation.definition.end.bracket.round.c
|
||||
"[" @punctuation.definition.array.begin.bracket.square.c
|
||||
"]" @punctuation.definition.array.end.bracket.square.c
|
||||
|
||||
; TODO:
|
||||
;
|
||||
; * TM-style grammar has a lot of `mac-classic` scopes. I doubt they'd be
|
||||
; present if this wasn't converted from a TextMate grammar, so I'm leaving
|
||||
; them out for now.
|
||||
;
|
20
packages/language-c/grammars/tree-sitter-c/indents.scm
Normal file
20
packages/language-c/grammars/tree-sitter-c/indents.scm
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
["{" "(" "["] @indent
|
||||
|
||||
["}" ")" "]"] @dedent
|
||||
|
||||
; `switch` statements have a couple schools of thought, indentation-wise, and
|
||||
; we might have to make this configurable somehow.
|
||||
(switch_statement
|
||||
body: (compound_statement "}" @match
|
||||
(#set! test.onlyIfLast true))
|
||||
(#set! indent.matchIndentOf parent.startPosition))
|
||||
|
||||
; 'case' and 'default' need to be indented one level more than their containing
|
||||
; `switch`.
|
||||
(["case" "default"] @match
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
|
||||
["case" "default"] @indent
|
1
packages/language-c/grammars/tree-sitter-c/locals.scm
Normal file
1
packages/language-c/grammars/tree-sitter-c/locals.scm
Normal file
@ -0,0 +1 @@
|
||||
;
|
BIN
packages/language-c/grammars/tree-sitter-c/tree-sitter-c.wasm
Executable file
BIN
packages/language-c/grammars/tree-sitter-c/tree-sitter-c.wasm
Executable file
Binary file not shown.
24
packages/language-c/grammars/tree-sitter-cpp/folds.scm
Normal file
24
packages/language-c/grammars/tree-sitter-cpp/folds.scm
Normal file
@ -0,0 +1,24 @@
|
||||
; When we've got
|
||||
;
|
||||
; if (foo) {
|
||||
; // something
|
||||
; } else {
|
||||
; // something else
|
||||
; }
|
||||
;
|
||||
; we want the folds to work a little differently so that collapsing the `if`
|
||||
; fold doesn't interfere with our ability to collapse the `else` fold.
|
||||
(if_statement
|
||||
consequence: (compound_statement) @fold
|
||||
(#set! fold.adjustToEndOfPreviousRow true))
|
||||
|
||||
[
|
||||
(field_declaration_list)
|
||||
(enumerator_list)
|
||||
(compound_statement)
|
||||
] @fold
|
||||
|
||||
; Divided folds for preprocessor statements because they can't reliably be
|
||||
; expressed with simple folds.
|
||||
["#ifndef" "#ifdef" "#elif" "#else" "#if"] @fold.start
|
||||
["#elif" "#else" "#endif"] @fold.end
|
397
packages/language-c/grammars/tree-sitter-cpp/highlights.scm
Normal file
397
packages/language-c/grammars/tree-sitter-cpp/highlights.scm
Normal file
@ -0,0 +1,397 @@
|
||||
; PREPROCESSOR
|
||||
; ============
|
||||
|
||||
[
|
||||
"#if"
|
||||
"#ifdef"
|
||||
"#ifndef"
|
||||
"#endif"
|
||||
"#elif"
|
||||
"#else"
|
||||
] @keyword.control.directive.conditional.cpp
|
||||
|
||||
"#define" @keyword.control.directive.define.cpp
|
||||
"#include" @keyword.control.directive.include.cpp
|
||||
|
||||
; This will match if the more specific rules above haven't matched. The
|
||||
; anonymous nodes will match under ideal conditions, but might not be present
|
||||
; if the parser is flummoxed.
|
||||
((preproc_directive) @keyword.control.directive.c
|
||||
(#set! test.shy true))
|
||||
|
||||
((preproc_ifdef
|
||||
(identifier) @entity.name.function.preprocessor.c
|
||||
(#match? @entity.name.function.preprocessor.c "[a-zA-Z_$][\\w$]*")))
|
||||
|
||||
(preproc_function_def
|
||||
(identifier) @entity.name.function.preprocessor.c
|
||||
(#set! test.final true))
|
||||
|
||||
(preproc_function_def
|
||||
(identifier) @entity.name.function.preprocessor.cpp
|
||||
(#set! test.final true)
|
||||
)
|
||||
|
||||
(system_lib_string) @string.quoted.other.lt-gt.include.c
|
||||
((system_lib_string) @punctuation.definition.string.begin.c
|
||||
(#set! adjust.endAfterFirstMatchOf "^<"))
|
||||
((system_lib_string) @punctuation.definition.string.end.c
|
||||
(#set! adjust.startBeforeFirstMatchOf ">$"))
|
||||
|
||||
|
||||
; TYPES
|
||||
; =====
|
||||
|
||||
; WORKAROUND: If we're in an error state, don't trust the parser's designation
|
||||
; of `type_identifier`. Someone's probably just typing on a new line.
|
||||
(ERROR
|
||||
(type_identifier) @_IGNORE_
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
(primitive_type) @storage.type.builtin.cpp
|
||||
|
||||
(class_specifier
|
||||
(type_identifier) @entity.name.class.cpp
|
||||
(#set! test.final true))
|
||||
|
||||
(type_identifier) @storage.type.other.cpp
|
||||
; (struct_specifier) @storage.type.cpp
|
||||
|
||||
[
|
||||
"enum"
|
||||
"long"
|
||||
"short"
|
||||
"signed"
|
||||
"struct"
|
||||
"typedef"
|
||||
"union"
|
||||
"unsigned"
|
||||
|
||||
"template"
|
||||
] @storage.type.cpp
|
||||
|
||||
[
|
||||
"const"
|
||||
"extern"
|
||||
"inline"
|
||||
"register"
|
||||
"restrict"
|
||||
"static"
|
||||
"volatile"
|
||||
|
||||
"private"
|
||||
"protected"
|
||||
"public"
|
||||
|
||||
"friend"
|
||||
"explicit"
|
||||
"virtual"
|
||||
"override"
|
||||
"final"
|
||||
"noexcept"
|
||||
] @storage.modifier.cpp
|
||||
|
||||
(
|
||||
(primitive_type) @support.type.stdint.cpp
|
||||
(#match? @support.type.stdint.cpp "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$")
|
||||
)
|
||||
|
||||
"typename" @storage.modifier.typename.cpp
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
; =========
|
||||
|
||||
(function_declarator
|
||||
(identifier) @entity.name.function.cpp)
|
||||
|
||||
(function_declarator
|
||||
(field_identifier) @entity.name.function.method.cpp)
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.function.c99.cpp
|
||||
; Regex copied from the TM grammar.
|
||||
(#match? @support.function.c99.cpp "^(_Exit|(?:nearbyint|nextafter|nexttoward|netoward|nan)[fl]?|a(?:cos|sin)h?[fl]?|abort|abs|asctime|assert|atan(?:[h2]?[fl]?)?|atexit|ato[ifl]|atoll|bsearch|btowc|cabs[fl]?|cacos|cacos[fl]|cacosh[fl]?|calloc|carg[fl]?|casinh?[fl]?|catanh?[fl]?|cbrt[fl]?|ccosh?[fl]?|ceil[fl]?|cexp[fl]?|cimag[fl]?|clearerr|clock|clog[fl]?|conj[fl]?|copysign[fl]?|cosh?[fl]?|cpow[fl]?|cproj[fl]?|creal[fl]?|csinh?[fl]?|csqrt[fl]?|ctanh?[fl]?|ctime|difftime|div|erfc?[fl]?|exit|fabs[fl]?|exp(?:2[fl]?|[fl]|m1[fl]?)?|fclose|fdim[fl]?|fe[gs]et(?:env|exceptflag|round)|feclearexcept|feholdexcept|feof|feraiseexcept|ferror|fetestexcept|feupdateenv|fflush|fgetpos|fgetw?[sc]|floor[fl]?|fmax?[fl]?|fmin[fl]?|fmod[fl]?|fopen|fpclassify|fprintf|fputw?[sc]|fread|free|freopen|frexp[fl]?|fscanf|fseek|fsetpos|ftell|fwide|fwprintf|fwrite|fwscanf|genv|get[sc]|getchar|gmtime|gwc|gwchar|hypot[fl]?|ilogb[fl]?|imaxabs|imaxdiv|isalnum|isalpha|isblank|iscntrl|isdigit|isfinite|isgraph|isgreater|isgreaterequal|isinf|isless(?:equal|greater)?|isw?lower|isnan|isnormal|isw?print|isw?punct|isw?space|isunordered|isw?upper|iswalnum|iswalpha|iswblank|iswcntrl|iswctype|iswdigit|iswgraph|isw?xdigit|labs|ldexp[fl]?|ldiv|lgamma[fl]?|llabs|lldiv|llrint[fl]?|llround[fl]?|localeconv|localtime|log[2b]?[fl]?|log1[p0][fl]?|longjmp|lrint[fl]?|lround[fl]?|malloc|mbr?len|mbr?towc|mbsinit|mbsrtowcs|mbstowcs|memchr|memcmp|memcpy|memmove|memset|mktime|modf[fl]?|perror|pow[fl]?|printf|puts|putw?c(?:har)?|qsort|raise|rand|remainder[fl]?|realloc|remove|remquo[fl]?|rename|rewind|rint[fl]?|round[fl]?|scalbl?n[fl]?|scanf|setbuf|setjmp|setlocale|setvbuf|signal|signbit|sinh?[fl]?|snprintf|sprintf|sqrt[fl]?|srand|sscanf|strcat|strchr|strcmp|strcoll|strcpy|strcspn|strerror|strftime|strlen|strncat|strncmp|strncpy|strpbrk|strrchr|strspn|strstr|strto[kdf]|strtoimax|strtol[dl]?|strtoull?|strtoumax|strxfrm|swprintf|swscanf|system|tan|tan[fl]|tanh[fl]?|tgamma[fl]?|time|tmpfile|tmpnam|tolower|toupper|trunc[fl]?|ungetw?c|va_arg|va_copy|va_end|va_start|vfw?printf|vfw?scanf|vprintf|vscanf|vsnprintf|vsprintf|vsscanf|vswprintf|vswscanf|vwprintf|vwscanf|wcrtomb|wcscat|wcschr|wcscmp|wcscoll|wcscpy|wcscspn|wcsftime|wcslen|wcsncat|wcsncmp|wcsncpy|wcspbrk|wcsrchr|wcsrtombs|wcsspn|wcsstr|wcsto[dkf]|wcstoimax|wcstol[dl]?|wcstombs|wcstoull?|wcstoumax|wcsxfrm|wctom?b|wmem(?:set|chr|cpy|cmp|move)|wprintf|wscanf)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; The "foo" in `thing->troz->foo(...)`.
|
||||
(call_expression
|
||||
(field_expression
|
||||
field: (field_identifier) @support.other.function.cpp)
|
||||
(#set! test.final true))
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.other.function.cpp
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
; STRINGS
|
||||
; =======
|
||||
|
||||
; CAVEAT: tree-sitter-c doesn't identify placeholders like `%c` in strings.
|
||||
; Candidate for an injection grammar.
|
||||
(string_literal "\"") @string.quoted.double.cpp
|
||||
|
||||
(string_literal
|
||||
"\"" @punctuation.definition.string.begin.cpp
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(string_literal
|
||||
"\"" @punctuation.definition.string.end.cpp
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
(char_literal "'") @string.quoted.single.cpp
|
||||
|
||||
(char_literal
|
||||
"'" @punctuation.definition.string.begin.cpp
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(char_literal
|
||||
"'" @punctuation.definition.string.end.cpp
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
(string_literal (escape_sequence) @constant.character.escape.cpp)
|
||||
(char_literal (escape_sequence) @constant.character.escape.cpp)
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
(this) @variable.language.this.cpp
|
||||
|
||||
; Declarations and assignments
|
||||
; ----------------------------
|
||||
|
||||
; The "x" in `int x`;
|
||||
(declaration
|
||||
declarator: (identifier) @variable.declaration.cpp)
|
||||
|
||||
; The "x" in `int x = y`;
|
||||
(init_declarator
|
||||
declarator: (identifier) @variable.declaration.cpp)
|
||||
|
||||
(field_declaration
|
||||
(field_identifier) @variable.declaration.cpp)
|
||||
|
||||
(field_declaration
|
||||
(pointer_declarator
|
||||
(field_identifier) @variable.declaration.cpp))
|
||||
|
||||
(field_declaration
|
||||
(array_declarator
|
||||
(field_identifier) @variable.declaration.cpp))
|
||||
|
||||
(init_declarator
|
||||
(pointer_declarator
|
||||
(identifier) @variable.declaration.cpp))
|
||||
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.cpp)
|
||||
|
||||
(reference_declarator
|
||||
(identifier) @variable.declaration.cpp)
|
||||
|
||||
; Function parameters
|
||||
; -------------------
|
||||
|
||||
(preproc_params
|
||||
(identifier) @variable.parameter.preprocessor.cpp)
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (identifier) @variable.parameter.cpp)
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator
|
||||
declarator: (identifier) @variable.parameter.cpp))
|
||||
|
||||
; The "foo" in `const char foo[]` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (array_declarator
|
||||
declarator: (identifier) @variable.parameter.cpp))
|
||||
|
||||
; The "argv" in `char* argv[]` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator
|
||||
declarator: (array_declarator
|
||||
declarator: (identifier) @variable.parameter.cpp)))
|
||||
|
||||
; The "size" in `finfo->size`.
|
||||
(field_expression
|
||||
"->"
|
||||
field: (field_identifier) @variable.other.member.cpp)
|
||||
|
||||
; Common naming idiom for C++ instanced vars: "fMemberName"
|
||||
; ((identifier) @variable.other.readwrite.member.cpp
|
||||
; (#match? @variable.other.readwrite.member.cpp "^(f|m)[A-Z]\\w*$"))
|
||||
|
||||
|
||||
|
||||
; NUMBERS
|
||||
; =======
|
||||
|
||||
(number_literal) @constant.numeric.cpp
|
||||
|
||||
; CONSTANTS
|
||||
; =========
|
||||
|
||||
[
|
||||
(null)
|
||||
(true)
|
||||
(false)
|
||||
(nullptr)
|
||||
] @constant.language._TYPE_.cpp
|
||||
|
||||
((identifier) @constant.cpp
|
||||
(#match? @constant.cpp "[_A-Z][_A-Z0-9]*$"))
|
||||
|
||||
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
; Match // comments.
|
||||
((comment) @comment.line.double-slash.cpp
|
||||
(#match? @comment.line.double-slash.cpp "^\\s*//"))
|
||||
|
||||
((comment) @punctuation.definition.comment.cpp
|
||||
(#match? @comment.line.double-slash.cpp "^\\s*//")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "//"))
|
||||
|
||||
; Match /* */ comments.
|
||||
((comment) @comment.block.cpp
|
||||
(#match? @comment.block.cpp "^/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.begin.cpp
|
||||
(#match? @punctuation.definition.comment.begin.cpp "^/\\*")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.end.cpp
|
||||
(#match? @punctuation.definition.comment.end.cpp "\\*/$")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\*/$"))
|
||||
|
||||
|
||||
; KEYWORDS
|
||||
; ========
|
||||
|
||||
[
|
||||
"break"
|
||||
"case"
|
||||
"continue"
|
||||
"default"
|
||||
"do"
|
||||
"else"
|
||||
"for"
|
||||
"goto"
|
||||
"if"
|
||||
"return"
|
||||
"switch"
|
||||
"while"
|
||||
|
||||
"new"
|
||||
"delete"
|
||||
] @keyword.control._TYPE_.cpp
|
||||
|
||||
[
|
||||
"catch"
|
||||
"operator"
|
||||
"try"
|
||||
"throw"
|
||||
"using"
|
||||
"namespace"
|
||||
] @keyword.control._TYPE_.cpp
|
||||
|
||||
; OPERATORS
|
||||
; =========
|
||||
|
||||
(pointer_declarator "*" @keyword.operator.pointer.cpp)
|
||||
(abstract_pointer_declarator "*" @keyword.operator.pointer.cpp)
|
||||
(pointer_expression "*" @keyword.operator.pointer.cpp)
|
||||
|
||||
|
||||
"sizeof" @keyword.operator.sizeof.cpp
|
||||
(pointer_expression "&" @keyword.operator.pointer.cpp)
|
||||
(reference_declarator "&" @keyword.operator.pointer.cpp)
|
||||
|
||||
|
||||
"=" @keyword.operator.assignment.cpp
|
||||
|
||||
[
|
||||
"%="
|
||||
"+="
|
||||
"-="
|
||||
"*="
|
||||
"/="
|
||||
"&="
|
||||
"^="
|
||||
"<<="
|
||||
">>="
|
||||
"|="
|
||||
] @keyword.operator.assignment.compound.cpp
|
||||
|
||||
(binary_expression
|
||||
["==" "!=" ">" "<" ">=" "<="] @keyword.operator.comparison.cpp)
|
||||
|
||||
|
||||
["&&" "||"] @keyword.operator.logical.cpp
|
||||
|
||||
"++" @keyword.operator.increment.cpp
|
||||
"--" @keyword.operator.decrement.cpp
|
||||
|
||||
(binary_expression
|
||||
["&" "|" "^" "~" "<<" ">>"]
|
||||
@keyword.operator.bitwise.cpp)
|
||||
|
||||
(binary_expression
|
||||
["<" ">"] @keyword.operator.comparison.cpp)
|
||||
|
||||
(binary_expression
|
||||
["+" "-" "*" "/" "%"] @keyword.operator.arithmetic.cpp)
|
||||
|
||||
(unary_expression
|
||||
["+" "-" "!"] @keyword.operator.unary.cpp)
|
||||
|
||||
(conditional_expression
|
||||
["?" ":"] @keyword.operator.ternary.cpp)
|
||||
|
||||
(qualified_identifier
|
||||
"::" @keyword.operator.accessor.namespace.cpp)
|
||||
|
||||
(field_expression "." @keyword.operator.accessor.dot.cpp)
|
||||
(preproc_params "..." @keyword.operator.ellipsis.cpp)
|
||||
|
||||
; PUNCTUATION
|
||||
; ===========
|
||||
|
||||
";" @punctuation.terminator.statement.cpp
|
||||
|
||||
"," @punctuation.separator.comma.cpp
|
||||
"->" @keyword.operator.accessor.cpp
|
||||
|
||||
(parameter_list
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.cpp
|
||||
")" @punctuation.definition.parameters.end.bracket.round.cpp
|
||||
(#set! test.final true))
|
||||
|
||||
(parenthesized_expression
|
||||
"(" @punctuation.definition.expression.begin.bracket.round.cpp
|
||||
")" @punctuation.definition.expression.end.bracket.round.cpp
|
||||
(#set! test.final true))
|
||||
|
||||
(if_statement
|
||||
condition: (condition_clause
|
||||
"(" @punctuation.definition.expression.begin.bracket.round.cpp
|
||||
")" @punctuation.definition.expression.end.bracket.round.cpp
|
||||
(#set! test.final true)))
|
||||
|
||||
"{" @punctuation.definition.block.begin.bracket.curly.cpp
|
||||
"}" @punctuation.definition.block.end.bracket.curly.cpp
|
||||
"(" @punctuation.definition.begin.bracket.round.cpp
|
||||
")" @punctuation.definition.end.bracket.round.cpp
|
||||
"[" @punctuation.definition.array.begin.bracket.square.cpp
|
||||
"]" @punctuation.definition.array.end.bracket.square.cpp
|
||||
|
||||
; TODO:
|
||||
;
|
||||
; * TM-style grammar has a lot of `mac-classic` scopes. I doubt they'd be
|
||||
; present if this wasn't converted from a TextMate grammar, so I'm leaving
|
||||
; them out for now.
|
||||
;
|
32
packages/language-c/grammars/tree-sitter-cpp/indents.scm
Normal file
32
packages/language-c/grammars/tree-sitter-cpp/indents.scm
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
["{" "(" "["] @indent
|
||||
|
||||
["}" ")" "]"] @dedent
|
||||
|
||||
|
||||
; With access specifiers like…
|
||||
;
|
||||
; class Foo {
|
||||
; public:
|
||||
; void bar() {}
|
||||
; }
|
||||
;
|
||||
; …prevailing style is to dedent the specifier so it matches the indentation of
|
||||
; the line above.
|
||||
(access_specifier) @dedent @indent
|
||||
|
||||
; `switch` statements have a couple schools of thought, indentation-wise, and
|
||||
; we might have to make this configurable somehow.
|
||||
(switch_statement
|
||||
body: (compound_statement "}" @match
|
||||
(#set! test.onlyIfLast true))
|
||||
(#set! indent.matchIndentOf parent.startPosition))
|
||||
|
||||
; 'case' and 'default' need to be indented one level more than their containing
|
||||
; `switch`.
|
||||
(["case" "default"] @match
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
|
||||
["case" "default"] @indent
|
1
packages/language-c/grammars/tree-sitter-cpp/locals.scm
Normal file
1
packages/language-c/grammars/tree-sitter-cpp/locals.scm
Normal file
@ -0,0 +1 @@
|
||||
;
|
BIN
packages/language-c/grammars/tree-sitter-cpp/tree-sitter-cpp.wasm
Executable file
BIN
packages/language-c/grammars/tree-sitter-cpp/tree-sitter-cpp.wasm
Executable file
Binary file not shown.
@ -10,7 +10,7 @@ describe "Language-C", ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-c')
|
||||
|
43
packages/language-clojure/grammars/tree-sitter-clojure.cson
Normal file
43
packages/language-clojure/grammars/tree-sitter-clojure.cson
Normal file
@ -0,0 +1,43 @@
|
||||
'name': 'Clojure'
|
||||
'scopeName': 'source.clojure'
|
||||
'type': 'modern-tree-sitter'
|
||||
'fileTypes': [
|
||||
'boot'
|
||||
'clj'
|
||||
'clj.hl'
|
||||
'cljc'
|
||||
'cljs'
|
||||
'cljs.hl'
|
||||
'cljx'
|
||||
'clojure'
|
||||
'edn'
|
||||
'org'
|
||||
'bb'
|
||||
'joke'
|
||||
'joker'
|
||||
]
|
||||
'firstLineMatch': '''(?x)
|
||||
# Hashbang
|
||||
^\\#!.*(?:\\s|\\/)
|
||||
boot
|
||||
(?:$|\\s)
|
||||
|
|
||||
# Modeline
|
||||
(?i:
|
||||
# Emacs
|
||||
-\\*-(?:\\s*(?=[^:;\\s]+\\s*-\\*-)|(?:.*?[;\\s]|(?<=-\\*-))mode\\s*:\\s*)
|
||||
clojure(script)?
|
||||
(?=[\\s;]|(?<![-*])-\\*-).*?-\\*-
|
||||
|
|
||||
# Vim
|
||||
(?:(?:\\s|^)vi(?:m[<=>]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=
|
||||
clojure
|
||||
(?=\\s|:|$)
|
||||
)
|
||||
'''
|
||||
treeSitter:
|
||||
grammar: 'ts/grammar.wasm'
|
||||
highlightsQuery: 'ts/highlights.scm'
|
||||
# localsQuery: 'ts/locals.scm'
|
||||
foldsQuery: 'ts/folds.scm'
|
||||
indentsQuery: 'ts/indents.scm'
|
7
packages/language-clojure/grammars/ts/folds.scm
Normal file
7
packages/language-clojure/grammars/ts/folds.scm
Normal file
@ -0,0 +1,7 @@
|
||||
[
|
||||
(list_lit)
|
||||
(vec_lit)
|
||||
(map_lit)
|
||||
(anon_fn_lit)
|
||||
(set_lit)
|
||||
] @fold
|
BIN
packages/language-clojure/grammars/ts/grammar.wasm
Executable file
BIN
packages/language-clojure/grammars/ts/grammar.wasm
Executable file
Binary file not shown.
58
packages/language-clojure/grammars/ts/highlights.scm
Normal file
58
packages/language-clojure/grammars/ts/highlights.scm
Normal file
@ -0,0 +1,58 @@
|
||||
(quoting_lit
|
||||
value: (list_lit
|
||||
"(" @punctuation.section.expression.begin
|
||||
.
|
||||
(sym_lit) @meta.symbol (#set! final "true")))
|
||||
|
||||
;; Collections
|
||||
(anon_fn_lit
|
||||
"(" @punctuation.section.expression.begin
|
||||
.
|
||||
(sym_lit) @entity.name.function @meta.expression
|
||||
")" @punctuation.section.expression.end)
|
||||
|
||||
(list_lit
|
||||
"(" @punctuation.section.expression.begin
|
||||
.
|
||||
(sym_lit) @entity.name.function @meta.expression
|
||||
")" @punctuation.section.expression.end)
|
||||
|
||||
(vec_lit
|
||||
"[" @punctuation.section.vector.begin
|
||||
"]" @punctuation.section.vector.end) @meta.vector
|
||||
|
||||
(map_lit
|
||||
"{" @punctuation.section.map.begin
|
||||
"}" @punctuation.section.map.end) @meta.map
|
||||
|
||||
(set_lit
|
||||
("#" "{") @punctuation.section.set.begin
|
||||
"}" @punctuation.section.set.end) @meta.map
|
||||
|
||||
; Includes
|
||||
((sym_name) @meta.symbol (#eq? @meta.symbol "import")) @keyword.control
|
||||
((sym_name) @meta.symbol (#eq? @meta.symbol "require")) @keyword.control
|
||||
((sym_name) @meta.symbol (#eq? @meta.symbol "use")) @keyword.control
|
||||
|
||||
(list_lit
|
||||
"(" @punctuation.section.expression.begin
|
||||
.
|
||||
((sym_lit) @meta.symbol (#eq? @meta.symbol "ns")) @keyword.control @meta.definition.global
|
||||
.
|
||||
(sym_lit) @meta.definition.global @entity.global
|
||||
")" @punctuation.section.expression.end)
|
||||
|
||||
(list_lit
|
||||
"(" @punctuation.section.expression.begin
|
||||
.
|
||||
((sym_lit) @meta.symbol (#match? @meta.symbol "^def")) @keyword.control
|
||||
.
|
||||
(sym_lit) @meta.definition.global @entity.global
|
||||
")" @punctuation.section.expression.end)
|
||||
|
||||
(sym_lit) @meta.symbol
|
||||
(kwd_lit) @constant.keyword
|
||||
(str_lit) @string.quoted.double
|
||||
(num_lit) @constant.numeric
|
||||
(comment) @comment.line.semicolon
|
||||
(dis_expr) @comment.block.clojure
|
0
packages/language-clojure/grammars/ts/indents.scm
Normal file
0
packages/language-clojure/grammars/ts/indents.scm
Normal file
34
packages/language-clojure/spec/fixtures/tokens.clj
vendored
Normal file
34
packages/language-clojure/spec/fixtures/tokens.clj
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
(ns foobar)
|
||||
; <- punctuation.section.expression.begin
|
||||
; ^ meta.definition.global
|
||||
; ^ entity.global
|
||||
; ^ punctuation.section.expression.end
|
||||
|
||||
(defn foobar [a b]
|
||||
; <- keyword.control
|
||||
; ^ entity.global
|
||||
; ^ meta.definition.global
|
||||
; ^ punctuation.section.vector.begin
|
||||
; ^ meta.vector
|
||||
; ^ meta.symbol
|
||||
; ^ punctuation.section.vector.end
|
||||
(+ a b 10 20))
|
||||
;^ meta.expression
|
||||
;^ entity.name.function
|
||||
; ^ constant.numeric
|
||||
|
||||
(def a "A STRING")
|
||||
; <- keyword.control
|
||||
; ^ entity.global
|
||||
; ^ string.quoted.double
|
||||
|
||||
#{'asd}
|
||||
; <- punctuation.section.set.begin
|
||||
; ^ meta.symbol
|
||||
; ^ punctuation.section.set.end
|
||||
|
||||
{:key "value"}
|
||||
; <- punctuation.section.map.begin
|
||||
; ^ constant.keyword
|
||||
; ^ meta.map
|
||||
; ^ punctuation.section.map.end
|
34
packages/language-clojure/spec/fixtures/tree-sitter-folds.clj
vendored
Normal file
34
packages/language-clojure/spec/fixtures/tree-sitter-folds.clj
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
(defn a [a b]
|
||||
; <- fold_begin.paren
|
||||
; ^ fold_new_position.paren
|
||||
(+ a b)
|
||||
[1
|
||||
; <- fold_begin.vector
|
||||
; ^ fold_new_position.vector
|
||||
2
|
||||
3]
|
||||
; ^ fold_end.vector
|
||||
{:a 10
|
||||
; <- fold_begin.map
|
||||
; ^ fold_new_position.map
|
||||
:b 20
|
||||
:c [1
|
||||
; ^ fold_begin.inner_vector
|
||||
; ^ fold_new_position.inner_vector
|
||||
2
|
||||
3]})
|
||||
; ^ fold_end.paren
|
||||
; ^ fold_end.map
|
||||
; ^ fold_end.inner_vector
|
||||
|
||||
#(inner
|
||||
; <- fold_begin.anon
|
||||
; ^ fold_new_position.anon
|
||||
"function"
|
||||
#{:with
|
||||
; <- fold_begin.set
|
||||
; ^ fold_new_position.set
|
||||
:inner
|
||||
:set})
|
||||
; ^ fold_end.anon
|
||||
; ^ fold_end.set
|
6
packages/language-clojure/spec/fixtures/tree-sitter-tokens.clj
vendored
Normal file
6
packages/language-clojure/spec/fixtures/tree-sitter-tokens.clj
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#_
|
||||
(+ 1 2)
|
||||
; <- comment.block
|
||||
|
||||
'(a b 1 2)
|
||||
; ^ !entity.name.function
|
36
packages/language-clojure/spec/tokenizer-spec.js
Normal file
36
packages/language-clojure/spec/tokenizer-spec.js
Normal file
@ -0,0 +1,36 @@
|
||||
/* global runGrammarTests, runFoldsTests */
|
||||
const path = require('path');
|
||||
|
||||
function setConfigForLanguageMode(mode) {
|
||||
let useTreeSitterParsers = mode !== 'textmate';
|
||||
let useExperimentalModernTreeSitter = mode === 'wasm-tree-sitter';
|
||||
atom.config.set('core.useTreeSitterParsers', useTreeSitterParsers);
|
||||
atom.config.set('core.useExperimentalModernTreeSitter', useExperimentalModernTreeSitter);
|
||||
}
|
||||
|
||||
describe('Clojure grammars', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await atom.packages.activatePackage('language-clojure');
|
||||
});
|
||||
|
||||
it('tokenizes the editor using TextMate parser', async () => {
|
||||
setConfigForLanguageMode('textmate');
|
||||
await runGrammarTests(path.join(__dirname, 'fixtures', 'tokens.clj'), /;/)
|
||||
});
|
||||
|
||||
it('tokenizes the editor using node tree-sitter parser the same as TextMate', async () => {
|
||||
setConfigForLanguageMode('wasm-tree-sitter');
|
||||
await runGrammarTests(path.join(__dirname, 'fixtures', 'tokens.clj'), /;/)
|
||||
});
|
||||
|
||||
it('tokenizes the editor using node tree-sitter parser (specific rules)', async () => {
|
||||
setConfigForLanguageMode('wasm-tree-sitter');
|
||||
await runGrammarTests(path.join(__dirname, 'fixtures', 'tree-sitter-tokens.clj'), /;/)
|
||||
});
|
||||
|
||||
it('folds Clojure code', async () => {
|
||||
setConfigForLanguageMode('wasm-tree-sitter');
|
||||
await runFoldsTests(path.join(__dirname, 'fixtures', 'tree-sitter-folds.clj'), /;/)
|
||||
});
|
||||
});
|
16
packages/language-css/grammars/modern-tree-sitter-css.cson
Normal file
16
packages/language-css/grammars/modern-tree-sitter-css.cson
Normal file
@ -0,0 +1,16 @@
|
||||
name: 'CSS'
|
||||
scopeName: 'source.css'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-css'
|
||||
|
||||
fileTypes: [
|
||||
'css'
|
||||
]
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter/tree-sitter-css.wasm'
|
||||
highlightsQuery: 'tree-sitter/queries/highlights.scm'
|
||||
foldsQuery: 'tree-sitter/queries/folds.scm'
|
||||
indentsQuery: 'tree-sitter/queries/indents.scm'
|
||||
|
||||
injectionRegex: '^(css|CSS)$'
|
@ -0,0 +1,2 @@
|
||||
|
||||
(block) @fold
|
@ -0,0 +1,273 @@
|
||||
|
||||
; WORKAROUND:
|
||||
;
|
||||
; When you're typing a new property name inside of a list, tree-sitter-css will
|
||||
; assume the thing you're typing is a descendant selector tag name until you
|
||||
; get to the colon. This prevents it from highlighting the incomplete line like
|
||||
; a selector tag name.
|
||||
|
||||
(descendant_selector
|
||||
(tag_name) @_IGNORE_
|
||||
(#set! test.final true))
|
||||
|
||||
(ERROR
|
||||
(attribute_name) @_IGNORE_
|
||||
(#set! test.final true))
|
||||
|
||||
((ERROR
|
||||
(attribute_name) @invalid.illegal)
|
||||
(#set! test.final true))
|
||||
|
||||
; WORKAROUND:
|
||||
;
|
||||
; `:hover` and other pseudo-classes don't highlight correctly inside a media
|
||||
; query (https://github.com/tree-sitter/tree-sitter-css/issues/28)
|
||||
(
|
||||
(ERROR) @entity.other.attribute-name.pseudo-class.css
|
||||
(#match? @entity.other.attribute-name.pseudo-class.css "^:[\\w-]+$")
|
||||
)
|
||||
|
||||
; WORKAROUND:
|
||||
;
|
||||
; In `::after`, the "after" has a node type of `tag_name`. We want to catch it
|
||||
; here so that it doesn't get scoped like an HTML tag name in a selector.
|
||||
|
||||
; Scope the entire `::after` range as one unit.
|
||||
((pseudo_element_selector)
|
||||
@entity.other.attribute-name.pseudo-element.css
|
||||
(#set! adjust.startAt lastChild.previousSibling.startPosition)
|
||||
(#set! adjust.endAt lastChild.endPosition))
|
||||
|
||||
; Claim this range and block it from being scoped as a tag name.
|
||||
(pseudo_element_selector
|
||||
(tag_name) @_IGNORE_
|
||||
(#set! test.onlyIfLast true)
|
||||
(#set! test.final true))
|
||||
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
(comment) @comment.block.css
|
||||
|
||||
; Scope the block-comment delimiters (`/*` and `*/`).
|
||||
((comment) @punctuation.definition.comment.begin.css
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*"))
|
||||
((comment) @punctuation.definition.comment.end.css
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\*/$"))
|
||||
|
||||
|
||||
; SELECTORS
|
||||
; =========
|
||||
|
||||
; (selectors "," @punctuation.separator.list.comma.css)
|
||||
|
||||
; The "div" in `div.foo {`.
|
||||
(tag_name) @entity.name.tag.css
|
||||
|
||||
; The "foo" in `div[attr=foo] {`.
|
||||
(attribute_selector (plain_value) @string.unquoted.css)
|
||||
|
||||
[
|
||||
(child_selector ">")
|
||||
(sibling_selector "~")
|
||||
(adjacent_sibling_selector "+")
|
||||
] @keyword.operator.combinator.css
|
||||
|
||||
; The "#foo" in `div#foo {`.
|
||||
(id_selector
|
||||
"#" @punctuation.definition.entity.id.css) @entity.other.attribute-name.id.css
|
||||
|
||||
; KNOWN ISSUE: Namespace selectors like `svg|link` are not supported. See:
|
||||
; https://github.com/tree-sitter/tree-sitter-css/issues/33
|
||||
|
||||
;(namespace_name) @entity.other.namespace-prefix.css
|
||||
|
||||
; The '.' in `.foo`.
|
||||
(class_selector
|
||||
"." @punctuation.definition.entity.css)
|
||||
|
||||
; The '.foo' in `.foo`.
|
||||
((class_selector) @entity.other.attribute-name.class.css
|
||||
(#set! adjust.startAt lastChild.previousSibling.startPosition))
|
||||
|
||||
; Pseudo-classes without arguments: the ":first-of-type" in `li:first-of-type`.
|
||||
((pseudo_class_selector (class_name) (arguments) .) @entity.other.attribute-name.pseudo-class.css
|
||||
(#set! adjust.startAt lastChild.previousSibling.previousSibling.startPosition)
|
||||
(#set! adjust.endAt lastChild.previousSibling.endPosition)
|
||||
(#set! test.final true))
|
||||
|
||||
; Pseudo-classes with arguments: the ":nth-of-type" in `li:nth-of-type(2n-1)`.
|
||||
((pseudo_class_selector (class_name) .) @entity.other.attribute-name.pseudo-class.css
|
||||
(#set! adjust.startAt lastChild.previousSibling.startPosition)
|
||||
(#set! adjust.endAt lastChild.endPosition))
|
||||
|
||||
(arguments
|
||||
"(" @punctuation.definition.arguments.begin.bracket.round.css
|
||||
")" @punctuation.definition.arguments.end.bracket.round.css)
|
||||
|
||||
(attribute_selector
|
||||
"[" @punctuation.definition.entity.begin.bracket.square.css
|
||||
(attribute_name) @entity.other.attribute-name.css
|
||||
"]" @punctuation.definition.entity.end.bracket.square.css)
|
||||
|
||||
(attribute_selector
|
||||
["=" "^=" "$=" "~=" "|="] @keyword.operator.pattern.css)
|
||||
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
(declaration
|
||||
(property_name) @variable.other.assignment.css
|
||||
(#match? @variable.other.assignment.css "^--" )
|
||||
(#set! test.final true))
|
||||
|
||||
; PROPERTIES
|
||||
; ==========
|
||||
|
||||
; TODO: Is it worth it to try to maintain a list of recognized property names?
|
||||
; Would be useful to know if you've typo'd something, but it would be a
|
||||
; maintenance headache.
|
||||
(declaration
|
||||
(property_name) @support.type.property-name.css)
|
||||
|
||||
; VALUES
|
||||
; ======
|
||||
|
||||
; Strings
|
||||
; -------
|
||||
|
||||
((string_value) @string.quoted.double.css
|
||||
(#match? @string.quoted.double.css "^\"")
|
||||
(#match? @string.quoted.double.css "\"$"))
|
||||
|
||||
((string_value) @string.quoted.single.css
|
||||
(#match? @string.quoted.single.css "^'")
|
||||
(#match? @string.quoted.single.css "'$"))
|
||||
|
||||
((string_value) @puncutation.definition.string.begin.css
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^[\"']"))
|
||||
|
||||
((string_value) @puncutation.definition.string.end.css
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "[\"']$"))
|
||||
|
||||
|
||||
; Property value constants
|
||||
; ------------------------
|
||||
|
||||
((plain_value) @support.constant.property-value.css
|
||||
(#match? @support.constant.property-value.css "^(above|absolute|active|add|additive|after-edge|alias|all|all-petite-caps|all-scroll|all-small-caps|alpha|alphabetic|alternate|alternate-reverse|always|antialiased|auto|auto-pos|available|avoid|avoid-column|avoid-page|avoid-region|backwards|balance|baseline|before-edge|below|bevel|bidi-override|blink|block|block-axis|block-start|block-end|bold|bolder|border|border-box|both|bottom|bottom-outside|break-all|break-word|bullets|butt|capitalize|caption|cell|center|central|char|circle|clip|clone|close-quote|closest-corner|closest-side|col-resize|collapse|color|color-burn|color-dodge|column|column-reverse|common-ligatures|compact|condensed|contain|content|content-box|contents|context-menu|contextual|copy|cover|crisp-edges|crispEdges|crosshair|cyclic|dark|darken|dashed|decimal|default|dense|diagonal-fractions|difference|digits|disabled|disc|discretionary-ligatures|distribute|distribute-all-lines|distribute-letter|distribute-space|dot|dotted|double|double-circle|downleft|downright|e-resize|each-line|ease|ease-in|ease-in-out|ease-out|economy|ellipse|ellipsis|embed|end|evenodd|ew-resize|exact|exclude|exclusion|expanded|extends|extra-condensed|extra-expanded|fallback|farthest-corner|farthest-side|fill|fill-available|fill-box|filled|fit-content|fixed|flat|flex|flex-end|flex-start|flip|flow-root|forwards|freeze|from-image|full-width|geometricPrecision|georgian|grab|grabbing|grayscale|grid|groove|hand|hanging|hard-light|help|hidden|hide|historical-forms|historical-ligatures|horizontal|horizontal-tb|hue|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|infinite|inherit|initial|inline|inline-axis|inline-block|inline-end|inline-flex|inline-grid|inline-list-item|inline-start|inline-table|inset|inside|inter-character|inter-ideograph|inter-word|intersect|invert|isolate|isolate-override|italic|jis04|jis78|jis83|jis90|justify|justify-all|kannada|keep-all|landscape|large|larger|left|light|lighten|lighter|line|line-edge|line-through|linear|linearRGB|lining-nums|list-item|local|loose|lowercase|lr|lr-tb|ltr|luminance|luminosity|main-size|mandatory|manipulation|manual|margin-box|match-parent|match-source|mathematical|max-content|medium|menu|message-box|middle|min-content|miter|mixed|move|multiply|n-resize|narrower|ne-resize|nearest-neighbor|nesw-resize|newspaper|no-change|no-clip|no-close-quote|no-common-ligatures|no-contextual|no-discretionary-ligatures|no-drop|no-historical-ligatures|no-open-quote|no-repeat|none|nonzero|normal|not-allowed|nowrap|ns-resize|numbers|numeric|nw-resize|nwse-resize|oblique|oldstyle-nums|open|open-quote|optimizeLegibility|optimizeQuality|optimizeSpeed|optional|ordinal|outset|outside|over|overlay|overline|padding|padding-box|page|painted|pan-down|pan-left|pan-right|pan-up|pan-x|pan-y|paused|petite-caps|pixelated|plaintext|pointer|portrait|pre|pre-line|pre-wrap|preserve-3d|progress|progressive|proportional-nums|proportional-width|proximity|radial|recto|region|relative|remove|repeat|repeat-[xy]|reset-size|reverse|revert|ridge|right|rl|rl-tb|round|row|row-resize|row-reverse|row-severse|rtl|ruby|ruby-base|ruby-base-container|ruby-text|ruby-text-container|run-in|running|s-resize|saturation|scale-down|screen|scroll|scroll-position|se-resize|semi-condensed|semi-expanded|separate|sesame|show|sideways|sideways-left|sideways-lr|sideways-right|sideways-rl|simplified|slashed-zero|slice|small|small-caps|small-caption|smaller|smooth|soft-light|solid|space|space-around|space-between|space-evenly|spell-out|square|sRGB|stacked-fractions|start|static|status-bar|swap|step-end|step-start|sticky|stretch|strict|stroke|stroke-box|style|sub|subgrid|subpixel-antialiased|subtract|super|sw-resize|symbolic|table|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row|table-row-group|tabular-nums|tb|tb-rl|text|text-after-edge|text-before-edge|text-bottom|text-top|thick|thin|titling-caps|top|top-outside|touch|traditional|transparent|triangle|ultra-condensed|ultra-expanded|under|underline|unicase|unset|upleft|uppercase|upright|use-glyph-orientation|use-script|verso|vertical|vertical-ideographic|vertical-lr|vertical-rl|vertical-text|view-box|visible|visibleFill|visiblePainted|visibleStroke|w-resize|wait|wavy|weight|whitespace|wider|words|wrap|wrap-reverse|x|x-large|x-small|xx-large|xx-small|y|zero|zoom-in|zoom-out)$"))
|
||||
|
||||
; All property values that have special meaning in `font-family`.
|
||||
; TODO: Restrict these to be meaningful only when the property name is font-related?
|
||||
((plain_value) @support.constant.property-value.font-name.css
|
||||
(#match? @support.constant.property-value.font-name.css "^(serif|sans-serif|monospace|cursive|fantasy|system-ui|ui-serif|ui-sans-serif|ui-monospace|ui-rounded|emoji|math|fangsong)$"))
|
||||
|
||||
; All property values that have special meaning in `list-style-type`.
|
||||
; TODO: Restrict these to be meaningful only when the property name is `list-style-type`?
|
||||
((plain_value) @support.constant.property-value.list-style-type.css
|
||||
(#match? @support.constant.property-value.list-style-type.css "^(arabic-indic|armenian|bengali|cambodian|circle|cjk-decimal|cjk-earthly-branch|cjk-heavenly-stem|cjk-ideographic|decimal|decimal-leading-zero|devanagari|disc|disclosure-closed|disclosure-open|ethiopic-halehame-am|ethiopic-halehame-ti-e[rt]|ethiopic-numeric|georgian|gujarati|gurmukhi|hangul|hangul-consonant|hebrew|hiragana|hiragana-iroha|japanese-formal|japanese-informal|kannada|katakana|katakana-iroha|khmer|korean-hangul-formal|korean-hanja-formal|korean-hanja-informal|lao|lower-alpha|lower-armenian|lower-greek|lower-latin|lower-roman|malayalam|mongolian|myanmar|oriya|persian|simp-chinese-formal|simp-chinese-informal|square|tamil|telugu|thai|tibetan|trad-chinese-formal|trad-chinese-informal|upper-alpha|upper-armenian|upper-latin|upper-roman|urdu)$"))
|
||||
|
||||
|
||||
; Numbers & units
|
||||
; ---------------
|
||||
|
||||
; This node type appears to always be a hex color.
|
||||
(color_value) @constant.other.color.rgb-value.hex.css
|
||||
|
||||
[(integer_value) (float_value)] @constant.numeric.css
|
||||
|
||||
; All unit types with valid scope names.
|
||||
((unit) @keyword.other.unit._TEXT_.css
|
||||
(#match? @keyword.other.unit._TEXT_.css "^(deg|grad|rad|turn|ch|cm|em|ex|fr|in|mm|mozmm|pc|pt|px|q|rem|vh|vmax|vmin|vw|dpi|dpcm|dpps|s|ms)$"))
|
||||
|
||||
((unit) @keyword.other.unit.percentage.css
|
||||
(#eq? @keyword.other.unit.percentage.css "%"))
|
||||
|
||||
; The magic color value `currentColor`.
|
||||
((plain_value) @support.constant.color.current.css
|
||||
(#eq? @support.constant.color.current.css "currentColor"))
|
||||
|
||||
; Match the TM bundle's special treatment of named colors.
|
||||
((plain_value) @support.constant.color.w3c-standard-color-name.css
|
||||
(#match? @support.constant.color.w3c-standard-color-name.css "^(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)$"))
|
||||
|
||||
((plain_value) @support.constant.color.w3c-extended-color-name.css
|
||||
(#match? @support.constant.color.w3c-extended-color-name.css "^(aliceblue|antiquewhite|aquamarine|azure|beige|bisque|blanchedalmond|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|gainsboro|ghostwhite|gold|goldenrod|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|limegreen|linen|magenta|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|oldlace|olivedrab|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|rebeccapurple|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|thistle|tomato|transparent|turquoise|violet|wheat|whitesmoke|yellowgreen)$"))
|
||||
|
||||
((plain_value) @invalid.deprecated.color.system.css
|
||||
(#match? @invalid.deprecated.color.system.css "^(ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)$"))
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
|
||||
; (call_expression
|
||||
; (function_name) @support.function.var.css
|
||||
; (#eq? @support.function.var.css "var")
|
||||
; )
|
||||
|
||||
((function_name) @support.function.var.css
|
||||
(arguments (plain_value) @variable.css)
|
||||
(#eq? @support.function.var.css "var"))
|
||||
|
||||
((function_name) @support.function._TEXT_.css
|
||||
; Because we just handled it above.
|
||||
(#not-eq? @support.function._TEXT_.css "var"))
|
||||
|
||||
|
||||
((function_name) @_IGNORE_
|
||||
(arguments (plain_value) @string.unquoted.css)
|
||||
(#eq? @_IGNORE_ "url"))
|
||||
|
||||
|
||||
; AT-RULES
|
||||
; ========
|
||||
|
||||
"@media" @keyword.control.at-rule.media.css
|
||||
"@import" @keyword.control.at-rule.import.css
|
||||
"@charset" @keyword.control.at-rule.charset.css
|
||||
"@namespace" @keyword.control.at-rule.namespace.css
|
||||
"@supports" @keyword.control.at-rule.supports.css
|
||||
"@keyframes" @keyword.control.at-rule.keyframes.css
|
||||
|
||||
; The parser is permissive and supports at-rule keywords that don't currently
|
||||
; exist, so we'll set a fallback scope for those.
|
||||
((at_keyword) @keyword.control.at-rule.other.css
|
||||
(#set! test.shy true))
|
||||
|
||||
[(to) (from)] @keyword.control._TYPE_.css
|
||||
(important) @keyword.control.important.css
|
||||
|
||||
(keyword_query) @support.constant.css
|
||||
(feature_name) @support.constant.css
|
||||
|
||||
; OPERATORS
|
||||
; =========
|
||||
|
||||
; Used in `@media` queries.
|
||||
["and" "not" "only" "or"] @keyword.operator.logical._TYPE_.css
|
||||
|
||||
; Used in `calc()` and elsewhere.
|
||||
(binary_expression ["+" "-" "*" "/"] @keyword.operator.arithmetic.css)
|
||||
|
||||
; PUNCTUATION
|
||||
; ===========
|
||||
|
||||
"{" @punctuation.brace.curly.begin.css
|
||||
"}" @punctuation.brace.curly.end.css
|
||||
";" @punctuation.terminator.rule.css
|
||||
"," @punctuation.separator.list.comma.css
|
||||
|
||||
(pseudo_class_selector
|
||||
[":" "::"] @punctuation.definition.entity.css)
|
||||
|
||||
(":" @punctuation.separator.key-value.css
|
||||
(#set! test.shy true))
|
||||
|
||||
|
||||
; SECTIONS
|
||||
; ========
|
||||
(rule_set (block) @meta.block.inside-selector.css)
|
||||
((block) @meta.block.css
|
||||
(#set! test.shy true))
|
||||
(selectors) @meta.selector.css
|
@ -0,0 +1,8 @@
|
||||
|
||||
[
|
||||
"{"
|
||||
] @indent
|
||||
|
||||
[
|
||||
"}"
|
||||
] @dedent
|
BIN
packages/language-css/grammars/tree-sitter/tree-sitter-css.wasm
Executable file
BIN
packages/language-css/grammars/tree-sitter/tree-sitter-css.wasm
Executable file
Binary file not shown.
37
packages/language-css/lib/main.js
Normal file
37
packages/language-css/lib/main.js
Normal file
@ -0,0 +1,37 @@
|
||||
exports.activate = () => {
|
||||
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type: 'comment',
|
||||
language: () => 'todo',
|
||||
content: (node) => node
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type: 'comment',
|
||||
language: () => 'hyperlink',
|
||||
content: (node) => node
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type: 'string_value',
|
||||
language: () => 'hyperlink',
|
||||
content: (node) => node
|
||||
});
|
||||
|
||||
// Catch things like
|
||||
//
|
||||
// @import url(https://www.example.com/style.css);
|
||||
//
|
||||
// where the URL is unquoted.
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type: 'call_expression',
|
||||
language: () => 'hyperlink',
|
||||
content: (node) => {
|
||||
let functionName = node.descendantsOfType('function_value')[0]?.text;
|
||||
if (!functionName === 'url') { return null; }
|
||||
|
||||
return node.descendantsOfType('plain_value');
|
||||
}
|
||||
});
|
||||
|
||||
};
|
@ -7,8 +7,9 @@
|
||||
"version": "0.45.4",
|
||||
"engines": {
|
||||
"atom": "*",
|
||||
"node": "*"
|
||||
"node": ">=14"
|
||||
},
|
||||
"main": "lib/main",
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
'.source.css':
|
||||
'core':
|
||||
'useTreeSitterParsers': false
|
||||
'languageParser': 'textmate'
|
||||
'editor':
|
||||
'commentStart': '/*'
|
||||
'commentEnd': '*/'
|
||||
|
@ -2,7 +2,7 @@ describe 'CSS grammar', ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
17
packages/language-go/grammars/modern-tree-sitter-go.cson
Normal file
17
packages/language-go/grammars/modern-tree-sitter-go.cson
Normal file
@ -0,0 +1,17 @@
|
||||
name: 'Go'
|
||||
scopeName: 'source.go'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-go'
|
||||
|
||||
fileTypes: [
|
||||
'go'
|
||||
]
|
||||
|
||||
comments:
|
||||
start: '// '
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-go/tree-sitter-go.wasm'
|
||||
highlightsQuery: 'tree-sitter-go/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-go/folds.scm'
|
||||
indentsQuery: 'tree-sitter-go/indents.scm'
|
9
packages/language-go/grammars/tree-sitter-go/folds.scm
Normal file
9
packages/language-go/grammars/tree-sitter-go/folds.scm
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
; This is enough to get all if/else if/else blocks folding without getting in
|
||||
; each others' way.
|
||||
(if_statement (block) @fold
|
||||
(#set! fold.adjustToEndOfPreviousRow true))
|
||||
|
||||
(block) @fold
|
||||
(import_spec_list) @fold
|
||||
(parameter_list) @fold
|
285
packages/language-go/grammars/tree-sitter-go/highlights.scm
Normal file
285
packages/language-go/grammars/tree-sitter-go/highlights.scm
Normal file
@ -0,0 +1,285 @@
|
||||
; CAVEATS:
|
||||
|
||||
; * No support for string placeholders in `Printf` functions (injection
|
||||
; candidate?)
|
||||
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
((comment) @comment.line.double-slash.go
|
||||
(#match? @comment.line.double-slash.go "^\/\/")
|
||||
(#set! test.final true))
|
||||
|
||||
((comment) @punctuation.definition.comment.go
|
||||
(#match? @punctuation.definition.comment.go "^\/\/")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^\/\/"))
|
||||
|
||||
|
||||
((comment) @comment.block.go
|
||||
(#match? @comment.block.go "^\\/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.begin.go
|
||||
(#match? @punctuation.definition.comment.begin.go "^\\/\\*")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^\\/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.end.go
|
||||
(#match? @punctuation.definition.comment.end.go "\\*\\/$")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\*\\/$"))
|
||||
|
||||
|
||||
; TYPES
|
||||
; =====
|
||||
|
||||
(type_declaration
|
||||
(type_spec
|
||||
name: (type_identifier) @entity.name.type.go)
|
||||
(#set! test.final true))
|
||||
|
||||
(type_identifier) @storage.type.other.go
|
||||
|
||||
[
|
||||
"func"
|
||||
"import"
|
||||
"package"
|
||||
] @keyword._TYPE_.go
|
||||
|
||||
"type" @storage.type.go
|
||||
|
||||
[
|
||||
"struct"
|
||||
] @storage.type._TYPE_.go
|
||||
|
||||
(struct_type
|
||||
(field_declaration_list
|
||||
(field_declaration
|
||||
(field_identifier) @entity.other.attribute-name.go)))
|
||||
|
||||
(keyed_element
|
||||
(field_identifier) @entity.other.attribute-name.go
|
||||
.
|
||||
":" @punctuation.separator.key-value.go)
|
||||
|
||||
[
|
||||
"break"
|
||||
"case"
|
||||
"continue"
|
||||
"default"
|
||||
"defer"
|
||||
"else"
|
||||
"fallthrough"
|
||||
"for"
|
||||
"go"
|
||||
"goto"
|
||||
"if"
|
||||
"range"
|
||||
"return"
|
||||
"select"
|
||||
"switch"
|
||||
] @keyword.control._TYPE_.go
|
||||
|
||||
|
||||
(function_declaration (identifier) @entity.name.function.go)
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.function.builtin.go
|
||||
(#match? @support.function.builtin.go "^(?:append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)$")
|
||||
(#set! test.final true))
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.other.function.go)
|
||||
|
||||
(call_expression
|
||||
(selector_expression
|
||||
field: (field_identifier) @support.other.function.go))
|
||||
|
||||
; OBJECTS
|
||||
; =======
|
||||
|
||||
(selector_expression
|
||||
operand: (selector_expression
|
||||
operand: (identifier) @support.other.object.go
|
||||
field: (field_identifier) @support.other.object.go))
|
||||
|
||||
; TODO: If we do this, then we have to do chaining (`a.b.c.Close()`) and that
|
||||
; won't be fun.
|
||||
|
||||
(selector_expression
|
||||
operand: (identifier) @support.other.object.go)
|
||||
|
||||
; PACKAGES
|
||||
; ========
|
||||
|
||||
(package_clause
|
||||
(package_identifier) @entity.name.package.go
|
||||
(#set! test.final true))
|
||||
|
||||
(package_identifier) @support.object.package.go
|
||||
|
||||
; STRINGS
|
||||
; =======
|
||||
|
||||
((interpreted_string_literal "\"") @string.quoted.double.go)
|
||||
(interpreted_string_literal
|
||||
"\"" @punctuation.definition.string.begin.go
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(interpreted_string_literal
|
||||
"\"" @punctuation.definition.string.end.go
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
(escape_sequence) @constant.character.escape.go
|
||||
|
||||
(rune_literal) @string.quoted.single.rune.go
|
||||
|
||||
(raw_string_literal) @string.quoted.raw.go
|
||||
((raw_string_literal)
|
||||
@punctuation.definition.string.begin.go
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^`"))
|
||||
((raw_string_literal)
|
||||
@punctuation.definition.string.end.go
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "`$"))
|
||||
|
||||
|
||||
; NUMBERS
|
||||
; =======
|
||||
|
||||
(int_literal) @constant.numeric.integer.go
|
||||
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
[
|
||||
"var"
|
||||
"const"
|
||||
] @storage.modifier._TYPE_.go
|
||||
|
||||
(parameter_declaration (identifier) @variable.parameter.go)
|
||||
(variadic_parameter_declaration (identifier) @variable.parameter.go)
|
||||
|
||||
(range_clause
|
||||
(expression_list
|
||||
(identifier) @variable.parameter.range.go))
|
||||
|
||||
(const_spec
|
||||
name: (identifier) @variable.other.assignment.const.go)
|
||||
|
||||
(var_spec
|
||||
name: (identifier) @variable.other.assignment.var.go)
|
||||
|
||||
; (var_declaration
|
||||
; (expression_list
|
||||
; (identifier) @variable.other.assignment.go))
|
||||
|
||||
(short_var_declaration
|
||||
(expression_list
|
||||
(identifier) @variable.other.assignment.var.go))
|
||||
|
||||
(assignment_statement
|
||||
(expression_list
|
||||
(identifier) @variable.other.assigment.go))
|
||||
|
||||
; CONSTANTS
|
||||
; =========
|
||||
|
||||
[
|
||||
(true)
|
||||
(false)
|
||||
(nil)
|
||||
] @constant.language._TYPE_.go
|
||||
|
||||
((identifier) @constant.language.iota.go
|
||||
(#eq? @constant.language.iota.go "iota"))
|
||||
|
||||
; OPERATORS
|
||||
; =========
|
||||
|
||||
(binary_expression
|
||||
[
|
||||
"=="
|
||||
"!="
|
||||
">"
|
||||
"<"
|
||||
] @keyword.operator.comparison.go)
|
||||
|
||||
[
|
||||
"="
|
||||
":="
|
||||
] @keyword.operator.assignment.go
|
||||
|
||||
[
|
||||
"+="
|
||||
"-="
|
||||
"|="
|
||||
"^="
|
||||
"*="
|
||||
"/="
|
||||
"%="
|
||||
"<<="
|
||||
">>="
|
||||
"&^="
|
||||
"&="
|
||||
] @keyword.operator.assignment.compound.go
|
||||
|
||||
"<-" @keyword.operator.channel.go
|
||||
|
||||
"++" @keyword.operator.increment.go
|
||||
"--" @keyword.operator.decrement.go
|
||||
|
||||
|
||||
|
||||
(binary_expression
|
||||
["+" "-" "*" "/" "%"] @keyword.operator.arithmetic.go)
|
||||
|
||||
(binary_expression
|
||||
["&" "|" "^" "&^" "<<" ">>"] @keyword.operator.arithmetic.bitwise.go)
|
||||
|
||||
(binary_expression ["&&" "||"] @keyword.operator.logical.go)
|
||||
|
||||
(variadic_parameter_declaration "..." @keyword.operator.ellipsis.go)
|
||||
|
||||
|
||||
(pointer_type "*" @keyword.operator.address.go)
|
||||
(unary_expression ["&" "*"] @keyword.operator.address.go)
|
||||
|
||||
(unary_expression "!" @keyword.operator.unary.go)
|
||||
|
||||
"." @keyword.operator.accessor.js
|
||||
|
||||
|
||||
; PUNCTUATION
|
||||
; ===========
|
||||
|
||||
";" @punctuation.terminator.go
|
||||
"," @punctuation.separator.comma.go
|
||||
":" @punctuation.separator.colon.go
|
||||
|
||||
(parameter_list
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.go
|
||||
")" @punctuation.definition.parameters.end.bracket.round.go
|
||||
(#set! test.final true))
|
||||
|
||||
(composite_literal
|
||||
body: (literal_value
|
||||
"{" @punctuation.definition.struct.begin.bracket.curly.go
|
||||
"}" @punctuation.definition.struct.end.bracket.curly.go
|
||||
(#set! test.final true)))
|
||||
|
||||
"{" @punctuation.definition.begin.bracket.curly.go
|
||||
"}" @punctuation.definition.end.bracket.curly.go
|
||||
"(" @punctuation.definition.group.begin.bracket.round.go
|
||||
")" @punctuation.definition.group.end.bracket.round.go
|
||||
"[" @punctuation.definition.begin.bracket.square.go
|
||||
"]" @punctuation.definition.end.bracket.square.go
|
||||
|
||||
; META
|
||||
; ====
|
||||
|
||||
(function_declaration
|
||||
(block) @meta.block.function.go
|
||||
(#set! test.final true))
|
||||
|
||||
(block) @meta.block.go
|
||||
|
||||
(import_spec) @meta.import-specifier.go
|
||||
(import_spec_list) @meta.import-specifier.list.go
|
9
packages/language-go/grammars/tree-sitter-go/indents.scm
Normal file
9
packages/language-go/grammars/tree-sitter-go/indents.scm
Normal file
@ -0,0 +1,9 @@
|
||||
[
|
||||
"{"
|
||||
"("
|
||||
] @indent
|
||||
|
||||
[
|
||||
"}"
|
||||
")"
|
||||
] @dedent
|
BIN
packages/language-go/grammars/tree-sitter-go/tree-sitter-go.wasm
Executable file
BIN
packages/language-go/grammars/tree-sitter-go/tree-sitter-go.wasm
Executable file
Binary file not shown.
@ -8,7 +8,7 @@
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"atom": "*",
|
||||
"node": "*"
|
||||
"node": ">=14"
|
||||
},
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"dependencies": {
|
||||
|
@ -2,7 +2,7 @@ describe 'Go grammar', ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-go')
|
||||
|
@ -5,7 +5,8 @@ describe 'Go settings', ->
|
||||
editor.destroy()
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open().then (o) ->
|
||||
|
17
packages/language-html/grammars/modern-tree-sitter-ejs.cson
Normal file
17
packages/language-html/grammars/modern-tree-sitter-ejs.cson
Normal file
@ -0,0 +1,17 @@
|
||||
name: 'EJS'
|
||||
scopeName: 'text.html.ejs'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-embedded-template'
|
||||
|
||||
fileTypes: [
|
||||
'ejs'
|
||||
'html.ejs'
|
||||
]
|
||||
|
||||
injectionRegex: '^(ejs|EJS)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-embedded-template/tree-sitter-embedded-template.wasm'
|
||||
highlightsQuery: 'tree-sitter-embedded-template/ejs/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-embedded-template/ejs/folds.scm'
|
||||
indentsQuery: 'tree-sitter-embedded-template/ejs/indents.scm'
|
17
packages/language-html/grammars/modern-tree-sitter-erb.cson
Normal file
17
packages/language-html/grammars/modern-tree-sitter-erb.cson
Normal file
@ -0,0 +1,17 @@
|
||||
name: 'ERB'
|
||||
scopeName: 'text.html.erb'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-embedded-template'
|
||||
|
||||
fileTypes: [
|
||||
'erb'
|
||||
'html.erb'
|
||||
]
|
||||
|
||||
injectionRegex: '^(erb|ERB)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-embedded-template/tree-sitter-embedded-template.wasm'
|
||||
highlightsQuery: 'tree-sitter-embedded-template/erb/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-embedded-template/erb/folds.scm'
|
||||
indentsQuery: 'tree-sitter-embedded-template/erb/indents.scm'
|
22
packages/language-html/grammars/modern-tree-sitter-html.cson
Normal file
22
packages/language-html/grammars/modern-tree-sitter-html.cson
Normal file
@ -0,0 +1,22 @@
|
||||
name: 'HTML'
|
||||
scopeName: 'text.html.basic'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-html'
|
||||
|
||||
injectionRegex: '(HTML|html|Html)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-html/tree-sitter-html.wasm'
|
||||
highlightsQuery: 'tree-sitter-html/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-html/folds.scm'
|
||||
indentsQuery: 'tree-sitter-html/indents.scm'
|
||||
|
||||
fileTypes: [
|
||||
'htm'
|
||||
'html'
|
||||
'shtml'
|
||||
]
|
||||
|
||||
comments:
|
||||
start: '<!-- '
|
||||
end: ' -->'
|
@ -0,0 +1,30 @@
|
||||
; We compare these to `firstChild.endPosition` because directives have a habit
|
||||
; of consuming all their preceding whitespace, including newlines.
|
||||
([(comment_directive) (directive) (output_directive)] @meta.embedded.block.ejs
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S")
|
||||
(#set! test.onlyIfNotEndsOnSameRowAs firstChild.endPosition))
|
||||
|
||||
([(comment_directive) (directive) (output_directive)] @meta.embedded.line.ejs
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S")
|
||||
(#set! test.onlyIfEndsOnSameRowAs firstChild.endPosition))
|
||||
|
||||
(comment_directive) @comment.block.ejs
|
||||
|
||||
; (output_directive
|
||||
; ["<%=" "%>"] @keyword.control.directive.output)
|
||||
;
|
||||
(directive
|
||||
["<%" "<%-" "<%_"] @keyword.directive.begin.ejs
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S"))
|
||||
|
||||
(directive
|
||||
["_%>" "%>" "-%>"] @keyword.directive.end.ejs)
|
||||
|
||||
; BUG: Some `directive` nodes are actually represented as `output_directive`
|
||||
; nodes.
|
||||
(output_directive
|
||||
["<%=" "<%" "<%-" "<%_" "<%%"] @keyword.directive.begin.ejs
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S"))
|
||||
|
||||
(output_directive
|
||||
["%>" "-%>" "_%>"] @keyword.directive.end.ejs)
|
@ -0,0 +1 @@
|
||||
;
|
@ -0,0 +1,33 @@
|
||||
; ((directive
|
||||
; "%>" @_IGNORE_
|
||||
; (#match! @_IGNORE_ "^$")
|
||||
; ) @_IGNORE_
|
||||
; (#set! test.final true))
|
||||
|
||||
; We compare these to `firstChild.endPosition` because directives have a habit
|
||||
; of consuming all their preceding whitespace, including newlines.
|
||||
([(comment_directive) (directive) (output_directive)] @meta.embedded.block.erb
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S")
|
||||
(#set! test.onlyIfNotEndsOnSameRowAs firstChild.endPosition))
|
||||
|
||||
([(comment_directive) (directive) (output_directive)] @meta.embedded.line.erb
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S")
|
||||
(#set! test.onlyIfEndsOnSameRowAs firstChild.endPosition))
|
||||
|
||||
(comment_directive) @comment.block.erb
|
||||
|
||||
(directive
|
||||
["<%" "<%-"] @keyword.directive.begin.erb
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S"))
|
||||
|
||||
(directive
|
||||
["%>" "-%>"] @keyword.directive.end.erb)
|
||||
|
||||
; BUG: Some `directive` nodes are actually represented as `output_directive`
|
||||
; nodes.
|
||||
(output_directive
|
||||
["<%=" "<%" "<%-"] @keyword.directive.begin.erb
|
||||
(#set! adjust.startBeforeFirstMatchOf "\\S"))
|
||||
|
||||
(output_directive
|
||||
["%>" "-%>"] @keyword.directive.end.erb)
|
@ -0,0 +1 @@
|
||||
;
|
Binary file not shown.
15
packages/language-html/grammars/tree-sitter-html/folds.scm
Normal file
15
packages/language-html/grammars/tree-sitter-html/folds.scm
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
; (element) @fold
|
||||
; (style_element) @fold
|
||||
; (script_element) @fold
|
||||
|
||||
[
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
] @fold
|
||||
|
||||
|
||||
((comment) @fold
|
||||
(#set! fold.endAt endPosition)
|
||||
(#set! fold.offsetEnd -3))
|
137
packages/language-html/grammars/tree-sitter-html/highlights.scm
Normal file
137
packages/language-html/grammars/tree-sitter-html/highlights.scm
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
; CAVEATS
|
||||
; =======
|
||||
;
|
||||
; * To recognize HTML entities, we're temporarily using a fork until
|
||||
; tree-sitter-html#50 lands. That gets us entity recognition in text, but not
|
||||
; in attribute values. We could fix that by writing a small parser to inject
|
||||
; into attribute values, but we could also just hold off for now.
|
||||
;
|
||||
|
||||
(doctype) @meta.tag.doctype.html
|
||||
|
||||
(doctype
|
||||
"<!" @punctuation.definition.tag.begin.html
|
||||
"doctype" @entity.name.tag.doctype.html
|
||||
">" @punctuation.definition.tag.end.html) @meta.tag.doctype.html
|
||||
|
||||
(style_element
|
||||
(raw_text) @meta.embedded.block.css.html)
|
||||
|
||||
(script_element
|
||||
(raw_text) @meta.embedded.block.js.html)
|
||||
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
(comment) @comment.block.html
|
||||
|
||||
((comment) @punctuation.definition.comment.begin.html
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^<!--"))
|
||||
|
||||
((comment) @punctuation.definition.comment.end.html
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "-->$"))
|
||||
|
||||
|
||||
; SUPPORT
|
||||
; =======
|
||||
|
||||
(start_tag
|
||||
(tag_name) @entity.name.tag.structure._TEXT_.html
|
||||
(#match? @entity.name.tag.structure._TEXT_.html "^(body|head|html|BODY|HEAD|HTML)$")
|
||||
(#set! test.final true))
|
||||
|
||||
(end_tag
|
||||
(tag_name) @entity.name.tag.structure._TEXT_.html
|
||||
(#match? @entity.name.tag.structure._TEXT_.html "^(body|head|html|BODY|HEAD|HTML)$")
|
||||
(#set! test.final true))
|
||||
|
||||
(start_tag
|
||||
(tag_name) @entity.name.tag.block._TEXT_.html
|
||||
(#match? @entity.name.tag.block._TEXT_.html "^(address|blockquote|dd|div|section|article|aside|header|footer|nav|menu|dl|dt|fieldset|form|frame|frameset|h1|h2|h3|h4|h5|h6|iframe|noframes|object|ol|p|ul|applet|center|dir|hr|pre|ADDRESS|BLOCKQUOTE|DD|DIV|SECTION|ARTICLE|ASIDE|HEADER|FOOTER|NAV|MENU|DL|DT|FIELDSET|FORM|FRAME|FRAMESET|H1|H2|H3|H4|H5|H6|IFRAME|NOFRAMES|OBJECT|OL|P|UL|APPLET|CENTER|DIR|HR|PRE)$")
|
||||
(#set! test.final true))
|
||||
|
||||
(end_tag
|
||||
(tag_name) @entity.name.tag.block._TEXT_.html
|
||||
(#match? @entity.name.tag.block._TEXT_.html "^(address|blockquote|dd|div|section|article|aside|header|footer|nav|menu|dl|dt|fieldset|form|frame|frameset|h1|h2|h3|h4|h5|h6|iframe|noframes|object|ol|p|ul|applet|center|dir|hr|pre|ADDRESS|BLOCKQUOTE|DD|DIV|SECTION|ARTICLE|ASIDE|HEADER|FOOTER|NAV|MENU|DL|DT|FIELDSET|FORM|FRAME|FRAMESET|H1|H2|H3|H4|H5|H6|IFRAME|NOFRAMES|OBJECT|OL|P|UL|APPLET|CENTER|DIR|HR|PRE)$")
|
||||
(#set! test.final true))
|
||||
|
||||
(start_tag
|
||||
(tag_name) @entity.name.tag.inline._TEXT_.html
|
||||
(#match? @entity.name.tag.inline._TEXT_.html "^(a|abbr|acronym|area|b|base|basefont|bdo|big|br|button|caption|cite|code|col|colgroup|del|dfn|em|font|head|html|i|img|input|ins|isindex|kbd|label|legend|li|link|map|meta|noscript|optgroup|option|param|q|s|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|var|A|ABBR|ACRONYM|AREA|B|BASE|BASEFONT|BDO|BIG|BR|BUTTON|CAPTION|CITE|CODE|COL|COLGROUP|DEL|DFN|EM|FONT|HEAD|HTML|I|IMG|INPUT|INS|ISINDEX|KBD|LABEL|LEGEND|LI|LINK|MAP|META|NOSCRIPT|OPTGROUP|OPTION|PARAM|Q|S|SAMP|SCRIPT|SELECT|SMALL|SPAN|STRIKE|STRONG|STYLE|SUB|SUP|TABLE|TBODY|TD|TEXTAREA|TFOOT|TH|THEAD|TITLE|TR|TT|U|VAR)$")
|
||||
(#set! test.final true))
|
||||
|
||||
(end_tag
|
||||
(tag_name) @entity.name.tag.inline._TEXT_.html
|
||||
(#match? @entity.name.tag.inline._TEXT_.html "^(a|abbr|acronym|area|b|base|basefont|bdo|big|br|button|caption|cite|code|col|colgroup|del|dfn|em|font|head|html|i|img|input|ins|isindex|kbd|label|legend|li|link|map|meta|noscript|optgroup|option|param|q|s|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|var|A|ABBR|ACRONYM|AREA|B|BASE|BASEFONT|BDO|BIG|BR|BUTTON|CAPTION|CITE|CODE|COL|COLGROUP|DEL|DFN|EM|FONT|HEAD|HTML|I|IMG|INPUT|INS|ISINDEX|KBD|LABEL|LEGEND|LI|LINK|MAP|META|NOSCRIPT|OPTGROUP|OPTION|PARAM|Q|S|SAMP|SCRIPT|SELECT|SMALL|SPAN|STRIKE|STRONG|STYLE|SUB|SUP|TABLE|TBODY|TD|TEXTAREA|TFOOT|TH|THEAD|TITLE|TR|TT|U|VAR)$")
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
; ELEMENTS
|
||||
; ========
|
||||
|
||||
; Tag names
|
||||
; ---------
|
||||
|
||||
(start_tag
|
||||
"<" @punctuation.definition.tag.begin.html
|
||||
">" @punctuation.definition.tag.end.html)
|
||||
|
||||
; Fallback for any tag that didn't get scoped in the Support section above.
|
||||
(start_tag
|
||||
(tag_name) @entity.name.tag.html)
|
||||
|
||||
(end_tag
|
||||
"</" @punctuation.definition.tag.begin.html
|
||||
">" @punctuation.definition.tag.end.html)
|
||||
|
||||
(end_tag
|
||||
(tag_name) @entity.name.tag.html)
|
||||
|
||||
(self_closing_tag
|
||||
"<" @punctuation.definition.tag.begin.html
|
||||
(tag_name) @entity.name.tag.html
|
||||
"/>" @punctuation.definition.tag.end.html)
|
||||
|
||||
|
||||
; Invalid tag names
|
||||
; -----------------
|
||||
|
||||
(erroneous_end_tag) @entity.name.tag.html
|
||||
(erroneous_end_tag_name) @invalid.illegal.erroneous-end-tag-name.html
|
||||
|
||||
|
||||
; Attributes
|
||||
; ----------
|
||||
|
||||
(attribute "=" @punctuation.separator.key-value.html)
|
||||
(attribute_name) @entity.other.attribute-name
|
||||
|
||||
; Single- and double-quotes around attribute values.
|
||||
((quoted_attribute_value ["\"" "'"] @punctuation.definition.string.begin.html)
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
((quoted_attribute_value ["\"" "'"] @punctuation.definition.string.end.html)
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
; If this matches, the value is double-quoted.
|
||||
(quoted_attribute_value "\"") @string.quoted.double.html
|
||||
|
||||
; If this matches, the value is single-quoted.
|
||||
(quoted_attribute_value "'") @string.quoted.single.html
|
||||
|
||||
; Prevent quoted attribute values from having `string.unquoted` applied.
|
||||
(quoted_attribute_value
|
||||
(attribute_value) @_IGNORE_
|
||||
(#set! test.final true))
|
||||
|
||||
; The "foo" in `<div class=foo>`.
|
||||
; Because of the preceding rule, if this matches and passes all tests, the
|
||||
; value must be unquoted.
|
||||
(attribute_value) @string.unquoted.html
|
||||
|
||||
|
||||
; MISC
|
||||
; ====
|
||||
|
||||
(entity) @constant.character.entity.html
|
@ -0,0 +1,9 @@
|
||||
|
||||
((start_tag) @indent
|
||||
; Only indent if this isn't a self-closing tag.
|
||||
(#not-match? @indent "^<(?:area|base|br|col|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)\\s"))
|
||||
|
||||
; `end_tag` will still match when only `</div` is present. Without enforcing
|
||||
; the presence of `>`, the dedent happens too soon.
|
||||
((end_tag) @dedent
|
||||
(#match? @dedent ">$"))
|
BIN
packages/language-html/grammars/tree-sitter-html/tree-sitter-html.wasm
Executable file
BIN
packages/language-html/grammars/tree-sitter-html/tree-sitter-html.wasm
Executable file
Binary file not shown.
@ -19,9 +19,43 @@ exports.activate = function() {
|
||||
}
|
||||
});
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'attribute_value',
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
// TODO: Inject hyperlink grammar into plain text?
|
||||
|
||||
// EMBEDDED
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.ejs', {
|
||||
type: 'template',
|
||||
language(node) {
|
||||
language() {
|
||||
return 'javascript';
|
||||
},
|
||||
content(node) {
|
||||
@ -32,7 +66,7 @@ exports.activate = function() {
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.ejs', {
|
||||
type: 'template',
|
||||
language(node) {
|
||||
language() {
|
||||
return 'html';
|
||||
},
|
||||
content(node) {
|
||||
@ -42,7 +76,7 @@ exports.activate = function() {
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.erb', {
|
||||
type: 'template',
|
||||
language(node) {
|
||||
language() {
|
||||
return 'ruby';
|
||||
},
|
||||
content(node) {
|
||||
@ -53,7 +87,7 @@ exports.activate = function() {
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.erb', {
|
||||
type: 'template',
|
||||
language(node) {
|
||||
language() {
|
||||
return 'html';
|
||||
},
|
||||
content(node) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
],
|
||||
"engines": {
|
||||
"atom": "*",
|
||||
"node": "*"
|
||||
"node": ">=14"
|
||||
},
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT",
|
||||
|
@ -5,7 +5,8 @@ describe 'TextMate HTML grammar', ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-html')
|
||||
|
@ -3,6 +3,7 @@ const dedent = require('dedent');
|
||||
describe('Tree-sitter HTML grammar', () => {
|
||||
beforeEach(async () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true);
|
||||
atom.config.set('core.useExperimentalModernTreeSitter', false);
|
||||
await atom.packages.activatePackage('language-html');
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
# name: 'Hyperlink'
|
||||
scopeName: 'text.hyperlink'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-hyperlink'
|
||||
|
||||
injectionRegex: 'hyperlink'
|
||||
treeSitter:
|
||||
grammar: 'ts/tree-sitter-hyperlink.wasm'
|
||||
highlightsQuery: 'ts/highlights.scm'
|
2
packages/language-hyperlink/grammars/ts/highlights.scm
Normal file
2
packages/language-hyperlink/grammars/ts/highlights.scm
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
(url) @markup.underline.link.hyperlink
|
BIN
packages/language-hyperlink/grammars/ts/tree-sitter-hyperlink.wasm
Executable file
BIN
packages/language-hyperlink/grammars/ts/tree-sitter-hyperlink.wasm
Executable file
Binary file not shown.
@ -4,7 +4,7 @@
|
||||
"description": "Hyperlink colorization in Atom",
|
||||
"engines": {
|
||||
"atom": "*",
|
||||
"node": "*"
|
||||
"node": ">=14"
|
||||
},
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT"
|
||||
|
17
packages/language-java/grammars/modern-tree-sitter-java.cson
Normal file
17
packages/language-java/grammars/modern-tree-sitter-java.cson
Normal file
@ -0,0 +1,17 @@
|
||||
name: 'Java'
|
||||
scopeName: 'source.java'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-java'
|
||||
|
||||
fileTypes: [
|
||||
'java'
|
||||
]
|
||||
|
||||
comments:
|
||||
start: '// '
|
||||
|
||||
treeSitter:
|
||||
grammar: 'tree-sitter-java/tree-sitter-java.wasm'
|
||||
highlightsQuery: 'tree-sitter-java/highlights.scm'
|
||||
indentsQuery: 'tree-sitter-java/indents.scm'
|
||||
foldsQuery: 'tree-sitter-java/folds.scm'
|
16
packages/language-java/grammars/tree-sitter-java/folds.scm
Normal file
16
packages/language-java/grammars/tree-sitter-java/folds.scm
Normal file
@ -0,0 +1,16 @@
|
||||
((comment) @fold
|
||||
(#set! fold.endAt endPosition)
|
||||
(#set! fold.adjustToEndOfPreviousRow true))
|
||||
|
||||
[
|
||||
(class_body)
|
||||
(enum_body)
|
||||
(interface_body)
|
||||
(annotation_type_body)
|
||||
(module_body)
|
||||
(constructor_body)
|
||||
(block)
|
||||
(switch_block)
|
||||
(annotation_argument_list)
|
||||
(formal_parameters)
|
||||
] @fold
|
401
packages/language-java/grammars/tree-sitter-java/highlights.scm
Normal file
401
packages/language-java/grammars/tree-sitter-java/highlights.scm
Normal file
@ -0,0 +1,401 @@
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
((comment) @comment.line.double-slash.java
|
||||
(#match? @comment.line.double-slash.java "^//"))
|
||||
|
||||
((comment) @punctuation.definition.comment.java
|
||||
(#match? @punctuation.definition.comment.java "^//")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^//"))
|
||||
|
||||
|
||||
((comment) @comment.block.documentation.javadoc.java
|
||||
(#match? @comment.block.documentation.javadoc.java "^/\\*\\*")
|
||||
(#set! test.final true)
|
||||
(#set! highlight.invalidateOnChange true))
|
||||
|
||||
((comment) @comment.block.java
|
||||
(#match? @comment.block.java "^/\\*")
|
||||
(#set! highlight.invalidateOnChange true))
|
||||
|
||||
((comment) @punctuation.definition.comment.begin.java
|
||||
(#match? @punctuation.definition.comment.begin.java "^/\\*\\*?")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.end.java
|
||||
(#match? @punctuation.definition.comment.end.java "\\*/$")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\*/$"))
|
||||
|
||||
; OBJECTS
|
||||
; =======
|
||||
|
||||
(class_declaration
|
||||
"class" @storage.modifier.class.java
|
||||
name: (_) @entity.name.type.class.java)
|
||||
|
||||
(superclass
|
||||
"extends" @storage.modifier.extends.java
|
||||
(type_identifier) @entity.other.inherited-class.java
|
||||
(#set! test.final true))
|
||||
|
||||
(class_declaration body: (_) @meta.class.body.java)
|
||||
|
||||
; INTERFACES
|
||||
; ==========
|
||||
|
||||
(interface_declaration
|
||||
"interface" @storage.modifier.interface
|
||||
name: (identifier) @entity.name.type.interface.java)
|
||||
|
||||
(interface_declaration body: (_) @meta.interface.body.java)
|
||||
|
||||
(annotation_type_declaration
|
||||
"@interface"
|
||||
@keyword.other.interface.annotated.java
|
||||
name: (_) @entity.name.type.interface.annotated.java)
|
||||
|
||||
(annotation_type_declaration body: (_) @meta.interface.annotated.body.java)
|
||||
|
||||
(annotation_type_element_declaration
|
||||
name: (_) @entity.name.function.interface.java)
|
||||
|
||||
|
||||
(extends_interfaces "extends" @storage.modifier.extends.java)
|
||||
|
||||
(extends_interfaces
|
||||
(interface_type_list
|
||||
(type_identifier) @entity.other.inherited-class.java)
|
||||
(#set! test.final true))
|
||||
|
||||
(super_interfaces "implements" @storage.modifier.implements.java)
|
||||
|
||||
(super_interfaces
|
||||
(interface_type_list
|
||||
(type_identifier) @entity.other.inherited-class.java)
|
||||
(#set! test.final true))
|
||||
|
||||
(static_initializer "static" @storage.modifier.static.java)
|
||||
|
||||
|
||||
; ANNOTATIONS
|
||||
; ===========
|
||||
|
||||
(marker_annotation
|
||||
"@" @punctuation.definition.annotation.java) @meta.declaration.annotation.java
|
||||
|
||||
; Cover both the '@' and the 'Foo' in `@Foo`.
|
||||
((marker_annotation) @storage.type.annotation.java @support.type.annotation.java
|
||||
(#set! adjust.endAt firstChild.nextSibling.endPosition))
|
||||
|
||||
(annotation
|
||||
"@" @punctuation.definition.annotation.java) @meta.declaration.annotation.java
|
||||
|
||||
; Cover both the '@' and the 'Foo' in `@Foo`.
|
||||
((annotation) @storage.type.annotation.java @support.type.annotation.java
|
||||
(#set! adjust.endAt firstChild.nextSibling.endPosition))
|
||||
|
||||
(element_value_pair key: (_) @variable.other.annotation.element.java)
|
||||
|
||||
; TYPES
|
||||
; =====
|
||||
|
||||
(object_creation_expression (type_identifier)
|
||||
@support.other.class.java
|
||||
(#set! test.final true))
|
||||
|
||||
; WORKAROUND: This matches often when the user is typing, so we shouldn't
|
||||
; highlight it until we know for sure what it is.
|
||||
(ERROR
|
||||
(type_identifier) @_IGNORE_
|
||||
(#set! test.final true))
|
||||
|
||||
; WORKAROUND: A chain like `System.out.println` shouldn't match at all until
|
||||
; it's out of an ERROR state; this should catch all references no matter how
|
||||
; long the chain is.
|
||||
(scoped_type_identifier
|
||||
(type_identifier) @_IGNORE
|
||||
(#set! test.onlyIfDescendantOfType ERROR)
|
||||
(#set! test.final true))
|
||||
|
||||
(type_identifier) @storage.type.java
|
||||
(type_parameter (identifier) @storage.type.java)
|
||||
|
||||
(void_type) @storage.type.void.java
|
||||
(integral_type) @storage.type.integral.java
|
||||
(floating_point_type) @storage.type.float.java
|
||||
(boolean_type) @storage.type.boolean.java
|
||||
|
||||
[
|
||||
"public"
|
||||
"private"
|
||||
"protected"
|
||||
"abstract"
|
||||
"static"
|
||||
"final"
|
||||
"strictfp"
|
||||
"synchronized"
|
||||
"native"
|
||||
"transient"
|
||||
"volatile"
|
||||
] @storage.modifier._TYPE_.java
|
||||
|
||||
(type_arguments (wildcard "?" @storage.type.generic.wildcard.java))
|
||||
(type_arguments (wildcard "extends" @storage.modifier.extends.java))
|
||||
(type_arguments (wildcard (super) @storage.modifier.super.java))
|
||||
|
||||
(type_bound "extends" @storage.modifier.extends)
|
||||
(type_bound "&" @punctuation.separator.types.java)
|
||||
|
||||
|
||||
|
||||
|
||||
; ENTITIES
|
||||
; ========
|
||||
|
||||
(enum_declaration "enum" @storage.type.enum.java)
|
||||
|
||||
(enum_declaration
|
||||
name: (identifier) @entity.name.type.enum.java)
|
||||
|
||||
(enum_declaration (enum_body) @meta.enum.body.java)
|
||||
|
||||
(enum_constant
|
||||
name: (identifier) @constant.other.enum.java)
|
||||
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
; =========
|
||||
|
||||
(method_declaration (identifier) @entity.name.function.method.java)
|
||||
|
||||
(method_declaration (block) @meta.method.body.java)
|
||||
|
||||
(constructor_declaration (identifier) @entity.name.function.method.constructor.java)
|
||||
|
||||
(constructor_body) @meta.method.constructor.body.java
|
||||
|
||||
(throws "throws" @storage.modifier.throws.java)
|
||||
|
||||
(method_invocation (identifier)
|
||||
@support.other.function.java)
|
||||
|
||||
(field_access (identifier) @constant.other.java
|
||||
(#match? @constant.other.java "^[A-Z][A-Z0-9_\\$]+$")
|
||||
(#set! test.final true))
|
||||
|
||||
(field_access
|
||||
object: (identifier) @support.other.class.java
|
||||
(#match? @support.other.class.java "^[A-Z]")
|
||||
(#set! test.final true))
|
||||
|
||||
(field_access
|
||||
field: (identifier) @support.other.class.java
|
||||
(#match? @support.other.class.java "^[A-Z]")
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
(method_invocation (identifier) @constant.other.java
|
||||
(#match? @constant.other.java "^[A-Z][A-Z0-9_\\$]+$")
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
[(this) (super)] @variable.language._TYPE_.java
|
||||
|
||||
(spread_parameter "..." @keyword.operator.ellipsis.java)
|
||||
|
||||
(formal_parameter (identifier) @variable.parameter.method.java)
|
||||
|
||||
(lambda_expression
|
||||
parameters: (identifier) @variable.parameter.lambda.java)
|
||||
|
||||
(lambda_expression
|
||||
parameters: (inferred_parameters
|
||||
(identifier) @variable.parameter.lambda.java))
|
||||
|
||||
(variable_declarator
|
||||
name: (identifier) @variable.other.assignment.java)
|
||||
|
||||
|
||||
|
||||
; PACKAGES
|
||||
; ========
|
||||
|
||||
(package_declaration) @meta.package.java
|
||||
|
||||
"package" @keyword.other.package.java
|
||||
|
||||
(import_declaration) @meta.import.java
|
||||
|
||||
(import_declaration
|
||||
["import"] @keyword.other._TYPE_.java)
|
||||
|
||||
(import_declaration (asterisk) @variable.language.wildcard.java)
|
||||
|
||||
|
||||
; STRINGS
|
||||
; =======
|
||||
|
||||
(character_literal) @string.quoted.single.java
|
||||
|
||||
((character_literal) @punctuation.definition.string.begin.java
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^'"))
|
||||
((character_literal) @punctuation.definition.string.end.java
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "'$"))
|
||||
|
||||
|
||||
(string_literal) @string.quoted.double.java
|
||||
|
||||
((string_literal) @punctuation.definition.string.begin.java
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^\""))
|
||||
((string_literal) @punctuation.definition.string.end.java
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\"$"))
|
||||
|
||||
; CAVEAT: Parser doesn't recognize escape sequences in strings.
|
||||
|
||||
; KEYWORDS
|
||||
; ========
|
||||
|
||||
[
|
||||
"assert"
|
||||
"break"
|
||||
"case"
|
||||
"catch"
|
||||
"continue"
|
||||
"default"
|
||||
"do"
|
||||
"else"
|
||||
"finally"
|
||||
"for"
|
||||
"if"
|
||||
"new"
|
||||
"return"
|
||||
"switch"
|
||||
"throw"
|
||||
"try"
|
||||
"while"
|
||||
] @keyword.control._TYPE_.java
|
||||
|
||||
; MISCELLANEOUS
|
||||
; =============
|
||||
|
||||
; (lambda_expression "->" @storage.type.function.arrow.java)
|
||||
|
||||
(catch_type "|" @punctuation.separator.catch.java)
|
||||
|
||||
|
||||
|
||||
; CONSTANTS
|
||||
; =========
|
||||
|
||||
[
|
||||
(true)
|
||||
(false)
|
||||
] @constant.language.boolean._TYPE_.java
|
||||
|
||||
(null_literal) @constant.language.null.java
|
||||
|
||||
; NUMBERS
|
||||
; =======
|
||||
|
||||
(decimal_integer_literal) @constant.numeric.integer.decimal.java
|
||||
(hex_integer_literal) @constant.numeric.integer.hexadecimal.java
|
||||
(octal_integer_literal) @constant.numeric.integer.octal.java
|
||||
(binary_integer_literal) @constant.numeric.integer.binary.java
|
||||
|
||||
(decimal_floating_point_literal) @constant.numeric.float.decimal.java
|
||||
(hex_floating_point_literal) @constant.numeric.float.hexadecimal.java
|
||||
|
||||
|
||||
; OPERATORS
|
||||
; =========
|
||||
|
||||
(ternary_expression ["?" ":"] @keyword.operator.ternary.java)
|
||||
|
||||
"instanceof" @keyword.operator.instanceof.java
|
||||
|
||||
"=" @keyword.operator.assignment.java
|
||||
|
||||
[
|
||||
"+="
|
||||
"-="
|
||||
"*="
|
||||
"/="
|
||||
"%="
|
||||
"&="
|
||||
"|="
|
||||
"^="
|
||||
"<<="
|
||||
">>="
|
||||
">>>="
|
||||
] @keyword.operator.assignment.compound.java
|
||||
|
||||
(binary_expression
|
||||
["&&" "||"] @keyword.operator.logical.java)
|
||||
(unary_expression "!" @keyword.operator.logical.java)
|
||||
|
||||
(binary_expression
|
||||
[
|
||||
"=="
|
||||
"!="
|
||||
"<="
|
||||
">="
|
||||
">"
|
||||
"<"
|
||||
] @keyword.operator.comparison.java)
|
||||
|
||||
(binary_expression
|
||||
[
|
||||
"-"
|
||||
"+"
|
||||
"*"
|
||||
"/"
|
||||
"%"
|
||||
] @keyword.operator.arithmetic.java)
|
||||
|
||||
(binary_expression
|
||||
["&" "|" "^" "~" "<<" ">>" ">>>"] @keyword.operator.bitwise.java)
|
||||
|
||||
"." @keyword.operator.accessor.dot.java
|
||||
"::" @keyword.operator.accessor.method-reference.java
|
||||
|
||||
; PUNCTUATION
|
||||
; ===========
|
||||
|
||||
";" @punctuation.terminator.statement.java
|
||||
|
||||
"," @punctuation.separator.comma.java
|
||||
"->" @punctuation.separator.lambda.java
|
||||
|
||||
(if_statement
|
||||
condition: (parenthesized_expression
|
||||
"(" @punctuation.definition.expression.begin.bracket.round.java
|
||||
")" @punctuation.definition.expression.end.bracket.round.java
|
||||
(#set! test.final true)))
|
||||
|
||||
(formal_parameters
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.java
|
||||
")" @punctuation.definition.parameters.end.bracket.round.java
|
||||
(#set! test.final true))
|
||||
|
||||
(argument_list
|
||||
"(" @punctuation.definition.arguments.begin.bracket.round.java
|
||||
")" @punctuation.definition.arguments.end.bracket.round.java
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
"{" @punctuation.definition.block.begin.bracket.curly.java
|
||||
"}" @punctuation.definition.block.end.bracket.curly.java
|
||||
"(" @punctuation.definition.expression.begin.bracket.round.java
|
||||
")" @punctuation.definition.expression.end.bracket.round.java
|
||||
"[" @punctuation.definition.array.begin.bracket.square.java
|
||||
"]" @punctuation.definition.array.end.bracket.square.java
|
||||
|
||||
(type_arguments "<" @punctuation.definition.type.begin.bracket.angle.java)
|
||||
(type_arguments ">" @punctuation.definition.type.end.bracket.angle.java)
|
||||
|
||||
(type_parameters "<" @punctuation.definition.type.begin.bracket.angle.java)
|
||||
(type_parameters ">" @punctuation.definition.type.end.bracket.angle.java)
|
25
packages/language-java/grammars/tree-sitter-java/indents.scm
Normal file
25
packages/language-java/grammars/tree-sitter-java/indents.scm
Normal file
@ -0,0 +1,25 @@
|
||||
; The closing brace of a switch statement's body should match the indentation of the line where the switch statement starts.
|
||||
(switch_statement
|
||||
body: (switch_block "}" @match
|
||||
(#set! test.onlyIfLast true))
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition))
|
||||
|
||||
; 'case' and 'default' need to be indented one level more than their containing
|
||||
; `switch`.
|
||||
(["case" "default"] @match
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
|
||||
[
|
||||
"{"
|
||||
"("
|
||||
"["
|
||||
] @indent
|
||||
|
||||
[
|
||||
"}"
|
||||
")"
|
||||
"]"
|
||||
] @dedent
|
||||
|
||||
["case" "default"] @indent
|
BIN
packages/language-java/grammars/tree-sitter-java/tree-sitter-java.wasm
Executable file
BIN
packages/language-java/grammars/tree-sitter-java/tree-sitter-java.wasm
Executable file
Binary file not shown.
3
packages/language-java/lib/main.js
Normal file
3
packages/language-java/lib/main.js
Normal file
@ -0,0 +1,3 @@
|
||||
exports.activate = () => {
|
||||
// TODO: Injections for language-todo and language-hyperlink.
|
||||
};
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "language-java",
|
||||
"main": "lib/main",
|
||||
"version": "0.32.1",
|
||||
"description": "Java language support in Atom",
|
||||
"engines": {
|
||||
"atom": "*",
|
||||
"node": "*"
|
||||
"node": ">=14"
|
||||
},
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT",
|
||||
|
@ -2,7 +2,8 @@ describe 'Java grammar', ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-java')
|
||||
|
||||
|
@ -7,6 +7,7 @@ describe 'Tree-sitter based Java grammar', ->
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
atom.config.set('core.useExperimentalModernTreeSitter', false)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-java')
|
||||
|
@ -2,7 +2,8 @@ describe 'Unified expression language grammar', ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
atom.config.set 'core.useTreeSitterParsers', false
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-java')
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
# "?." means "?." or "."
|
||||
# Even though sometimes it doesn't seem like using the chaining operator would make any sense, it's still supported.
|
||||
# Example: Math?.PI
|
||||
# Negative look-behinds for "." should cover "?."
|
||||
'scopeName': 'source.js'
|
||||
'fileTypes': [
|
||||
'js'
|
||||
@ -284,8 +288,8 @@
|
||||
]
|
||||
}
|
||||
{
|
||||
# [.]foo = function...
|
||||
'begin': '(?=(\\.)?[a-zA-Z_$][\\w$]*\\s*=\\s*(\\basync\\b\\s*)?\\bfunction\\b)'
|
||||
# [?.]foo = function...
|
||||
'begin': '(?=(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*\\s*=\\s*(\\basync\\b\\s*)?\\bfunction\\b)'
|
||||
'end': '(?<=})'
|
||||
'patterns': [
|
||||
{
|
||||
@ -300,10 +304,14 @@
|
||||
'name': 'meta.function.js'
|
||||
'patterns': [
|
||||
{
|
||||
'match': '(\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)\\s*'
|
||||
'match': '(\\?\\.|\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)\\s*'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_illegal_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'entity.name.function.js'
|
||||
'3':
|
||||
@ -533,10 +541,10 @@
|
||||
]
|
||||
}
|
||||
{
|
||||
# [.]foo = ... => ...
|
||||
# [?.]foo = ... => ...
|
||||
'begin': '''(?x)
|
||||
(?=
|
||||
(\\.)?[a-zA-Z_$][\\w$]*
|
||||
(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*
|
||||
\\s*(=)\\s*
|
||||
((\\(([^\\(\\)]*)?\\))|[\\w$]+)
|
||||
\\s*=>
|
||||
@ -546,8 +554,8 @@
|
||||
(?<=})|
|
||||
((?!
|
||||
\\s*{|
|
||||
\\G(\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*\\(|
|
||||
\\G(\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*[\\w$]+|
|
||||
\\G(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*\\(|
|
||||
\\G(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*[\\w$]+|
|
||||
\\s*/\\*|\\s*//
|
||||
)(?=\\s*\\S))
|
||||
'''
|
||||
@ -564,10 +572,14 @@
|
||||
'name': 'meta.function.arrow.js'
|
||||
'patterns': [
|
||||
{
|
||||
'match': '\\G(\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)'
|
||||
'match': '\\G(\\?\\.|\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_illegal_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'entity.name.function.js'
|
||||
'3':
|
||||
@ -720,7 +732,7 @@
|
||||
'name': 'meta.class.js'
|
||||
}
|
||||
{
|
||||
'match': '(new)\\s+([\\w$]+[\\w.$]*)'
|
||||
'match': '(new)\\s+([\\w$]+(?:\\??\\.[\\w$]*)*)'
|
||||
'name': 'meta.class.instance.constructor.js'
|
||||
'captures':
|
||||
'1':
|
||||
@ -729,8 +741,7 @@
|
||||
'name': 'entity.name.type.instance.js'
|
||||
'patterns': [
|
||||
{
|
||||
'match': '\\.'
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'include': '#period_or_illegal_optional_property'
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -743,8 +754,10 @@
|
||||
'name': 'entity.name.type.object.console.js'
|
||||
'end': '''(?x)
|
||||
(?<=\\)) | (?=
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*(\\.)\\s*
|
||||
(assert|clear|debug|error|info|log|profile|profileEnd|time|timeEnd|warn)
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s*
|
||||
(assert|clear|count|countReset|debug|dir|dirxml|error|group|groupCollapsed|
|
||||
groupEnd|info|log|profile|profileEnd|table|time|timeEnd|timeLog|trace|
|
||||
timeStamp|warn)
|
||||
\\s*\\(
|
||||
)) \\s*\\S
|
||||
)
|
||||
@ -754,10 +767,14 @@
|
||||
'include': '#comments'
|
||||
}
|
||||
{
|
||||
'begin': '\\s*(\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.function.console.js'
|
||||
'end': '(?<=\\))'
|
||||
@ -770,6 +787,45 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# JSON
|
||||
'begin': '(?<![\\w$])JSON(?![\\w$]|\\s*:)'
|
||||
'beginCaptures':
|
||||
'0':
|
||||
'name': 'support.class.json.js'
|
||||
'end': '''(?x)
|
||||
(?<=\\)) | (?=
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s*
|
||||
(parse|stringify)
|
||||
\\s*\\(
|
||||
)) \\s*\\S
|
||||
)
|
||||
'''
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#comments'
|
||||
}
|
||||
{
|
||||
'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.function.json.js'
|
||||
'end': '(?<=\\))'
|
||||
'name': 'meta.method-call.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#arguments'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# Math
|
||||
'begin': '(?<![\\w$])Math(?![\\w$]|\\s*:)'
|
||||
@ -779,7 +835,7 @@
|
||||
'end': '''(?x)
|
||||
(?<=E|LN10|LN2|LOG10E|LOG2E|PI|SQRT1_2|SQRT2|\\)
|
||||
) | (?=
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*\\.\\s* (
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s* (
|
||||
((abs|acos|acosh|asin|asinh|atan|atan2|atanh|cbrt|ceil|clz32|cos|cosh|exp|
|
||||
expm1|floor|fround|hypot|imul|log|log10|log1p|log2|max|min|pow|random|
|
||||
round|sign|sin|sinh|sqrt|tan|tanh|trunc)\\s*\\(
|
||||
@ -793,10 +849,14 @@
|
||||
}
|
||||
{
|
||||
# Math.random()
|
||||
'begin': '\\s*(\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.function.math.js'
|
||||
'end': '(?<=\\))'
|
||||
@ -809,10 +869,14 @@
|
||||
}
|
||||
{
|
||||
# Math.PI
|
||||
'match': '\\s*(\\.)\\s*(\\w+)\\b'
|
||||
'match': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\b'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.constant.property.math.js'
|
||||
}
|
||||
@ -826,7 +890,7 @@
|
||||
'name': 'support.class.promise.js'
|
||||
'end': '''(?x)
|
||||
(?<=\\)) | (?=
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*\\.\\s*(all|race|reject|resolve)\\s*\\() )\\s*\\S
|
||||
(?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s*(all|allSettled|any|race|reject|resolve)\\s*\\() )\\s*\\S
|
||||
)
|
||||
'''
|
||||
'patterns': [
|
||||
@ -835,10 +899,14 @@
|
||||
}
|
||||
{
|
||||
# Promise.all()
|
||||
'begin': '\\s*(\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.function.promise.js'
|
||||
'end': '(?<=\\))'
|
||||
@ -941,6 +1009,7 @@
|
||||
'name': 'meta.control.yield.js'
|
||||
}
|
||||
{
|
||||
# This is "..." so don't need to check "?."
|
||||
'match': '(?:(?<=\\.{3})|(?<!\\.))\\b(await)(?!\\s*:)\\b'
|
||||
'name': 'keyword.control.js'
|
||||
}
|
||||
@ -955,6 +1024,8 @@
|
||||
'match': '(?<!\\.)\\b(delete|in|of|instanceof|new|typeof|void)(?!\\s*:)\\b'
|
||||
'name': 'keyword.operator.$1.js'
|
||||
}
|
||||
# By default, three dots = spread
|
||||
# `keyword.operator.rest.js` is only done in specific cases in functions
|
||||
{
|
||||
'match': '\\.\\.\\.'
|
||||
'name': 'keyword.operator.spread.js'
|
||||
@ -973,23 +1044,28 @@
|
||||
}
|
||||
{
|
||||
'match': '''(?x) (?<!\\$) \\b
|
||||
(AggregateError|Array|ArrayBuffer|Atomics|Boolean|DataView|Date|Error|EvalError|Float32Array|Float64Array
|
||||
|Function|Generator|GeneratorFunction|Int16Array|Int32Array|Int8Array|InternalError|Intl|JSON|Map|Number
|
||||
(AggregateError|Array|ArrayBuffer|AsyncFunction|AsyncGeneratorFunction|Atomics|BigInt|BigInt64Array
|
||||
|BigUInt64Array|Boolean|DataView|Date|Error|EvalError|FinalizationRegistry|Float32Array|Float64Array
|
||||
|Function|Generator|GeneratorFunction|Int16Array|Int32Array|Int8Array|InternalError|Intl|Map|Number
|
||||
|Object|Proxy|RangeError|ReferenceError|Reflect|RegExp|Set|SharedArrayBuffer|SIMD|String|Symbol|SyntaxError
|
||||
|TypeError|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|URIError|WeakMap|WeakSet)
|
||||
|TypedArray|TypeError|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|URIError|WeakMap|WeakRef|WeakSet)
|
||||
\\b
|
||||
'''
|
||||
'name': 'support.class.js'
|
||||
}
|
||||
{
|
||||
'match': '''(?x) (\\.) \\s* (?:
|
||||
'match': '''(?x) (\\?\\.|\\.) \\s* (?:
|
||||
(constructor|length|prototype) |
|
||||
(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)
|
||||
)\\b
|
||||
'''
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.variable.property.js'
|
||||
'3':
|
||||
@ -1067,7 +1143,7 @@
|
||||
'name': 'support.class.dom.js'
|
||||
}
|
||||
{
|
||||
'match': '''(?x) (\\.) \\s*
|
||||
'match': '''(?x) (\\?\\.|\\.) \\s*
|
||||
(?:
|
||||
(ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE
|
||||
|DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR
|
||||
@ -1105,7 +1181,11 @@
|
||||
'''
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'support.constant.dom.js'
|
||||
'3':
|
||||
@ -1138,7 +1218,7 @@
|
||||
]
|
||||
}
|
||||
{
|
||||
'begin': '\\?'
|
||||
'begin': '(?<!\\?)\\?(?!\\.|\\?)'
|
||||
'beginCaptures':
|
||||
'0':
|
||||
'name': 'keyword.operator.ternary.js'
|
||||
@ -1189,10 +1269,6 @@
|
||||
'match': ','
|
||||
'name': 'meta.delimiter.object.comma.js'
|
||||
}
|
||||
{
|
||||
'match': '\\.'
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
}
|
||||
{
|
||||
# Allows the special return snippet to fire.
|
||||
'match': '({)(})'
|
||||
@ -1233,6 +1309,7 @@
|
||||
]
|
||||
}
|
||||
{
|
||||
# This is inconsistent with the () and {}, however the current tests *rely* on this
|
||||
'match': '\\[|\\]'
|
||||
'name': 'meta.brace.square.js'
|
||||
}
|
||||
@ -1314,13 +1391,25 @@
|
||||
'operators':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '%=|\\+=|-=|\\*=|(?<!\\()/='
|
||||
# %= **= *= /= += -=
|
||||
'match': '%=|\\*\\*=|\\*=|(?<!\\()/=|\\+=|-='
|
||||
'name': 'keyword.operator.assignment.compound.js'
|
||||
}
|
||||
{
|
||||
'match': '&=|\\^=|<<=|>>=|>>>=|\\|='
|
||||
# &&= ||= ??=
|
||||
'match': '&&=|\\|\\|=|\\?\\?='
|
||||
'name': 'keyword.operator.assignment.compound.logical.js'
|
||||
}
|
||||
{
|
||||
'match': '&=|\\^=|\\|='
|
||||
'name': 'keyword.operator.assignment.compound.bitwise.js'
|
||||
}
|
||||
{
|
||||
'match': '<<=|>>=|>>>='
|
||||
'name': 'keyword.operator.assignment.compound.bitwise.shift.js'
|
||||
}
|
||||
# Bitwise shift to match >> instead of >
|
||||
# Then comparison to match != instead of !
|
||||
{
|
||||
'match': '<<|>>>|>>'
|
||||
'name': 'keyword.operator.bitwise.shift.js'
|
||||
@ -1330,7 +1419,8 @@
|
||||
'name': 'keyword.operator.comparison.js'
|
||||
}
|
||||
{
|
||||
'match': '&&|!!|!|\\|\\|'
|
||||
# One of: && !! ! || ??
|
||||
'match': '&&|!!|!|\\|\\||\\?\\?'
|
||||
'name': 'keyword.operator.logical.js'
|
||||
}
|
||||
{
|
||||
@ -1350,7 +1440,7 @@
|
||||
'name': 'keyword.operator.increment.js'
|
||||
}
|
||||
{
|
||||
'match': '%|\\*|/|-|\\+'
|
||||
'match': '%|\\*\\*|\\*|/|-|\\+'
|
||||
'name': 'keyword.operator.js'
|
||||
}
|
||||
]
|
||||
@ -1447,11 +1537,17 @@
|
||||
]
|
||||
}
|
||||
{
|
||||
'begin': '(Relay\\.QL|gql)\\s*(`)'
|
||||
'begin': '(Relay(\\?\\.|\\.)QL|gql)\\s*(`)'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'entity.name.function.js'
|
||||
'2':
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'3':
|
||||
'name': 'punctuation.definition.string.begin.js'
|
||||
'end': '`'
|
||||
'endCaptures':
|
||||
@ -1559,7 +1655,38 @@
|
||||
'match': '(\\.\\.\\.)([a-zA-Z_$][\\w$]*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'keyword.operator.spread.js'
|
||||
'name': 'keyword.operator.rest.js'
|
||||
'2':
|
||||
'name': 'variable.parameter.rest.function.js'
|
||||
}
|
||||
{
|
||||
'include': '$self'
|
||||
}
|
||||
{
|
||||
'match': '[a-zA-Z_$][\\w$]*'
|
||||
'name': 'variable.parameter.function.js'
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# Or starting with optional chaining
|
||||
'begin': '(\\?\\.)(\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.optional.js'
|
||||
'2':
|
||||
'name': 'punctuation.definition.parameters.begin.bracket.round.js'
|
||||
'end': '\\)'
|
||||
'endCaptures':
|
||||
'0':
|
||||
'name': 'punctuation.definition.parameters.end.bracket.round.js'
|
||||
'name': 'meta.parameters.js'
|
||||
'patterns': [
|
||||
{
|
||||
'match': '(\\.\\.\\.)([a-zA-Z_$][\\w$]*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'keyword.operator.rest.js'
|
||||
'2':
|
||||
'name': 'variable.parameter.rest.function.js'
|
||||
}
|
||||
@ -1662,104 +1789,19 @@
|
||||
'method_calls':
|
||||
'patterns': [
|
||||
{
|
||||
# .methodCall(arg1, "arg2", [...])
|
||||
'begin': '(\\.)\\s*([\\w$]+)\\s*(?=\\()'
|
||||
# [?].methodCall(arg1, "arg2", [...])
|
||||
'begin': '(\\?\\.|\\.)\\s*([\\w$]+)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\bon(Rowsinserted|Rowsdelete|Rowenter|Rowexit|Resize|Resizestart|Resizeend|Reset|
|
||||
Readystatechange|Mouseout|Mouseover|Mousedown|Mouseup|Mousemove|
|
||||
Before(cut|deactivate|unload|update|paste|print|editfocus|activate)|
|
||||
Blur|Scrolltop|Submit|Select|Selectstart|Selectionchange|Hover|Help|
|
||||
Change|Contextmenu|Controlselect|Cut|Cellchange|Clock|Close|Deactivate|
|
||||
Datasetchanged|Datasetcomplete|Dataavailable|Drop|Drag|Dragstart|Dragover|
|
||||
Dragdrop|Dragenter|Dragend|Dragleave|Dblclick|Unload|Paste|Propertychange|Error|
|
||||
Errorupdate|Keydown|Keyup|Keypress|Focus|Load|Activate|Afterupdate|Afterprint|Abort)\\b
|
||||
'''
|
||||
'name': 'support.function.event-handler.js'
|
||||
}
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\b(catch|finally|then|shift|showModelessDialog|showModalDialog|showHelp|scroll|scrollX|scrollByPages|
|
||||
scrollByLines|scrollY|scrollTo|stop|strike|sizeToContent|sidebar|signText|sort|
|
||||
sup|sub|substr|substring|splice|split|send|set(Milliseconds|Seconds|Minutes|Hours|
|
||||
Month|Year|FullYear|Date|UTC(Milliseconds|Seconds|Minutes|Hours|Month|FullYear|Date)|
|
||||
Time|Hotkeys|Cursor|ZOptions|Active|Resizable|RequestHeader)|search|slice|
|
||||
savePreferences|small|home|handleEvent|navigate|char|charCodeAt|charAt|concat|
|
||||
contextual|confirm|compile|clear|captureEvents|call|createStyleSheet|createPopup|
|
||||
createEventObject|to(GMTString|UTCString|String|Source|UpperCase|LowerCase|LocaleString)|
|
||||
test|taint|taintEnabled|indexOf|italics|disableExternalCapture|dump|detachEvent|unshift|
|
||||
untaint|unwatch|updateCommands|join|javaEnabled|pop|push|plugins.refresh|paddings|parse|stringify|
|
||||
print|prompt|preference|enableExternalCapture|exec|execScript|valueOf|UTC|find|file|
|
||||
fileModifiedDate|fileSize|fileCreatedDate|fileUpdatedDate|fixed|fontsize|fontcolor|
|
||||
forward|fromCharCode|watch|link|load|lastIndexOf|anchor|attachEvent|atob|apply|alert|
|
||||
abort|routeEvents|resize|resizeBy|resizeTo|recalc|returnValue|replace|reverse|reload|
|
||||
releaseCapture|releaseEvents|go|get(Milliseconds|Seconds|Minutes|Hours|Month|Day|Year|FullYear|
|
||||
Time|Date|TimezoneOffset|UTC(Milliseconds|Seconds|Minutes|Hours|Day|Month|FullYear|Date)|
|
||||
Attention|Selection|ResponseHeader|AllResponseHeaders)|moveBy|moveBelow|moveTo|
|
||||
moveToAbsolute|moveAbove|mergeAttributes|match|margins|btoa|big|bold|borderWidths|blink|back)\\b
|
||||
'''
|
||||
'name': 'support.function.js'
|
||||
}
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\b(acceptNode|add|addEventListener|addTextTrack|adoptNode|after|animate|append|
|
||||
appendChild|appendData|before|blur|canPlayType|captureStream|
|
||||
caretPositionFromPoint|caretRangeFromPoint|checkValidity|clear|click|
|
||||
cloneContents|cloneNode|cloneRange|close|closest|collapse|
|
||||
compareBoundaryPoints|compareDocumentPosition|comparePoint|contains|
|
||||
convertPointFromNode|convertQuadFromNode|convertRectFromNode|createAttribute|
|
||||
createAttributeNS|createCaption|createCDATASection|createComment|
|
||||
createContextualFragment|createDocument|createDocumentFragment|
|
||||
createDocumentType|createElement|createElementNS|createEntityReference|
|
||||
createEvent|createExpression|createHTMLDocument|createNodeIterator|
|
||||
createNSResolver|createProcessingInstruction|createRange|createShadowRoot|
|
||||
createTBody|createTextNode|createTFoot|createTHead|createTreeWalker|delete|
|
||||
deleteCaption|deleteCell|deleteContents|deleteData|deleteRow|deleteTFoot|
|
||||
deleteTHead|detach|disconnect|dispatchEvent|elementFromPoint|elementsFromPoint|
|
||||
enableStyleSheetsForSet|entries|evaluate|execCommand|exitFullscreen|
|
||||
exitPointerLock|expand|extractContents|fastSeek|firstChild|focus|forEach|get|
|
||||
getAll|getAnimations|getAttribute|getAttributeNames|getAttributeNode|
|
||||
getAttributeNodeNS|getAttributeNS|getBoundingClientRect|getBoxQuads|
|
||||
getClientRects|getContext|getDestinationInsertionPoints|getElementById|
|
||||
getElementsByClassName|getElementsByName|getElementsByTagName|
|
||||
getElementsByTagNameNS|getItem|getNamedItem|getSelection|getStartDate|
|
||||
getVideoPlaybackQuality|has|hasAttribute|hasAttributeNS|hasAttributes|
|
||||
hasChildNodes|hasFeature|hasFocus|importNode|initEvent|insertAdjacentElement|
|
||||
insertAdjacentHTML|insertAdjacentText|insertBefore|insertCell|insertData|
|
||||
insertNode|insertRow|intersectsNode|isDefaultNamespace|isEqualNode|
|
||||
isPointInRange|isSameNode|item|key|keys|lastChild|load|lookupNamespaceURI|
|
||||
lookupPrefix|matches|move|moveAttribute|moveAttributeNode|moveChild|
|
||||
moveNamedItem|namedItem|nextNode|nextSibling|normalize|observe|open|
|
||||
parentNode|pause|play|postMessage|prepend|preventDefault|previousNode|
|
||||
previousSibling|probablySupportsContext|queryCommandEnabled|
|
||||
queryCommandIndeterm|queryCommandState|queryCommandSupported|queryCommandValue|
|
||||
querySelector|querySelectorAll|registerContentHandler|registerElement|
|
||||
registerProtocolHandler|releaseCapture|releaseEvents|remove|removeAttribute|
|
||||
removeAttributeNode|removeAttributeNS|removeChild|removeEventListener|
|
||||
removeItem|replace|replaceChild|replaceData|replaceWith|reportValidity|
|
||||
requestFullscreen|requestPointerLock|reset|scroll|scrollBy|scrollIntoView|
|
||||
scrollTo|seekToNextFrame|select|selectNode|selectNodeContents|set|setAttribute|
|
||||
setAttributeNode|setAttributeNodeNS|setAttributeNS|setCapture|
|
||||
setCustomValidity|setEnd|setEndAfter|setEndBefore|setItem|setNamedItem|
|
||||
setRangeText|setSelectionRange|setSinkId|setStart|setStartAfter|setStartBefore|
|
||||
slice|splitText|stepDown|stepUp|stopImmediatePropagation|stopPropagation|
|
||||
submit|substringData|supports|surroundContents|takeRecords|terminate|toBlob|
|
||||
toDataURL|toggle|toString|values|write|writeln)\\b
|
||||
'''
|
||||
'name': 'support.function.dom.js'
|
||||
}
|
||||
{
|
||||
'match': "[a-zA-Z_$][\\w$]*"
|
||||
'name': 'entity.name.function.js'
|
||||
}
|
||||
{
|
||||
'match': '\\d[\\w$]*'
|
||||
'name': 'invalid.illegal.identifier.js'
|
||||
'include': '#method_names'
|
||||
}
|
||||
]
|
||||
'end': '(?<=\\))'
|
||||
@ -1770,6 +1812,142 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# [?].methodCall?.(arg1, "arg2", [...])
|
||||
'begin': '(\\?\\.|\\.)\\s*([\\w$]+)\\s*(\\?\\.)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_method'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#method_names'
|
||||
}
|
||||
]
|
||||
'3':
|
||||
'name': 'meta.delimiter.method.optional.js'
|
||||
'end': '(?<=\\))'
|
||||
'name': 'meta.method-call.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#arguments'
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# [array]?.(arg1, "arg2", [...])
|
||||
# The array itself is not in the method-call scope, maybe later
|
||||
'begin': '(?<=\\])\\s*(\\?\\.)\\s*(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.method.optional.js'
|
||||
'end': '(?<=\\))'
|
||||
'name': 'meta.method-call.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#arguments'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
'method_names':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\bon(Rowsinserted|Rowsdelete|Rowenter|Rowexit|Resize|Resizestart|Resizeend|Reset|
|
||||
Readystatechange|Mouseout|Mouseover|Mousedown|Mouseup|Mousemove|
|
||||
Before(cut|deactivate|unload|update|paste|print|editfocus|activate)|
|
||||
Blur|Scrolltop|Submit|Select|Selectstart|Selectionchange|Hover|Help|
|
||||
Change|Contextmenu|Controlselect|Cut|Cellchange|Clock|Close|Deactivate|
|
||||
Datasetchanged|Datasetcomplete|Dataavailable|Drop|Drag|Dragstart|Dragover|
|
||||
Dragdrop|Dragenter|Dragend|Dragleave|Dblclick|Unload|Paste|Propertychange|Error|
|
||||
Errorupdate|Keydown|Keyup|Keypress|Focus|Load|Activate|Afterupdate|Afterprint|Abort)\\b
|
||||
'''
|
||||
'name': 'support.function.event-handler.js'
|
||||
}
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\b(catch|finally|then|shift|showModelessDialog|showModalDialog|showHelp|scroll|scrollX|scrollByPages|
|
||||
scrollByLines|scrollY|scrollTo|stop|strike|sizeToContent|sidebar|signText|sort|
|
||||
sup|sub|substr|substring|splice|split|send|set(Milliseconds|Seconds|Minutes|Hours|
|
||||
Month|Year|FullYear|Date|UTC(Milliseconds|Seconds|Minutes|Hours|Month|FullYear|Date)|
|
||||
Time|Hotkeys|Cursor|ZOptions|Active|Resizable|RequestHeader)|search|slice|
|
||||
savePreferences|small|home|handleEvent|navigate|char|charCodeAt|charAt|concat|
|
||||
contextual|confirm|compile|clear|captureEvents|call|createStyleSheet|createPopup|
|
||||
createEventObject|to(GMTString|UTCString|String|Source|UpperCase|LowerCase|LocaleString)|
|
||||
test|taint|taintEnabled|indexOf|italics|disableExternalCapture|dump|detachEvent|unshift|
|
||||
untaint|unwatch|updateCommands|join|javaEnabled|pop|push|plugins.refresh|paddings|parse|stringify|
|
||||
print|prompt|preference|enableExternalCapture|exec|execScript|valueOf|UTC|find|file|
|
||||
fileModifiedDate|fileSize|fileCreatedDate|fileUpdatedDate|fixed|fontsize|fontcolor|
|
||||
forward|fromCharCode|watch|link|load|lastIndexOf|anchor|attachEvent|atob|apply|alert|
|
||||
abort|routeEvents|resize|resizeBy|resizeTo|recalc|returnValue|replace|reverse|reload|
|
||||
releaseCapture|releaseEvents|go|get(Milliseconds|Seconds|Minutes|Hours|Month|Day|Year|FullYear|
|
||||
Time|Date|TimezoneOffset|UTC(Milliseconds|Seconds|Minutes|Hours|Day|Month|FullYear|Date)|
|
||||
Attention|Selection|ResponseHeader|AllResponseHeaders)|moveBy|moveBelow|moveTo|
|
||||
moveToAbsolute|moveAbove|mergeAttributes|match|margins|btoa|big|bold|borderWidths|blink|back)\\b
|
||||
'''
|
||||
'name': 'support.function.js'
|
||||
}
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\b(acceptNode|add|addEventListener|addTextTrack|adoptNode|after|animate|append|
|
||||
appendChild|appendData|before|blur|canPlayType|captureStream|
|
||||
caretPositionFromPoint|caretRangeFromPoint|checkValidity|clear|click|
|
||||
cloneContents|cloneNode|cloneRange|close|closest|collapse|
|
||||
compareBoundaryPoints|compareDocumentPosition|comparePoint|contains|
|
||||
convertPointFromNode|convertQuadFromNode|convertRectFromNode|createAttribute|
|
||||
createAttributeNS|createCaption|createCDATASection|createComment|
|
||||
createContextualFragment|createDocument|createDocumentFragment|
|
||||
createDocumentType|createElement|createElementNS|createEntityReference|
|
||||
createEvent|createExpression|createHTMLDocument|createNodeIterator|
|
||||
createNSResolver|createProcessingInstruction|createRange|createShadowRoot|
|
||||
createTBody|createTextNode|createTFoot|createTHead|createTreeWalker|delete|
|
||||
deleteCaption|deleteCell|deleteContents|deleteData|deleteRow|deleteTFoot|
|
||||
deleteTHead|detach|disconnect|dispatchEvent|elementFromPoint|elementsFromPoint|
|
||||
enableStyleSheetsForSet|entries|evaluate|execCommand|exitFullscreen|
|
||||
exitPointerLock|expand|extractContents|fastSeek|firstChild|focus|forEach|get|
|
||||
getAll|getAnimations|getAttribute|getAttributeNames|getAttributeNode|
|
||||
getAttributeNodeNS|getAttributeNS|getBoundingClientRect|getBoxQuads|
|
||||
getClientRects|getContext|getDestinationInsertionPoints|getElementById|
|
||||
getElementsByClassName|getElementsByName|getElementsByTagName|
|
||||
getElementsByTagNameNS|getItem|getNamedItem|getSelection|getStartDate|
|
||||
getVideoPlaybackQuality|has|hasAttribute|hasAttributeNS|hasAttributes|
|
||||
hasChildNodes|hasFeature|hasFocus|importNode|initEvent|insertAdjacentElement|
|
||||
insertAdjacentHTML|insertAdjacentText|insertBefore|insertCell|insertData|
|
||||
insertNode|insertRow|intersectsNode|isDefaultNamespace|isEqualNode|
|
||||
isPointInRange|isSameNode|item|key|keys|lastChild|load|lookupNamespaceURI|
|
||||
lookupPrefix|matches|move|moveAttribute|moveAttributeNode|moveChild|
|
||||
moveNamedItem|namedItem|nextNode|nextSibling|normalize|observe|open|
|
||||
parentNode|pause|play|postMessage|prepend|preventDefault|previousNode|
|
||||
previousSibling|probablySupportsContext|queryCommandEnabled|
|
||||
queryCommandIndeterm|queryCommandState|queryCommandSupported|queryCommandValue|
|
||||
querySelector|querySelectorAll|registerContentHandler|registerElement|
|
||||
registerProtocolHandler|releaseCapture|releaseEvents|remove|removeAttribute|
|
||||
removeAttributeNode|removeAttributeNS|removeChild|removeEventListener|
|
||||
removeItem|replace|replaceChild|replaceData|replaceWith|reportValidity|
|
||||
requestFullscreen|requestPointerLock|reset|scroll|scrollBy|scrollIntoView|
|
||||
scrollTo|seekToNextFrame|select|selectNode|selectNodeContents|set|setAttribute|
|
||||
setAttributeNode|setAttributeNodeNS|setAttributeNS|setCapture|
|
||||
setCustomValidity|setEnd|setEndAfter|setEndBefore|setItem|setNamedItem|
|
||||
setRangeText|setSelectionRange|setSinkId|setStart|setStartAfter|setStartBefore|
|
||||
slice|splitText|stepDown|stepUp|stopImmediatePropagation|stopPropagation|
|
||||
submit|substringData|supports|surroundContents|takeRecords|terminate|toBlob|
|
||||
toDataURL|toggle|toString|values|write|writeln)\\b
|
||||
'''
|
||||
'name': 'support.function.dom.js'
|
||||
}
|
||||
{
|
||||
'match': "[a-zA-Z_$][\\w$]*"
|
||||
'name': 'entity.name.function.js'
|
||||
}
|
||||
{
|
||||
'match': '\\d[\\w$]*'
|
||||
'name': 'invalid.illegal.identifier.js'
|
||||
}
|
||||
]
|
||||
'function_calls':
|
||||
'patterns': [
|
||||
@ -1804,64 +1982,149 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# functionCall?.(arg1, "arg2", [...])
|
||||
'begin': '([\\w$]+)\\s*(\\?\\.)(?=\\()'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '''(?x)
|
||||
\\b(isNaN|isFinite|eval|uneval|parseInt|parseFloat|decodeURI|
|
||||
decodeURIComponent|encodeURI|encodeURIComponent|escape|unescape|
|
||||
require|set(Interval|Timeout)|clear(Interval|Timeout))\\b
|
||||
'''
|
||||
'name': 'support.function.js'
|
||||
}
|
||||
{
|
||||
'match': "[a-zA-Z_$][\\w$]*"
|
||||
'name': 'entity.name.function.js'
|
||||
}
|
||||
{
|
||||
'match': '\\d[\\w$]*'
|
||||
'name': 'invalid.illegal.identifier.js'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'meta.delimiter.method.optional.js'
|
||||
'end': '(?<=\\))'
|
||||
'name': 'meta.function-call.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#arguments'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
'objects':
|
||||
'patterns': [
|
||||
# "Obj." is already enough to prove objectness,
|
||||
# however "Obj.[8]" is impossible, and
|
||||
# "Obj?.()" is a function
|
||||
{
|
||||
# OBJ in OBJ.prop, OBJ.methodCall()
|
||||
'match': '[A-Z][A-Z0-9_$]*(?=\\s*\\.\\s*[a-zA-Z_$]\\w*)'
|
||||
'match': '[A-Z][A-Z0-9_$]*(?=\\s*\\??\\.\\s*[a-zA-Z_$]\\w*)'
|
||||
'name': 'constant.other.object.js'
|
||||
}
|
||||
{
|
||||
# obj in obj.prop, obj.methodCall()
|
||||
'match': '[a-zA-Z_$][\\w$]*(?=\\s*\\.\\s*[a-zA-Z_$]\\w*)'
|
||||
'match': '[a-zA-Z_$][\\w$]*(?=\\s*\\??\\.\\s*[a-zA-Z_$]\\w*)'
|
||||
'name': 'variable.other.object.js'
|
||||
}
|
||||
{
|
||||
# OBJ in OBJ[8], OBJ?.[8]
|
||||
'match': '[A-Z][A-Z0-9_$]*(?=\\s*(\\?\\.)?\\s*\\[)'
|
||||
'name': 'constant.other.object.js'
|
||||
}
|
||||
{
|
||||
# obj in obj[8], obj?.[8]
|
||||
'match': '[a-zA-Z_$][\\w$]*(?=\\s*(\\?\\.)?\\s*\\[)'
|
||||
'name': 'variable.other.object.js'
|
||||
}
|
||||
]
|
||||
'properties':
|
||||
'patterns': [
|
||||
# object.prop includes object?.prop
|
||||
{
|
||||
# Specifically ?.[], for example divArray?.[8]
|
||||
'begin': '(\\?\\.)\\s*(\\[)'
|
||||
'beginCaptures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.optional.js'
|
||||
'2':
|
||||
'name': 'meta.brace.square.js'
|
||||
'end': '\\]'
|
||||
'endCaptures':
|
||||
'0':
|
||||
'name': 'meta.brace.square.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '$self'
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
# PROP1 in obj.PROP1.prop2, func().PROP1.prop2
|
||||
'match': '(\\.)\\s*([A-Z][A-Z0-9_$]*\\b\\$*)(?=\\s*\\.\\s*[a-zA-Z_$]\\w*)'
|
||||
'match': '(\\?\\.|\\.)\\s*([A-Z][A-Z0-9_$]*\\b\\$*)(?=\\s*(\\?\\.|\\.)\\s*[a-zA-Z_$]\\w*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'constant.other.object.property.js'
|
||||
}
|
||||
{
|
||||
# prop1 in obj.prop1.prop2, func().prop1.prop2
|
||||
'match': '(\\.)\\s*(\\$*[a-zA-Z_$][\\w$]*)(?=\\s*\\.\\s*[a-zA-Z_$]\\w*)'
|
||||
'match': '(\\?\\.|\\.)\\s*(\\$*[a-zA-Z_$][\\w$]*)(?=\\s*(\\?\\.|\\.)\\s*[a-zA-Z_$]\\w*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'variable.other.object.property.js'
|
||||
}
|
||||
{
|
||||
# PROP in obj.PROP, func().PROP
|
||||
'match': '(\\.)\\s*([A-Z][A-Z0-9_$]*\\b\\$*)'
|
||||
'match': '(\\?\\.|\\.)\\s*([A-Z][A-Z0-9_$]*\\b\\$*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'constant.other.property.js'
|
||||
}
|
||||
{
|
||||
# prop in obj.prop, func().prop
|
||||
'match': '(\\.)\\s*(\\$*[a-zA-Z_$][\\w$]*)'
|
||||
'match': '(\\?\\.|\\.)\\s*(\\$*[a-zA-Z_$][\\w$]*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'variable.other.property.js'
|
||||
}
|
||||
{
|
||||
# 123illegal in obj.123illegal, func().123illegal
|
||||
'match': '(\\.)\\s*([0-9][\\w$]*)'
|
||||
'match': '(\\?\\.|\\.)\\s*([0-9][\\w$]*)'
|
||||
'captures':
|
||||
'1':
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
'patterns': [
|
||||
{
|
||||
'include': '#period_or_optional_property'
|
||||
}
|
||||
]
|
||||
'2':
|
||||
'name': 'invalid.illegal.identifier.js'
|
||||
}
|
||||
@ -2026,3 +2289,47 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
'period_or_illegal_optional_property':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '\\.'
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
}
|
||||
{
|
||||
'match': '\\?\\.'
|
||||
'name': 'invalid.illegal.meta.delimiter.property.optional.js'
|
||||
}
|
||||
]
|
||||
'period_or_illegal_optional_method':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '\\.'
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
}
|
||||
{
|
||||
'match': '\\?\\.'
|
||||
'name': 'invalid.illegal.meta.delimiter.method.optional.js'
|
||||
}
|
||||
]
|
||||
'period_or_optional_property':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '\\.'
|
||||
'name': 'meta.delimiter.property.period.js'
|
||||
}
|
||||
{
|
||||
'match': '\\?\\.'
|
||||
'name': 'meta.delimiter.property.optional.js'
|
||||
}
|
||||
]
|
||||
'period_or_optional_method':
|
||||
'patterns': [
|
||||
{
|
||||
'match': '\\.'
|
||||
'name': 'meta.delimiter.method.period.js'
|
||||
}
|
||||
{
|
||||
'match': '\\?\\.'
|
||||
'name': 'meta.delimiter.method.optional.js'
|
||||
}
|
||||
]
|
||||
|
@ -0,0 +1,31 @@
|
||||
name: 'JavaScript'
|
||||
scopeName: 'source.js'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-javascript'
|
||||
|
||||
injectionRegex: '^(js|javascript)$'
|
||||
treeSitter:
|
||||
grammar: 'ts/grammar.wasm'
|
||||
highlightsQuery: 'ts/highlights.scm'
|
||||
localsQuery: 'ts/locals.scm'
|
||||
foldsQuery: 'ts/folds.scm'
|
||||
indentsQuery: 'ts/indents.scm'
|
||||
tagsQuery: 'ts/tags.scm'
|
||||
|
||||
firstLineRegex: [
|
||||
# shebang line
|
||||
'^#!.*\\b(node)\\r?\\n'
|
||||
|
||||
# vim modeline
|
||||
'vim\\b.*\\bset\\b.*\\b(filetype|ft|syntax)=(js|javascript)'
|
||||
]
|
||||
|
||||
fileTypes: [
|
||||
'js',
|
||||
'cjs',
|
||||
'mjs',
|
||||
'jsx'
|
||||
]
|
||||
|
||||
comments:
|
||||
start: '// '
|
@ -0,0 +1,12 @@
|
||||
name: 'JSDoc'
|
||||
scopeName: 'source.jsdoc'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-jsdoc'
|
||||
|
||||
injectionRegex: '^jsdoc$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'ts/jsdoc/tree-sitter-jsdoc.wasm'
|
||||
highlightsQuery: 'ts/jsdoc/highlights.scm'
|
||||
foldsQuery: 'ts/jsdoc/folds.scm'
|
||||
indentsQuery: 'ts/jsdoc/indents.scm'
|
@ -0,0 +1,9 @@
|
||||
name: 'JavaScript RegExp'
|
||||
scopeName: 'source.regexp.js'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-regex'
|
||||
|
||||
injectionRegex: '^(js-regex)$'
|
||||
treeSitter:
|
||||
grammar: 'ts/regex/tree-sitter-regex.wasm'
|
||||
highlightsQuery: 'ts/regex/highlights.scm'
|
@ -184,9 +184,13 @@ scopes:
|
||||
'"*="': 'keyword.operator.js'
|
||||
'"/="': 'keyword.operator.js'
|
||||
'"%="': 'keyword.operator.js'
|
||||
'"**="': 'keyword.operator.js'
|
||||
'"<<="': 'keyword.operator.js'
|
||||
'">>="': 'keyword.operator.js'
|
||||
'">>>="': 'keyword.operator.js'
|
||||
'"&&="': 'keyword.operator.js'
|
||||
'"||="': 'keyword.operator.js'
|
||||
'"??="': 'keyword.operator.js'
|
||||
'"&="': 'keyword.operator.js'
|
||||
'"^="': 'keyword.operator.js'
|
||||
'"|="': 'keyword.operator.js'
|
||||
@ -196,6 +200,7 @@ scopes:
|
||||
'"*"': 'keyword.operator.js'
|
||||
'"/"': 'keyword.operator.js'
|
||||
'"%"': 'keyword.operator.js'
|
||||
'"**"': 'keyword.operator.js'
|
||||
'"=="': 'keyword.operator.js'
|
||||
'"==="': 'keyword.operator.js'
|
||||
'"!="': 'keyword.operator.js'
|
||||
@ -204,25 +209,28 @@ scopes:
|
||||
'"<="': 'keyword.operator.js'
|
||||
'">"': 'keyword.operator.js'
|
||||
'"<"': 'keyword.operator.js'
|
||||
'":"': 'keyword.operator.js'
|
||||
'"?"': 'keyword.operator.js'
|
||||
'"&&"': 'keyword.operator.js'
|
||||
'"||"': 'keyword.operator.js'
|
||||
'"??"': 'keyword.operator.js'
|
||||
'"&"': 'keyword.operator.js'
|
||||
'"~"': 'keyword.operator.js'
|
||||
'"^"': 'keyword.operator.js'
|
||||
'"|"': 'keyword.operator.js'
|
||||
'"~"': 'keyword.operator.js'
|
||||
'">>"': 'keyword.operator.js'
|
||||
'">>>"': 'keyword.operator.js'
|
||||
'"<<"': 'keyword.operator.js'
|
||||
'"|"': 'keyword.operator.js'
|
||||
'"++"': 'keyword.operator.js'
|
||||
'"--"': 'keyword.operator.js'
|
||||
'"..."': 'keyword.operator.spread.js'
|
||||
'"?"': 'keyword.operator.js'
|
||||
'":"': 'keyword.operator.js'
|
||||
|
||||
'"in"': 'keyword.operator.in'
|
||||
'"instanceof"': 'keyword.operator.instanceof'
|
||||
'"of"': 'keyword.operator.of'
|
||||
'"new"': 'keyword.operator.new'
|
||||
'"delete"': 'keyword.operator.delete'
|
||||
'"void"': 'keyword.operator.void'
|
||||
'"typeof"': 'keyword.operator.typeof'
|
||||
|
||||
'"get"': 'keyword.operator.setter'
|
||||
@ -254,7 +262,6 @@ scopes:
|
||||
'"async"': 'keyword.control'
|
||||
'"await"': 'keyword.control'
|
||||
'"debugger"': 'keyword.control'
|
||||
'"delete"': 'keyword.control'
|
||||
|
||||
'jsx_attribute > property_identifier': 'entity.other.attribute-name'
|
||||
'jsx_opening_element > identifier': 'entity.name.tag'
|
||||
|
73
packages/language-javascript/grammars/ts/folds.scm
Normal file
73
packages/language-javascript/grammars/ts/folds.scm
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
[
|
||||
(switch_body)
|
||||
(class_body)
|
||||
(object)
|
||||
(formal_parameters)
|
||||
(template_string)
|
||||
(named_imports)
|
||||
] @fold
|
||||
|
||||
((arguments) @fold
|
||||
(#set! fold.adjustToEndOfPreviousRow true))
|
||||
|
||||
|
||||
; When we've got
|
||||
;
|
||||
; if (foo) {
|
||||
; // something
|
||||
; } else {
|
||||
; // something else
|
||||
; }
|
||||
;
|
||||
; we want the folds to work a little differently so that collapsing the `if`
|
||||
; fold doesn't interfere with our ability to collapse the `else` fold.
|
||||
((if_statement
|
||||
consequence: (statement_block) @fold)
|
||||
(#set! fold.adjustToEndOfPreviousRow true))
|
||||
|
||||
(else_clause (statement_block) @fold)
|
||||
|
||||
(statement_block) @fold
|
||||
|
||||
((comment) @fold
|
||||
(#set! fold.endAt endPosition)
|
||||
(#set! fold.adjustEndColumn 0))
|
||||
|
||||
|
||||
; When you have…
|
||||
;
|
||||
; <Element
|
||||
; foo="bar"
|
||||
; baz="thud">
|
||||
;
|
||||
; </Element>
|
||||
;
|
||||
; …this will put the fold on line 3 and let you fold up the contents separately
|
||||
; from the opening tag's attributes.
|
||||
;
|
||||
(jsx_element
|
||||
(jsx_opening_element ">" @fold)
|
||||
(#set! fold.endAt parent.parent.lastChild.startPosition)
|
||||
(#set! fold.adjustToEndOfPreviousRow true)
|
||||
)
|
||||
|
||||
; When you have…
|
||||
;
|
||||
; <Element
|
||||
; foo="bar"
|
||||
; baz="thud"
|
||||
; >
|
||||
;
|
||||
; </Element>
|
||||
;
|
||||
; …the presence of the `>` on its own line will let you treat the opening tag's
|
||||
; attributes and the element's contents as separate folds.
|
||||
;
|
||||
(jsx_element
|
||||
(jsx_opening_element) @fold
|
||||
(#set! fold.endAt lastChild.previousSibling.endPosition))
|
||||
|
||||
((jsx_self_closing_element) @fold
|
||||
; Exclude both the slash and angle bracket `/>` from the fold.
|
||||
(#set! fold.endAt lastChild.previousSibling.startPosition))
|
BIN
packages/language-javascript/grammars/ts/grammar.wasm
Executable file
BIN
packages/language-javascript/grammars/ts/grammar.wasm
Executable file
Binary file not shown.
936
packages/language-javascript/grammars/ts/highlights.scm
Normal file
936
packages/language-javascript/grammars/ts/highlights.scm
Normal file
@ -0,0 +1,936 @@
|
||||
|
||||
; STRINGS
|
||||
; =======
|
||||
|
||||
; Single-quoted.
|
||||
(string "'") @string.quoted.single.js
|
||||
|
||||
(string
|
||||
"'" @punctuation.definition.string.begin.js
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(string
|
||||
"'" @punctuation.definition.string.end.js
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
; Double-quoted.
|
||||
(string "\"") @string.quoted.double.js
|
||||
|
||||
(string
|
||||
"\"" @punctuation.definition.string.begin.js
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(string
|
||||
"\"" @punctuation.definition.string.end.js
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
; Template string (backticks).
|
||||
(template_string) @string.quoted.template.js
|
||||
|
||||
(template_string
|
||||
"`" @punctuation.definition.string.begin.js
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(template_string
|
||||
"`" @punctuation.definition.string.end.js
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
; Interpolations inside of template strings.
|
||||
(template_substitution
|
||||
"${" @punctuation.definition.template-expression.begin.js
|
||||
"}" @punctuation.definition.template-expression.end.js
|
||||
) @meta.embedded.line.interpolation.js
|
||||
|
||||
(string
|
||||
(escape_sequence) @constant.character.escape.js)
|
||||
|
||||
(template_string
|
||||
(escape_sequence) @constant.character.escape.js)
|
||||
|
||||
|
||||
; NUMBERS
|
||||
; =======
|
||||
|
||||
(number) @constant.numeric.js
|
||||
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
["var" "const" "let"] @storage.type._TYPE_.js
|
||||
|
||||
; A simple variable declaration:
|
||||
; The "foo" in `let foo = true`
|
||||
(variable_declarator
|
||||
name: (identifier) @variable.other.assignment.js)
|
||||
|
||||
; A reassignment of a variable declared earlier:
|
||||
; The "foo" in `foo = true`
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.js)
|
||||
|
||||
; A variable object destructuring:
|
||||
; The "foo" in `let { foo } = something`
|
||||
(assignment_expression
|
||||
left: (member_expression
|
||||
property: (property_identifier)) @variable.other.assignment.property.js)
|
||||
|
||||
; The "foo" in `foo += 1`.
|
||||
(augmented_assignment_expression
|
||||
left: (identifier) @variable.other.assignment.js)
|
||||
|
||||
; The "foo" in `foo++`.
|
||||
(update_expression
|
||||
argument: (identifier) @variable.other.assignment.js)
|
||||
|
||||
; `object_pattern` appears to only be encountered in assignment expressions, so
|
||||
; this won't match other uses of object/prop shorthand.
|
||||
((object_pattern
|
||||
(shorthand_property_identifier_pattern) @variable.other.assignment.destructuring.js))
|
||||
|
||||
; A variable object destructuring with default value:
|
||||
; The "foo" in `let { foo = true } = something`
|
||||
(object_assignment_pattern
|
||||
(shorthand_property_identifier_pattern) @variable.other.assignment.destructuring.js)
|
||||
|
||||
; A variable object alias destructuring:
|
||||
; The "bar" and "foo" in `let { bar: foo } = something`
|
||||
(object_pattern
|
||||
(pair_pattern
|
||||
; TODO: This arguably isn't an object key.
|
||||
key: (_) @entity.other.attribute-name.js
|
||||
value: (identifier) @variable.other.assignment.destructuring.js))
|
||||
|
||||
; A variable object alias destructuring with default value:
|
||||
; The "bar" and "foo" in `let { bar: foo = true } = something`
|
||||
(object_pattern
|
||||
(pair_pattern
|
||||
; TODO: This arguably isn't an object key.
|
||||
key: (_) @entity.other.attribute-name.js
|
||||
value: (assignment_pattern
|
||||
left: (identifier) @variable.other.assignment.destructuring.js)))
|
||||
|
||||
; A variable array destructuring:
|
||||
; The "foo" and "bar" in `let [foo, bar] = something`
|
||||
(variable_declarator
|
||||
(array_pattern
|
||||
(identifier) @variable.other.assignment.destructuring.js))
|
||||
|
||||
; A variable declaration in a for…(in|of) loop:
|
||||
; The "foo" in `for (let foo of bar) {`
|
||||
(for_in_statement
|
||||
left: (identifier) @variable.other.assignment.loop.js)
|
||||
|
||||
; A variable array destructuring in a for…(in|of) loop:
|
||||
; The "foo" and "bar" in `for (let [foo, bar] of baz)`
|
||||
(for_in_statement
|
||||
left: (array_pattern
|
||||
(identifier) @variable.other.assignment.loop.js))
|
||||
|
||||
; A variable object destructuring in a for…(in|of) loop:
|
||||
; The "foo" and "bar" in `for (let { foo, bar } of baz)`
|
||||
(for_in_statement
|
||||
left: (object_pattern
|
||||
(shorthand_property_identifier_pattern) @variable.other.assignment.loop.js))
|
||||
|
||||
; A variable object destructuring in a for…(in|of) loop:
|
||||
; The "foo" in `for (let { bar: foo } of baz)`
|
||||
(for_in_statement
|
||||
left: (object_pattern
|
||||
(pair_pattern
|
||||
key: (_) @entity.other.attribute-name.js
|
||||
value: (identifier) @variable.other.assignment.loop.js)
|
||||
(#set! test.final true)))
|
||||
|
||||
; The "error" in `} catch (error) {`
|
||||
(catch_clause
|
||||
parameter: (identifier) @variable.other.assignment.catch.js)
|
||||
|
||||
; Single parameter of an arrow function:
|
||||
; The "foo" in `(foo => …)`
|
||||
(arrow_function parameter: (identifier) @variable.parameter.js)
|
||||
|
||||
|
||||
; PARAMETERS
|
||||
; ----------
|
||||
|
||||
(formal_parameters
|
||||
[
|
||||
; The "foo" in `function (foo) {`.
|
||||
(identifier) @variable.parameter.js
|
||||
; The "foo" and "bar" in `function ([foo, bar]) {`.
|
||||
(array_pattern
|
||||
(identifier) @variable.parameter.destructuring.array.js)
|
||||
|
||||
(object_pattern
|
||||
[
|
||||
; The "foo" in `function ({ key: foo }) {`.
|
||||
(pair_pattern value: (identifier) @variable.parameter.destructuring.value.js)
|
||||
|
||||
; The "key" in `function ({ key: foo }) {`.
|
||||
(pair_pattern key: (property_identifier) @variable.parameter.destructuring.key.js)
|
||||
|
||||
; The "foo" in `function ({ foo }) {`.
|
||||
(shorthand_property_identifier_pattern) @variable.parameter.destructuring.shorthand.js
|
||||
])
|
||||
])
|
||||
|
||||
; The "foo" in `function (...foo) {`.
|
||||
(formal_parameters
|
||||
(rest_pattern
|
||||
(identifier) @variable.parameter.js))
|
||||
|
||||
; The "foo" in `function (foo = false) {`.
|
||||
(formal_parameters
|
||||
(assignment_pattern
|
||||
(identifier) @variable.parameter.js))
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
; =========
|
||||
|
||||
; Named function expressions:
|
||||
; the "foo" in `let bar = function foo () {`
|
||||
(function
|
||||
name: (identifier) @entity.name.function.definition.js)
|
||||
|
||||
; Function definitions:
|
||||
; the "foo" in `function foo () {`
|
||||
(function_declaration
|
||||
name: (identifier) @entity.name.function.definition.js)
|
||||
|
||||
; Named generator function expressions:
|
||||
; the "foo" in `let bar = function* foo () {`
|
||||
(generator_function
|
||||
name: (identifier) @entity.name.function.generator.definition.js)
|
||||
|
||||
; Generator function definitions:
|
||||
; the "foo" in `function* foo () {`
|
||||
(generator_function_declaration
|
||||
name: (identifier) @entity.name.function.generator.definition.js)
|
||||
|
||||
; Method definitions:
|
||||
; the "foo" in `foo () {` (inside a class body)
|
||||
(method_definition
|
||||
name: (property_identifier) @entity.name.function.method.definition.js)
|
||||
|
||||
; Function property assignment:
|
||||
; The "foo" in `thing.foo = (arg) => {}`
|
||||
(assignment_expression
|
||||
left: (member_expression
|
||||
property: (property_identifier) @entity.name.function.definition.js
|
||||
(#set! test.final true))
|
||||
right: [(arrow_function) (function)])
|
||||
|
||||
; Function variable assignment:
|
||||
; The "foo" in `let foo = function () {`
|
||||
(variable_declarator
|
||||
name: (identifier) @entity.name.function.definition.js
|
||||
value: [(function) (arrow_function)])
|
||||
|
||||
; Function variable reassignment:
|
||||
; The "foo" in `foo = function () {`
|
||||
(assignment_expression
|
||||
left: (identifier) @function
|
||||
right: [(function) (arrow_function)])
|
||||
|
||||
; Object key-value pair function:
|
||||
; The "foo" in `{ foo: function () {} }`
|
||||
(pair
|
||||
key: (property_identifier) @entity.name.function.method.definition.js
|
||||
value: [(function) (arrow_function)])
|
||||
|
||||
(function "function" @storage.type.function.js)
|
||||
(function_declaration "function" @storage.type.function.js)
|
||||
|
||||
(generator_function "function" @storage.type.function.js)
|
||||
(generator_function_declaration "function" @storage.type.function.js)
|
||||
|
||||
(generator_function "*" @storage.modifier.generator.js)
|
||||
(generator_function_declaration "*" @storage.modifier.generator.js)
|
||||
(method_definition "*" @storage.modifier.generator.js)
|
||||
|
||||
|
||||
; SUPPORT
|
||||
; =======
|
||||
|
||||
; Array methods.
|
||||
(member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "Array")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(from|isArray|of)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Date methods.
|
||||
(member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "Date")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(now|parse|UTC)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; JSON methods.
|
||||
(member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "JSON")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(parse|stringify)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Math methods.
|
||||
(member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "Math")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(abs|acos|acosh|asin|asinh|atan|atanh|atan2|cbrt|ceil|clz32|cos|cosh|exp|expm1|floor|fround|hypot|imul|log|log1p|log10|log2|max|min|pow|random|round|sign|sin|sinh|sqrt|tan|tanh|trunc)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Object methods.
|
||||
(member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "Object")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(assign|create|defineProperty|defineProperties|entries|freeze|fromEntries|getOwnPropertyDescriptor|getOwnPropertyDescriptors|getOwnPropertyNames|getOwnPropertySymbols|getPrototypeOf|is|isExtensible|isFrozen|isSealed|keys|preventExtensions|seal|setPrototypeOf|values)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Reflect methods.
|
||||
(member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "Reflect")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(apply|construct|defineProperty|deleteProperty|get|getOwnPropertyDescriptor|getPrototypeOf|has|isExtensible|ownKeys|preventExtensions|set|setPrototypeOf)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Intl.X instantiations.
|
||||
(new_expression
|
||||
constructor: (member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "Intl")
|
||||
property: (property_identifier) @support.class.builtin.js
|
||||
(#match? @support.class.builtin.js "^(Collator|DateTimeFormat|DisplayNames|ListFormat|Locale|NumberFormat|PluralRules|Segmenter)$"))
|
||||
(#set! test.final true))
|
||||
|
||||
; Built-in class instantiations.
|
||||
(new_expression
|
||||
constructor: (identifier) @support.class.builtin.instance.js
|
||||
(#match? @support.class.builtin.instance.js "^(AggregateError|Array|ArrayBuffer|BigInt64Array|BigUint64Array|Boolean|DataView|Date|Error|EvalError|FinalizationRegistry|Float32Array|Float64Array|Function|ImageCapture|Int8Array|Int16Array|Int32Array|Map|Number|Object|Promise|RangeError|ReferenceError|RegExp|Set|String|SyntaxError|TypeError|Uint8Array|Uint8ClampedArray|Uint16Array|Uint32Array|URIError|URL|WeakMap|WeakRef|WeakSet|XMLHttpRequest)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Built-in constructors that can be invoked without `new`.
|
||||
(call_expression
|
||||
(identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(AggregateError|Array|ArrayBuffer|Boolean|BigInt|Error|EvalError|Function|Number|Object|Proxy|RangeError|String|Symbol|SyntaxError|URIError)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Built-in functions.
|
||||
(call_expression
|
||||
(identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Built-in `console` functions.
|
||||
|
||||
(member_expression
|
||||
object: (identifier) @support.class.builtin.console.js
|
||||
(#eq? @support.class.builtin.console.js "console")
|
||||
property: (property_identifier) @support.function.builtin.console.js
|
||||
(#match? @support.function.builtin.console.js "^(assert|clear|count(Reset)?|debug|dir(xml)?|error|group(End)?info|log|profile(End)?|table|time(End|Log|Stamp)?|trace|warn)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Static methods of `Promise`.
|
||||
(member_expression
|
||||
object: (identifier) @support.class.builtin.js
|
||||
(#eq? @support.class.builtin.js "Promise")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(all|allSettled|any|race|resolve|reject)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; All “well-known” symbols (as they are referred to in the spec).
|
||||
(member_expression
|
||||
object: (identifier) @support.class.builtin.js
|
||||
property: (property_identifier) @support.property.builtin.js
|
||||
(#eq? @support.class.builtin.js "Symbol")
|
||||
(#match? @support.property.builtin.js "^(asyncIterator|hasInstance|isConcatSpreadable|iterator|match|matchAll|replace|search|split|species|toPrimitive|toStringTag|unscopables)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Static methods of `Symbol`.
|
||||
(member_expression
|
||||
object: (identifier) @support.class.builtin.js
|
||||
(#eq? @support.class.builtin.js "Symbol")
|
||||
property: (property_identifier) @support.function.builtin.js
|
||||
(#match? @support.function.builtin.js "^(for|keyFor)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Other built-in objects.
|
||||
((identifier) @support.class.builtin.js
|
||||
(#match? @support.class.builtin.js "^(Symbol)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Deprecated built-in functions.
|
||||
(call_expression
|
||||
(identifier) @invalid.deprecated.function.js
|
||||
(#match? @invalid.deprecated.function.js "^(escape|unescape)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Built-in DOM classes.
|
||||
((identifier) @support.class.builtin.js
|
||||
(#match? @support.class.builtin.js "^(Document|Element|HTMLElement|HTMLDocument|HTML(Select|BR|HR|LI|Div|Map|Mod|Pre|Area|Base|Body|Data|Font|Form|Head|Html|Link|Menu|Meta|Slot|Span|Time|Audio|DList|Embed|Image|Input|Label|Media|Meter|OList|Param|Quote|Style|Table|Title|Track|UList|Video|Anchor|Button|Canvas|Dialog|IFrame|Legend|Object|Option|Output|Script|Source|Content|Details|Heading|Marquee|Picture|Unknown|DataList|FieldSet|FrameSet|MenuItem|OptGroup|Progress|TableCol|TableRow|Template|TextArea|Paragraph|TableCell|Options|TableCaption|TableSection|FormControls))$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Deprecated built-in DOM classes.
|
||||
((identifier) @invalid.deprecated.class.js
|
||||
(#match? @invalid.deprecated.class.js "^(HTMLShadowElement)$")
|
||||
(#set! test.final true))
|
||||
|
||||
; Built-in DOM methods on `document`.
|
||||
(call_expression
|
||||
function: (member_expression
|
||||
object: (identifier) @support.object.builtin.js
|
||||
(#eq? @support.object.builtin.js "document")
|
||||
property: (property_identifier) @support.function.method.builtin.js
|
||||
(#match? @support.function.method.builtin.js "^(adoptNode|append|caretPositionFromPoint|caretRangeFromPoint|createAttribute(?:NS)?|createCDATASection|createComment|createDocumentFragment|createElement(?:NS)?|createEvent|createNodeIterator|createProcessingInstruction|createRange|createTextNode|createTreeWalker|elementFromPoint|elementsFromPoint|exitFullscreen|exitPictureInPicture|exitPointerLock|getAnimations|getElementById|getElementsByClassName|getElementsByTagName(?:NS)?|getSelection|hasStorageAccess|importNode|prepend|querySelector|querySelectorAll|releaseCapture|replaceChildren|requestStorageAccess|createExpression|createNSResolver|evaluate|getElementsByName|hasFocus|write|writeln|open|close)$")
|
||||
(#set! test.final true)))
|
||||
|
||||
; Built-in DOM methods on nodes. These will show up as builtins on _any_ class, but
|
||||
; they're distinctive enough that we're OK with that possibility.
|
||||
(call_expression
|
||||
function: (member_expression
|
||||
property: (property_identifier) @support.function.method.builtin.js
|
||||
(#match? @support.function.method.builtin.js "^(addEventListener|appendChild|cloneNode|compareDocumentPosition|contains|getElementsByClassName|getElementsByTagName(?:NS)?|getRootNode|hasChildNodes|insertBefore|isDefaultNamespace|isEqualNode|isSameNode|lookupPrefix|lookupNamespaceURI|normalize|querySelector|querySelectorAll|removeChild|replaceChild|removeEventListener)$")
|
||||
(#set! test.final true)))
|
||||
|
||||
|
||||
; FUNCTION CALLS
|
||||
; ==============
|
||||
|
||||
; An invocation of any function.
|
||||
(call_expression
|
||||
function: (identifier) @support.other.function.js)
|
||||
|
||||
; An invocation of any method.
|
||||
(call_expression
|
||||
function: (member_expression
|
||||
property: (property_identifier) @support.other.function.method.js
|
||||
(#set! test.final true)))
|
||||
|
||||
|
||||
; OBJECTS
|
||||
; =======
|
||||
|
||||
; The "foo" in `foo.bar`.
|
||||
(member_expression
|
||||
object: (identifier) @support.other.object.js)
|
||||
|
||||
; The "FOO" in `FOO.bar` should also be scoped as a constant.
|
||||
(member_expression
|
||||
object: (identifier) @constant.other.object.js
|
||||
(#match? @constant.other.object.js "^[_A-Z]+$"))
|
||||
|
||||
; The "bar" in `foo.bar`, `foo.bar.baz`, and `foo.bar[baz]`.
|
||||
(member_expression
|
||||
property: (property_identifier) @support.other.property.js)
|
||||
|
||||
; The "BAR" in `foo.BAR` should also be scoped as a constant.
|
||||
(member_expression
|
||||
property: (property_identifier) @constant.other.property.js
|
||||
(#match? @constant.other.property.js "^[_A-Z]+$"))
|
||||
|
||||
; The "foo" in `{ foo: true }`.
|
||||
(pair
|
||||
key: (property_identifier) @entity.other.attribute-name.js)
|
||||
|
||||
; TODO: This is both a key and a value, so opinions may vary on how to treat it.
|
||||
; The "foo" in `{ foo }`.
|
||||
(object
|
||||
(shorthand_property_identifier) @entity.other.attribute-name.shorthand.js)
|
||||
|
||||
|
||||
; CLASSES
|
||||
; =======
|
||||
|
||||
; The "class" in `class Foo {`.
|
||||
(class_declaration
|
||||
"class" @storage.type.class.js)
|
||||
|
||||
; The "class" in `bar = class Foo {`
|
||||
(class
|
||||
"class" @storage.type.class.js)
|
||||
|
||||
; The "Foo" in `class Foo {`.
|
||||
(class_declaration
|
||||
name: (identifier) @entity.name.type.class.js)
|
||||
|
||||
; The "Foo" in `bar = class Foo {`.
|
||||
(class
|
||||
name: (identifier) @entity.name.type.class.js)
|
||||
|
||||
; The "Bar" in `class Foo extends Bar {`.
|
||||
(class_heritage
|
||||
"extends" @storage.modifier.extends.js
|
||||
(identifier) @entity.other.inherited-class.js)
|
||||
|
||||
; The "Foo" in `new Foo()`.
|
||||
(new_expression
|
||||
constructor: (identifier) @support.other.class.instance.js)
|
||||
|
||||
; A class getter:
|
||||
; the "get" in `get foo () {...`
|
||||
(method_definition
|
||||
"get" @storage.modifier.getter.js)
|
||||
|
||||
; A class setter:
|
||||
; the "set" in `set foo (value) {...`
|
||||
(method_definition
|
||||
"set" @storage.modifier.setter.js)
|
||||
|
||||
|
||||
; IMPORTS/EXPORTS
|
||||
; ===============
|
||||
|
||||
; The "Foo" in `import Foo from './bar'`
|
||||
(import_clause
|
||||
(identifier) @variable.other.assignment.import.js)
|
||||
|
||||
; The "Foo" in `import { Foo } from './bar'`
|
||||
(import_specifier
|
||||
(identifier) @variable.other.assignment.import.js)
|
||||
|
||||
; The "Foo" in `export { Foo }`
|
||||
(export_specifier
|
||||
name: (identifier) @variable.other.assignment.export.js)
|
||||
|
||||
; The "default" in `export { Foo as default }`
|
||||
(export_specifier
|
||||
alias: (identifier) @keyword.control.default.js
|
||||
(#eq? @keyword.control.default.js "default"))
|
||||
|
||||
; The "default" in `export default Foo`
|
||||
(export_statement
|
||||
"default" @keyword.control.default.js)
|
||||
|
||||
; The "Foo" in `export Foo`
|
||||
(export_statement
|
||||
(identifier) @variable.other.assignment.export.js)
|
||||
|
||||
|
||||
; COMMENTS
|
||||
; ========
|
||||
|
||||
; Line comments. `//`
|
||||
((comment) @comment.line.double-slash.js
|
||||
(#match? @comment.line.double-slash.js "^\/\/"))
|
||||
|
||||
((comment) @punctuation.definition.comment.js
|
||||
(#match? @punctuation.definition.comment.js "^\/\/")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^\/\/"))
|
||||
|
||||
; Block comments. `/* */`
|
||||
((comment) @comment.block.js
|
||||
(#match? @comment.block.js "^/\\*")
|
||||
(#match? @comment.block.js "\\*/$"))
|
||||
|
||||
((comment) @punctuation.definition.comment.begin.js
|
||||
(#match? @punctuation.definition.comment.begin.js "^/\\*")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*"))
|
||||
|
||||
((comment) @punctuation.definition.comment.end.js
|
||||
(#match? @punctuation.definition.comment.end.js "\\*/$")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\*/$"))
|
||||
|
||||
(hash_bang_line) @comment.line.shebang.js
|
||||
((hash_bang_line) @punctuation.definition.comment.js
|
||||
(#set! adjust.endAfterFirstMatchOf "^#!"))
|
||||
|
||||
|
||||
; KEYWORDS
|
||||
; ========
|
||||
|
||||
[
|
||||
"catch"
|
||||
"finally"
|
||||
"throw"
|
||||
"try"
|
||||
] @keyword.control.trycatch._TYPE_.js
|
||||
|
||||
[
|
||||
"return"
|
||||
"yield"
|
||||
"continue"
|
||||
"break"
|
||||
"switch"
|
||||
"case"
|
||||
"default"
|
||||
] @keyword.control.flow._TYPE_.js
|
||||
|
||||
[
|
||||
"import"
|
||||
"from"
|
||||
"export"
|
||||
"as"
|
||||
] @keyword.control._TYPE_.js
|
||||
|
||||
[
|
||||
"delete"
|
||||
"typeof"
|
||||
"void"
|
||||
] @keyword.operator.unary._TYPE_.js
|
||||
|
||||
[
|
||||
"if"
|
||||
"else"
|
||||
] @keyword.control.conditional._TYPE_.js
|
||||
|
||||
"new" @keyword.operator.new.js
|
||||
|
||||
[
|
||||
"do"
|
||||
"for"
|
||||
"in"
|
||||
"of"
|
||||
"while"
|
||||
] @keyword.control.loop._TYPE_.js
|
||||
|
||||
"with" @keyword.control.with.js @invalid.deprecated.with.js
|
||||
|
||||
["async" "static"] @storage.modifier._TYPE_.js
|
||||
["await"] @keyword.control.await.js
|
||||
|
||||
[
|
||||
"debugger"
|
||||
] @keyword.other._TYPE_.js
|
||||
|
||||
; BUILTINS
|
||||
; ========
|
||||
|
||||
[
|
||||
(this)
|
||||
(super)
|
||||
] @variable.language._TYPE_.js
|
||||
|
||||
((identifier) @support.object.builtin._TEXT_.js
|
||||
(#match? @support.object.builtin._TEXT_.js "^(arguments|module|window|document)$")
|
||||
(#is-not? local)
|
||||
(#set! test.final true))
|
||||
|
||||
((identifier) @support.object.builtin.filename.js
|
||||
(#eq? @support.object.builtin.filename.js "__filename")
|
||||
(#is-not? local)
|
||||
(#set! test.final true))
|
||||
|
||||
((identifier) @support.object.builtin.dirname.js
|
||||
(#eq? @support.object.builtin.dirname.js "__dirname")
|
||||
(#is-not? local)
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
((identifier) @support.function.builtin.require.js
|
||||
(#eq? @support.function.builtin.require.js "require")
|
||||
(#is-not? local)
|
||||
(#set! test.final true))
|
||||
|
||||
[
|
||||
(null)
|
||||
(undefined)
|
||||
] @constant.language._TYPE_.js
|
||||
|
||||
[
|
||||
(true)
|
||||
(false)
|
||||
] @constant.language.boolean._TYPE_.js
|
||||
|
||||
((identifier) @constant.language.infinity.js
|
||||
(#eq? @constant.language.infinity.js "Infinity")
|
||||
(#set! test.final true))
|
||||
|
||||
(arrow_function
|
||||
"=>" @punctuation.function.arrow.js)
|
||||
|
||||
; Things that `LOOK_LIKE_CONSTANTS`.
|
||||
([(property_identifier) (identifier)] @constant.other.js
|
||||
(#match? @constant.other.js "^[A-Z_][A-Z0-9_]*$")
|
||||
(#set! test.shy true))
|
||||
|
||||
; TODO: What do we do with computed object keys?
|
||||
;
|
||||
; { [foo]: "bar" }
|
||||
;
|
||||
; If we scope the whole thing as `entity.other.attribute-name`, it arguably
|
||||
; looks too similar to an ordinary object key. The Babel grammar scopes the
|
||||
; `[foo]` as an object key, but the `foo` inside it as a variable. But we
|
||||
; aren't scoping all identifiers as variables, so we don't have that option.
|
||||
; (pair
|
||||
; key: (computed_property_name
|
||||
; ["[""]"] @entity.other.attribute-name.computed.js))
|
||||
|
||||
|
||||
; REGEX
|
||||
; =====
|
||||
|
||||
; NOTE: An injection grammar tokenizes the contents of regular
|
||||
; expressions. Thus we're highlighting only sparingly here.
|
||||
|
||||
(regex) @string.regexp.js
|
||||
(regex
|
||||
"/" @punctuation.definition.string.begin.js
|
||||
(#set! test.onlyIfFirst true))
|
||||
|
||||
(regex
|
||||
"/" @punctuation.definition.string.end.js
|
||||
(#set! test.onlyIfLast true))
|
||||
|
||||
(regex_flags) @keyword.other.js
|
||||
|
||||
|
||||
; JSX
|
||||
; ===
|
||||
|
||||
; The "Foo" in `<Foo />`.
|
||||
(jsx_self_closing_element
|
||||
name: (identifier) @entity.name.tag.js
|
||||
) @meta.tag.js
|
||||
|
||||
; The "Foo" in `<Foo>`.
|
||||
(jsx_opening_element
|
||||
name: (identifier) @entity.name.tag.js)
|
||||
|
||||
; The "Foo" in `</Foo>`.
|
||||
(jsx_closing_element
|
||||
"/" @punctuation.definition.tag.end.js
|
||||
(#set! test.final true)
|
||||
name: (identifier) @entity.name.tag.js)
|
||||
|
||||
; The "bar" in `<Foo bar={true} />`.
|
||||
(jsx_attribute
|
||||
(property_identifier) @entity.other.attribute-name.js)
|
||||
|
||||
; All JSX expressions/interpolations within braces.
|
||||
((jsx_expression) @meta.embedded.block.jsx.js
|
||||
(#match? @meta.embedded.block.jsx.js "\\n")
|
||||
(#set! test.final true))
|
||||
|
||||
(jsx_expression) @meta.embedded.line.jsx.js
|
||||
|
||||
(jsx_opening_element
|
||||
"<" @punctuation.definition.tag.begin.js
|
||||
">" @punctuation.definition.tag.end.js)
|
||||
|
||||
(jsx_closing_element
|
||||
"<" @punctuation.definition.tag.begin.js
|
||||
">" @punctuation.definition.tag.end.js)
|
||||
|
||||
(jsx_self_closing_element
|
||||
"<" @punctuation.definition.tag.begin.js
|
||||
(#set! test.final true))
|
||||
|
||||
((jsx_self_closing_element
|
||||
; The "/>" in `<Foo />`, extended to cover both anonymous nodes at once.
|
||||
"/") @punctuation.definition.tag.end.js
|
||||
(#set! adjust.startAt lastChild.previousSibling.startPosition)
|
||||
(#set! adjust.endAt lastChild.endPosition)
|
||||
(#set! test.final true))
|
||||
|
||||
|
||||
; OPERATORS
|
||||
; ==========
|
||||
|
||||
"=" @keyword.operator.assignment.js
|
||||
|
||||
["&" "|" "<<" ">>" ">>>" "~" "^"] @keyword.operator.bitwise.js
|
||||
|
||||
["&&" "||" "&&" "??" "!"] @keyword.operator.logical.js
|
||||
|
||||
"..." @keyword.operator.spread.js
|
||||
|
||||
["in" "instanceof"] @keyword.operator.expression._TYPE_.js
|
||||
|
||||
["==" "===" "!=" "!=="] @keyword.operator.comparison.js
|
||||
|
||||
["++" "--"] @keyword.operator.increment.js
|
||||
|
||||
(binary_expression
|
||||
[">" "<" ">=" "<="] @keyword.operator.relational.js)
|
||||
|
||||
(binary_expression
|
||||
["/" "+" "-" "*" "**" "%"] @keyword.operator.arithmetic.js)
|
||||
|
||||
(unary_expression ["+" "-"] @keyword.operator.unary.js)
|
||||
|
||||
(ternary_expression ["?" ":"] @keyword.operator.ternary.js)
|
||||
|
||||
[
|
||||
"&&="
|
||||
"||="
|
||||
"??="
|
||||
"+="
|
||||
"-="
|
||||
"*="
|
||||
"**="
|
||||
"/="
|
||||
"%="
|
||||
"^="
|
||||
"&="
|
||||
"|="
|
||||
"<<="
|
||||
">>="
|
||||
">>>="
|
||||
] @keyword.operator.assignment.compound.js
|
||||
|
||||
; TODO: There might be debate over whether `.` is treated as punctuation or as
|
||||
; an operator. But the addition of `?.` to the language makes me feel like both
|
||||
; should be treated as operators just for the benefit of syntax highlighting.
|
||||
|
||||
"." @keyword.operator.accessor.js
|
||||
|
||||
; The optional chaining accessor is listed in the bundled `highlights.scm` as
|
||||
; an anonymous node, but it appears not to be implemented that way, so we can't
|
||||
; use "?." to target it.
|
||||
(optional_chain) @keyword.operator.accessor.optional-chaining.js
|
||||
|
||||
; Optional chaining is illegal…:
|
||||
|
||||
; …on the left-hand side of an assignment.
|
||||
(assignment_expression
|
||||
left: (_) @_IGNORE_
|
||||
(#set! prohibitsOptionalChaining true))
|
||||
|
||||
; …within a `new` expression.
|
||||
(new_expression
|
||||
constructor: (_) @_IGNORE_
|
||||
(#set! prohibitsOptionalChaining true))
|
||||
|
||||
((optional_chain) @invalid.illegal.optional-chain.js
|
||||
(#set! test.onlyIfDescendantOfNodeWithData prohibitsOptionalChaining))
|
||||
|
||||
|
||||
; PUNCTUATION
|
||||
; ===========
|
||||
|
||||
(formal_parameters
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.js
|
||||
")"@punctuation.definition.parameters.end.bracket.round.js
|
||||
(#set! test.final true))
|
||||
|
||||
(object
|
||||
"{" @punctuation.definition.object.begin.bracket.curly.js
|
||||
"}" @punctuation.definition.object.end.bracket.curly.js
|
||||
(#set! test.final true))
|
||||
|
||||
(arguments
|
||||
"(" @punctuation.definition.arguments.begin.bracket.round.js
|
||||
")" @punctuation.definition.arguments.end.bracket.round.js
|
||||
(#set! test.final true))
|
||||
|
||||
(computed_property_name
|
||||
"[" @punctuation.definition.computed-property.begin.bracket.square.js
|
||||
"]" @punctuation.definition.computed-property.end.bracket.square.js
|
||||
(#set! test.final true))
|
||||
|
||||
(subscript_expression
|
||||
"[" @punctuation.definition.subscript.begin.bracket.square.js
|
||||
"]" @punctuation.definition.subscript.end.bracket.square.js
|
||||
(#set! test.final true))
|
||||
|
||||
(array
|
||||
"[" @punctuation.definition.array.begin.bracket.square.js
|
||||
"]" @punctuation.definition.array.end.bracket.square.js
|
||||
(#set! test.final true))
|
||||
|
||||
(array_pattern
|
||||
"[" @punctuation.definition.array.begin.bracket.square.js
|
||||
"]" @punctuation.definition.array.end.bracket.square.js
|
||||
(#set! test.final true))
|
||||
|
||||
"{" @punctuation.definition.block.begin.bracket.curly.js
|
||||
"}" @punctuation.definition.block.end.bracket.curly.js
|
||||
"(" @punctuation.definition.begin.bracket.round.js
|
||||
")" @punctuation.definition.end.bracket.round.js
|
||||
"[" @punctuation.definition.begin.bracket.square.js
|
||||
"]" @punctuation.definition.end.bracket.square.js
|
||||
|
||||
(array
|
||||
"," @punctuation.separator.array.comma.js
|
||||
(#set! test.final true))
|
||||
|
||||
(array_pattern
|
||||
"," @punctuation.separator.array.comma.js
|
||||
(#set! test.final true))
|
||||
|
||||
(pair
|
||||
":" @punctuation.separator.key-value.colon.js
|
||||
(#set! test.final true))
|
||||
|
||||
";" @punctuation.terminator.statement.js
|
||||
"," @punctuation.separator.comma.js
|
||||
":" @punctuation.separator.colon.js
|
||||
|
||||
; META
|
||||
; ====
|
||||
|
||||
; The interiors of functions (useful for snippets and commands).
|
||||
(method_definition
|
||||
body: (statement_block) @meta.block.function.js
|
||||
(#set! test.final true))
|
||||
|
||||
(function_declaration
|
||||
body: (statement_block) @meta.block.function.js
|
||||
(#set! test.final true))
|
||||
|
||||
(generator_function_declaration
|
||||
body: (statement_block) @meta.block.function.js
|
||||
(#set! test.final true))
|
||||
|
||||
(function
|
||||
body: (statement_block) @meta.block.function.js
|
||||
(#set! test.final true))
|
||||
|
||||
(generator_function
|
||||
body: (statement_block) @meta.block.function.js
|
||||
(#set! test.final true))
|
||||
|
||||
; The interior of a class body (useful for snippets and commands).
|
||||
(class_body) @meta.block.class.js
|
||||
|
||||
; All other sorts of blocks.
|
||||
(statement_block) @meta.block.js
|
||||
|
||||
; The inside of a parameter definition list.
|
||||
((formal_parameters) @meta.parameters.js
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
; The inside of an object literal.
|
||||
((object) @meta.object.js
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
|
||||
; MISC
|
||||
; ====
|
||||
|
||||
; A label. Rare, but it can be used to prefix any statement and to control
|
||||
; which loop is affected in `continue` or `break` statements. Svelte uses them
|
||||
; for another purpose.
|
||||
(statement_identifier) @entity.name.label.js
|
||||
|
||||
;
|
||||
; Inside of the parameters of an arrow function, the highlighting of parameters
|
||||
; can change while the user is typing. For instance, if the user is adding a
|
||||
; default value to a parameter, the parse tree will go into an error state
|
||||
; until there are tokens on either side of `=`.
|
||||
;
|
||||
; We're trying to catch and minimize that here. This expression catches and
|
||||
; highlights any parameters preceding the invalid one, but sadly can't reach
|
||||
; the invalid parameter itself.
|
||||
;
|
||||
; This doesn't happen inside functions defined with the `function` annotation,
|
||||
; probably because the parsing there is much more straightforward.
|
||||
|
||||
; ((sequence_expression
|
||||
; left: (identifier) @variable.parameter.js)
|
||||
; right: (arrow_function))
|
||||
|
||||
; TODO: Any identifier not yet scoped might as well be scoped as a variable,
|
||||
; but that's an opinionated choice. We might want to make this configurable.
|
||||
; ((identifier) @variable.other.other.js
|
||||
; (#set! test.shy true))
|
157
packages/language-javascript/grammars/ts/indents.scm
Normal file
157
packages/language-javascript/grammars/ts/indents.scm
Normal file
@ -0,0 +1,157 @@
|
||||
|
||||
; ((template_string) @ignore
|
||||
; (#set! test.onlyIfNotOnStartingOrEndingRow true))
|
||||
|
||||
; STATEMENT BLOCKS
|
||||
; ================
|
||||
|
||||
; More accurate indentation matching for all blocks delimited by braces.
|
||||
(statement_block "}" @match
|
||||
(#set! indent.matchIndentOf parent.firstChild.startPosition))
|
||||
|
||||
|
||||
; SWITCH STATEMENTS
|
||||
; =================
|
||||
|
||||
; The closing brace of a switch statement's body should match the indentation
|
||||
; of the line where the switch statement starts.
|
||||
(switch_statement
|
||||
body: (switch_body "}" @match
|
||||
(#set! test.onlyIfLast true))
|
||||
(#set! indent.matchIndentOf parent.startPosition))
|
||||
|
||||
; 'case' and 'default' need to be indented one level more than their containing
|
||||
; `switch`. TODO: Might need to make this configurable.
|
||||
(["case" "default"] @match
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
|
||||
|
||||
; ONE-LINE CONDITIONALS
|
||||
; =====================
|
||||
|
||||
; An `if` statement without an opening brace should indent the next line…
|
||||
(if_statement
|
||||
condition: (parenthesized_expression ")" @indent
|
||||
(#set! test.onlyIfLastTextOnRow true)))
|
||||
; (as should a braceless `else`…)
|
||||
("else" @indent
|
||||
(#set! test.onlyIfLastTextOnRow true))
|
||||
|
||||
; …and keep that indent level if the user types a comment before the
|
||||
; consequence…
|
||||
(if_statement
|
||||
consequence: (empty_statement) @match
|
||||
(#set! test.onlyIfNotStartsOnSameRowAs parent.startPosition)
|
||||
(#set! indent.matchIndentOf parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
|
||||
; …and keep that indent level after the user starts typing…
|
||||
(if_statement
|
||||
condition: (_) @indent
|
||||
consequence: [
|
||||
(expression_statement)
|
||||
(return_statement)
|
||||
(continue_statement)
|
||||
(break_statement)
|
||||
(throw_statement)
|
||||
(debugger_statement)
|
||||
] @match
|
||||
; When an opening curly brace is unpaired, it might get interpreted as part
|
||||
; of an `expression_statement`, for some reason.
|
||||
(#not-match? @match "^\\s*{")
|
||||
(#set! indent.matchIndentOf parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
|
||||
; …but dedent after exactly one statement.
|
||||
(if_statement
|
||||
condition: (_) @indent
|
||||
consequence: [
|
||||
(expression_statement)
|
||||
(return_statement)
|
||||
(continue_statement)
|
||||
(break_statement)
|
||||
(throw_statement)
|
||||
(debugger_statement)
|
||||
] @dedent.next
|
||||
; When an opening curly brace is unpaired, it might get interpreted as part
|
||||
; of an `expression_statement`, for some reason.
|
||||
(#not-match? @dedent.next "^\\s*{"))
|
||||
|
||||
(else_clause
|
||||
[
|
||||
(expression_statement)
|
||||
(return_statement)
|
||||
(continue_statement)
|
||||
(break_statement)
|
||||
(throw_statement)
|
||||
(debugger_statement)
|
||||
] @dedent.next
|
||||
(#set! test.onlyIfNotStartsOnSameRowAs parent.startPosition))
|
||||
|
||||
|
||||
; HANGING INDENT ON SPLIT LINES
|
||||
; =============================
|
||||
|
||||
; TODO: We might want to make this configurable behavior with the
|
||||
; `onlyIfConfig` scope test.
|
||||
|
||||
; Any of these at the end of a line indicate the next line should be indented…
|
||||
(["||" "&&" "?"] @indent
|
||||
(#set! test.onlyIfLastTextOnRow true))
|
||||
|
||||
; …and the line after that should be dedented.
|
||||
(binary_expression
|
||||
["||" "&&"]
|
||||
right: (_) @dedent.next
|
||||
(#set! test.onlyIfNotStartsOnSameRowAs parent.startPosition))
|
||||
|
||||
; let foo = this.longTernaryCondition() ?
|
||||
; consequenceWhichIsItselfRatherLong :
|
||||
; alternativeThatIsNotBrief;
|
||||
;
|
||||
; …followed by a dedent.
|
||||
(ternary_expression
|
||||
alternative: (_) @dedent.next
|
||||
(#set! test.onlyIfNotStartsOnSameRowAs parent.startPosition))
|
||||
|
||||
|
||||
; DEDENT-NEXT IN LIMITED SCENARIOS
|
||||
; ================================
|
||||
|
||||
; Catches unusual hanging-indent scenarios when calling a method, such as:
|
||||
;
|
||||
; return this.veryLongMethodNameWithSeveralArgumentsThat(are, too,
|
||||
; short, forEach, toHave, itsOwn, line);
|
||||
;
|
||||
; (arguments ")" @dedent.next
|
||||
; (#set! test.onlyIfNotStartsOnSameRowAs parent.firstChild.startPosition)
|
||||
; (#set! test.onlyIfNotFirstTextOnRow true))
|
||||
|
||||
|
||||
; GENERAL
|
||||
; =======
|
||||
|
||||
; Weed out `}`s that should not signal dedents.
|
||||
(template_substitution "}" @_IGNORE_ (#set! test.final true))
|
||||
|
||||
[
|
||||
"{"
|
||||
"("
|
||||
"["
|
||||
] @indent
|
||||
|
||||
[
|
||||
"}"
|
||||
")"
|
||||
"]"
|
||||
] @dedent
|
||||
|
||||
["case" "default"] @indent
|
||||
|
||||
|
||||
; JSX
|
||||
; ===
|
||||
|
||||
(jsx_opening_element ">") @indent
|
||||
(jsx_closing_element ">") @dedent
|
1
packages/language-javascript/grammars/ts/jsdoc/folds.scm
Normal file
1
packages/language-javascript/grammars/ts/jsdoc/folds.scm
Normal file
@ -0,0 +1 @@
|
||||
;
|
@ -0,0 +1,31 @@
|
||||
; Highlight this comment even if it's not “valid” JSDoc.
|
||||
((ERROR) @comment.block.documentation.js.jsdoc
|
||||
(#set! test.onlyIfRoot true))
|
||||
|
||||
((ERROR) @punctuation.definition.begin.comment.js.jsdoc
|
||||
(#set! test.onlyIfRoot true)
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*\\*"))
|
||||
|
||||
((ERROR) @punctuation.definition.end.comment.js.jsdoc
|
||||
(#set! test.onlyIfRoot true)
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "(?:\\*)?\\*/$"))
|
||||
|
||||
|
||||
(document) @comment.block.documentation.js.jsdoc
|
||||
|
||||
((document) @punctuation.definition.begin.comment.js.jsdoc
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^/\\*\\*"))
|
||||
|
||||
((document) @punctuation.definition.end.comment.js.jsdoc
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "(?:\\*)?\\*/$"))
|
||||
|
||||
|
||||
(tag_name) @storage.type.class.jsdoc
|
||||
|
||||
((tag (type)) @entity.other.type.instance.jsdoc
|
||||
; Join the type with its surrounding braces.
|
||||
(#set! adjust.startAt firstChild.nextSibling.startPosition)
|
||||
(#set! adjust.endAt firstChild.nextSibling.nextSibling.nextSibling.endPosition))
|
||||
|
||||
"{" @punctuation.definition.begin.bracket.curly.jsdoc
|
||||
"}" @punctuation.definition.end.bracket.curly.jsdoc
|
@ -0,0 +1 @@
|
||||
;
|
BIN
packages/language-javascript/grammars/ts/jsdoc/tree-sitter-jsdoc.wasm
Executable file
BIN
packages/language-javascript/grammars/ts/jsdoc/tree-sitter-jsdoc.wasm
Executable file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user