Skip to content

Commit

Permalink
improve hover feature
Browse files Browse the repository at this point in the history
  • Loading branch information
stackoverflow committed Jun 11, 2024
1 parent 6f935f0 commit 64a8e32
Show file tree
Hide file tree
Showing 19 changed files with 278 additions and 135 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ktfmt = "0.44"
# replaces nuValidator's log4j dependency
# something related to log4j-1.2-api is apparently broken in 2.17.2
log4j = "2.17.1"
lsp4j = "0.22.0"
lsp4j = "0.23.1"
msgpack = "0.9.0"
nexusPublishPlugin = "1.3.0"
nuValidator = "20.+"
Expand Down
4 changes: 2 additions & 2 deletions pkl-lsp/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ net.bytebuddy:byte-buddy:1.14.11=testCompileClasspath,testImplementationDependen
net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.25.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.22.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.lsp4j:org.eclipse.lsp4j:0.22.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.23.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.lsp4j:org.eclipse.lsp4j:0.23.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:22.3.3=runtimeClasspath,testRuntimeClasspath
org.graalvm.truffle:truffle-api:22.3.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
Expand Down
4 changes: 2 additions & 2 deletions pkl-lsp/src/main/kotlin/org/pkl/lsp/PklVisitor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -360,15 +360,15 @@ open class PklVisitor<R> : NodeVisitor() {
return visitModuleMember(o)
}

open fun visitTypeAliasHeader(o: TypeAliasHeader): R? {
open fun visitTypeAliasHeader(o: PklTypeAliasHeader): R? {
return visitModifierListOwner(o)
}

open fun visitTypeAnnotation(o: PklTypeAnnotation): R? {
return visitElement(o)
}

open fun visitTypeArgumentList(o: TypeArgumentList): R? {
open fun visitTypeArgumentList(o: PklTypeArgumentList): R? {
return visitElement(o)
}

Expand Down
2 changes: 1 addition & 1 deletion pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/Basic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class PklQualifiedIdentifierImpl(
override val ctx: QualifiedIdentifierContext
) : AbstractNode(parent, ctx), PklQualifiedIdentifier {
override val identifiers: List<Terminal> by lazy { terminals }
override val fullName: String by lazy { identifiers.joinToString(".") { it.text } }
override val fullName: String by lazy { text }

override fun <R> accept(visitor: PklVisitor<R>): R? {
return visitor.visitQualifiedIdentifier(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class ClassMemberCache(
val name = member.name
// record [member] if it (re)defines a property;
// don't record [member] if it amends/overrides a property defined in a superclass.
if (member.typeAnnotation?.pklType != null || properties[name] == null) {
if (member.typeAnnotation?.type != null || properties[name] == null) {
properties[name] = member
}
leafProperties[name] = member
Expand Down
2 changes: 1 addition & 1 deletion pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/Expr.kt
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ class PklParameterImpl(override val parent: Node, override val ctx: ParameterCon
override val typedIdentifier: PklTypedIdentifier? by lazy {
children.firstInstanceOf<PklTypedIdentifier>()
}
override val type: PklType? by lazy { typedIdentifier?.typeAnnotation?.pklType }
override val type: PklType? by lazy { typedIdentifier?.typeAnnotation?.type }

override fun <R> accept(visitor: PklVisitor<R>): R? {
return visitor.visitParameter(this)
Expand Down
88 changes: 11 additions & 77 deletions pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,12 @@ package org.pkl.lsp.ast

import java.io.File
import kotlin.io.path.invariantSeparatorsPathString
import org.pkl.lsp.PklBaseModule
import org.pkl.lsp.PklLSPServer
import org.pkl.lsp.inferImportPropertyName
import org.pkl.lsp.*
import org.pkl.lsp.resolvers.ResolveVisitors
import org.pkl.lsp.resolvers.Resolvers
import org.pkl.lsp.type.Type
import org.pkl.lsp.type.TypeParameterBindings
import org.pkl.lsp.type.computeResolvedImportType
import org.pkl.lsp.unexpectedType

val PklClass.supertype: PklType?
get() = classHeader.extends
Expand Down Expand Up @@ -79,6 +76,15 @@ fun SimpleTypeName.resolve(): Node? {
)
}

fun Node.isAncestor(of: Node): Boolean {
var node = of.parent
while (node != null) {
if (this == node) return true
node = node.parent
}
return false
}

fun PklClass.isSubclassOf(other: PklClass): Boolean {
// optimization
if (this === other) return true
Expand Down Expand Up @@ -319,84 +325,12 @@ fun Node.findBySpan(line: Int, col: Int, includeTerminals: Boolean = false): Nod
return childHit ?: hit
}

fun Node.toMarkdown(): String {
val markdown = render()
return showDocCommentAndModule(this, markdown)
}

fun Node.render(): String =
when (this) {
is PklProperty -> {
val modifiers = modifiers.render()
"$modifiers$name: ${type?.render() ?: "unknown"}"
}
is PklStringLiteralType -> "\"$text\""
is PklMethod -> {
val modifiers = modifiers.render()
modifiers + methodHeader.render()
}
is PklMethodHeader -> {
val name = identifier?.text ?: "???"
val typePars = typeParameterList?.render() ?: ""
val pars = parameterList?.render() ?: "()"
val retType = returnType?.render()?.let { ": $it" } ?: ""
"$name$typePars$pars$retType"
}
is PklParameterList -> {
elements.joinToString(", ", prefix = "(", postfix = ")") { it.render() }
}
is PklTypeParameterList -> {
typeParameters.joinToString(", ", prefix = "<", postfix = ">") { it.render() }
}
is PklParameter ->
if (isUnderscore) {
"_"
} else {
// cannot be null here if it's not underscore
typedIdentifier!!.render()
}
is PklTypeAnnotation -> ": ${pklType!!.render()}"
is PklTypedIdentifier -> {
val name = identifier!!.text
typeAnnotation?.let { "$name${it.render()}" } ?: name
}
is PklTypeParameter -> {
val vari = variance?.name?.lowercase()?.let { "$it " } ?: ""
"$vari$name"
}
is PklClass -> {
val modifiers = modifiers.render()
val name = classHeader.identifier?.text ?: "???"
"$modifiers$name"
}
is PklModuleDeclaration -> {
val modifiers = modifiers.render()
// can never be null
val idents = moduleHeader!!.qualifiedIdentifier!!.render()
"${modifiers}module $idents"
}
is PklQualifiedIdentifier -> identifiers.joinToString(".") { it.text }
else -> text
}

// render modifiers
private fun List<Terminal>?.render(): String {
return this?.let { if (isEmpty()) "" else joinToString(" ", postfix = " ") { it.text } } ?: ""
}

private fun showDocCommentAndModule(node: Node, text: String): String {
val markdown = "```pkl\n$text\n```"
return if (node is PklDocCommentOwner) {
node.parsedComment?.let { "$markdown\n\n---\n\n$it" } ?: markdown
} else markdown
}

fun Node.toURIString(server: PklLSPServer): String {
val mod = if (this is PklModule) this else enclosingModule!!
val uri = mod.uri.toString()
return if (uri.startsWith("pkl:")) {
val name = uri.replace("pkl:", "")
val uriStr = server.stdlibDir.resolve("$name.pkl").invariantSeparatorsPathString
"pkl:$uriStr"
"pkl://$uriStr"
} else uri
}
9 changes: 5 additions & 4 deletions pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/Member.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class PklClassPropertyImpl(override val parent: Node, override val ctx: ClassPro

override val name: String by lazy { ctx.Identifier().text }

override val type: PklType? by lazy { typeAnnotation?.pklType }
override val type: PklType? by lazy { typeAnnotation?.type }

override val isDefinition: Boolean by lazy { expr != null }

Expand Down Expand Up @@ -79,9 +79,7 @@ class PklMethodHeaderImpl(override val parent: Node, override val ctx: MethodHea

override val identifier: Terminal? by lazy { terminals.find { it.type == TokenType.Identifier } }

override val returnType: PklType? by lazy {
children.firstInstanceOf<PklTypeAnnotation>()?.pklType
}
override val returnType: PklType? by lazy { children.firstInstanceOf<PklTypeAnnotation>()?.type }

override fun <R> accept(visitor: PklVisitor<R>): R? {
return visitor.visitMethodHeader(this)
Expand Down Expand Up @@ -128,6 +126,9 @@ class PklObjectPropertyImpl(override val parent: Node, override val ctx: ObjectP
override val type: PklType? = null
override val expr: PklExpr? by lazy { children.firstInstanceOf<PklExpr>() }
override val isDefinition: Boolean by lazy { expr != null }
override val typeAnnotation: PklTypeAnnotation? by lazy {
children.firstInstanceOf<PklTypeAnnotation>()
}

override fun <R> accept(visitor: PklVisitor<R>): R? {
return visitor.visitObjectProperty(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ private constructor(
val name = member.name
// record [member] if it (re)defines a property;
// don't record [member] if it amends/overrides a property defined in a supermodule.
if (member.typeAnnotation?.pklType != null || properties[name] == null) {
if (member.typeAnnotation?.type != null || properties[name] == null) {
properties[name] = member
typesAndProperties[name] = member
}
Expand Down
2 changes: 1 addition & 1 deletion pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/ModuleOrClass.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class PklModuleImpl(override val ctx: PklParser.ModuleContext, override val uri:

// TODO: fix uri name
override val moduleName: String? by lazy {
declaration?.moduleHeader?.shortDisplayName ?: uri.toString()
declaration?.moduleHeader?.moduleName ?: uri.toString()
}

override fun <R> accept(visitor: PklVisitor<R>): R? {
Expand Down
28 changes: 19 additions & 9 deletions pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/Node.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ interface PklDocCommentOwner : Node {
val parsedComment: String?
get() {
val doc = docComment?.text?.trim() ?: return null
return doc.lines().joinToString("\n") { it.removePrefix("///") }.trimIndent()
return doc.lines().joinToString("\n") { it.trimStart().removePrefix("///") }.trimIndent()
}
}

Expand Down Expand Up @@ -222,11 +222,10 @@ sealed interface PklProperty : PklNavigableElement, ModifierListOwner, Identifie
val type: PklType?
val expr: PklExpr?
val isDefinition: Boolean
val typeAnnotation: PklTypeAnnotation?
}

interface PklClassProperty : PklProperty, PklModuleMember, PklClassMember, PklTypeDefOrProperty {
val typeAnnotation: PklTypeAnnotation?

val objectBody: PklObjectBody?
}

Expand Down Expand Up @@ -315,12 +314,12 @@ interface PklParameterList : Node {
}

interface PklTypeAlias : PklTypeDef {
val typeAliasHeader: TypeAliasHeader
val typeAliasHeader: PklTypeAliasHeader
val type: PklType
val isRecursive: Boolean
}

interface TypeAliasHeader : IdentifierOwner, ModifierListOwner {
interface PklTypeAliasHeader : IdentifierOwner, ModifierListOwner {
val typeParameterList: PklTypeParameterList?
}

Expand Down Expand Up @@ -512,7 +511,7 @@ interface PklParenthesizedExpr : PklExpr {
}

interface PklTypeAnnotation : Node {
val pklType: PklType?
val type: PklType?
}

interface PklTypedIdentifier : PklNavigableElement, IdentifierOwner {
Expand Down Expand Up @@ -543,10 +542,10 @@ interface PklStringLiteralType : PklType {

interface PklDeclaredType : PklType {
val name: PklTypeName
val typeArgumentList: TypeArgumentList?
val typeArgumentList: PklTypeArgumentList?
}

interface TypeArgumentList : Node {
interface PklTypeArgumentList : Node {
val types: List<PklType>
}

Expand Down Expand Up @@ -638,6 +637,15 @@ abstract class AbstractNode(override val parent: Node?, protected open val ctx:
override val children: List<Node> by lazy { childrenByType.values.flatten() }

override val text: String by lazy { ctx.text }

// Two nodes are the same if their contexts are the same object
override fun equals(other: Any?): Boolean {
return when (other) {
null -> false
is AbstractNode -> ctx === other.ctx
else -> false
}
}
}

fun List<ParseTree>.toNode(parent: Node?, idx: Int): Node? {
Expand All @@ -649,6 +657,7 @@ fun ParseTree.toNode(parent: Node?): Node? {
// a module can never be constructed from this function
// is ModuleContext -> PklModuleImpl(this)
is ModuleDeclContext -> PklModuleDeclarationImpl(parent!!, this)
is ModuleHeaderContext -> PklModuleHeaderImpl(parent!!, this)
is ImportClauseContext -> PklImportImpl(parent!!, this)
is ModuleExtendsOrAmendsClauseContext -> PklModuleExtendsAmendsClauseImpl(parent!!, this)
is ClazzContext -> PklClassImpl(parent!!, this)
Expand All @@ -674,6 +683,7 @@ fun ParseTree.toNode(parent: Node?): Node? {
is UnionTypeContext -> PklUnionTypeImpl(parent!!, this)
is DefaultUnionTypeContext -> PklDefaultUnionTypeImpl(parent!!, this)
is FunctionTypeContext -> PklFunctionTypeImpl(parent!!, this)
is TypeArgumentListContext -> PklTypeArgumentListImpl(parent!!, this)
is ThisExprContext -> PklThisExprImpl(parent!!, this)
is OuterExprContext -> PklOuterExprImpl(parent!!, this)
is ModuleExprContext -> PklModuleExprImpl(parent!!, this)
Expand Down Expand Up @@ -727,7 +737,7 @@ fun ParseTree.toNode(parent: Node?): Node? {
is ObjectSpreadContext -> PklObjectSpreadImpl(parent!!, this)
is TypeParameterContext -> PklTypeParameterImpl(parent!!, this)
is TypeParameterListContext -> PklTypeParameterListImpl(parent!!, this)
is TypeAliasHeaderContext -> TypeAliasHeaderImpl(parent!!, this)
is TypeAliasHeaderContext -> PklTypeAliasHeaderImpl(parent!!, this)
is TypeAliasContext -> PklTypeAliasImpl(parent!!, this)
// is TypeAnnotationContext -> Ty
// treat modifiers as terminals; matches how we do it in pkl-intellij
Expand Down
18 changes: 9 additions & 9 deletions pkl-lsp/src/main/kotlin/org/pkl/lsp/ast/Type.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.pkl.lsp.PklVisitor

class PklTypeAnnotationImpl(override val parent: Node, ctx: TypeAnnotationContext) :
AbstractNode(parent, ctx), PklTypeAnnotation {
override val pklType: PklType? by lazy { children.firstInstanceOf<PklType>() }
override val type: PklType? by lazy { children.firstInstanceOf<PklType>() }

override fun <R> accept(visitor: PklVisitor<R>): R? {
return visitor.visitTypeAnnotation(this)
Expand Down Expand Up @@ -67,8 +67,8 @@ class PklDeclaredTypeImpl(override val parent: Node, override val ctx: DeclaredT
toTypeName(children.firstInstanceOf<PklQualifiedIdentifier>()!!)
}

override val typeArgumentList: TypeArgumentList? by lazy {
children.firstInstanceOf<TypeArgumentList>()
override val typeArgumentList: PklTypeArgumentList? by lazy {
children.firstInstanceOf<PklTypeArgumentList>()
}

private fun toTypeName(ident: PklQualifiedIdentifier): PklTypeName {
Expand All @@ -80,8 +80,8 @@ class PklDeclaredTypeImpl(override val parent: Node, override val ctx: DeclaredT
}
}

class TypeArgumentListImpl(override val parent: Node, ctx: TypeArgumentListContext) :
AbstractNode(parent, ctx), TypeArgumentList {
class PklTypeArgumentListImpl(override val parent: Node, ctx: TypeArgumentListContext) :
AbstractNode(parent, ctx), PklTypeArgumentList {
override val types: List<PklType> by lazy { children.filterIsInstance<PklType>() }

override fun <R> accept(visitor: PklVisitor<R>): R? {
Expand Down Expand Up @@ -151,8 +151,8 @@ class PklDefaultUnionTypeImpl(override val parent: Node, ctx: DefaultUnionTypeCo

class PklTypeAliasImpl(override val parent: Node?, ctx: TypeAliasContext) :
AbstractNode(parent, ctx), PklTypeAlias {
override val typeAliasHeader: TypeAliasHeader by lazy {
children.firstInstanceOf<TypeAliasHeader>()!!
override val typeAliasHeader: PklTypeAliasHeader by lazy {
children.firstInstanceOf<PklTypeAliasHeader>()!!
}
override val modifiers: List<Terminal>? by lazy { typeAliasHeader.modifiers }
override val name: String by lazy { ctx.typeAliasHeader().Identifier().text }
Expand All @@ -167,8 +167,8 @@ class PklTypeAliasImpl(override val parent: Node?, ctx: TypeAliasContext) :
}
}

class TypeAliasHeaderImpl(override val parent: Node?, ctx: TypeAliasHeaderContext) :
AbstractNode(parent, ctx), TypeAliasHeader {
class PklTypeAliasHeaderImpl(override val parent: Node?, ctx: TypeAliasHeaderContext) :
AbstractNode(parent, ctx), PklTypeAliasHeader {
override val modifiers: List<Terminal>? by lazy { terminals.takeWhile { it.isModifier } }
override val identifier: Terminal? by lazy { terminals.find { it.type == TokenType.Identifier } }
override val typeParameterList: PklTypeParameterList? by lazy {
Expand Down
Loading

0 comments on commit 64a8e32

Please sign in to comment.