mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix(lsp/java): signature help is not shown sometimes
This commit is contained in:
@@ -235,7 +235,7 @@ public class IDEEditor extends CodeEditor implements IEditor, ILspEditor {
|
||||
languageServer.signatureHelp(
|
||||
new SignatureHelpParams(
|
||||
getFile().toPath(),
|
||||
new Position(getCursor().getLeftLine(), getCursor().getLeftColumn()))));
|
||||
getCursorLSPPosition())));
|
||||
|
||||
future.whenComplete(
|
||||
(help, error) -> {
|
||||
@@ -743,8 +743,10 @@ public class IDEEditor extends CodeEditor implements IEditor, ILspEditor {
|
||||
* @param event The content change event.
|
||||
*/
|
||||
private void checkForSignatureHelp(@NonNull ContentChangeEvent event) {
|
||||
final var changeLength = event.getChangedText().length();
|
||||
if (event.getAction() != ContentChangeEvent.ACTION_INSERT
|
||||
|| event.getChangedText().length() != 1) {
|
||||
|| changeLength > 0
|
||||
&& changeLength <= 2) { // changeLength will be 2 as '(' and ')' are inserted at the same time
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -880,7 +882,7 @@ public class IDEEditor extends CodeEditor implements IEditor, ILspEditor {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unused")
|
||||
public void executeCommand(Command command) {
|
||||
public void executeCommand(@Nullable Command command) {
|
||||
if (command == null) {
|
||||
LOG.warn("Cannot execute command in editor. Command is null.");
|
||||
return;
|
||||
|
||||
@@ -18,5 +18,12 @@
|
||||
package com.itsaky.androidide.lsp.api
|
||||
|
||||
import com.itsaky.androidide.lsp.models.SnippetDescription
|
||||
import io.github.rosemoe.sora.lang.completion.snippet.CodeSnippet
|
||||
|
||||
fun describeSnippet(prefix: String) = SnippetDescription(prefix.length)
|
||||
@JvmOverloads
|
||||
fun describeSnippet(
|
||||
prefix: String,
|
||||
deleteSelected: Boolean = true,
|
||||
snippet: CodeSnippet? = null,
|
||||
allowCommandExecution: Boolean = false
|
||||
) = SnippetDescription(prefix.length, deleteSelected, snippet, allowCommandExecution)
|
||||
|
||||
+11
-3
@@ -17,7 +17,6 @@
|
||||
|
||||
package com.itsaky.androidide.lsp.java.edits
|
||||
|
||||
import com.itsaky.androidide.lsp.edits.IEditHandler
|
||||
import com.itsaky.androidide.lsp.java.JavaCompilerProvider
|
||||
import com.itsaky.androidide.lsp.java.compiler.JavaCompilerService
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem
|
||||
@@ -31,13 +30,22 @@ import java.nio.file.Path
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class IJavaEditHandler(protected val file: Path) : IEditHandler {
|
||||
abstract class AdvancedJavaEditHandler(protected val file: Path) : BaseJavaEditHandler() {
|
||||
|
||||
override fun performEdits(item: CompletionItem, editor: CodeEditor, text: Content, line: Int, column: Int, index: Int) {
|
||||
override fun performEdits(
|
||||
item: CompletionItem,
|
||||
editor: CodeEditor,
|
||||
text: Content,
|
||||
line: Int,
|
||||
column: Int,
|
||||
index: Int
|
||||
) {
|
||||
val compiler = JavaCompilerProvider.get(ProjectManager.findModuleForFile(file) ?: return)
|
||||
if (compiler != null) {
|
||||
performEdits(compiler, editor, item)
|
||||
}
|
||||
|
||||
executeCommand(editor, item.command)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.lsp.java.edits
|
||||
|
||||
import com.itsaky.androidide.editor.api.ILspEditor
|
||||
import com.itsaky.androidide.lsp.edits.DefaultEditHandler
|
||||
import com.itsaky.androidide.lsp.models.Command
|
||||
import io.github.rosemoe.sora.widget.CodeEditor
|
||||
|
||||
/**
|
||||
* Implementation of [DefaultEditHandler] which avoids reflection in
|
||||
* [DefaultEditHandler.executeCommand].
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
open class BaseJavaEditHandler : DefaultEditHandler() {
|
||||
|
||||
override fun executeCommand(editor: CodeEditor, command: Command?) {
|
||||
if (editor is ILspEditor) {
|
||||
editor.executeCommand(command)
|
||||
return
|
||||
}
|
||||
super.executeCommand(editor, command)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ import java.nio.file.Path
|
||||
* @param file The file in which this edit will be performed.
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ClassImportEditHandler(val imports: Set<String>, file: Path) : IJavaEditHandler(file) {
|
||||
class ClassImportEditHandler(val imports: Set<String>, file: Path) : AdvancedJavaEditHandler(file) {
|
||||
|
||||
override fun performEdits(
|
||||
compiler: JavaCompilerService,
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class MultipleClassImportEditHandler(
|
||||
private val classes: Set<String>,
|
||||
private val imported: Set<String>,
|
||||
file: Path
|
||||
) : IJavaEditHandler(file) {
|
||||
) : AdvancedJavaEditHandler(file) {
|
||||
|
||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.lsp.java.models
|
||||
|
||||
import com.itsaky.androidide.lsp.edits.IEditHandler
|
||||
import com.itsaky.androidide.lsp.java.edits.BaseJavaEditHandler
|
||||
import com.itsaky.androidide.lsp.models.Command
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem
|
||||
import com.itsaky.androidide.lsp.models.CompletionItemKind
|
||||
import com.itsaky.androidide.lsp.models.ICompletionData
|
||||
import com.itsaky.androidide.lsp.models.InsertTextFormat
|
||||
import com.itsaky.androidide.lsp.models.MatchLevel
|
||||
import com.itsaky.androidide.lsp.models.TextEdit
|
||||
|
||||
/**
|
||||
* Completion item model for java completion items.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class JavaCompletionItem(
|
||||
label: String,
|
||||
detail: String,
|
||||
insertText: String?,
|
||||
insertTextFormat: InsertTextFormat?,
|
||||
sortText: String?,
|
||||
command: Command?,
|
||||
kind: CompletionItemKind,
|
||||
matchLevel: MatchLevel,
|
||||
additionalTextEdits: List<TextEdit>?,
|
||||
data: ICompletionData?,
|
||||
|
||||
// Override the default edit handler
|
||||
editHandler: IEditHandler = BaseJavaEditHandler()
|
||||
) :
|
||||
CompletionItem(
|
||||
label,
|
||||
detail,
|
||||
insertText,
|
||||
insertTextFormat,
|
||||
sortText,
|
||||
command,
|
||||
kind,
|
||||
matchLevel,
|
||||
additionalTextEdits,
|
||||
data,
|
||||
editHandler
|
||||
) {
|
||||
|
||||
constructor() :
|
||||
this(
|
||||
"", // label
|
||||
"", // detail
|
||||
null, // insertText
|
||||
null, // insertTextFormat
|
||||
null, // sortText
|
||||
null, // command
|
||||
CompletionItemKind.NONE, // kind
|
||||
MatchLevel.NO_MATCH, // match level
|
||||
ArrayList(), // additionalEdits
|
||||
null // data
|
||||
)
|
||||
}
|
||||
+7
-6
@@ -22,6 +22,7 @@ import com.itsaky.androidide.lsp.api.describeSnippet
|
||||
import com.itsaky.androidide.lsp.java.compiler.CompileTask
|
||||
import com.itsaky.androidide.lsp.java.compiler.JavaCompilerService
|
||||
import com.itsaky.androidide.lsp.java.edits.ClassImportEditHandler
|
||||
import com.itsaky.androidide.lsp.java.models.JavaCompletionItem
|
||||
import com.itsaky.androidide.lsp.java.providers.BaseJavaServiceProvider
|
||||
import com.itsaky.androidide.lsp.java.utils.EditHelper
|
||||
import com.itsaky.androidide.lsp.models.ClassCompletionData
|
||||
@@ -147,7 +148,7 @@ abstract class IJavaCompletionProvider(
|
||||
): CompletionItem {
|
||||
abortIfCancelled()
|
||||
abortCompletionIfCancelled()
|
||||
val item = CompletionItem()
|
||||
val item = JavaCompletionItem()
|
||||
item.setLabel(keyword)
|
||||
item.kind = KEYWORD
|
||||
item.detail = "keyword"
|
||||
@@ -166,7 +167,7 @@ abstract class IJavaCompletionProvider(
|
||||
abortIfCancelled()
|
||||
abortCompletionIfCancelled()
|
||||
val first = overloads[0]
|
||||
val item = CompletionItem()
|
||||
val item = JavaCompletionItem()
|
||||
item.setLabel(first.simpleName.toString())
|
||||
item.kind = CompletionItemKind.METHOD
|
||||
item.detail = printMethodDetail(first)
|
||||
@@ -186,7 +187,7 @@ abstract class IJavaCompletionProvider(
|
||||
item.command = Command("Trigger Parameter Hints", Command.TRIGGER_PARAMETER_HINTS)
|
||||
}
|
||||
item.insertTextFormat = SNIPPET // Snippet
|
||||
item.snippetDescription = describeSnippet(partial)
|
||||
item.snippetDescription = describeSnippet(prefix = partial, allowCommandExecution = true)
|
||||
}
|
||||
return item
|
||||
}
|
||||
@@ -217,7 +218,7 @@ abstract class IJavaCompletionProvider(
|
||||
|
||||
abortIfCancelled()
|
||||
abortCompletionIfCancelled()
|
||||
val item = CompletionItem()
|
||||
val item = JavaCompletionItem()
|
||||
item.setLabel(element.simpleName.toString())
|
||||
item.kind = kind(element)
|
||||
item.detail = element.toString()
|
||||
@@ -247,7 +248,7 @@ abstract class IJavaCompletionProvider(
|
||||
): CompletionItem {
|
||||
abortIfCancelled()
|
||||
abortCompletionIfCancelled()
|
||||
val item = CompletionItem()
|
||||
val item = JavaCompletionItem()
|
||||
item.setLabel(simpleName(className).toString())
|
||||
item.kind = CompletionItemKind.CLASS
|
||||
item.detail = packageName(className).toString()
|
||||
@@ -280,7 +281,7 @@ abstract class IJavaCompletionProvider(
|
||||
if (packageName == name) {
|
||||
packageName = " "
|
||||
}
|
||||
return CompletionItem().apply {
|
||||
return JavaCompletionItem().apply {
|
||||
setLabel(simpleName)
|
||||
this.detail = packageName
|
||||
this.insertText = simpleName
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ import com.itsaky.androidide.lsp.api.describeSnippet
|
||||
import com.itsaky.androidide.lsp.java.compiler.CompileTask
|
||||
import com.itsaky.androidide.lsp.java.compiler.JavaCompilerService
|
||||
import com.itsaky.androidide.lsp.java.edits.MultipleClassImportEditHandler
|
||||
import com.itsaky.androidide.lsp.java.models.JavaCompletionItem
|
||||
import com.itsaky.androidide.lsp.java.utils.EditHelper
|
||||
import com.itsaky.androidide.lsp.java.utils.EditHelper.repeatSpaces
|
||||
import com.itsaky.androidide.lsp.java.utils.JavaPoetUtils.Companion.buildMethod
|
||||
@@ -172,7 +173,7 @@ class ScopeCompletionProvider(
|
||||
abortIfCancelled()
|
||||
abortCompletionIfCancelled()
|
||||
|
||||
val item = CompletionItem()
|
||||
val item = JavaCompletionItem()
|
||||
item.setLabel(methodSpec.name)
|
||||
item.kind = com.itsaky.androidide.lsp.models.CompletionItemKind.METHOD
|
||||
item.detail = method.returnType.toString() + " " + method
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ package com.itsaky.androidide.lsp.java.providers.completion
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.api.ICompletionCancelChecker
|
||||
import com.itsaky.androidide.lsp.api.describeSnippet
|
||||
import com.itsaky.androidide.lsp.java.parser.ParseTask
|
||||
import com.itsaky.androidide.lsp.java.models.JavaCompletionItem
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem
|
||||
import com.itsaky.androidide.lsp.models.CompletionItemKind.SNIPPET
|
||||
import com.itsaky.androidide.lsp.models.CompletionResult
|
||||
@@ -83,7 +83,7 @@ class TopLevelSnippetsProvider {
|
||||
): CompletionItem {
|
||||
abortIfCancelled()
|
||||
abortCompletionIfCancelled()
|
||||
val item = CompletionItem()
|
||||
val item = JavaCompletionItem()
|
||||
item.setLabel(label)
|
||||
item.kind = SNIPPET
|
||||
item.insertText = snippet
|
||||
|
||||
@@ -53,7 +53,7 @@ open class DefaultEditHandler : IEditHandler {
|
||||
performEditsInternal(item, editor, text, line, column, index)
|
||||
}
|
||||
|
||||
private fun performEditsInternal(
|
||||
protected open fun performEditsInternal(
|
||||
item: CompletionItem,
|
||||
editor: CodeEditor,
|
||||
text: Content,
|
||||
@@ -89,23 +89,27 @@ open class DefaultEditHandler : IEditHandler {
|
||||
column: Int,
|
||||
index: Int
|
||||
) {
|
||||
item.snippetDescription!!
|
||||
val snippetDescription = item.snippetDescription!!
|
||||
val snippet = CodeSnippetParser.parse(item.insertText)
|
||||
val prefixLength = item.snippetDescription!!.selectedLength
|
||||
val prefixLength = snippetDescription.selectedLength
|
||||
val selectedText = text.subSequence(index - prefixLength, index).toString()
|
||||
var actionIndex = index
|
||||
if (item.snippetDescription!!.deleteSelected) {
|
||||
if (snippetDescription.deleteSelected) {
|
||||
text.delete(index - prefixLength, index)
|
||||
actionIndex -= prefixLength
|
||||
}
|
||||
editor.snippetController.startSnippet(actionIndex, snippet, selectedText)
|
||||
|
||||
if (snippetDescription.allowCommandExecution) {
|
||||
executeCommand(editor, item.command)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun executeCommand(editor: CodeEditor, command: Command?) {
|
||||
if (command == null) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
val klass = editor::class.java
|
||||
val method = klass.getMethod("executeCommand", Command::class.java)
|
||||
|
||||
@@ -124,7 +124,8 @@ open class CompletionItem(
|
||||
var kind: CompletionItemKind,
|
||||
var matchLevel: MatchLevel,
|
||||
var additionalTextEdits: List<TextEdit>?,
|
||||
var data: ICompletionData?
|
||||
var data: ICompletionData?,
|
||||
var editHandler: IEditHandler = DefaultEditHandler()
|
||||
) :
|
||||
io.github.rosemoe.sora.lang.completion.CompletionItem(label, detail), Comparable<CompletionItem> {
|
||||
|
||||
@@ -147,7 +148,6 @@ open class CompletionItem(
|
||||
}
|
||||
|
||||
var insertTextFormat: InsertTextFormat = insertTextFormat ?: PLAIN_TEXT
|
||||
var editHandler: IEditHandler = DefaultEditHandler()
|
||||
var additionalEditHandler: IEditHandler? = null
|
||||
var snippetDescription: SnippetDescription? = null
|
||||
var overrideTypeText: String? = null
|
||||
@@ -268,7 +268,8 @@ data class SnippetDescription
|
||||
constructor(
|
||||
val selectedLength: Int,
|
||||
val deleteSelected: Boolean = true,
|
||||
val snippet: CodeSnippet? = null
|
||||
val snippet: CodeSnippet? = null,
|
||||
val allowCommandExecution: Boolean = false
|
||||
)
|
||||
|
||||
data class Command(var title: String, var command: String) {
|
||||
|
||||
@@ -17,16 +17,14 @@
|
||||
|
||||
package com.itsaky.androidide.lsp.xml.edits
|
||||
|
||||
import com.itsaky.androidide.lsp.edits.DefaultEditHandler
|
||||
|
||||
/**
|
||||
* Handles insertion of attribute values.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class AttrValueEditHandler : QualifiedValueEditHandler() {
|
||||
|
||||
|
||||
override fun isPartialPart(c: Char): Boolean {
|
||||
return super.isPartialPart(c) || c in charArrayOf('@', '.', ':', '/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -18,10 +18,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
|
||||
import io.github.rosemoe.sora.widget.CodeEditor
|
||||
|
||||
/**
|
||||
* Handles edits for attribute values with qualified binary names. The default implementation in
|
||||
@@ -30,7 +27,7 @@ import io.github.rosemoe.sora.widget.CodeEditor
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
open class QualifiedValueEditHandler : DefaultEditHandler() {
|
||||
|
||||
|
||||
override fun isPartialPart(c: Char): Boolean {
|
||||
return super.isPartialPart(c) || c == '.' // Tags can contain '.' as well
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user