Fix a ruby folding issue

This commit is contained in:
Max Brunsfeld
2018-07-19 17:15:04 -07:00
parent 9136909f0b
commit a283ca365f
3 changed files with 146 additions and 29 deletions

View File

@@ -13,6 +13,7 @@ class TreeSitterGrammar {
if (params.injectionRegExp) this.injectionRegExp = new RegExp(params.injectionRegExp)
this.folds = params.folds || []
this.folds.forEach(normalizeFoldSpecification)
this.commentStrings = {
commentStartString: params.comments && params.comments.start,
@@ -72,3 +73,36 @@ class TreeSitterGrammar {
if (this.registration) this.registration.dispose()
}
}
const NODE_NAME_REGEX = /[\w_]+/
function matcherForSpec (spec) {
if (typeof spec === 'string') {
if (spec[0] === '"' && spec[spec.length - 1] === '"') {
return {
type: spec.substr(1, spec.length - 2),
named: false
}
}
if (!NODE_NAME_REGEX.test(spec)) {
return {type: spec, named: false}
}
return {type: spec, named: true}
}
return spec
}
function normalizeFoldSpecification (spec) {
if (spec.type) {
if (Array.isArray(spec.type)) {
spec.matchers = spec.type.map(matcherForSpec)
} else {
spec.matchers = [matcherForSpec(spec.type)]
}
}
if (spec.start) normalizeFoldSpecification(spec.start)
if (spec.end) normalizeFoldSpecification(spec.end)
}

View File

@@ -269,42 +269,32 @@ class TreeSitterLanguageMode {
}
getFoldableRangeForNode (node, grammar, existenceOnly) {
const {children, type: nodeType} = node
const {children} = node
const childCount = children.length
let childTypes
for (var i = 0, {length} = grammar.folds; i < length; i++) {
const foldEntry = grammar.folds[i]
const foldSpec = grammar.folds[i]
if (foldEntry.type) {
if (typeof foldEntry.type === 'string') {
if (foldEntry.type !== nodeType) continue
} else {
if (!foldEntry.type.includes(nodeType)) continue
}
}
if (foldSpec.matchers && !hasMatchingFoldSpec(foldSpec.matchers, node)) continue
let foldStart
const startEntry = foldEntry.start
const startEntry = foldSpec.start
if (startEntry) {
let foldStartNode
if (startEntry.index != null) {
const child = children[startEntry.index]
if (!child || (startEntry.type && startEntry.type !== child.type)) continue
foldStart = child.endPosition
foldStartNode = children[startEntry.index]
if (!foldStartNode || startEntry.matchers && !hasMatchingFoldSpec(startEntry.matchers, foldStartNode)) continue
} else {
if (!childTypes) childTypes = children.map(child => child.type)
const index = typeof startEntry.type === 'string'
? childTypes.indexOf(startEntry.type)
: childTypes.findIndex(type => startEntry.type.includes(type))
if (index === -1) continue
foldStart = children[index].endPosition
foldStartNode = children.find(child => hasMatchingFoldSpec(startEntry.matchers, child))
if (!foldStartNode) continue
}
foldStart = new Point(foldStartNode.endPosition.row, Infinity)
} else {
foldStart = new Point(node.startPosition.row, Infinity)
}
let foldEnd
const endEntry = foldEntry.end
const endEntry = foldSpec.end
if (endEntry) {
let foldEndNode
if (endEntry.index != null) {
@@ -312,12 +302,8 @@ class TreeSitterLanguageMode {
foldEndNode = children[index]
if (!foldEndNode || (endEntry.type && endEntry.type !== foldEndNode.type)) continue
} else {
if (!childTypes) childTypes = children.map(foldEndNode => foldEndNode.type)
const index = typeof endEntry.type === 'string'
? childTypes.indexOf(endEntry.type)
: childTypes.findIndex(type => endEntry.type.includes(type))
if (index === -1) continue
foldEndNode = children[index]
foldEndNode = children.find(child => hasMatchingFoldSpec(endEntry.matchers, child))
if (!foldEndNode) continue
}
if (foldEndNode.endIndex - foldEndNode.startIndex > 1 && foldEndNode.startPosition.row > foldStart.row) {
@@ -768,7 +754,12 @@ class LayerHighlightIterator {
} else {
this.atEnd = false
this.openTags.push(id)
const {startIndex} = this.treeCursor
while (this.treeCursor.gotoFirstChild()) {
if (this.treeCursor.startIndex > startIndex) {
this.treeCursor.gotoParent()
break
}
this.containingNodeTypes.push(this.treeCursor.nodeType)
this.containingNodeChildIndices.push(0)
const scopeName = this.currentScopeName()
@@ -1041,6 +1032,10 @@ function last (array) {
return array[array.length - 1]
}
function hasMatchingFoldSpec (specs, node) {
return specs.some(({type, named}) => type === node.type && named === node.isNamed)
}
// TODO: Remove this once TreeSitterLanguageMode implements its own auto-indent system.
[
'_suggestedIndentForLineWithScopeAtBufferRow',