Skip to content

Instantly share code, notes, and snippets.

@andy0130tw
Last active August 15, 2024 18:16
Show Gist options
  • Save andy0130tw/d5b18efc53bf3af1fddcc8db12198734 to your computer and use it in GitHub Desktop.
Save andy0130tw/d5b18efc53bf3af1fddcc8db12198734 to your computer and use it in GitHub Desktop.
import { foldService } from '@codemirror/language'
/** @param {string} text */
function indentLevel(text) {
const mat = /** @type {RegExpMatchArray} */ (
text.match(/^( *)([^ ]?)/))
return mat[2] ? mat[1].length : -1
}
export const foldByIndentation = foldService.of(({ doc }, from, _to) => {
const line = doc.lineAt(from)
if (line.number == doc.lines) return null
// do not make an empty line foldable
const indThis = indentLevel(line.text)
if (indThis < 0) return null
// find the next non-empty line, recording the level
// if it is indented more than the current line
let indMin
let extent = line.number
for (let i = line.number + 1; i <= doc.lines; i++) {
const ind = indentLevel(doc.line(i).text)
if (ind < 0) continue
if (ind <= indThis) return null
indMin = ind
extent = i
break
}
// there might be no such line
if (indMin == null) return null
// skip until another non-empty line with less indentation level
for (let i = extent + 1; i <= doc.lines; i++) {
const ind = indentLevel(doc.line(i).text)
if (ind < 0) continue
if (ind < indMin) break
extent = i
}
return extent == line.number ? null : {
from: doc.line(line.number).to,
to: doc.line(extent).to,
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment