mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
feat: add indentation support for XML language
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
; Indents query for AndroidIDE
|
||||
|
||||
(xml_decl
|
||||
"<?" @indent
|
||||
"?>" @outdent)
|
||||
|
||||
(empty_element
|
||||
tag_name: (name) @indent
|
||||
"/>" @outdent)
|
||||
|
||||
(end_tag_element
|
||||
(tag_start
|
||||
tag_name: (name) @indent)
|
||||
(tag_end
|
||||
"</" @outdent)
|
||||
)
|
||||
+40
-19
@@ -26,6 +26,7 @@ import com.itsaky.androidide.editor.schemes.LanguageSpecProvider.getLanguageSpec
|
||||
import com.itsaky.androidide.editor.schemes.LocalCaptureSpecProvider.newLocalCaptureSpec
|
||||
import com.itsaky.androidide.treesitter.TSLanguage
|
||||
import com.itsaky.androidide.treesitter.TSParser
|
||||
import com.itsaky.androidide.treesitter.TSQueryCapture
|
||||
import com.itsaky.androidide.treesitter.TSQueryCursor
|
||||
import com.itsaky.androidide.treesitter.TSQueryMatch
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
@@ -69,10 +70,14 @@ abstract class TreeSitterLanguage(context: Context, lang: TSLanguage, type: Stri
|
||||
}
|
||||
}
|
||||
|
||||
fun finalizeIndent(indent: Int) : Int {
|
||||
open fun finalizeIndent(indent: Int): Int {
|
||||
return max(0, indent) * tabSize
|
||||
}
|
||||
|
||||
|
||||
open fun validateIndentCapture(match: TSQueryMatch, capture: TSQueryCapture): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getAnalyzeManager(): AnalyzeManager {
|
||||
return this.analyzer
|
||||
}
|
||||
@@ -80,35 +85,51 @@ abstract class TreeSitterLanguage(context: Context, lang: TSLanguage, type: Stri
|
||||
override fun getSymbolPairs(): SymbolPairMatch {
|
||||
return CommonSymbolPairs()
|
||||
}
|
||||
|
||||
|
||||
override fun getIndentAdvance(line: String): Int {
|
||||
return computeIndent(line, 0, line.length)
|
||||
}
|
||||
|
||||
protected fun computeIndent(content: String, line: Int, column: Int, decrementBy: Int = 0): Int {
|
||||
return TSParser().use { parser ->
|
||||
parser.language = languageSpec.language
|
||||
val tree = parser.parseString(line)
|
||||
|
||||
val tree = parser.parseString(content)
|
||||
|
||||
return@use TSQueryCursor().use { cursor ->
|
||||
cursor.exec(languageSpec.indentsQuery, tree.rootNode)
|
||||
|
||||
|
||||
var indent = 0
|
||||
var match: TSQueryMatch? = cursor.nextMatch()
|
||||
val captures = mutableListOf<TSQueryCapture>()
|
||||
while (match != null) {
|
||||
for (capture in match.captures) {
|
||||
val captureName =
|
||||
languageSpec.indentsQuery.getCaptureNameForId(capture.index)
|
||||
if (captureName == "indent") {
|
||||
++indent
|
||||
} else if (captureName == "outdent") {
|
||||
--indent
|
||||
}
|
||||
}
|
||||
captures.addAll(match.captures)
|
||||
match = cursor.nextMatch()
|
||||
}
|
||||
|
||||
if (indent > 1) {
|
||||
|
||||
captures.sortBy { it.node.startByte }
|
||||
|
||||
for (capture in captures) {
|
||||
val capLine = capture.node.startPoint.row
|
||||
val capCol = capture.node.endPoint.column / 2
|
||||
|
||||
if (capLine > line || (capLine == line && capCol > column)) {
|
||||
break
|
||||
}
|
||||
|
||||
val captureName =
|
||||
languageSpec.indentsQuery.getCaptureNameForId(capture.index)
|
||||
if (captureName == "indent") {
|
||||
++indent
|
||||
} else if (captureName == "outdent") {
|
||||
--indent
|
||||
}
|
||||
}
|
||||
|
||||
if (decrementBy == 0 && indent > 1) {
|
||||
indent = 1
|
||||
}
|
||||
|
||||
finalizeIndent(indent)
|
||||
|
||||
finalizeIndent(indent) - decrementBy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,12 @@ import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage
|
||||
import com.itsaky.androidide.lsp.api.ILanguageServer
|
||||
import com.itsaky.androidide.lsp.api.ILanguageServerRegistry
|
||||
import com.itsaky.androidide.lsp.xml.XMLLanguageServer
|
||||
import com.itsaky.androidide.treesitter.TSQueryCapture
|
||||
import com.itsaky.androidide.treesitter.TSQueryMatch
|
||||
import com.itsaky.androidide.treesitter.xml.TSLanguageXml
|
||||
import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler
|
||||
import io.github.rosemoe.sora.text.ContentReference
|
||||
import io.github.rosemoe.sora.text.TextUtils.countLeadingSpaceCount
|
||||
import io.github.rosemoe.sora.util.MyCharacter
|
||||
|
||||
/**
|
||||
@@ -54,4 +57,24 @@ class XMLLanguage(context: Context) :
|
||||
override fun getNewlineHandlers(): Array<NewlineHandler> {
|
||||
return emptyArray()
|
||||
}
|
||||
|
||||
override fun getIndentAdvance(content: ContentReference, line: Int, column: Int): Int {
|
||||
return computeIndent(
|
||||
content.toString(),
|
||||
line,
|
||||
column,
|
||||
decrementBy = countLeadingSpaceCount(content.getLine(line), tabSize)
|
||||
)
|
||||
}
|
||||
|
||||
override fun finalizeIndent(indent: Int): Int {
|
||||
// Indentation can be negative in XML
|
||||
return indent * tabSize
|
||||
}
|
||||
|
||||
override fun validateIndentCapture(match: TSQueryMatch, capture: TSQueryCapture): Boolean {
|
||||
// sometimes there are captures whose start and end bytes are the same
|
||||
// those capture must not be considered
|
||||
return capture.node.startByte < capture.node.endByte
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ object LanguageSpecProvider {
|
||||
|
||||
private const val BASE_SPEC_PATH = "editor/treesitter"
|
||||
private val log = ILogger.newInstance("LanguageSpecProvider")
|
||||
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun getLanguageSpec(
|
||||
|
||||
Reference in New Issue
Block a user