Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve locality in live templates contexts #247

Merged
merged 2 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/main/kotlin/org/move/ide/liveTemplates/MvContextType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.PsiUtilCore
import org.move.ide.MvHighlighter
import org.move.lang.MoveLanguage
import org.move.lang.core.psi.MvBlockFields
import org.move.lang.core.psi.MvCodeBlock
import org.move.lang.core.psi.MvEnumBody
import org.move.lang.core.psi.MvModule
import org.move.lang.core.psi.MvType

sealed class MvContextType(presentableName: String): TemplateContextType(presentableName) {

Expand Down Expand Up @@ -40,13 +43,22 @@ sealed class MvContextType(presentableName: String): TemplateContextType(present
override fun isInContext(element: PsiElement): Boolean = owner(element) is MvModule
}

class Block: MvContextType("Block") {
class Block: MvContextType("Code block") {
override fun isInContext(element: PsiElement): Boolean = owner(element) is MvCodeBlock
}

class Type: MvContextType("Type") {
override fun isInContext(element: PsiElement): Boolean = owner(element) is MvType
}

companion object {
private fun owner(element: PsiElement): PsiElement? = PsiTreeUtil.findFirstParent(element) {
it is MvCodeBlock || it is MvModule || it is PsiFile
it is MvCodeBlock
|| it is MvModule
|| it is PsiFile
|| it is MvType
// filter out enum/struct body
|| it is MvEnumBody || it is MvBlockFields
}
}
}
13 changes: 7 additions & 6 deletions src/main/kotlin/org/move/lang/core/MvPsiPattern.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ object MvPsiPattern {
typeParameter()
.afterLeafSkipping(
whitespaceAndErrors(),
PlatformPatterns.psiElement(COLON),
psiElement(COLON),
)

fun ability(): PsiElementPattern.Capture<PsiElement> = psiElementWithParent<MvAbility>()

fun path(): PsiElementPattern.Capture<PsiElement> = psiElementWithParent<MvPath>()

fun refExpr(): PsiElementPattern.Capture<PsiElement> =
fun pathExpr(): PsiElementPattern.Capture<PsiElement> =
path()
.withSuperParent(2, MvPathExpr::class.java)

Expand Down Expand Up @@ -109,8 +109,9 @@ object MvPsiPattern {

inline fun <reified I: PsiElement> psiElementWithParent() =
psiElement()
.withParent(or(psiElement<I>(), psiElement<PsiErrorElement>().withParent(psiElement<I>()))
)
.withParent(
or(psiElement<I>(), psiElement<PsiErrorElement>().withParent(psiElement<I>()))
)

inline fun <reified I: PsiElement> psiElementAfterSiblingSkipping(
skip: ElementPattern<*>,
Expand All @@ -132,7 +133,7 @@ object MvPsiPattern {
val simplePathPattern: PsiElementPattern.Capture<PsiElement>
get() {
val simplePath = psiElement<MvPath>()
.with(object : PatternCondition<MvPath>("SimplePath") {
.with(object: PatternCondition<MvPath>("SimplePath") {
override fun accepts(path: MvPath, context: ProcessingContext?): Boolean =
path.pathAddress == null &&
path.path == null &&
Expand Down Expand Up @@ -224,7 +225,7 @@ private val PsiElement.prevVisibleOrNewLine: PsiElement?
}

inline fun <reified I: PsiElement> psiElement(): PsiElementPattern.Capture<I> {
return PlatformPatterns.psiElement(I::class.java)
return psiElement(I::class.java)
}

inline fun <reified I: PsiElement> PsiElementPattern.Capture<PsiElement>.withParent(): PsiElementPattern.Capture<PsiElement> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ fun MvNamedElement.getLookupElementBuilder2(
.withTypeText(this.containingFile?.name)

is MvStruct -> {
val tailText = if (completionCtx.structAsType) "" else " { ... }"
base
.withTailText(tailText)
val tailText = this.tupleFields?.let {
it.tupleFieldDeclList
.joinToString(", ", "(", ")") { it.type.text }
}
base.withTailText(tailText)
.withTypeText(this.containingFile?.name)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.editor.EditorModificationUtil
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import org.move.lang.MvElementTypes
import org.move.lang.MvElementTypes.COLON_COLON
import org.move.lang.core.MvPsiPattern
import org.move.lang.core.completion.MACRO_PRIORITY
import org.move.lang.core.psi.MvPath

object AssertMacroCompletionProvider : MvCompletionProvider() {
object AssertMacroCompletionProvider: MvCompletionProvider() {
override val elementPattern: ElementPattern<out PsiElement>
get() = MvPsiPattern.path()
.andNot(MvPsiPattern.pathType())
.andNot(MvPsiPattern.schemaLit())
get() = MvPsiPattern.pathExpr()
.andNot(
PlatformPatterns.psiElement()
.afterLeaf(PlatformPatterns.psiElement(MvElementTypes.COLON_COLON))
psiElement().afterLeaf(psiElement(COLON_COLON))
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.editor.EditorModificationUtil
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import org.move.lang.MvElementTypes
import org.move.lang.MvElementTypes.COLON_COLON
import org.move.lang.core.MvPsiPattern
import org.move.lang.core.completion.VECTOR_LITERAL_PRIORITY
import org.move.lang.core.completion.withPriority
import org.move.lang.core.psi.MvPath

object VectorLiteralCompletionProvider : MvCompletionProvider() {

override val elementPattern: ElementPattern<out PsiElement>
get() = MvPsiPattern.path()
.andNot(MvPsiPattern.pathType())
.andNot(MvPsiPattern.schemaLit())
get() = MvPsiPattern.pathExpr()
.andNot(
PlatformPatterns.psiElement()
.afterLeaf(PlatformPatterns.psiElement(MvElementTypes.COLON_COLON))
psiElement().afterLeaf(psiElement(COLON_COLON))
)


Expand All @@ -41,7 +42,8 @@ object VectorLiteralCompletionProvider : MvCompletionProvider() {
.withInsertHandler { ctx, _ ->
EditorModificationUtil.moveCaretRelatively(ctx.editor, -1)
}
result.addElement(PrioritizedLookupElement.withPriority(lookupElement, VECTOR_LITERAL_PRIORITY))
.withPriority(VECTOR_LITERAL_PRIORITY)
result.addElement(lookupElement)
}

}
3 changes: 2 additions & 1 deletion src/main/kotlin/org/move/utils/SignatureUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ object SignatureUtils {
}
append(")")
}
}
}

4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@
implementation="org.move.ide.liveTemplates.MvContextType$Block"
contextId="MOVE_BLOCK"
baseContextId="MOVE_FILE" />
<liveTemplateContext
implementation="org.move.ide.liveTemplates.MvContextType$Type"
contextId="MOVE_TYPE"
baseContextId="MOVE_FILE" />

<renamePsiElementProcessor implementation="org.move.ide.refactoring.MvRenameProcessor"
order="first"
Expand Down
64 changes: 64 additions & 0 deletions src/test/kotlin/org/move/ide/liveTemplates/MvLiveTemplatesTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.move.ide.liveTemplates

import com.intellij.openapi.actionSystem.IdeActions
import org.intellij.lang.annotations.Language
import org.move.utils.tests.MvTestBase

class MvLiveTemplatesTest: MvTestBase() {

fun `test no test function in type`() = noSnippet("""
module 0x1::m {
struct S { val: t/*caret*/}
}
""")

fun `test no test function in struct fields block`() = noSnippet("""
module 0x1::m {
struct S { t/*caret*/ }
}
""")

fun `test no test function in enum variants block`() = noSnippet("""
module 0x1::m {
enum S { t/*caret*/ }
}
""")

fun `test no test function in tuple struct type`() = noSnippet("""
module 0x1::m {
struct S(u8, t/*caret*/)
}
""")

fun `test no test function in expr`() = noSnippet("""
module 0x1::m {
fun main() {
t/*caret*/
}
}
""")

fun `test no test function outside module`() = noSnippet("""
t/*caret*/
module 0x1::m {
}
""")

fun `test test function in module body`() = expandSnippet("""
module 0x1::m {
t/*caret*/
}
""", """
module 0x1::m {
#[test]
fun /*caret*/() {

}
}
""")

private fun expandSnippet(@Language("Move") before: String, @Language("Move") after: String) =
checkEditorAction(before, after, IdeActions.ACTION_EXPAND_LIVE_TEMPLATE_BY_TAB)

private fun noSnippet(@Language("Move") code: String) = expandSnippet(code, code)
}
51 changes: 51 additions & 0 deletions src/test/kotlin/org/move/lang/completion/BuiltInsCompletionTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,57 @@ class BuiltInsCompletionTest : CompletionTestCase() {
}
""")

fun `test no vector completion in use`() = checkNoCompletion("""
module 0x1::m {
use vec/*caret*/
}
""")

fun `test no vector completion in fq path`() = checkNoCompletion("""
module 0x1::m {
fun main() {
aptos::vec/*caret*/
}
}
""")

fun `test no vector lit in path qualifier`() = checkNoCompletion("""
module 0x1::m {
fun main() {
vec/*caret*/::call();
}
}
""")

fun `test no assert! in use`() = checkNoCompletion("""
module 0x1::m {
use ass/*caret*/
}
""")

fun `test no assert! in fq path`() = checkNoCompletion("""
module 0x1::m {
fun main() {
aptos_framework::aptos::ass/*caret*/
}
}
""")

fun `test no assert! in path qualifier`() = checkNoCompletion("""
module 0x1::m {
fun main() {
ass/*caret*/::call();
}
}
""")

fun `test no assert! in type`() = checkNoCompletion("""
module 0x1::m {
fun main(s: ass/*caret*/) {
}
}
""")

private fun checkContainsBuiltins(@Language("Move") text: String) {
val functionNames = BUILTIN_FUNCTIONS
for (name in functionNames) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class LookupElementTest: MvTestBase() {
struct MyStruct { val: u8 }
//^
}
""", tailText = " { ... }", typeText = "main.move"
""", typeText = "main.move"
)

fun `test module`() = checkNamedItem(
Expand Down Expand Up @@ -169,26 +169,13 @@ class LookupElementTest: MvTestBase() {
}
""", typeText = "u8"
)
//
// fun `test import module lookup`() = checkNamedItem("""
// module 0x1::m {
// public fun identity(a: u8): u8 { a }
// }
// module 0x1::main {
// use 0x1::m;
// //^
// }
// """, tailText = " 0x1", typeText = "main.move")

// fun `test import function lookup`() = checkNamedItem("""
// module 0x1::m {
// public fun identity(a: u8): u8 { a }
// }
// module 0x1::main {
// use 0x1::m::identity;
// //^
// }
// """, tailText = "(a: u8): u8", typeText = "main.move")
fun `test lookup for tuple struct`() = checkNamedItem("""
module 0x1::m {
struct SS(u8, u16);
//^
}
""", tailText = "(u8, u16)", typeText = "main.move")

private fun checkNamedItem(
@Language("Move") code: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.move.utils.tests.completion

import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.elementType
import com.intellij.psi.util.prevLeaf
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import com.intellij.testFramework.fixtures.impl.BaseFixture
import org.intellij.lang.annotations.Language
import org.move.lang.MvElementTypes
import org.move.utils.tests.InlineFile
import org.move.utils.tests.hasCaretMarker
import org.move.utils.tests.replaceCaretMarker
Expand Down Expand Up @@ -55,7 +59,16 @@ class MvCompletionTestFixture(
val lookups = myFixture.completeBasic()
checkNotNull(lookups) {
val element = myFixture.file.findElementAt(myFixture.caretOffset - 1)
"Expected zero completions, but one completion was auto inserted: `${element?.text}`."
// handle assert!()
var elementText = element?.text
if (element != null) {
if (element.prevSibling.elementType == MvElementTypes.EXCL) {
// IDENTIFIER + ! + (
elementText =
element.prevSibling.prevSibling.text + element.prevSibling.text + elementText
}
}
"Expected zero completions, but one completion was auto inserted: `$elementText`."
}
check(lookups.isEmpty()) {
"Expected zero completions, got ${lookups.map { it.lookupString }}."
Expand Down