From 64aff3bee0fe9ee513cec6175fcd11c772539aa9 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Tue, 6 Sep 2022 12:27:30 +0530 Subject: [PATCH] Added insertion handlers for XML completion items --- .../lsp/edits/DefaultEditHandler.kt | 36 +++++++++++++------ .../xml/edits/QualifiedValueEditHandler.kt | 32 +++-------------- .../lsp/xml/edits/TagEditHandler.kt | 30 ++++++++++++++++ .../completion/IXmlCompletionProvider.kt | 7 +++- 4 files changed, 67 insertions(+), 38 deletions(-) create mode 100644 lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/TagEditHandler.kt diff --git a/lsp/models/src/main/java/com/itsaky/androidide/lsp/edits/DefaultEditHandler.kt b/lsp/models/src/main/java/com/itsaky/androidide/lsp/edits/DefaultEditHandler.kt index fe702b492..d33aa3604 100644 --- a/lsp/models/src/main/java/com/itsaky/androidide/lsp/edits/DefaultEditHandler.kt +++ b/lsp/models/src/main/java/com/itsaky/androidide/lsp/edits/DefaultEditHandler.kt @@ -49,20 +49,27 @@ open class DefaultEditHandler : IEditHandler { ThreadUtils.runOnUiThread { performEditsInternal(item, editor, text, line, column, index) } return } - + performEditsInternal(item, editor, text, line, column, index) } - - private fun performEditsInternal(item: CompletionItem, editor: CodeEditor, text: Content, line: Int, column: Int, index: Int) { + + private fun performEditsInternal( + item: CompletionItem, + editor: CodeEditor, + text: Content, + line: Int, + column: Int, + index: Int + ) { if (item.insertTextFormat == SNIPPET) { insertSnippet(item, editor, text, line, column, index) return } - + val start = getIdentifierStart(text.getLine(line), column) text.delete(line, start, line, column) editor.commitText(item.insertText) - + text.beginBatchEdit() if (item.additionalEditHandler != null) { item.additionalEditHandler!!.performEdits(item, editor, text, line, column, index) @@ -70,11 +77,18 @@ open class DefaultEditHandler : IEditHandler { RewriteHelper.performEdits(item.additionalTextEdits!!, editor) } text.beginBatchEdit() - + executeCommand(editor, item.command) } - - protected open fun insertSnippet(item: CompletionItem, editor: CodeEditor, text: Content, line: Int, column: Int, index: Int) { + + protected open fun insertSnippet( + item: CompletionItem, + editor: CodeEditor, + text: Content, + line: Int, + column: Int, + index: Int + ) { item.snippetDescription!! val snippet = CodeSnippetParser.parse(item.insertText) val prefixLength = item.snippetDescription!!.selectedLength @@ -86,7 +100,7 @@ open class DefaultEditHandler : IEditHandler { } editor.snippetController.startSnippet(actionIndex, snippet, selectedText) } - + protected open fun executeCommand(editor: CodeEditor, command: Command?) { if (command == null) { return @@ -104,7 +118,7 @@ open class DefaultEditHandler : IEditHandler { protected open fun getIdentifierStart(text: CharSequence, end: Int): Int { var start = end while (start > 0) { - if (Character.isJavaIdentifierPart(text[start - 1])) { + if (isPartialPart(text[start - 1])) { start-- continue } @@ -112,4 +126,6 @@ open class DefaultEditHandler : IEditHandler { } return start } + + protected open fun isPartialPart(c: Char) = Character.isJavaIdentifierPart(c) } diff --git a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/QualifiedValueEditHandler.kt b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/QualifiedValueEditHandler.kt index c84747925..2f2e34fe2 100644 --- a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/QualifiedValueEditHandler.kt +++ b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/QualifiedValueEditHandler.kt @@ -17,6 +17,7 @@ package com.itsaky.androidide.lsp.xml.edits +import com.itsaky.androidide.lsp.edits.DefaultEditHandler import com.itsaky.androidide.lsp.edits.IEditHandler import com.itsaky.androidide.lsp.models.CompletionItem import io.github.rosemoe.sora.text.Content @@ -28,32 +29,9 @@ import io.github.rosemoe.sora.widget.CodeEditor * * @author Akash Yadav */ -class QualifiedValueEditHandler : IEditHandler { - - override fun performEdits(item: CompletionItem, editor: CodeEditor, text: Content, line: Int, column: Int, index: Int) { - val cursor = editor.cursor - val text = editor.text - val line = cursor.leftLine - val column = cursor.leftColumn - val start = getIdentifierStart(text.getLine(line), column) - - text.delete(line, start, line, column) - - // Do not use CompletionItem.insertText as it is always '.' - editor.commitText( - item.label - ) - } - private fun getIdentifierStart(text: CharSequence, end: Int): Int { - var start = end - while (start > 0) { - val c = text[start - 1] - if (Character.isJavaIdentifierPart(c) || c == '.') { - start-- - continue - } - break - } - return start +open class QualifiedValueEditHandler : DefaultEditHandler() { + + override fun isPartialPart(c: Char): Boolean { + return super.isPartialPart(c) || c == '.' // Tags can contain '.' as well } } diff --git a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/TagEditHandler.kt b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/TagEditHandler.kt new file mode 100644 index 000000000..15be787c1 --- /dev/null +++ b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/edits/TagEditHandler.kt @@ -0,0 +1,30 @@ +/* + * This file is part of AndroidIDE. + * + * AndroidIDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AndroidIDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AndroidIDE. If not, see . + */ + +package com.itsaky.androidide.lsp.xml.edits + +/** + * Handles insertion of a tag name. + * + * @author Akash Yadav + */ +open class TagEditHandler : QualifiedValueEditHandler() { + + override fun isPartialPart(c: Char): Boolean { + return super.isPartialPart(c) || c == '-' // Tags can contain '-' as well + } +} diff --git a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt index 781607568..60367ca52 100644 --- a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt +++ b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt @@ -33,6 +33,8 @@ import com.itsaky.androidide.lsp.models.CompletionParams import com.itsaky.androidide.lsp.models.CompletionResult import com.itsaky.androidide.lsp.models.InsertTextFormat.SNIPPET import com.itsaky.androidide.lsp.models.MatchLevel +import com.itsaky.androidide.lsp.xml.edits.QualifiedValueEditHandler +import com.itsaky.androidide.lsp.xml.edits.TagEditHandler import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE_VALUE @@ -101,7 +103,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) this.attrAtCursor = document.findAttrAt(params.position.requireIndex()) ?: return CompletionResult.EMPTY } - + this.allNamespaces = findAllNamespaces(this.nodeAtCursor) return doComplete(params, pathData, document, type, prefix) } @@ -140,6 +142,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) this.label = simpleName this.detail = qualifiedName this.sortText = label.toString() + this.editHandler = TagEditHandler() this.matchLevel = matchLevel this.kind = CLASS this.data = CompletionData().apply { className = qualifiedName } @@ -210,6 +213,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) this.overrideTypeText = type.uppercase() this.sortText = if (pck == ResourceTableRegistry.PCK_ANDROID) "zzz$text" else text this.insertText = text + this.editHandler = QualifiedValueEditHandler() this.matchLevel = matchLevel } } @@ -232,6 +236,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) this.kind = VALUE this.sortText = "000$name" this.insertText = name + this.editHandler = QualifiedValueEditHandler() this.matchLevel = matchLevel } }