mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-08-17 15:10:22 +03:00
Merge pull request #435 - move to WASM version of Oniguruma
Using "second-mate"
This commit is contained in:
commit
c3bcd06059
@ -6,6 +6,9 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Migrated away from `node-oniguruma` in favor of `vscode-oniguruma` (WASM
|
||||
version). This fixes issues with Electron 21
|
||||
|
||||
## 1.103.0
|
||||
|
||||
- Added a new feature to Search for Pulsar's settings
|
||||
|
@ -45,7 +45,7 @@
|
||||
"base16-tomorrow-dark-theme": "file:packages/base16-tomorrow-dark-theme",
|
||||
"base16-tomorrow-light-theme": "file:packages/base16-tomorrow-light-theme",
|
||||
"bookmarks": "file:packages/bookmarks",
|
||||
"bracket-matcher": "https://github.com/pulsar-edit/bracket-matcher.git#c877977",
|
||||
"bracket-matcher": "file:packages/bracket-matcher",
|
||||
"chai": "4.3.4",
|
||||
"clear-cut": "^2.0.2",
|
||||
"coffeescript": "1.12.7",
|
||||
@ -62,7 +62,7 @@
|
||||
"exception-reporting": "file:packages/exception-reporting",
|
||||
"find-and-replace": "https://github.com/atom-community/find-and-replace/archive/refs/tags/v0.220.1.tar.gz",
|
||||
"find-parent-dir": "^0.3.0",
|
||||
"first-mate": "7.4.3",
|
||||
"second-mate": "https://github.com/pulsar-edit/second-mate.git#14aa7bd",
|
||||
"focus-trap": "6.3.0",
|
||||
"fs-admin": "0.19.0",
|
||||
"fs-plus": "^3.1.1",
|
||||
|
1
packages/bracket-matcher/CONTRIBUTING.md
Normal file
1
packages/bracket-matcher/CONTRIBUTING.md
Normal file
@ -0,0 +1 @@
|
||||
[See how you can contribute](https://github.com/pulsar-edit/.github/blob/main/CONTRIBUTING.md)
|
20
packages/bracket-matcher/LICENSE.md
Normal file
20
packages/bracket-matcher/LICENSE.md
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2014 GitHub Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
52
packages/bracket-matcher/README.md
Normal file
52
packages/bracket-matcher/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Bracket Matcher package
|
||||
|
||||
Highlights and jumps between `[]`, `()`, and `{}`. Also highlights matching XML
|
||||
and HTML tags.
|
||||
|
||||
Autocompletes `[]`, `()`, `{}`, `""`, `''`, `“”`, `‘’`, `«»`, `‹›`, and
|
||||
backticks by default.
|
||||
|
||||
Use <kbd>ctrl-m</kbd> to jump to the bracket matching the one adjacent to the cursor.
|
||||
It jumps to the nearest enclosing bracket when there's no adjacent bracket,
|
||||
|
||||
Use <kbd>ctrl-cmd-m</kbd> to select all the text inside the current brackets.
|
||||
|
||||
Use <kbd>alt-cmd-.</kbd> to close the current XML/HTML tag.
|
||||
|
||||
---
|
||||
### Configuration
|
||||
|
||||
Matching brackets and quotes are sensibly inserted for you. If you dislike this
|
||||
functionality, you can disable it from the Bracket Matcher section of the
|
||||
Settings View.
|
||||
|
||||
#### Custom Pairs
|
||||
|
||||
You can customize matching pairs in Bracket Matcher at any time. You can do so either globally via the Settings View or at the scope level via your `config.cson`. Changes take effect immediately.
|
||||
|
||||
* **Autocomplete Characters** - Comma-separated pairs that the editor will treat as brackets / quotes. Entries in this field override the package defaults.
|
||||
* For example: `<>, (), []`
|
||||
|
||||
* **Pairs With Extra Newline** - Comma-separated pairs that enhance the editor's auto indent feature. When used, a newline is automatically added between the pair when enter is pressed between them. Note: This feature is meant to be used in combination with brackets defined for indentation by the active language package (`increaseIndentPattern` / `decreaseIndentPattern`).
|
||||
Example:
|
||||
```
|
||||
fn main() {
|
||||
| <---- Cursor positioned at one indent level higher
|
||||
}
|
||||
```
|
||||
|
||||
#### Scoped settings
|
||||
In addition to the global settings, you are also able to add scope-specific modifications to Pulsar in your `config.cson`. This is especially useful for editor rule changes specific to each language. Scope-specific settings override package defaults _and_ global settings.
|
||||
Example:
|
||||
```cson
|
||||
".rust.source":
|
||||
"bracket-matcher":
|
||||
autocompleteCharacters: [
|
||||
"()"
|
||||
"[]"
|
||||
"{}"
|
||||
"<>"
|
||||
"\"\""
|
||||
"``"
|
||||
]
|
||||
```
|
18
packages/bracket-matcher/keymaps/bracket-matcher.cson
Normal file
18
packages/bracket-matcher/keymaps/bracket-matcher.cson
Normal file
@ -0,0 +1,18 @@
|
||||
'atom-text-editor':
|
||||
'ctrl-m': 'bracket-matcher:go-to-matching-bracket'
|
||||
'ctrl-]': 'bracket-matcher:remove-brackets-from-selection'
|
||||
|
||||
'.platform-darwin atom-text-editor':
|
||||
'ctrl-cmd-m': 'bracket-matcher:select-inside-brackets'
|
||||
'alt-cmd-.': 'bracket-matcher:close-tag'
|
||||
'ctrl-backspace': 'bracket-matcher:remove-matching-brackets'
|
||||
|
||||
'.platform-linux atom-text-editor':
|
||||
'ctrl-alt-,': 'bracket-matcher:select-inside-brackets'
|
||||
'ctrl-alt-.': 'bracket-matcher:close-tag'
|
||||
'ctrl-alt-backspace': 'bracket-matcher:remove-matching-brackets'
|
||||
|
||||
'.platform-win32 atom-text-editor':
|
||||
'ctrl-alt-,': 'bracket-matcher:select-inside-brackets'
|
||||
'ctrl-alt-.': 'bracket-matcher:close-tag'
|
||||
'ctrl-alt-backspace': 'bracket-matcher:remove-matching-brackets'
|
585
packages/bracket-matcher/lib/bracket-matcher-view.js
Normal file
585
packages/bracket-matcher/lib/bracket-matcher-view.js
Normal file
@ -0,0 +1,585 @@
|
||||
const {CompositeDisposable} = require('atom')
|
||||
const _ = require('underscore-plus')
|
||||
const {Range, Point} = require('atom')
|
||||
const TagFinder = require('./tag-finder')
|
||||
|
||||
const MAX_ROWS_TO_SCAN = 10000
|
||||
const ONE_CHAR_FORWARD_TRAVERSAL = Object.freeze(Point(0, 1))
|
||||
const ONE_CHAR_BACKWARD_TRAVERSAL = Object.freeze(Point(0, -1))
|
||||
const TWO_CHARS_BACKWARD_TRAVERSAL = Object.freeze(Point(0, -2))
|
||||
const MAX_ROWS_TO_SCAN_FORWARD_TRAVERSAL = Object.freeze(Point(MAX_ROWS_TO_SCAN, 0))
|
||||
const MAX_ROWS_TO_SCAN_BACKWARD_TRAVERSAL = Object.freeze(Point(-MAX_ROWS_TO_SCAN, 0))
|
||||
|
||||
module.exports =
|
||||
class BracketMatcherView {
|
||||
constructor (editor, editorElement, matchManager) {
|
||||
this.destroy = this.destroy.bind(this)
|
||||
this.updateMatch = this.updateMatch.bind(this)
|
||||
this.editor = editor
|
||||
this.matchManager = matchManager
|
||||
this.gutter = this.editor.gutterWithName('line-number')
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
this.tagFinder = new TagFinder(this.editor)
|
||||
this.pairHighlighted = false
|
||||
this.tagHighlighted = false
|
||||
|
||||
// ranges for possible selection
|
||||
this.bracket1Range = null
|
||||
this.bracket2Range = null
|
||||
|
||||
this.subscriptions.add(
|
||||
this.editor.onDidTokenize(this.updateMatch),
|
||||
this.editor.getBuffer().onDidChangeText(this.updateMatch),
|
||||
this.editor.onDidChangeGrammar(this.updateMatch),
|
||||
this.editor.onDidChangeSelectionRange(this.updateMatch),
|
||||
this.editor.onDidAddCursor(this.updateMatch),
|
||||
this.editor.onDidRemoveCursor(this.updateMatch),
|
||||
|
||||
atom.commands.add(editorElement, 'bracket-matcher:go-to-matching-bracket', () =>
|
||||
this.goToMatchingBracket()
|
||||
),
|
||||
|
||||
atom.commands.add(editorElement, 'bracket-matcher:go-to-enclosing-bracket', () =>
|
||||
this.gotoPrecedingStartBracket()
|
||||
),
|
||||
|
||||
atom.commands.add(editorElement, 'bracket-matcher:select-inside-brackets', () =>
|
||||
this.selectInsideBrackets()
|
||||
),
|
||||
|
||||
atom.commands.add(editorElement, 'bracket-matcher:close-tag', () =>
|
||||
this.closeTag()
|
||||
),
|
||||
|
||||
atom.commands.add(editorElement, 'bracket-matcher:remove-matching-brackets', () =>
|
||||
this.removeMatchingBrackets()
|
||||
),
|
||||
|
||||
atom.commands.add(editorElement, 'bracket-matcher:select-matching-brackets', () =>
|
||||
this.selectMatchingBrackets()
|
||||
),
|
||||
|
||||
this.editor.onDidDestroy(this.destroy)
|
||||
)
|
||||
|
||||
this.updateMatch()
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.subscriptions.dispose()
|
||||
}
|
||||
|
||||
updateMatch () {
|
||||
if (this.pairHighlighted) {
|
||||
this.editor.destroyMarker(this.startMarker.id)
|
||||
this.editor.destroyMarker(this.endMarker.id)
|
||||
}
|
||||
|
||||
this.pairHighlighted = false
|
||||
this.tagHighlighted = false
|
||||
|
||||
if (!this.editor.getLastSelection().isEmpty()) return
|
||||
|
||||
const {position, matchPosition} = this.findCurrentPair()
|
||||
|
||||
let startRange = null
|
||||
let endRange = null
|
||||
let highlightTag = false
|
||||
let highlightPair = false
|
||||
if (position && matchPosition) {
|
||||
this.bracket1Range = (startRange = Range(position, position.traverse(ONE_CHAR_FORWARD_TRAVERSAL)))
|
||||
this.bracket2Range = (endRange = Range(matchPosition, matchPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL)))
|
||||
highlightPair = true
|
||||
} else {
|
||||
this.bracket1Range = null
|
||||
this.bracket2Range = null
|
||||
if (this.hasSyntaxTree()) {
|
||||
({startRange, endRange} = this.findMatchingTagNameRangesWithSyntaxTree())
|
||||
} else {
|
||||
({startRange, endRange} = this.tagFinder.findMatchingTags())
|
||||
if (this.isCursorOnCommentOrString()) return
|
||||
}
|
||||
if (startRange) {
|
||||
highlightTag = true
|
||||
highlightPair = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!highlightTag && !highlightPair) return
|
||||
|
||||
this.startMarker = this.createMarker(startRange)
|
||||
this.endMarker = this.createMarker(endRange)
|
||||
this.pairHighlighted = highlightPair
|
||||
this.tagHighlighted = highlightTag
|
||||
}
|
||||
|
||||
selectMatchingBrackets () {
|
||||
if (!this.bracket1Range && !this.bracket2Range) return
|
||||
this.editor.setSelectedBufferRanges([this.bracket1Range, this.bracket2Range])
|
||||
this.matchManager.changeBracketsMode = true
|
||||
}
|
||||
|
||||
removeMatchingBrackets () {
|
||||
if (this.editor.hasMultipleCursors()) {
|
||||
this.editor.backspace()
|
||||
return
|
||||
}
|
||||
|
||||
this.editor.transact(() => {
|
||||
if (this.editor.getLastSelection().isEmpty()) {
|
||||
this.editor.selectLeft()
|
||||
}
|
||||
|
||||
const text = this.editor.getSelectedText()
|
||||
this.editor.moveRight()
|
||||
|
||||
// check if the character to the left is part of a pair
|
||||
if (
|
||||
this.matchManager.pairedCharacters.hasOwnProperty(text) ||
|
||||
this.matchManager.pairedCharactersInverse.hasOwnProperty(text)
|
||||
) {
|
||||
let {position, matchPosition, bracket} = this.findCurrentPair()
|
||||
|
||||
if (position && matchPosition) {
|
||||
this.editor.setCursorBufferPosition(matchPosition)
|
||||
this.editor.delete()
|
||||
// if on the same line and the cursor is in front of an end pair
|
||||
// offset by one to make up for the missing character
|
||||
if (position.row === matchPosition.row && this.matchManager.pairedCharactersInverse.hasOwnProperty(bracket)) {
|
||||
position = position.traverse(ONE_CHAR_BACKWARD_TRAVERSAL)
|
||||
}
|
||||
this.editor.setCursorBufferPosition(position)
|
||||
this.editor.delete()
|
||||
} else {
|
||||
this.editor.backspace()
|
||||
}
|
||||
} else {
|
||||
this.editor.backspace()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
findMatchingEndBracket (startBracketPosition, startBracket, endBracket) {
|
||||
if (startBracket === endBracket) return
|
||||
|
||||
if (this.hasSyntaxTree()) {
|
||||
return this.findMatchingEndBracketWithSyntaxTree(startBracketPosition, startBracket, endBracket)
|
||||
} else {
|
||||
const scopeDescriptor = this.editor.scopeDescriptorForBufferPosition(startBracketPosition)
|
||||
if (this.isScopeCommentedOrString(scopeDescriptor.getScopesArray())) return
|
||||
return this.findMatchingEndBracketWithRegexSearch(startBracketPosition, startBracket, endBracket)
|
||||
}
|
||||
}
|
||||
|
||||
findMatchingStartBracket (endBracketPosition, startBracket, endBracket) {
|
||||
if (startBracket === endBracket) return
|
||||
|
||||
if (this.hasSyntaxTree()) {
|
||||
return this.findMatchingStartBracketWithSyntaxTree(endBracketPosition, startBracket, endBracket)
|
||||
} else {
|
||||
const scopeDescriptor = this.editor.scopeDescriptorForBufferPosition(endBracketPosition)
|
||||
if (this.isScopeCommentedOrString(scopeDescriptor.getScopesArray())) return
|
||||
return this.findMatchingStartBracketWithRegexSearch(endBracketPosition, startBracket, endBracket)
|
||||
}
|
||||
}
|
||||
|
||||
findMatchingEndBracketWithSyntaxTree (bracketPosition, startBracket, endBracket) {
|
||||
let result
|
||||
const bracketEndPosition = bracketPosition.traverse([0, startBracket.length])
|
||||
this.editor.buffer.getLanguageMode().getSyntaxNodeContainingRange(
|
||||
new Range(bracketPosition, bracketEndPosition),
|
||||
node => {
|
||||
if (bracketEndPosition.isGreaterThan(node.startPosition) && bracketEndPosition.isLessThan(node.endPosition)) {
|
||||
const matchNode = node.children.find(child =>
|
||||
bracketEndPosition.isLessThanOrEqual(child.startPosition) &&
|
||||
child.type === endBracket
|
||||
)
|
||||
if (matchNode) result = Point.fromObject(matchNode.startPosition)
|
||||
return true
|
||||
}
|
||||
}
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
findMatchingStartBracketWithSyntaxTree (bracketPosition, startBracket, endBracket) {
|
||||
let result
|
||||
const bracketEndPosition = bracketPosition.traverse([0, startBracket.length])
|
||||
this.editor.buffer.getLanguageMode().getSyntaxNodeContainingRange(
|
||||
new Range(bracketPosition, bracketEndPosition),
|
||||
node => {
|
||||
if (bracketPosition.isGreaterThan(node.startPosition)) {
|
||||
const matchNode = node.children.find(child =>
|
||||
bracketPosition.isGreaterThanOrEqual(child.endPosition) &&
|
||||
child.type === startBracket
|
||||
)
|
||||
if (matchNode) result = Point.fromObject(matchNode.startPosition)
|
||||
return true
|
||||
}
|
||||
}
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
findMatchingTagNameRangesWithSyntaxTree () {
|
||||
const position = this.editor.getCursorBufferPosition()
|
||||
const {startTag, endTag} = this.findContainingTagsWithSyntaxTree(position)
|
||||
if (startTag && (startTag.range.containsPoint(position) || endTag.range.containsPoint(position))) {
|
||||
if (startTag === endTag) {
|
||||
const {range} = startTag.child(1)
|
||||
return {startRange: range, endRange: range}
|
||||
} else if (endTag.firstChild.type === '</') {
|
||||
return {
|
||||
startRange: startTag.child(1).range,
|
||||
endRange: endTag.child(1).range
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
startRange: startTag.child(1).range,
|
||||
endRange: endTag.child(2).range
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
findMatchingTagsWithSyntaxTree () {
|
||||
const position = this.editor.getCursorBufferPosition()
|
||||
const {startTag, endTag} = this.findContainingTagsWithSyntaxTree(position)
|
||||
if (startTag) {
|
||||
return {startRange: startTag.range, endRange: endTag.range}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
findContainingTagsWithSyntaxTree (position) {
|
||||
let startTag, endTag
|
||||
if (position.column === this.editor.buffer.lineLengthForRow(position.row)) position.column--;
|
||||
this.editor.buffer.getLanguageMode().getSyntaxNodeAtPosition(position, node => {
|
||||
if (node.type.includes('element') && node.childCount > 0) {
|
||||
const {firstChild, lastChild} = node
|
||||
if (
|
||||
firstChild.childCount > 2 &&
|
||||
firstChild.firstChild.type === '<'
|
||||
) {
|
||||
if (lastChild === firstChild && firstChild.lastChild.type === '/>') {
|
||||
startTag = firstChild
|
||||
endTag = firstChild
|
||||
} else if (
|
||||
lastChild.childCount > 2 &&
|
||||
(lastChild.firstChild.type === '</' ||
|
||||
lastChild.firstChild.type === '<' && lastChild.child(1).type === '/')
|
||||
) {
|
||||
startTag = firstChild
|
||||
endTag = lastChild
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return {startTag, endTag}
|
||||
}
|
||||
|
||||
findMatchingEndBracketWithRegexSearch (startBracketPosition, startBracket, endBracket) {
|
||||
const scanRange = new Range(
|
||||
startBracketPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL),
|
||||
startBracketPosition.traverse(MAX_ROWS_TO_SCAN_FORWARD_TRAVERSAL)
|
||||
)
|
||||
let endBracketPosition = null
|
||||
let unpairedCount = 0
|
||||
this.editor.scanInBufferRange(this.matchManager.pairRegexes[startBracket], scanRange, result => {
|
||||
if (this.isRangeCommentedOrString(result.range)) return
|
||||
switch (result.match[0]) {
|
||||
case startBracket:
|
||||
unpairedCount++
|
||||
break
|
||||
case endBracket:
|
||||
unpairedCount--
|
||||
if (unpairedCount < 0) {
|
||||
endBracketPosition = result.range.start
|
||||
result.stop()
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
return endBracketPosition
|
||||
}
|
||||
|
||||
findMatchingStartBracketWithRegexSearch (endBracketPosition, startBracket, endBracket) {
|
||||
const scanRange = new Range(
|
||||
endBracketPosition.traverse(MAX_ROWS_TO_SCAN_BACKWARD_TRAVERSAL),
|
||||
endBracketPosition
|
||||
)
|
||||
let startBracketPosition = null
|
||||
let unpairedCount = 0
|
||||
this.editor.backwardsScanInBufferRange(this.matchManager.pairRegexes[startBracket], scanRange, result => {
|
||||
if (this.isRangeCommentedOrString(result.range)) return
|
||||
switch (result.match[0]) {
|
||||
case startBracket:
|
||||
unpairedCount--
|
||||
if (unpairedCount < 0) {
|
||||
startBracketPosition = result.range.start
|
||||
result.stop()
|
||||
break
|
||||
}
|
||||
break
|
||||
case endBracket:
|
||||
unpairedCount++
|
||||
}
|
||||
})
|
||||
|
||||
return startBracketPosition
|
||||
}
|
||||
|
||||
findPrecedingStartBracket (cursorPosition) {
|
||||
if (this.hasSyntaxTree()) {
|
||||
return this.findPrecedingStartBracketWithSyntaxTree(cursorPosition)
|
||||
} else {
|
||||
return this.findPrecedingStartBracketWithRegexSearch(cursorPosition)
|
||||
}
|
||||
}
|
||||
|
||||
findPrecedingStartBracketWithSyntaxTree (cursorPosition) {
|
||||
let result
|
||||
this.editor.buffer.getLanguageMode().getSyntaxNodeAtPosition(cursorPosition, node => {
|
||||
for (const child of node.children) {
|
||||
if (cursorPosition.isLessThanOrEqual(child.startPosition)) break
|
||||
if (
|
||||
child.type in this.matchManager.pairedCharacters ||
|
||||
child.type in this.matchManager.pairedCharactersInverse
|
||||
) {
|
||||
result = Point.fromObject(child.startPosition)
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
findPrecedingStartBracketWithRegexSearch (cursorPosition) {
|
||||
const scanRange = new Range(Point.ZERO, cursorPosition)
|
||||
const startBracket = _.escapeRegExp(_.keys(this.matchManager.pairedCharacters).join(''))
|
||||
const endBracket = _.escapeRegExp(_.keys(this.matchManager.pairedCharactersInverse).join(''))
|
||||
const combinedRegExp = new RegExp(`[${startBracket}${endBracket}]`, 'g')
|
||||
const startBracketRegExp = new RegExp(`[${startBracket}]`, 'g')
|
||||
const endBracketRegExp = new RegExp(`[${endBracket}]`, 'g')
|
||||
let startPosition = null
|
||||
let unpairedCount = 0
|
||||
this.editor.backwardsScanInBufferRange(combinedRegExp, scanRange, result => {
|
||||
if (this.isRangeCommentedOrString(result.range)) return
|
||||
if (result.match[0].match(endBracketRegExp)) {
|
||||
unpairedCount++
|
||||
} else if (result.match[0].match(startBracketRegExp)) {
|
||||
unpairedCount--
|
||||
if (unpairedCount < 0) {
|
||||
startPosition = result.range.start
|
||||
result.stop()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return startPosition
|
||||
}
|
||||
|
||||
createMarker (bufferRange) {
|
||||
const marker = this.editor.markBufferRange(bufferRange)
|
||||
this.editor.decorateMarker(marker, {type: 'highlight', class: 'bracket-matcher', deprecatedRegionClass: 'bracket-matcher'})
|
||||
if (atom.config.get('bracket-matcher.highlightMatchingLineNumber', {scope: this.editor.getRootScopeDescriptor()}) && this.gutter) {
|
||||
this.gutter.decorateMarker(marker, {type: 'highlight', class: 'bracket-matcher', deprecatedRegionClass: 'bracket-matcher'})
|
||||
}
|
||||
return marker
|
||||
}
|
||||
|
||||
findCurrentPair () {
|
||||
const currentPosition = this.editor.getCursorBufferPosition()
|
||||
const previousPosition = currentPosition.traverse(ONE_CHAR_BACKWARD_TRAVERSAL)
|
||||
const nextPosition = currentPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL)
|
||||
const currentCharacter = this.editor.getTextInBufferRange(new Range(currentPosition, nextPosition))
|
||||
const previousCharacter = this.editor.getTextInBufferRange(new Range(previousPosition, currentPosition))
|
||||
|
||||
let position, matchPosition, currentBracket, matchingBracket
|
||||
if ((matchingBracket = this.matchManager.pairedCharacters[currentCharacter])) {
|
||||
position = currentPosition
|
||||
currentBracket = currentCharacter
|
||||
matchPosition = this.findMatchingEndBracket(position, currentBracket, matchingBracket)
|
||||
} else if ((matchingBracket = this.matchManager.pairedCharacters[previousCharacter])) {
|
||||
position = previousPosition
|
||||
currentBracket = previousCharacter
|
||||
matchPosition = this.findMatchingEndBracket(position, currentBracket, matchingBracket)
|
||||
} else if ((matchingBracket = this.matchManager.pairedCharactersInverse[previousCharacter])) {
|
||||
position = previousPosition
|
||||
currentBracket = previousCharacter
|
||||
matchPosition = this.findMatchingStartBracket(position, matchingBracket, currentBracket)
|
||||
} else if ((matchingBracket = this.matchManager.pairedCharactersInverse[currentCharacter])) {
|
||||
position = currentPosition
|
||||
currentBracket = currentCharacter
|
||||
matchPosition = this.findMatchingStartBracket(position, matchingBracket, currentBracket)
|
||||
}
|
||||
|
||||
return {position, matchPosition, bracket: currentBracket}
|
||||
}
|
||||
|
||||
goToMatchingBracket () {
|
||||
if (!this.pairHighlighted) return this.gotoPrecedingStartBracket()
|
||||
const position = this.editor.getCursorBufferPosition()
|
||||
|
||||
if (this.tagHighlighted) {
|
||||
let tagCharacterOffset
|
||||
let startRange = this.startMarker.getBufferRange()
|
||||
const tagLength = startRange.end.column - startRange.start.column
|
||||
let endRange = this.endMarker.getBufferRange()
|
||||
if (startRange.compare(endRange) > 0) {
|
||||
[startRange, endRange] = [endRange, startRange]
|
||||
}
|
||||
|
||||
// include the <
|
||||
startRange = new Range(startRange.start.traverse(ONE_CHAR_BACKWARD_TRAVERSAL), endRange.end.traverse(ONE_CHAR_BACKWARD_TRAVERSAL))
|
||||
// include the </
|
||||
endRange = new Range(endRange.start.traverse(TWO_CHARS_BACKWARD_TRAVERSAL), endRange.end.traverse(TWO_CHARS_BACKWARD_TRAVERSAL))
|
||||
|
||||
if (position.isLessThan(endRange.start)) {
|
||||
tagCharacterOffset = position.column - startRange.start.column
|
||||
if (tagCharacterOffset > 0) { tagCharacterOffset++ }
|
||||
tagCharacterOffset = Math.min(tagCharacterOffset, tagLength + 2) // include </
|
||||
this.editor.setCursorBufferPosition(endRange.start.traverse([0, tagCharacterOffset]))
|
||||
} else {
|
||||
tagCharacterOffset = position.column - endRange.start.column
|
||||
if (tagCharacterOffset > 1) { tagCharacterOffset-- }
|
||||
tagCharacterOffset = Math.min(tagCharacterOffset, tagLength + 1) // include <
|
||||
this.editor.setCursorBufferPosition(startRange.start.traverse([0, tagCharacterOffset]))
|
||||
}
|
||||
} else {
|
||||
const previousPosition = position.traverse(ONE_CHAR_BACKWARD_TRAVERSAL)
|
||||
const startPosition = this.startMarker.getStartBufferPosition()
|
||||
const endPosition = this.endMarker.getStartBufferPosition()
|
||||
|
||||
if (position.isEqual(startPosition)) {
|
||||
this.editor.setCursorBufferPosition(endPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL))
|
||||
} else if (previousPosition.isEqual(startPosition)) {
|
||||
this.editor.setCursorBufferPosition(endPosition)
|
||||
} else if (position.isEqual(endPosition)) {
|
||||
this.editor.setCursorBufferPosition(startPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL))
|
||||
} else if (previousPosition.isEqual(endPosition)) {
|
||||
this.editor.setCursorBufferPosition(startPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gotoPrecedingStartBracket () {
|
||||
if (this.pairHighlighted) return
|
||||
|
||||
const matchPosition = this.findPrecedingStartBracket(this.editor.getCursorBufferPosition())
|
||||
if (matchPosition) {
|
||||
this.editor.setCursorBufferPosition(matchPosition)
|
||||
} else {
|
||||
let startRange, endRange
|
||||
if (this.hasSyntaxTree()) {
|
||||
({startRange, endRange} = this.findMatchingTagsWithSyntaxTree())
|
||||
} else {
|
||||
({startRange, endRange} = this.tagFinder.findStartEndTags())
|
||||
}
|
||||
|
||||
if (startRange) {
|
||||
if (startRange.compare(endRange) > 0) {
|
||||
[startRange, endRange] = [endRange, startRange]
|
||||
}
|
||||
this.editor.setCursorBufferPosition(startRange.start)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiCursorSelect() {
|
||||
this.editor.getCursorBufferPositions().forEach(position => {
|
||||
let startPosition = this.findPrecedingStartBracket(position)
|
||||
if(startPosition) {
|
||||
const startBracket = this.editor.getTextInRange(Range.fromPointWithDelta(startPosition, 0, 1))
|
||||
const endPosition = this.findMatchingEndBracket(startPosition, startBracket, this.matchManager.pairedCharacters[startBracket])
|
||||
startPosition = startPosition.traverse([0, 1])
|
||||
if (startPosition && endPosition) {
|
||||
const rangeToSelect = new Range(startPosition, endPosition)
|
||||
this.editor.addSelectionForBufferRange(rangeToSelect)
|
||||
}
|
||||
} else {
|
||||
let startRange, endRange;
|
||||
if (this.hasSyntaxTree()) {
|
||||
({startRange, endRange} = this.findMatchingTagsWithSyntaxTree())
|
||||
} else {
|
||||
({startRange, endRange} = this.tagFinder.findStartEndTags(true))
|
||||
if (startRange && startRange.compare(endRange) > 0) {
|
||||
[startRange, endRange] = [endRange, startRange]
|
||||
}
|
||||
}
|
||||
if (startRange) {
|
||||
const startPosition = startRange.end
|
||||
const endPosition = endRange.start
|
||||
const rangeToSelect = new Range(startPosition, endPosition)
|
||||
this.editor.setSelectedBufferRange(rangeToSelect)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectInsideBrackets () {
|
||||
let endPosition, endRange, startPosition, startRange
|
||||
if (this.pairHighlighted) {
|
||||
startRange = this.startMarker.getBufferRange()
|
||||
endRange = this.endMarker.getBufferRange()
|
||||
|
||||
if (this.tagHighlighted) {
|
||||
if (this.hasSyntaxTree()) {
|
||||
({startRange, endRange} = this.findMatchingTagsWithSyntaxTree())
|
||||
} else {
|
||||
({startRange, endRange} = this.tagFinder.findStartEndTags(true))
|
||||
if (startRange && startRange.compare(endRange) > 0) {
|
||||
[startRange, endRange] = [endRange, startRange]
|
||||
}
|
||||
}
|
||||
}
|
||||
startPosition = startRange.end
|
||||
endPosition = endRange.start
|
||||
|
||||
const rangeToSelect = new Range(startPosition, endPosition)
|
||||
this.editor.setSelectedBufferRange(rangeToSelect)
|
||||
} else {
|
||||
this.multiCursorSelect();
|
||||
}
|
||||
}
|
||||
|
||||
// Insert at the current cursor position a closing tag if there exists an
|
||||
// open tag that is not closed afterwards.
|
||||
closeTag () {
|
||||
const cursorPosition = this.editor.getCursorBufferPosition()
|
||||
const preFragment = this.editor.getTextInBufferRange([Point.ZERO, cursorPosition])
|
||||
const postFragment = this.editor.getTextInBufferRange([cursorPosition, Point.INFINITY])
|
||||
|
||||
const tag = this.tagFinder.closingTagForFragments(preFragment, postFragment)
|
||||
if (tag) {
|
||||
this.editor.insertText(`</${tag}>`)
|
||||
}
|
||||
}
|
||||
|
||||
isCursorOnCommentOrString () {
|
||||
return this.isScopeCommentedOrString(this.editor.getLastCursor().getScopeDescriptor().getScopesArray())
|
||||
}
|
||||
|
||||
isRangeCommentedOrString (range) {
|
||||
return this.isScopeCommentedOrString(this.editor.scopeDescriptorForBufferPosition(range.start).getScopesArray())
|
||||
}
|
||||
|
||||
isScopeCommentedOrString (scopesArray) {
|
||||
for (let scope of scopesArray.reverse()) {
|
||||
scope = scope.split('.')
|
||||
if (scope.includes('embedded') && scope.includes('source')) return false
|
||||
if (scope.includes('comment') || scope.includes('string')) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
hasSyntaxTree () {
|
||||
return this.editor.buffer.getLanguageMode().getSyntaxNodeAtPosition
|
||||
}
|
||||
}
|
299
packages/bracket-matcher/lib/bracket-matcher.js
Normal file
299
packages/bracket-matcher/lib/bracket-matcher.js
Normal file
@ -0,0 +1,299 @@
|
||||
const _ = require('underscore-plus')
|
||||
const {CompositeDisposable} = require('atom')
|
||||
const SelectorCache = require('./selector-cache')
|
||||
|
||||
module.exports =
|
||||
class BracketMatcher {
|
||||
constructor (editor, editorElement, matchManager) {
|
||||
this.insertText = this.insertText.bind(this)
|
||||
this.insertNewline = this.insertNewline.bind(this)
|
||||
this.backspace = this.backspace.bind(this)
|
||||
this.editor = editor
|
||||
this.matchManager = matchManager
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
this.bracketMarkers = []
|
||||
|
||||
this.origEditorInsertText = this.editor.insertText.bind(this.editor)
|
||||
_.adviseBefore(this.editor, 'insertText', this.insertText)
|
||||
_.adviseBefore(this.editor, 'insertNewline', this.insertNewline)
|
||||
_.adviseBefore(this.editor, 'backspace', this.backspace)
|
||||
|
||||
this.subscriptions.add(
|
||||
atom.commands.add(editorElement, 'bracket-matcher:remove-brackets-from-selection', event => {
|
||||
if (!this.removeBrackets()) event.abortKeyBinding()
|
||||
}),
|
||||
|
||||
this.editor.onDidDestroy(() => this.unsubscribe())
|
||||
)
|
||||
}
|
||||
|
||||
insertText (text, options) {
|
||||
if (!text) return true
|
||||
if ((options && options.select) || (options && options.undo === 'skip')) return true
|
||||
|
||||
let autoCompleteOpeningBracket, bracketMarker, pair
|
||||
if (this.matchManager.changeBracketsMode) {
|
||||
this.matchManager.changeBracketsMode = false
|
||||
if (this.isClosingBracket(text)) {
|
||||
text = this.matchManager.pairedCharactersInverse[text]
|
||||
}
|
||||
if (this.isOpeningBracket(text)) {
|
||||
this.editor.mutateSelectedText(selection => {
|
||||
const selectionText = selection.getText()
|
||||
if (this.isOpeningBracket(selectionText)) {
|
||||
selection.insertText(text)
|
||||
}
|
||||
if (this.isClosingBracket(selectionText)) {
|
||||
selection.insertText(this.matchManager.pairedCharacters[text])
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (this.wrapSelectionInBrackets(text)) return false
|
||||
if (this.editor.hasMultipleCursors()) return true
|
||||
|
||||
const cursorBufferPosition = this.editor.getCursorBufferPosition()
|
||||
const previousCharacters = this.editor.getTextInBufferRange([[cursorBufferPosition.row, 0], cursorBufferPosition])
|
||||
const nextCharacter = this.editor.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.traverse([0, 1])])
|
||||
const previousCharacter = previousCharacters.slice(-1)
|
||||
|
||||
const hasWordAfterCursor = /\w/.test(nextCharacter)
|
||||
const hasWordBeforeCursor = /\w/.test(previousCharacter)
|
||||
const hasQuoteBeforeCursor = this.isQuote(previousCharacter) && (previousCharacter === text[0])
|
||||
const hasEscapeCharacterBeforeCursor = endsWithEscapeCharacter(previousCharacters)
|
||||
const hasEscapeSequenceBeforeCursor = endsWithEscapeSequence(previousCharacters)
|
||||
|
||||
if (text === '#' && this.isCursorOnInterpolatedString()) {
|
||||
autoCompleteOpeningBracket = this.getScopedSetting('bracket-matcher.autocompleteBrackets') && !hasEscapeCharacterBeforeCursor
|
||||
text += '{'
|
||||
pair = '}'
|
||||
} else {
|
||||
autoCompleteOpeningBracket = (
|
||||
this.isOpeningBracket(text) &&
|
||||
!hasWordAfterCursor &&
|
||||
this.getScopedSetting('bracket-matcher.autocompleteBrackets') &&
|
||||
!(this.isQuote(text) && (hasWordBeforeCursor || hasQuoteBeforeCursor || hasEscapeSequenceBeforeCursor)) &&
|
||||
!hasEscapeCharacterBeforeCursor
|
||||
)
|
||||
pair = this.matchManager.pairedCharacters[text]
|
||||
}
|
||||
|
||||
let skipOverExistingClosingBracket = false
|
||||
if (this.isClosingBracket(text) && (nextCharacter === text) && !hasEscapeCharacterBeforeCursor) {
|
||||
bracketMarker = this.bracketMarkers.find(marker => marker.isValid() && marker.getBufferRange().end.isEqual(cursorBufferPosition))
|
||||
if (bracketMarker || this.getScopedSetting('bracket-matcher.alwaysSkipClosingPairs')) {
|
||||
skipOverExistingClosingBracket = true
|
||||
}
|
||||
}
|
||||
|
||||
if (skipOverExistingClosingBracket) {
|
||||
if (bracketMarker) bracketMarker.destroy()
|
||||
_.remove(this.bracketMarkers, bracketMarker)
|
||||
this.editor.moveRight()
|
||||
return false
|
||||
} else if (autoCompleteOpeningBracket) {
|
||||
this.editor.transact(() => {
|
||||
this.origEditorInsertText(text + pair)
|
||||
this.editor.moveLeft()
|
||||
})
|
||||
const range = [cursorBufferPosition, cursorBufferPosition.traverse([0, text.length])]
|
||||
this.bracketMarkers.push(this.editor.markBufferRange(range))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
insertNewline () {
|
||||
if (this.editor.hasMultipleCursors()) return
|
||||
if (!this.editor.getLastSelection().isEmpty()) return
|
||||
|
||||
const cursorBufferPosition = this.editor.getCursorBufferPosition()
|
||||
const previousCharacters = this.editor.getTextInBufferRange([[cursorBufferPosition.row, 0], cursorBufferPosition])
|
||||
const nextCharacter = this.editor.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.traverse([0, 1])])
|
||||
const previousCharacter = previousCharacters.slice(-1)
|
||||
const hasEscapeCharacterBeforeCursor = endsWithEscapeCharacter(previousCharacters)
|
||||
|
||||
if (
|
||||
this.matchManager.pairsWithExtraNewline[previousCharacter] === nextCharacter &&
|
||||
!hasEscapeCharacterBeforeCursor
|
||||
) {
|
||||
this.editor.transact(() => {
|
||||
this.origEditorInsertText('\n\n')
|
||||
this.editor.moveUp()
|
||||
if (this.getScopedSetting('editor.autoIndent')) {
|
||||
const cursorRow = this.editor.getCursorBufferPosition().row
|
||||
this.editor.autoIndentBufferRows(cursorRow, cursorRow + 1)
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
backspace () {
|
||||
if (this.editor.hasMultipleCursors()) return
|
||||
if (!this.editor.getLastSelection().isEmpty()) return
|
||||
|
||||
const cursorBufferPosition = this.editor.getCursorBufferPosition()
|
||||
const previousCharacters = this.editor.getTextInBufferRange([[cursorBufferPosition.row, 0], cursorBufferPosition])
|
||||
const nextCharacter = this.editor.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.traverse([0, 1])])
|
||||
const previousCharacter = previousCharacters.slice(-1)
|
||||
const hasEscapeCharacterBeforeCursor = endsWithEscapeCharacter(previousCharacters)
|
||||
|
||||
if (
|
||||
this.matchManager.pairedCharacters[previousCharacter] === nextCharacter &&
|
||||
!hasEscapeCharacterBeforeCursor &&
|
||||
this.getScopedSetting('bracket-matcher.autocompleteBrackets')
|
||||
) {
|
||||
this.editor.transact(() => {
|
||||
this.editor.moveLeft()
|
||||
this.editor.delete()
|
||||
this.editor.delete()
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
removeBrackets () {
|
||||
let bracketsRemoved = false
|
||||
this.editor.mutateSelectedText(selection => {
|
||||
let selectionEnd
|
||||
if (!this.selectionIsWrappedByMatchingBrackets(selection)) return
|
||||
|
||||
const range = selection.getBufferRange()
|
||||
const options = {reversed: selection.isReversed()}
|
||||
const selectionStart = range.start
|
||||
if (range.start.row === range.end.row) {
|
||||
selectionEnd = range.end.traverse([0, -2])
|
||||
} else {
|
||||
selectionEnd = range.end.traverse([0, -1])
|
||||
}
|
||||
|
||||
const text = selection.getText()
|
||||
selection.insertText(text.substring(1, text.length - 1))
|
||||
selection.setBufferRange([selectionStart, selectionEnd], options)
|
||||
bracketsRemoved = true
|
||||
})
|
||||
return bracketsRemoved
|
||||
}
|
||||
|
||||
wrapSelectionInBrackets (bracket) {
|
||||
let pair
|
||||
if (bracket === '#') {
|
||||
if (!this.isCursorOnInterpolatedString()) return false
|
||||
bracket = '#{'
|
||||
pair = '}'
|
||||
} else {
|
||||
if (!this.isOpeningBracket(bracket)) return false
|
||||
pair = this.matchManager.pairedCharacters[bracket]
|
||||
}
|
||||
|
||||
if (!this.editor.selections.some(s => !s.isEmpty())) return false
|
||||
if (!this.getScopedSetting('bracket-matcher.wrapSelectionsInBrackets')) return false
|
||||
|
||||
let selectionWrapped = false
|
||||
this.editor.mutateSelectedText(selection => {
|
||||
let selectionEnd
|
||||
if (selection.isEmpty()) return
|
||||
|
||||
// Don't wrap in #{} if the selection spans more than one line
|
||||
if ((bracket === '#{') && !selection.getBufferRange().isSingleLine()) return
|
||||
|
||||
selectionWrapped = true
|
||||
const range = selection.getBufferRange()
|
||||
const options = {reversed: selection.isReversed()}
|
||||
selection.insertText(`${bracket}${selection.getText()}${pair}`)
|
||||
const selectionStart = range.start.traverse([0, bracket.length])
|
||||
if (range.start.row === range.end.row) {
|
||||
selectionEnd = range.end.traverse([0, bracket.length])
|
||||
} else {
|
||||
selectionEnd = range.end
|
||||
}
|
||||
selection.setBufferRange([selectionStart, selectionEnd], options)
|
||||
})
|
||||
|
||||
return selectionWrapped
|
||||
}
|
||||
|
||||
isQuote (string) {
|
||||
return /['"`]/.test(string)
|
||||
}
|
||||
|
||||
isCursorOnInterpolatedString () {
|
||||
const cursor = this.editor.getLastCursor()
|
||||
const languageMode = this.editor.getBuffer().getLanguageMode()
|
||||
if (languageMode.getSyntaxNodeAtPosition) {
|
||||
const node = languageMode.getSyntaxNodeAtPosition(
|
||||
cursor.getBufferPosition(),
|
||||
(node, grammar) => grammar.scopeName === 'source.ruby' && /string|symbol/.test(node.type)
|
||||
)
|
||||
if (node) {
|
||||
const {firstChild} = node
|
||||
if (firstChild) {
|
||||
return ['"', ':"', '%('].includes(firstChild.text)
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
if (this.interpolatedStringSelector == null) {
|
||||
const segments = [
|
||||
'*.*.*.interpolated.ruby',
|
||||
'string.interpolated.ruby',
|
||||
'string.regexp.interpolated.ruby',
|
||||
'string.quoted.double.coffee',
|
||||
'string.unquoted.heredoc.ruby',
|
||||
'string.quoted.double.livescript',
|
||||
'string.quoted.double.heredoc.livescript',
|
||||
'string.quoted.double.elixir',
|
||||
'string.quoted.double.heredoc.elixir',
|
||||
'comment.documentation.heredoc.elixir'
|
||||
]
|
||||
this.interpolatedStringSelector = SelectorCache.get(segments.join(' | '))
|
||||
}
|
||||
return this.interpolatedStringSelector.matches(this.editor.getLastCursor().getScopeDescriptor().getScopesArray())
|
||||
}
|
||||
}
|
||||
|
||||
isOpeningBracket (string) {
|
||||
return this.matchManager.pairedCharacters.hasOwnProperty(string)
|
||||
}
|
||||
|
||||
isClosingBracket (string) {
|
||||
return this.matchManager.pairedCharactersInverse.hasOwnProperty(string)
|
||||
}
|
||||
|
||||
selectionIsWrappedByMatchingBrackets (selection) {
|
||||
if (selection.isEmpty()) return false
|
||||
const selectedText = selection.getText()
|
||||
const firstCharacter = selectedText[0]
|
||||
const lastCharacter = selectedText[selectedText.length - 1]
|
||||
return this.matchManager.pairedCharacters[firstCharacter] === lastCharacter
|
||||
}
|
||||
|
||||
unsubscribe () {
|
||||
this.subscriptions.dispose()
|
||||
}
|
||||
|
||||
getScopedSetting (key) {
|
||||
return atom.config.get(key, {scope: this.editor.getRootScopeDescriptor()})
|
||||
}
|
||||
}
|
||||
|
||||
const BACKSLASHES_REGEX = /(\\+)$/
|
||||
const ESCAPE_SEQUENCE_REGEX = /(\\+)[^\\]$/
|
||||
|
||||
// odd number of backslashes
|
||||
function endsWithEscapeCharacter (string) {
|
||||
const backslashesMatch = string.match(BACKSLASHES_REGEX)
|
||||
return backslashesMatch && backslashesMatch[1].length % 2 === 1
|
||||
}
|
||||
|
||||
// even number of backslashes or odd number of backslashes followed by another character
|
||||
function endsWithEscapeSequence (string) {
|
||||
const backslashesMatch = string.match(BACKSLASHES_REGEX)
|
||||
const escapeSequenceMatch = string.match(ESCAPE_SEQUENCE_REGEX)
|
||||
return (
|
||||
(escapeSequenceMatch && escapeSequenceMatch[1].length % 2 === 1) ||
|
||||
(backslashesMatch && backslashesMatch[1].length % 2 === 0)
|
||||
)
|
||||
}
|
20
packages/bracket-matcher/lib/main.js
Normal file
20
packages/bracket-matcher/lib/main.js
Normal file
@ -0,0 +1,20 @@
|
||||
const MatchManager = require('./match-manager')
|
||||
const BracketMatcherView = require('./bracket-matcher-view')
|
||||
const BracketMatcher = require('./bracket-matcher')
|
||||
|
||||
module.exports = {
|
||||
activate () {
|
||||
const watchedEditors = new WeakSet()
|
||||
|
||||
atom.workspace.observeTextEditors(editor => {
|
||||
if (watchedEditors.has(editor)) return
|
||||
|
||||
const editorElement = atom.views.getView(editor)
|
||||
const matchManager = new MatchManager(editor, editorElement)
|
||||
new BracketMatcherView(editor, editorElement, matchManager)
|
||||
new BracketMatcher(editor, editorElement, matchManager)
|
||||
watchedEditors.add(editor)
|
||||
editor.onDidDestroy(() => watchedEditors.delete(editor))
|
||||
})
|
||||
}
|
||||
}
|
60
packages/bracket-matcher/lib/match-manager.js
Normal file
60
packages/bracket-matcher/lib/match-manager.js
Normal file
@ -0,0 +1,60 @@
|
||||
const _ = require('underscore-plus')
|
||||
const {CompositeDisposable} = require('atom')
|
||||
|
||||
module.exports =
|
||||
class MatchManager {
|
||||
appendPair (pairList, [itemLeft, itemRight]) {
|
||||
const newPair = {}
|
||||
newPair[itemLeft] = itemRight
|
||||
pairList = _.extend(pairList, newPair)
|
||||
}
|
||||
|
||||
processAutoPairs (autocompletePairs, pairedList, dataFun) {
|
||||
if (autocompletePairs.length) {
|
||||
for (let autocompletePair of autocompletePairs) {
|
||||
const pairArray = autocompletePair.split('')
|
||||
this.appendPair(pairedList, dataFun(pairArray))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateConfig () {
|
||||
this.pairedCharacters = {}
|
||||
this.pairedCharactersInverse = {}
|
||||
this.pairRegexes = {}
|
||||
this.pairsWithExtraNewline = {}
|
||||
this.processAutoPairs(this.getScopedSetting('bracket-matcher.autocompleteCharacters'), this.pairedCharacters, x => [x[0], x[1]])
|
||||
this.processAutoPairs(this.getScopedSetting('bracket-matcher.autocompleteCharacters'), this.pairedCharactersInverse, x => [x[1], x[0]])
|
||||
this.processAutoPairs(this.getScopedSetting('bracket-matcher.pairsWithExtraNewline'), this.pairsWithExtraNewline, x => [x[0], x[1]])
|
||||
for (let startPair in this.pairedCharacters) {
|
||||
const endPair = this.pairedCharacters[startPair]
|
||||
this.pairRegexes[startPair] = new RegExp(`[${_.escapeRegExp(startPair + endPair)}]`, 'g')
|
||||
}
|
||||
}
|
||||
|
||||
getScopedSetting (key) {
|
||||
return atom.config.get(key, {scope: this.editor.getRootScopeDescriptor()})
|
||||
}
|
||||
|
||||
constructor (editor, editorElement) {
|
||||
this.destroy = this.destroy.bind(this)
|
||||
this.editor = editor
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
|
||||
this.updateConfig()
|
||||
|
||||
// Subscribe to config changes
|
||||
const scope = this.editor.getRootScopeDescriptor()
|
||||
this.subscriptions.add(
|
||||
atom.config.observe('bracket-matcher.autocompleteCharacters', {scope}, () => this.updateConfig()),
|
||||
atom.config.observe('bracket-matcher.pairsWithExtraNewline', {scope}, () => this.updateConfig()),
|
||||
this.editor.onDidDestroy(this.destroy)
|
||||
)
|
||||
|
||||
this.changeBracketsMode = false
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.subscriptions.dispose()
|
||||
}
|
||||
}
|
11
packages/bracket-matcher/lib/selector-cache.js
Normal file
11
packages/bracket-matcher/lib/selector-cache.js
Normal file
@ -0,0 +1,11 @@
|
||||
const {ScopeSelector} = require('second-mate')
|
||||
const cache = {}
|
||||
|
||||
exports.get = function (selector) {
|
||||
let scopeSelector = cache[selector]
|
||||
if (!scopeSelector) {
|
||||
scopeSelector = new ScopeSelector(selector)
|
||||
cache[selector] = scopeSelector
|
||||
}
|
||||
return scopeSelector
|
||||
}
|
18
packages/bracket-matcher/lib/self-closing-tags.json
Normal file
18
packages/bracket-matcher/lib/self-closing-tags.json
Normal file
@ -0,0 +1,18 @@
|
||||
[
|
||||
"area",
|
||||
"base",
|
||||
"br",
|
||||
"col",
|
||||
"command",
|
||||
"embed",
|
||||
"hr",
|
||||
"img",
|
||||
"input",
|
||||
"keygen",
|
||||
"link",
|
||||
"meta",
|
||||
"param",
|
||||
"source",
|
||||
"track",
|
||||
"wbr"
|
||||
]
|
258
packages/bracket-matcher/lib/tag-finder.js
Normal file
258
packages/bracket-matcher/lib/tag-finder.js
Normal file
@ -0,0 +1,258 @@
|
||||
const {Range} = require('atom')
|
||||
const _ = require('underscore-plus')
|
||||
const SelfClosingTags = require('./self-closing-tags')
|
||||
|
||||
const TAG_SELECTOR_REGEX = /(\b|\.)(meta\.tag|punctuation\.definition\.tag)/
|
||||
const COMMENT_SELECTOR_REGEX = /(\b|\.)comment/
|
||||
|
||||
// Creates a regex to match opening tag with match[1] and closing tags with match[2]
|
||||
//
|
||||
// * tagNameRegexStr - a regex string describing how to match the tagname.
|
||||
// Should not contain capturing match groups.
|
||||
//
|
||||
// Returns a {RegExp}.
|
||||
const generateTagStartOrEndRegex = function (tagNameRegexStr) {
|
||||
const notSelfClosingTagEnd = "(?:[^>\\/\"']|\"[^\"]*\"|'[^']*')*>"
|
||||
return new RegExp(`<(${tagNameRegexStr})${notSelfClosingTagEnd}|<\\/(${tagNameRegexStr})>`)
|
||||
}
|
||||
|
||||
const tagStartOrEndRegex = generateTagStartOrEndRegex('\\w[-\\w]*(?:(?:\\:|\\.)\\w[-\\w]*)*')
|
||||
|
||||
// Helper to find the matching start/end tag for the start/end tag under the
|
||||
// cursor in XML, HTML, etc. editors.
|
||||
module.exports =
|
||||
class TagFinder {
|
||||
constructor (editor) {
|
||||
// 1. Tag prefix
|
||||
// 2. Closing tag (optional)
|
||||
// 3. Tag name
|
||||
// 4. Attributes (ids, classes, etc. - optional)
|
||||
// 5. Tag suffix
|
||||
// 6. Self-closing tag (optional)
|
||||
this.editor = editor
|
||||
this.tagPattern = /(<(\/)?)(.+?)(\s+.*?)?((\/)?>|$)/
|
||||
this.wordRegex = /.*?(>|$)/
|
||||
}
|
||||
|
||||
patternForTagName (tagName) {
|
||||
tagName = _.escapeRegExp(tagName)
|
||||
// 1. Start tag
|
||||
// 2. Tag name
|
||||
// 3. Attributes (optional)
|
||||
// 4. Tag suffix
|
||||
// 5. Self-closing tag (optional)
|
||||
// 6. End tag
|
||||
return new RegExp(`(<(${tagName})(\\s+[^>]*?)?((/)?>))|(</${tagName}[^>]*>)`, 'gi')
|
||||
}
|
||||
|
||||
isRangeCommented (range) {
|
||||
return this.scopesForPositionMatchRegex(range.start, COMMENT_SELECTOR_REGEX)
|
||||
}
|
||||
|
||||
isCursorOnTag () {
|
||||
return this.scopesForPositionMatchRegex(this.editor.getCursorBufferPosition(), TAG_SELECTOR_REGEX)
|
||||
}
|
||||
|
||||
scopesForPositionMatchRegex (position, regex) {
|
||||
const {tokenizedBuffer, buffer} = this.editor
|
||||
const {grammar} = tokenizedBuffer
|
||||
let column = 0
|
||||
const line = tokenizedBuffer.tokenizedLineForRow(position.row)
|
||||
if (line == null) { return false }
|
||||
const lineLength = buffer.lineLengthForRow(position.row)
|
||||
const scopeIds = line.openScopes.slice()
|
||||
for (let i = 0; i < line.tags.length; i++) {
|
||||
const tag = line.tags[i]
|
||||
if (tag >= 0) {
|
||||
const nextColumn = column + tag
|
||||
if ((nextColumn > position.column) || (nextColumn === lineLength)) { break }
|
||||
column = nextColumn
|
||||
} else if ((tag & 1) === 1) {
|
||||
scopeIds.push(tag)
|
||||
} else {
|
||||
scopeIds.pop()
|
||||
}
|
||||
}
|
||||
|
||||
return scopeIds.some(scopeId => regex.test(grammar.scopeForId(scopeId)))
|
||||
}
|
||||
|
||||
findStartTag (tagName, endPosition, fullRange = false) {
|
||||
const scanRange = new Range([0, 0], endPosition)
|
||||
const pattern = this.patternForTagName(tagName)
|
||||
let startRange = null
|
||||
let unpairedCount = 0
|
||||
this.editor.backwardsScanInBufferRange(pattern, scanRange, ({match, range, stop}) => {
|
||||
if (this.isRangeCommented(range)) return
|
||||
|
||||
const [entireMatch, isStartTag, tagName, attributes, suffix, isSelfClosingTag, isEndTag] = match
|
||||
|
||||
if (isSelfClosingTag) return
|
||||
|
||||
if (isStartTag) {
|
||||
unpairedCount--
|
||||
if (unpairedCount < 0) {
|
||||
stop()
|
||||
startRange = range
|
||||
if (!fullRange) {
|
||||
// Move the start past the initial <
|
||||
startRange.start = startRange.start.translate([0, 1])
|
||||
|
||||
// End right after the tag name
|
||||
startRange.end = startRange.start.translate([0, tagName.length])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unpairedCount++
|
||||
}
|
||||
})
|
||||
|
||||
return startRange
|
||||
}
|
||||
|
||||
findEndTag (tagName, startPosition, fullRange = false) {
|
||||
const scanRange = new Range(startPosition, this.editor.buffer.getEndPosition())
|
||||
const pattern = this.patternForTagName(tagName)
|
||||
let endRange = null
|
||||
let unpairedCount = 0
|
||||
this.editor.scanInBufferRange(pattern, scanRange, ({match, range, stop}) => {
|
||||
if (this.isRangeCommented(range)) return
|
||||
|
||||
const [entireMatch, isStartTag, tagName, attributes, suffix, isSelfClosingTag, isEndTag] = match
|
||||
|
||||
if (isSelfClosingTag) return
|
||||
|
||||
if (isStartTag) {
|
||||
unpairedCount++
|
||||
} else {
|
||||
unpairedCount--
|
||||
if (unpairedCount < 0) {
|
||||
stop()
|
||||
endRange = range
|
||||
if (!fullRange) {
|
||||
// Subtract </ and > from range
|
||||
endRange = range.translate([0, 2], [0, -1])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return endRange
|
||||
}
|
||||
|
||||
findStartEndTags (fullRange = false) {
|
||||
let ranges = {}
|
||||
const endPosition = this.editor.getLastCursor().getCurrentWordBufferRange({wordRegex: this.wordRegex}).end
|
||||
this.editor.backwardsScanInBufferRange(this.tagPattern, [[0, 0], endPosition], ({match, range, stop}) => {
|
||||
stop()
|
||||
|
||||
const [entireMatch, prefix, isClosingTag, tagName, attributes, suffix, isSelfClosingTag] = Array.from(match)
|
||||
|
||||
let startRange = range
|
||||
if (!fullRange) {
|
||||
if (range.start.row === range.end.row) {
|
||||
// Move the start past the initial <
|
||||
startRange.start = startRange.start.translate([0, prefix.length])
|
||||
// End right after the tag name
|
||||
startRange.end = startRange.start.translate([0, tagName.length])
|
||||
} else {
|
||||
startRange = Range.fromObject([range.start.translate([0, prefix.length]), [range.start.row, Infinity]])
|
||||
}
|
||||
}
|
||||
|
||||
let endRange
|
||||
if (isSelfClosingTag) {
|
||||
endRange = startRange
|
||||
} else if (isClosingTag) {
|
||||
endRange = this.findStartTag(tagName, startRange.start, fullRange)
|
||||
} else {
|
||||
endRange = this.findEndTag(tagName, startRange.end, fullRange)
|
||||
}
|
||||
|
||||
if (startRange && endRange) ranges = {startRange, endRange}
|
||||
})
|
||||
|
||||
return ranges
|
||||
}
|
||||
|
||||
findMatchingTags () {
|
||||
return (this.isCursorOnTag() && this.findStartEndTags()) || {}
|
||||
}
|
||||
|
||||
// Parses a fragment of html returning the stack (i.e., an array) of open tags
|
||||
//
|
||||
// fragment - the fragment of html to be analysed
|
||||
// stack - an array to be populated (can be non-empty)
|
||||
// matchExpr - a RegExp describing how to match opening/closing tags
|
||||
// the opening/closing descriptions must be captured subexpressions
|
||||
// so that the code can refer to match[1] to check if an opening
|
||||
// tag has been found, and to match[2] to check if a closing tag
|
||||
// has been found
|
||||
// cond - a condition to be checked at each iteration. If the function
|
||||
// returns false the processing is immediately interrupted. When
|
||||
// called the current stack is provided to the function.
|
||||
//
|
||||
// Returns an array of strings. Each string is a tag that is still to be closed
|
||||
// (the most recent non closed tag is at the end of the array).
|
||||
parseFragment (fragment, stack, matchExpr, cond) {
|
||||
let match = fragment.match(matchExpr)
|
||||
while (match && cond(stack)) {
|
||||
if (SelfClosingTags.indexOf(match[1]) === -1) {
|
||||
const topElem = stack[stack.length - 1]
|
||||
|
||||
if (match[2] && (topElem === match[2])) {
|
||||
stack.pop()
|
||||
} else if (match[1]) {
|
||||
stack.push(match[1])
|
||||
}
|
||||
}
|
||||
|
||||
fragment = fragment.substr(match.index + match[0].length)
|
||||
match = fragment.match(matchExpr)
|
||||
}
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
// Parses the given fragment of html code returning the last unclosed tag.
|
||||
//
|
||||
// fragment - a string containing a fragment of html code.
|
||||
//
|
||||
// Returns an array of strings. Each string is a tag that is still to be closed
|
||||
// (the most recent non closed tag is at the end of the array).
|
||||
tagsNotClosedInFragment (fragment) {
|
||||
return this.parseFragment(fragment, [], tagStartOrEndRegex, () => true)
|
||||
}
|
||||
|
||||
// Parses the given fragment of html code and returns true if the given tag
|
||||
// has a matching closing tag in it. If tag is reopened and reclosed in the
|
||||
// given fragment then the end point of that pair does not count as a matching
|
||||
// closing tag.
|
||||
tagDoesNotCloseInFragment (tags, fragment) {
|
||||
if (tags.length === 0) { return false }
|
||||
|
||||
let stack = tags
|
||||
const stackLength = stack.length
|
||||
const tag = tags[tags.length - 1]
|
||||
const escapedTag = _.escapeRegExp(tag)
|
||||
stack = this.parseFragment(fragment, stack, generateTagStartOrEndRegex(escapedTag), s =>
|
||||
s.length >= stackLength || s[s.length - 1] === tag
|
||||
)
|
||||
|
||||
return (stack.length > 0) && (stack[stack.length - 1] === tag)
|
||||
}
|
||||
|
||||
// Parses preFragment and postFragment returning the last open tag in
|
||||
// preFragment that is not closed in postFragment.
|
||||
//
|
||||
// Returns a tag name or null if it can't find it.
|
||||
closingTagForFragments (preFragment, postFragment) {
|
||||
const tags = this.tagsNotClosedInFragment(preFragment)
|
||||
const tag = tags[tags.length - 1]
|
||||
if (this.tagDoesNotCloseInFragment(tags, postFragment)) {
|
||||
return tag
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
22
packages/bracket-matcher/menus/bracket-matcher.cson
Normal file
22
packages/bracket-matcher/menus/bracket-matcher.cson
Normal file
@ -0,0 +1,22 @@
|
||||
'menu': [
|
||||
{
|
||||
'label': 'Packages'
|
||||
'submenu': [
|
||||
'label': 'Bracket Matcher'
|
||||
'submenu': [
|
||||
{ 'label': 'Go To Matching Bracket', 'command': 'bracket-matcher:go-to-matching-bracket' }
|
||||
{ 'label': 'Select Inside Brackets', 'command': 'bracket-matcher:select-inside-brackets' }
|
||||
{ 'label': 'Remove Brackets From Selection', 'command': 'bracket-matcher:remove-brackets-from-selection' }
|
||||
{ 'label': 'Close Current Tag', 'command': 'bracket-matcher:close-tag' }
|
||||
{ 'label': 'Remove Matching Brackets', 'command': 'bracket-matcher:remove-matching-brackets' }
|
||||
{ 'label': 'Select Matching Brackets', 'command': 'bracket-matcher:select-matching-brackets' }
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
'label': 'Selection'
|
||||
'submenu': [
|
||||
{ 'label': 'Select Inside Brackets', 'command': 'bracket-matcher:select-inside-brackets' }
|
||||
]
|
||||
}
|
||||
]
|
67
packages/bracket-matcher/package.json
Normal file
67
packages/bracket-matcher/package.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "bracket-matcher",
|
||||
"version": "0.92.0",
|
||||
"main": "./lib/main",
|
||||
"description": "Highlight the matching bracket for the `(){}[]` character under the cursor. Move the cursor to the matching bracket with `ctrl-m`.",
|
||||
"repository": "https://github.com/pulsar-edit/bracket-matcher",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"atom": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"underscore-plus": "1.x"
|
||||
},
|
||||
"configSchema": {
|
||||
"autocompleteCharacters": {
|
||||
"description": "Autocompleted characters treated as matching pairs, such as `()`, and `{}`.",
|
||||
"type": "array",
|
||||
"default": [
|
||||
"()",
|
||||
"[]",
|
||||
"{}",
|
||||
"\"\"",
|
||||
"''",
|
||||
"``",
|
||||
"“”",
|
||||
"‘’",
|
||||
"«»",
|
||||
"‹›"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"pairsWithExtraNewline": {
|
||||
"description": "Automatically add a newline between the pair when enter is pressed.",
|
||||
"type": "array",
|
||||
"default": [
|
||||
"()",
|
||||
"[]",
|
||||
"{}"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"autocompleteBrackets": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Autocomplete bracket and quote characters, such as `(` and `)`, and `\"`."
|
||||
},
|
||||
"wrapSelectionsInBrackets": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Wrap selected text in brackets or quotes when the editor contains selections and the opening bracket or quote is typed."
|
||||
},
|
||||
"highlightMatchingLineNumber": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Highlight the line number of the matching bracket."
|
||||
},
|
||||
"alwaysSkipClosingPairs": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Always skip closing pairs in front of the cursor."
|
||||
}
|
||||
}
|
||||
}
|
1913
packages/bracket-matcher/spec/bracket-matcher-spec.js
Normal file
1913
packages/bracket-matcher/spec/bracket-matcher-spec.js
Normal file
File diff suppressed because it is too large
Load Diff
142
packages/bracket-matcher/spec/close-tag-spec.js
Normal file
142
packages/bracket-matcher/spec/close-tag-spec.js
Normal file
@ -0,0 +1,142 @@
|
||||
const TagFinder = require('../lib/tag-finder')
|
||||
const tagFinder = new TagFinder()
|
||||
|
||||
describe('closeTag', () => {
|
||||
describe('TagFinder::parseFragment', () => {
|
||||
let fragment = ''
|
||||
|
||||
beforeEach(() => fragment = '<html><head><body></body>')
|
||||
|
||||
it('returns the last not closed elem in fragment, matching a given pattern', () => {
|
||||
const stack = tagFinder.parseFragment(fragment, [], /<(\w+)|<\/(\w*)/, () => true)
|
||||
expect(stack[stack.length - 1]).toBe('head')
|
||||
})
|
||||
|
||||
it('stops when cond become true', () => {
|
||||
const stack = tagFinder.parseFragment(fragment, [], /<(\w+)|<\/(\w*)/, () => false)
|
||||
expect(stack.length).toBe(0)
|
||||
})
|
||||
|
||||
it('uses the given match expression to match tags', () => {
|
||||
const stack = tagFinder.parseFragment(fragment, [], /<(body)|(notag)/, () => true)
|
||||
expect(stack[stack.length - 1]).toBe('body')
|
||||
})
|
||||
})
|
||||
|
||||
describe('TagFinder::tagsNotClosedInFragment', () => {
|
||||
it('returns the outermost tag not closed in an HTML fragment', () => {
|
||||
const fragment = '<html><head></head><body><h1><p></p>'
|
||||
const tags = tagFinder.tagsNotClosedInFragment(fragment)
|
||||
expect(tags).toEqual(['html', 'body', 'h1'])
|
||||
})
|
||||
|
||||
it('is not confused by tag attributes', () => {
|
||||
const fragment = '<html><head></head><body class="c"><h1 class="p"><p></p>'
|
||||
const tags = tagFinder.tagsNotClosedInFragment(fragment)
|
||||
expect(tags).toEqual(['html', 'body', 'h1'])
|
||||
})
|
||||
|
||||
it('is not confused by namespace prefixes', () => {
|
||||
const fragment = '<xhtml:html><xhtml:body><xhtml:h1>'
|
||||
const tags = tagFinder.tagsNotClosedInFragment(fragment)
|
||||
expect(tags).toEqual(['xhtml:html', 'xhtml:body', 'xhtml:h1'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('TagFinder::tagDoesNotCloseInFragment', () => {
|
||||
it('returns true if the given tag is not closed in the given fragment', () => {
|
||||
const fragment = '</other1></other2></html>'
|
||||
expect(tagFinder.tagDoesNotCloseInFragment('body', fragment)).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false if the given tag is closed in the given fragment', () => {
|
||||
const fragment = '</other1></body></html>'
|
||||
expect(tagFinder.tagDoesNotCloseInFragment(['body'], fragment)).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true even if the given tag is re-opened and re-closed', () => {
|
||||
const fragment = '<other> </other><body></body><html>'
|
||||
expect(tagFinder.tagDoesNotCloseInFragment(['body'], fragment)).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false even if the given tag is re-opened and re-closed before closing', () => {
|
||||
const fragment = '<other> </other><body></body></body><html>'
|
||||
expect(tagFinder.tagDoesNotCloseInFragment(['body'], fragment)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('TagFinder::closingTagForFragments', () => {
|
||||
it('returns the last opened in preFragment tag that is not closed in postFragment', () => {
|
||||
const preFragment = '<html><head></head><body><h1></h1><p>'
|
||||
const postFragment = '</body></html>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('p')
|
||||
})
|
||||
|
||||
it('correctly handles empty postFragment', () => {
|
||||
const preFragment = '<html><head></head><body><h1></h1><p>'
|
||||
const postFragment = ''
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('p')
|
||||
})
|
||||
|
||||
it('correctly handles malformed tags', () => {
|
||||
const preFragment = '<html><head></head></htm'
|
||||
const postFragment = ''
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('html')
|
||||
})
|
||||
|
||||
it('returns null if there is no open tag to be closed', () => {
|
||||
const preFragment = '<html><head></head><body><h1></h1><p>'
|
||||
const postFragment = '</p></body></html>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe(null)
|
||||
})
|
||||
|
||||
it('correctly closes tags containing hyphens', () => {
|
||||
const preFragment = '<html><head></head><body><h1></h1><my-element>'
|
||||
const postFragment = '</body></html>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('my-element')
|
||||
})
|
||||
|
||||
it('correctly closes tags containing attributes', () => {
|
||||
const preFragment = '<html><head></head><body class="foo bar"><div>'
|
||||
const postFragment = '</body></html>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('div')
|
||||
})
|
||||
|
||||
it('correctly closes tags containing an XML namespace', () => {
|
||||
const preFragment = '<html><head></head><body><custom:tag>'
|
||||
const postFragment = '</body></html>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('custom:tag')
|
||||
})
|
||||
|
||||
it('correctly closes tags containing multiple XML namespaces', () => {
|
||||
// This is not exactly valid syntax but it can't hurt to support it
|
||||
const preFragment = '<html><head></head><body><custom:custom2:tag>'
|
||||
const postFragment = '</body></html>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('custom:custom2:tag')
|
||||
})
|
||||
|
||||
it('correctly closes tags in the present of JSX tags containing member accesses', () => {
|
||||
const preFragment = '<Foo><Bar.Baz></Bar.Baz>'
|
||||
const postFragment = ''
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('Foo')
|
||||
})
|
||||
|
||||
it('correctly closes JSX tags containing member accesses', () => {
|
||||
const preFragment = '<Foo.Bar><div></div>'
|
||||
const postFragment = ''
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('Foo.Bar')
|
||||
})
|
||||
|
||||
it('correctly closes JSX tags containing deep member accesses', () => {
|
||||
const preFragment = '<Foo.Bar.Baz><div></div>'
|
||||
const postFragment = ''
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('Foo.Bar.Baz')
|
||||
})
|
||||
|
||||
it('correctly closes tags when there are other tags with the same prefix', () => {
|
||||
const preFragment = '<thead><th>'
|
||||
const postFragment = '</thead>'
|
||||
expect(tagFinder.closingTagForFragments(preFragment, postFragment)).toBe('th')
|
||||
})
|
||||
})
|
||||
})
|
6
packages/bracket-matcher/spec/fixtures/multiplecursor.md
vendored
Normal file
6
packages/bracket-matcher/spec/fixtures/multiplecursor.md
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[link-1](http://example.com/)
|
||||
[another-link-2](http://example.com/)
|
||||
[yet-another-link-3](http://example.com/)
|
||||
[final-link-4](http://example.com/)
|
||||
(different-type)
|
||||
not anywhere
|
15
packages/bracket-matcher/spec/fixtures/sample.html
vendored
Normal file
15
packages/bracket-matcher/spec/fixtures/sample.html
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<body>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<p><a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
13
packages/bracket-matcher/spec/fixtures/sample.js
vendored
Normal file
13
packages/bracket-matcher/spec/fixtures/sample.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
var quicksort = function () {
|
||||
var sort = function(items) {
|
||||
if (items.length <= 1) return items;
|
||||
var pivot = items.shift(), current, left = [], right = [];
|
||||
while(items.length > 0) {
|
||||
current = items.shift();
|
||||
current < pivot ? left.push(current) : right.push(current);
|
||||
}
|
||||
return sort(left).concat(pivot).concat(sort(right));
|
||||
};
|
||||
|
||||
return sort(Array.apply(this, arguments));
|
||||
};
|
17
packages/bracket-matcher/spec/fixtures/sample.xml
vendored
Normal file
17
packages/bracket-matcher/spec/fixtures/sample.xml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<body id="bod">
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
hello
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
world
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
@import "syntax-variables";
|
||||
|
||||
.bracket-matcher .region {
|
||||
border-bottom: 1px dotted lime;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.line-number.bracket-matcher.bracket-matcher {
|
||||
color: @syntax-gutter-text-color-selected;
|
||||
background-color: @syntax-gutter-background-color-selected;
|
||||
}
|
@ -295,7 +295,7 @@ describe "Clojure grammar", ->
|
||||
#!/usr/bin/env boot
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
\x20#!/usr/sbin/boot
|
||||
@ -306,7 +306,7 @@ describe "Clojure grammar", ->
|
||||
#!\t/usr/bin/env --boot=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -325,7 +325,7 @@ describe "Clojure grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : ClojureScript ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*clojure-*- */
|
||||
@ -343,7 +343,7 @@ describe "Clojure grammar", ->
|
||||
// -*-font:mode;mode:clojure--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -370,7 +370,7 @@ describe "Clojure grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=clojure ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=clojure:
|
||||
@ -388,4 +388,4 @@ describe "Clojure grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=clojure ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -29,7 +29,7 @@ describe "CoffeeScript (Literate) grammar", ->
|
||||
#!/usr/local/bin/env coffee --literate -w
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
#!/usr/local/bin/coffee --no-head -literate -w
|
||||
@ -37,7 +37,7 @@ describe "CoffeeScript (Literate) grammar", ->
|
||||
#!/usr/local/bin/env coffee --illiterate -w=l
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -56,7 +56,7 @@ describe "CoffeeScript (Literate) grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : LiTcOFFEe ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*litcoffee-*- */
|
||||
@ -74,7 +74,7 @@ describe "CoffeeScript (Literate) grammar", ->
|
||||
// -*-font:mode;mode:litcoffee--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -101,7 +101,7 @@ describe "CoffeeScript (Literate) grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=litcoffee ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=litcoffee:
|
||||
@ -119,4 +119,4 @@ describe "CoffeeScript (Literate) grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=litcoffee ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -1393,7 +1393,7 @@ describe "CoffeeScript grammar", ->
|
||||
#!/usr/bin/env coffee
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
\x20#!/usr/sbin/coffee
|
||||
@ -1404,7 +1404,7 @@ describe "CoffeeScript grammar", ->
|
||||
#!\t/usr/bin/env --coffee=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -1423,7 +1423,7 @@ describe "CoffeeScript grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : Coffee ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*coffee-*- */
|
||||
@ -1441,7 +1441,7 @@ describe "CoffeeScript grammar", ->
|
||||
// -*-font:mode;mode:coffee--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -1468,7 +1468,7 @@ describe "CoffeeScript grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=cOFFEe ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=coffee:
|
||||
@ -1486,4 +1486,4 @@ describe "CoffeeScript grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=coffee ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -3508,7 +3508,7 @@ describe 'CSS grammar', ->
|
||||
"-*- font:x;foo : bar ; mode : cSS ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*css-*- */
|
||||
@ -3526,7 +3526,7 @@ describe 'CSS grammar', ->
|
||||
// -*-font:mode;mode:css--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -3553,7 +3553,7 @@ describe 'CSS grammar', ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=css ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=css:
|
||||
@ -3571,7 +3571,7 @@ describe 'CSS grammar', ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=CSS ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
describe "Missing supported properties regressions", ->
|
||||
it "recognises place-items property as supported", ->
|
||||
|
@ -18,45 +18,45 @@ describe 'Go settings', ->
|
||||
it 'matches lines correctly using the increaseIndentPattern', ->
|
||||
increaseIndentRegex = languageMode.increaseIndentRegexForScopeDescriptor(['source.go'])
|
||||
|
||||
expect(increaseIndentRegex.testSync(' case true:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' default:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('func something() {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' if true {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' else {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' switch {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' switch true {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' select {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' select true {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' for v := range val {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' for i := 0; i < 10; i++ {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' for i := 0; i < 10; i++ {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' type something struct {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' fmt.Printf("some%s",')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' aSlice := []string{}{')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' case true:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' default:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('func something() {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' if true {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' else {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' switch {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' switch true {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' select {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' select true {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' for v := range val {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' for i := 0; i < 10; i++ {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' for i := 0; i < 10; i++ {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' type something struct {')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' fmt.Printf("some%s",')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' aSlice := []string{}{')).toBeTruthy()
|
||||
|
||||
it 'matches lines correctly using the decreaseIndentPattern', ->
|
||||
decreaseIndentRegex = languageMode.decreaseIndentRegexForScopeDescriptor(['source.go'])
|
||||
|
||||
expect(decreaseIndentRegex.testSync(' case true:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' default:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' }')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' },')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' )')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' ),')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' case true:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' default:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' }')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' },')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' )')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' ),')).toBeTruthy()
|
||||
|
||||
it 'matches lines correctly using the decreaseNextIndentPattern', ->
|
||||
decreaseNextIndentRegex = languageMode.decreaseNextIndentRegexForScopeDescriptor(['source.go'])
|
||||
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println("something"))')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println("something")),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println("something"), "x"),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println(fmt.Sprint("something"))),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println(fmt.Sprint("something"), "x")),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println("something"))')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println("something")),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println("something"), "x"),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println(fmt.Sprint("something"))),')).toBeTruthy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println(fmt.Sprint("something"), "x")),')).toBeTruthy()
|
||||
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println("something")')).toBeFalsy()
|
||||
expect(decreaseNextIndentRegex.testSync(' fmt.Println("something"),')).toBeFalsy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println("something")')).toBeFalsy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(' fmt.Println("something"),')).toBeFalsy()
|
||||
|
||||
# a line with many (), testing for catastrophic backtracking.
|
||||
# see https://github.com/atom/language-go/issues/78
|
||||
longLine = 'first.second().third().fourth().fifth().sixth().seventh().eighth().ninth().tenth()'
|
||||
expect(decreaseNextIndentRegex.testSync(longLine)).toBeFalsy()
|
||||
expect(decreaseNextIndentRegex.findNextMatchSync(longLine)).toBeFalsy()
|
||||
|
@ -601,8 +601,8 @@ describe 'TextMate HTML grammar', ->
|
||||
|
||||
describe 'firstLineMatch', ->
|
||||
it 'recognises HTML5 doctypes', ->
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync('<!DOCTYPE html>')).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync('<!doctype HTML>')).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync('<!DOCTYPE html>')).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync('<!doctype HTML>')).not.toBeNull()
|
||||
|
||||
it 'recognises Emacs modelines', ->
|
||||
valid = '''
|
||||
@ -621,7 +621,7 @@ describe 'TextMate HTML grammar', ->
|
||||
"-*- font:x;foo : bar ; mode : HtML ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
'''
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = '''
|
||||
/* --*html-*- */
|
||||
@ -640,7 +640,7 @@ describe 'TextMate HTML grammar', ->
|
||||
// -*-font:mode;mode:html--*-
|
||||
'''
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it 'recognises Vim modelines', ->
|
||||
valid = '''
|
||||
@ -667,7 +667,7 @@ describe 'TextMate HTML grammar', ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=html ts=4
|
||||
'''
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = '''
|
||||
ex: se filetype=html:
|
||||
@ -685,7 +685,7 @@ describe 'TextMate HTML grammar', ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=HTML ts=4
|
||||
'''
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
describe 'tags', ->
|
||||
it 'tokenizes style tags as such', ->
|
||||
|
@ -2400,7 +2400,7 @@ describe "JavaScript grammar", ->
|
||||
#!/usr/bin/env node
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
\x20#!/usr/sbin/node
|
||||
@ -2411,7 +2411,7 @@ describe "JavaScript grammar", ->
|
||||
#!\t/usr/bin/env --node=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -2430,7 +2430,7 @@ describe "JavaScript grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : jS ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*js-*- */
|
||||
@ -2448,7 +2448,7 @@ describe "JavaScript grammar", ->
|
||||
// -*-font:mode;mode:js--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -2475,7 +2475,7 @@ describe "JavaScript grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=javascript ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=javascript:
|
||||
@ -2493,4 +2493,4 @@ describe "JavaScript grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=javascript ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -721,9 +721,6 @@
|
||||
'match': '^\\s*(package)\\s+([^\\s;]+)'
|
||||
'name': 'meta.class.perl'
|
||||
}
|
||||
{
|
||||
'include: "#sub'
|
||||
}
|
||||
{
|
||||
'captures':
|
||||
'1':
|
||||
|
@ -183,7 +183,7 @@ describe "Perl 6 grammar", ->
|
||||
#!/usr/bin/env perl6
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
#! pearl6
|
||||
@ -200,11 +200,11 @@ describe "Perl 6 grammar", ->
|
||||
#!\t/usr/bin/env --perl6=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises the Perl6 pragma", ->
|
||||
line = "use v6;"
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
modelines = """
|
||||
@ -222,7 +222,7 @@ describe "Perl 6 grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : pErL6 ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in modelines.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*perl6-*- */
|
||||
@ -241,7 +241,7 @@ describe "Perl 6 grammar", ->
|
||||
"""
|
||||
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -268,7 +268,7 @@ describe "Perl 6 grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=perl6 ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=perl6:
|
||||
@ -286,7 +286,7 @@ describe "Perl 6 grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=perl6 ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
# Local variables:
|
||||
# mode: CoffeeScript
|
||||
|
@ -1439,7 +1439,7 @@ Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
#!/usr/bin/env perl
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
#! pearl
|
||||
@ -1456,7 +1456,7 @@ Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
#!\t/usr/bin/env --perl=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -1474,7 +1474,7 @@ Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
"-*- font:x;foo : bar ; mode : pErL ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*perl-*- */
|
||||
@ -1491,7 +1491,7 @@ Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
// -*-font:mode;mode:perl--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -1518,7 +1518,7 @@ Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=perl ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=perl:
|
||||
@ -1536,7 +1536,7 @@ Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=perl ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
# Local variables:
|
||||
# mode: CoffeeScript
|
||||
|
@ -161,11 +161,11 @@ describe 'PHP in HTML', ->
|
||||
<?php namespace foo;
|
||||
'''
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
# Do not allow matching XML declaration until the grammar scoring system takes into account
|
||||
# the length of the first line match so that longer matches get the priority over shorter matches.
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync('<?xml version="1.0" encoding="UTF-8"?>')).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync('<?xml version="1.0" encoding="UTF-8"?>')).toBeNull()
|
||||
|
||||
it 'recognises interpreter directives', ->
|
||||
valid = '''
|
||||
@ -184,7 +184,7 @@ describe 'PHP in HTML', ->
|
||||
#!/usr/bin/env php
|
||||
'''
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = '''
|
||||
\x20#!/usr/sbin/php
|
||||
@ -196,7 +196,7 @@ describe 'PHP in HTML', ->
|
||||
#!\t/usr/bin/env --php=bar
|
||||
'''
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it 'recognises Emacs modelines', ->
|
||||
valid = '''
|
||||
@ -215,7 +215,7 @@ describe 'PHP in HTML', ->
|
||||
"-*- font:x;foo : bar ; mode : php ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
'''
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = '''
|
||||
/* --*php-*- */
|
||||
@ -233,7 +233,7 @@ describe 'PHP in HTML', ->
|
||||
// -*-font:mode;mode:php--*-
|
||||
'''
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it 'recognises Vim modelines', ->
|
||||
valid = '''
|
||||
@ -260,7 +260,7 @@ describe 'PHP in HTML', ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=phtml ts=4
|
||||
'''
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = '''
|
||||
ex: se filetype=php:
|
||||
@ -278,7 +278,7 @@ describe 'PHP in HTML', ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=php ts=4
|
||||
'''
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it 'should tokenize <?php use Some\\Name ?>', ->
|
||||
lines = grammar.tokenizeLines '''
|
||||
|
@ -18,66 +18,66 @@ describe 'Python settings', ->
|
||||
it 'matches lines correctly using the increaseIndentPattern', ->
|
||||
increaseIndentRegex = languageMode.increaseIndentRegexForScopeDescriptor(['source.python'])
|
||||
|
||||
expect(increaseIndentRegex.testSync('for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('async for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' async for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('class TheClass(Object):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' class TheClass(Object):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('async def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' async def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('if this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' if this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('elif this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' elif this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('else:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' else:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('except Exception:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' except Exception:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('except Exception as e:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' except Exception as e:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('finally:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' finally:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('async with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' async with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('while True:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync(' while True:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.testSync('\t\t while True:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('async for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' async for i in range(n):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('class TheClass(Object):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' class TheClass(Object):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('async def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' async def f(x):')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('if this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' if this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('elif this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' elif this_var == that_var:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('else:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' else:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('except Exception:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' except Exception:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('except Exception as e:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' except Exception as e:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('finally:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' finally:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('async with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' async with open("filename") as f:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('while True:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync(' while True:')).toBeTruthy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('\t\t while True:')).toBeTruthy()
|
||||
|
||||
it 'does not match lines incorrectly using the increaseIndentPattern', ->
|
||||
increaseIndentRegex = languageMode.increaseIndentRegexForScopeDescriptor(['source.python'])
|
||||
|
||||
expect(increaseIndentRegex.testSync('for i in range(n)')).toBeFalsy()
|
||||
expect(increaseIndentRegex.testSync('class TheClass(Object)')).toBeFalsy()
|
||||
expect(increaseIndentRegex.testSync('def f(x)')).toBeFalsy()
|
||||
expect(increaseIndentRegex.testSync('if this_var == that_var')).toBeFalsy()
|
||||
expect(increaseIndentRegex.testSync('"for i in range(n):"')).toBeFalsy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('for i in range(n)')).toBeFalsy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('class TheClass(Object)')).toBeFalsy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('def f(x)')).toBeFalsy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('if this_var == that_var')).toBeFalsy()
|
||||
expect(increaseIndentRegex.findNextMatchSync('"for i in range(n):"')).toBeFalsy()
|
||||
|
||||
it 'matches lines correctly using the decreaseIndentPattern', ->
|
||||
decreaseIndentRegex = languageMode.decreaseIndentRegexForScopeDescriptor(['source.python'])
|
||||
|
||||
expect(decreaseIndentRegex.testSync('elif this_var == that_var:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' elif this_var == that_var:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync('else:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' else:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync('except Exception:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' except Exception:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync('except Exception as e:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' except Exception as e:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync('finally:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync(' finally:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.testSync('\t\t finally:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('elif this_var == that_var:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' elif this_var == that_var:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('else:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' else:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('except Exception:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' except Exception:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('except Exception as e:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' except Exception as e:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('finally:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' finally:')).toBeTruthy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('\t\t finally:')).toBeTruthy()
|
||||
|
||||
it 'does not match lines incorrectly using the decreaseIndentPattern', ->
|
||||
decreaseIndentRegex = languageMode.decreaseIndentRegexForScopeDescriptor(['source.python'])
|
||||
|
||||
# NOTE! This first one is different from most other rote tests here.
|
||||
expect(decreaseIndentRegex.testSync('else: expression()')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.testSync('elif this_var == that_var')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.testSync(' elif this_var == that_var')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.testSync('else')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.testSync(' "finally:"')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('else: expression()')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('elif this_var == that_var')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' elif this_var == that_var')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync('else')).toBeFalsy()
|
||||
expect(decreaseIndentRegex.findNextMatchSync(' "finally:"')).toBeFalsy()
|
||||
|
@ -14,8 +14,8 @@ describe "Python grammar", ->
|
||||
grammar = atom.grammars.grammarForScopeName("source.python")
|
||||
|
||||
it "recognises shebang on firstline", ->
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync("#!/usr/bin/env python")).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync("#! /usr/bin/env python")).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync("#!/usr/bin/env python")).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync("#! /usr/bin/env python")).not.toBeNull()
|
||||
|
||||
it "parses the grammar", ->
|
||||
expect(grammar).toBeDefined()
|
||||
|
@ -964,7 +964,7 @@ describe "TextMate Ruby grammar", ->
|
||||
#!/usr/bin/env ruby
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
\x20#!/usr/sbin/ruby
|
||||
@ -975,7 +975,7 @@ describe "TextMate Ruby grammar", ->
|
||||
#!\t/usr/bin/env --ruby=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -994,7 +994,7 @@ describe "TextMate Ruby grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : RUBY ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*ruby-*- */
|
||||
@ -1012,7 +1012,7 @@ describe "TextMate Ruby grammar", ->
|
||||
// -*-font:mode;mode:ruby--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -1039,7 +1039,7 @@ describe "TextMate Ruby grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=ruby ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=ruby:
|
||||
@ -1057,4 +1057,4 @@ describe "TextMate Ruby grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=ruby ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -361,7 +361,7 @@ describe "Shell script grammar", ->
|
||||
#!/usr/bin/env bash
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
\x20#!/usr/sbin/bash
|
||||
@ -373,7 +373,7 @@ describe "Shell script grammar", ->
|
||||
#!\t/usr/bin/env --bash=bar
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Emacs modelines", ->
|
||||
valid = """
|
||||
@ -392,7 +392,7 @@ describe "Shell script grammar", ->
|
||||
"-*- font:x;foo : bar ; mode : sH ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*sh-*- */
|
||||
@ -410,7 +410,7 @@ describe "Shell script grammar", ->
|
||||
// -*-font:mode;mode:sh--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -437,7 +437,7 @@ describe "Shell script grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=sh ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=sh:
|
||||
@ -455,4 +455,4 @@ describe "Shell script grammar", ->
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=sh ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -122,7 +122,7 @@ attrName="attrValue">
|
||||
"-*- font:x;foo : bar ; mode : xMl ; bar : foo ; foooooo:baaaaar;fo:ba-*-";
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
/* --*XML-*- */
|
||||
@ -140,7 +140,7 @@ attrName="attrValue">
|
||||
// -*-font:mode;mode:xml--*-
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises Vim modelines", ->
|
||||
valid = """
|
||||
@ -167,7 +167,7 @@ attrName="attrValue">
|
||||
# vim:noexpandtab titlestring=hi\|there\\\\ ft=xml ts=4
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
ex: se filetype=xml:
|
||||
@ -185,7 +185,7 @@ attrName="attrValue">
|
||||
# vim:noexpandtab titlestring=hi\\|there\\\\\\ ft=xml ts=4
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
||||
it "recognises a valid XML declaration", ->
|
||||
valid = """
|
||||
@ -196,7 +196,7 @@ attrName="attrValue">
|
||||
<?xml version="1.0" encoding='UTF-8' standalone='no' ?>
|
||||
"""
|
||||
for line in valid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).not.toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).not.toBeNull()
|
||||
|
||||
invalid = """
|
||||
<?XML version="1.0"?>
|
||||
@ -209,4 +209,4 @@ attrName="attrValue">
|
||||
<?xml version="1.0">
|
||||
"""
|
||||
for line in invalid.split /\n/
|
||||
expect(grammar.firstLineRegex.scanner.findNextMatchSync(line)).toBeNull()
|
||||
expect(grammar.firstLineRegex.findNextMatchSync(line)).toBeNull()
|
||||
|
@ -5,13 +5,14 @@ const temp = require('temp').track();
|
||||
const TextBuffer = require('text-buffer');
|
||||
const GrammarRegistry = require('../src/grammar-registry');
|
||||
const TreeSitterGrammar = require('../src/tree-sitter-grammar');
|
||||
const FirstMate = require('first-mate');
|
||||
const { OnigRegExp } = require('oniguruma');
|
||||
const SecondMate = require('second-mate');
|
||||
const { OnigScanner } = SecondMate;
|
||||
|
||||
describe('GrammarRegistry', () => {
|
||||
let grammarRegistry;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
await SecondMate.ready
|
||||
grammarRegistry = new GrammarRegistry({ config: atom.config });
|
||||
expect(subscriptionCount(grammarRegistry)).toBe(1);
|
||||
});
|
||||
@ -102,7 +103,7 @@ describe('GrammarRegistry', () => {
|
||||
);
|
||||
|
||||
const grammar = grammarRegistry.grammarForId('source.js');
|
||||
expect(grammar instanceof FirstMate.Grammar).toBe(true);
|
||||
expect(grammar instanceof SecondMate.Grammar).toBe(true);
|
||||
expect(grammar.scopeName).toBe('source.js');
|
||||
|
||||
grammarRegistry.removeGrammar(grammar);
|
||||
@ -127,7 +128,7 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
grammarRegistry.removeGrammar(grammar);
|
||||
expect(
|
||||
grammarRegistry.grammarForId('source.js') instanceof FirstMate.Grammar
|
||||
grammarRegistry.grammarForId('source.js') instanceof SecondMate.Grammar
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@ -560,7 +561,7 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
const grammar = grammarRegistry.selectGrammar('test.js');
|
||||
expect(grammar.scopeName).toBe('source.js');
|
||||
expect(grammar instanceof FirstMate.Grammar).toBe(true);
|
||||
expect(grammar instanceof SecondMate.Grammar).toBe(true);
|
||||
});
|
||||
|
||||
it('favors a tree-sitter grammar over a text-mate grammar when `core.useTreeSitterParsers` is true', () => {
|
||||
@ -766,7 +767,7 @@ describe('GrammarRegistry', () => {
|
||||
grammarRegistry.addGrammar(grammar1);
|
||||
const grammar2 = {
|
||||
name: 'foo++',
|
||||
contentRegex: new OnigRegExp('.*bar'),
|
||||
contentRegex: new OnigScanner(['.*bar']),
|
||||
fileTypes: ['foo']
|
||||
};
|
||||
grammarRegistry.addGrammar(grammar2);
|
||||
|
@ -1,7 +1,7 @@
|
||||
const _ = require('underscore-plus');
|
||||
const Grim = require('grim');
|
||||
const CSON = require('season');
|
||||
const FirstMate = require('first-mate');
|
||||
const SecondMate = require('second-mate');
|
||||
const { Disposable, CompositeDisposable } = require('event-kit');
|
||||
const TextMateLanguageMode = require('./text-mate-language-mode');
|
||||
const TreeSitterLanguageMode = require('./tree-sitter-language-mode');
|
||||
@ -20,7 +20,7 @@ module.exports = class GrammarRegistry {
|
||||
constructor({ config } = {}) {
|
||||
this.config = config;
|
||||
this.subscriptions = new CompositeDisposable();
|
||||
this.textmateRegistry = new FirstMate.GrammarRegistry({
|
||||
this.textmateRegistry = new SecondMate.GrammarRegistry({
|
||||
maxTokensPerLine: 100,
|
||||
maxLineLength: 1000
|
||||
});
|
||||
@ -264,7 +264,7 @@ module.exports = class GrammarRegistry {
|
||||
if (grammar.contentRegex) {
|
||||
const contentMatch = isTreeSitter
|
||||
? grammar.contentRegex.test(contents)
|
||||
: grammar.contentRegex.testSync(contents);
|
||||
: grammar.contentRegex.findNextMatchSync(contents);
|
||||
if (contentMatch) {
|
||||
score += 0.05;
|
||||
} else {
|
||||
@ -339,8 +339,8 @@ module.exports = class GrammarRegistry {
|
||||
.split('\n')
|
||||
.slice(0, numberOfNewlinesInRegex + 1)
|
||||
.join('\n');
|
||||
if (grammar.firstLineRegex.testSync) {
|
||||
return grammar.firstLineRegex.testSync(prefix);
|
||||
if (grammar.firstLineRegex.findNextMatchSync) {
|
||||
return grammar.firstLineRegex.findNextMatchSync(prefix);
|
||||
} else {
|
||||
return grammar.firstLineRegex.test(prefix);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ const NullGrammar = require('./null-grammar');
|
||||
const TextMateLanguageMode = require('./text-mate-language-mode');
|
||||
const ScopeDescriptor = require('./scope-descriptor');
|
||||
|
||||
const TextMateScopeSelector = require('first-mate').ScopeSelector;
|
||||
const TextMateScopeSelector = require('second-mate').ScopeSelector;
|
||||
const GutterContainer = require('./gutter-container');
|
||||
let TextEditorComponent = null;
|
||||
let TextEditorElement = null;
|
||||
|
@ -5,7 +5,7 @@ const TokenizedLine = require('./tokenized-line');
|
||||
const TokenIterator = require('./token-iterator');
|
||||
const ScopeDescriptor = require('./scope-descriptor');
|
||||
const NullGrammar = require('./null-grammar');
|
||||
const { OnigRegExp } = require('oniguruma');
|
||||
const { OnigScanner } = require('second-mate');
|
||||
const {
|
||||
toFirstMateScopeId,
|
||||
fromFirstMateScopeId
|
||||
@ -144,7 +144,7 @@ class TextMateLanguageMode {
|
||||
);
|
||||
if (!decreaseIndentRegex) return;
|
||||
|
||||
if (!decreaseIndentRegex.testSync(line)) return;
|
||||
if (!decreaseIndentRegex.findNextMatchSync(line)) return;
|
||||
|
||||
const precedingRow = this.buffer.previousNonBlankRow(bufferRow);
|
||||
if (precedingRow == null) return;
|
||||
@ -156,14 +156,14 @@ class TextMateLanguageMode {
|
||||
scopeDescriptor
|
||||
);
|
||||
if (increaseIndentRegex) {
|
||||
if (!increaseIndentRegex.testSync(precedingLine)) desiredIndentLevel -= 1;
|
||||
if (!increaseIndentRegex.findNextMatchSync(precedingLine)) desiredIndentLevel -= 1;
|
||||
}
|
||||
|
||||
const decreaseNextIndentRegex = this.decreaseNextIndentRegexForScopeDescriptor(
|
||||
scopeDescriptor
|
||||
);
|
||||
if (decreaseNextIndentRegex) {
|
||||
if (decreaseNextIndentRegex.testSync(precedingLine))
|
||||
if (decreaseNextIndentRegex.findNextMatchSync(precedingLine))
|
||||
desiredIndentLevel -= 1;
|
||||
}
|
||||
|
||||
@ -203,17 +203,17 @@ class TextMateLanguageMode {
|
||||
if (!increaseIndentRegex) return desiredIndentLevel;
|
||||
|
||||
if (!this.isRowCommented(precedingRow)) {
|
||||
if (increaseIndentRegex && increaseIndentRegex.testSync(precedingLine))
|
||||
if (increaseIndentRegex && increaseIndentRegex.findNextMatchSync(precedingLine))
|
||||
desiredIndentLevel += 1;
|
||||
if (
|
||||
decreaseNextIndentRegex &&
|
||||
decreaseNextIndentRegex.testSync(precedingLine)
|
||||
decreaseNextIndentRegex.findNextMatchSync(precedingLine)
|
||||
)
|
||||
desiredIndentLevel -= 1;
|
||||
}
|
||||
|
||||
if (!this.buffer.isRowBlank(precedingRow)) {
|
||||
if (decreaseIndentRegex && decreaseIndentRegex.testSync(line))
|
||||
if (decreaseIndentRegex && decreaseIndentRegex.findNextMatchSync(line))
|
||||
desiredIndentLevel -= 1;
|
||||
}
|
||||
|
||||
@ -812,7 +812,7 @@ class TextMateLanguageMode {
|
||||
if (indentation < startIndentLevel) {
|
||||
break;
|
||||
} else if (indentation === startIndentLevel) {
|
||||
if (foldEndRegex && foldEndRegex.searchSync(line)) foldEndRow = nextRow;
|
||||
if (foldEndRegex && foldEndRegex.findNextMatchSync(line)) foldEndRow = nextRow;
|
||||
break;
|
||||
}
|
||||
foldEndRow = nextRow;
|
||||
@ -848,7 +848,7 @@ class TextMateLanguageMode {
|
||||
regexForPattern(pattern) {
|
||||
if (pattern) {
|
||||
if (!this.regexesByPattern[pattern]) {
|
||||
this.regexesByPattern[pattern] = new OnigRegExp(pattern);
|
||||
this.regexesByPattern[pattern] = new OnigScanner([pattern]);
|
||||
}
|
||||
return this.regexesByPattern[pattern];
|
||||
}
|
||||
|
@ -19,10 +19,11 @@
|
||||
}
|
||||
StartupTime.addMarker('window:start', startWindowTime);
|
||||
|
||||
window.onload = function() {
|
||||
window.onload = async function() {
|
||||
try {
|
||||
StartupTime.addMarker('window:onload:start');
|
||||
const startTime = Date.now();
|
||||
await require('second-mate').ready
|
||||
|
||||
process.on('unhandledRejection', function(error, promise) {
|
||||
console.error(
|
||||
|
47
yarn.lock
47
yarn.lock
@ -2659,11 +2659,9 @@ braces@~3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
"bracket-matcher@https://github.com/pulsar-edit/bracket-matcher.git#c877977":
|
||||
"bracket-matcher@file:packages/bracket-matcher":
|
||||
version "0.92.0"
|
||||
resolved "https://github.com/pulsar-edit/bracket-matcher.git#c877977ac7e9b7fe43c2100a1880c7ffc119280b"
|
||||
dependencies:
|
||||
first-mate "^7.4.1"
|
||||
underscore-plus "1.x"
|
||||
|
||||
browser-stdout@1.3.1:
|
||||
@ -3991,7 +3989,7 @@ electron@12.2.3:
|
||||
"@types/node" "^14.6.2"
|
||||
extract-zip "^1.0.3"
|
||||
|
||||
emissary@^1, emissary@^1.0.0, emissary@^1.1.0, emissary@^1.2.0, emissary@^1.3.2:
|
||||
emissary@^1.0.0, emissary@^1.1.0, emissary@^1.2.0, emissary@^1.3.2, emissary@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/emissary/-/emissary-1.3.3.tgz#a618d92d682b232d31111dc3625a5df661799606"
|
||||
integrity sha512-pD6FWNBSlEOzSJDCTcSGVLgNnGw5fnCvvGMdQ/TN43efeXZ/QTq8+hZoK3OOEXPRNjMmSJmeOnEJh+bWT5O8rQ==
|
||||
@ -4390,7 +4388,7 @@ etch@^0.12.2, etch@^0.12.6:
|
||||
resolved "https://registry.yarnpkg.com/etch/-/etch-0.12.8.tgz#c24bc9bd3a6148f62204ce8643d2e899b9ecb9de"
|
||||
integrity sha512-dFLRe4wLroVtwzyy1vGlE3BSDZHiL0kZME5XgNGzZIULcYTvVno8vbiIleAesoKJmwWaxDTzG+4eppg2zk14JQ==
|
||||
|
||||
event-kit@2.5.3, event-kit@^2.0.0, event-kit@^2.1.0, event-kit@^2.2.0, event-kit@^2.4.0, event-kit@^2.5.3:
|
||||
event-kit@2.5.3, event-kit@^2.0.0, event-kit@^2.1.0, event-kit@^2.4.0, event-kit@^2.5.3:
|
||||
version "2.5.3"
|
||||
resolved "https://registry.yarnpkg.com/event-kit/-/event-kit-2.5.3.tgz#d47e4bc116ec0aacd00263791fa1a55eb5e79ba1"
|
||||
integrity sha512-b7Qi1JNzY4BfAYfnIRanLk0DOD1gdkWHT4GISIn8Q2tAf3LpU8SP2CMwWaq40imYoKWbtN4ZhbSRxvsnikooZQ==
|
||||
@ -4605,19 +4603,6 @@ find-up@^5.0.0:
|
||||
locate-path "^6.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
first-mate@7.4.3, first-mate@^7.4.1:
|
||||
version "7.4.3"
|
||||
resolved "https://registry.yarnpkg.com/first-mate/-/first-mate-7.4.3.tgz#058b9b6d2f43e38a5f0952669338cff2c46ae2dd"
|
||||
integrity sha512-PtZUpaPmcV5KV4Rw5TfwczEnExN+X1o3Q/G82E4iRJ0tW91fm3Yi7pa5t4cBH8r3D6EyoBKvfpG2jKE+TZ0/nw==
|
||||
dependencies:
|
||||
emissary "^1"
|
||||
event-kit "^2.2.0"
|
||||
fs-plus "^3.0.0"
|
||||
grim "^2.0.1"
|
||||
oniguruma "^7.2.3"
|
||||
season "^6.0.2"
|
||||
underscore-plus "^1"
|
||||
|
||||
flat-cache@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
|
||||
@ -5194,7 +5179,7 @@ graphql@14.5.8:
|
||||
dependencies:
|
||||
iterall "^1.2.2"
|
||||
|
||||
grim@2.0.3, grim@^2.0.1, grim@^2.0.2:
|
||||
grim@2.0.3, grim@^2.0.1, grim@^2.0.2, grim@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/grim/-/grim-2.0.3.tgz#66e575efc4577981d959da0764926b4aaded4b0d"
|
||||
integrity sha512-FM20Ump11qYLK9k9DbL8yzVpy+YBieya1JG15OeH8s+KbHq8kL4SdwRtURwIUHniSxb24EoBUpwKfFjGNVi4/Q==
|
||||
@ -7422,13 +7407,6 @@ onetime@^5.1.0:
|
||||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
oniguruma@^7.2.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.3.tgz#e0b0b415302de8cdd6564e57a1a822ac0ab57012"
|
||||
integrity sha512-PZZcE0yfg8Q1IvaJImh21RUTHl8ep0zwwyoE912KqlWVrsGByjjj29sdACcD1BFyX2bLkfuOJeP+POzAGVWtbA==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
"open-on-github@file:packages/open-on-github":
|
||||
version "1.3.2"
|
||||
|
||||
@ -8503,6 +8481,18 @@ season@^6.0.2:
|
||||
fs-plus "^3.0.0"
|
||||
yargs "^3.23.0"
|
||||
|
||||
"second-mate@https://github.com/pulsar-edit/second-mate.git#14aa7bd":
|
||||
version "8.0.0"
|
||||
resolved "https://github.com/pulsar-edit/second-mate.git#14aa7bd94b90c47aa99f000394301b9573b8898b"
|
||||
dependencies:
|
||||
emissary "^1.3.3"
|
||||
event-kit "^2.5.3"
|
||||
fs-plus "^3.0.0"
|
||||
grim "^2.0.3"
|
||||
season "^6.0.2"
|
||||
underscore-plus "^1"
|
||||
vscode-oniguruma "^1.7.0"
|
||||
|
||||
selector-kit@^0.1:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/selector-kit/-/selector-kit-0.1.0.tgz#304338fceccea35ec28ffaddb792ab7715633e6f"
|
||||
@ -9810,6 +9800,11 @@ verror@^1.10.0:
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
vscode-oniguruma@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b"
|
||||
integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==
|
||||
|
||||
vscode-ripgrep@1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.9.0.tgz#d6cdea4d290f3c2919472cdcfe2440d5fb1f99db"
|
||||
|
Loading…
Reference in New Issue
Block a user