Skip to content

Commit

Permalink
WIP: @examples trait for completions
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz committed Sep 29, 2023
1 parent ef8880e commit 76f2673
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 8 deletions.
22 changes: 22 additions & 0 deletions modules/core/src/test/smithy/demo.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,28 @@ operation GetVersion {
@documentation("""
Create a hero.
""")
@examples([{
title: "Valid input"
documentation: "This is a valid input"
input: {
hero: {
good: {
howGood: 10
}
}
}
}, {
title: "Valid input v2"
documentation: "This is also a valid input, but for a bad hero"
input: {
hero: {
bad: {
evilName: "Evil"
powerLevel: 10
}
}
}
}])
operation CreateHero {
input: CreateHeroInput
output: CreateHeroOutput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import playground.smithyql.SourceFile
import playground.smithyql.WithSource
import playground.smithyql.parser.SourceParser
import playground.smithyql.syntax._
import smithy.api.Examples
import smithy4s.Hints
import smithy4s.dynamic.DynamicSchemaIndex

trait CompletionProvider {
Expand Down Expand Up @@ -103,7 +105,12 @@ object CompletionProvider {
.service
.endpoints
.map { endpoint =>
OperationName[Id](endpoint.name) -> endpoint.input.compile(CompletionVisitor)
OperationName[Id](endpoint.name) -> endpoint
.input
.addHints(
endpoint.hints.get(Examples).map(Hints(_)).getOrElse(Hints.empty)
)
.compile(CompletionVisitor)
}
.toMap
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package playground.language
import cats.Id
import cats.implicits._
import cats.kernel.Eq
import playground.NodeEncoder
import playground.ServiceNameExtractor
import playground.TextUtils
import playground.language.CompletionItem.InsertUseClause.NotRequired
import playground.language.CompletionItem.InsertUseClause.Required
import playground.smithyql.InputNode
import playground.smithyql.NodeContext
import playground.smithyql.NodeContext.EmptyPath
import playground.smithyql.NodeContext.PathEntry
Expand All @@ -23,6 +25,7 @@ import playground.smithyql.WithSource
import playground.smithyql.format.Formatter
import smithy.api
import smithy4s.Bijection
import smithy4s.Document
import smithy4s.Endpoint
import smithy4s.Hints
import smithy4s.Lazy
Expand Down Expand Up @@ -145,15 +148,17 @@ object CompletionItem {
label: String,
insertText: InsertText,
schema: Schema[_],
sortTextOverride: Option[String] = None,
): CompletionItem = {
val isField = kind === CompletionItemKind.Field

val sortText =
val sortText = sortTextOverride.orElse {
isField match {
case true if isRequiredField(schema) => Some(s"1_$label")
case true => Some(s"2_$label")
case false => None
}
}

CompletionItem(
kind = kind,
Expand Down Expand Up @@ -530,15 +535,55 @@ object CompletionVisitor extends SchemaVisitor[CompletionResolver] {
fields: Vector[SchemaField[S, _]],
make: IndexedSeq[Any] => S,
): CompletionResolver[S] = {
// Artificial schema resembling this one. Should be pretty much equivalent.
val schema = Schema.struct(fields)(make).addHints(hints).withId(shapeId)
val documentDecoder = Document.Decoder.fromSchema(schema)

val nodeEncoder = NodeEncoder.derive(schema)

val compiledFields = fields.map(field => (field.mapK(this), field.instance))

/* todo: pass this outside of Hints? (visitor context?) */
val examples = hints
.get(api.Examples)
.foldMap(_.value)
.zipWithIndex
.map { case (example, index) =>
val name = example.title
val doc = example.documentation

val text = Formatter[InputNode]
.format(
nodeEncoder
.toNode(documentDecoder.decode(example.input.get).toTry.get /* todo: be graceful */ )
.mapK(WithSource.liftId),
Int.MaxValue,
)
.trim()
.tail
.init /* HACK: trim opening/closing braces */
.trim()

CompletionItem.fromHints(
kind = CompletionItemKind.Constant /* todo */,
label = s"Example: $name",
insertText = InsertText.JustString(text),
// issue: this doesn't work if the schema already has a Documentation hint. We should remove it first, or do something else.
schema = schema.addHints(
doc.map(api.Documentation(_)).map(Hints(_)).getOrElse(Hints.empty)
),
sortTextOverride = Some(s"0_$index"),
)
}

structLike(
inBody =
fields
// todo: filter out present fields
.sortBy(field => (field.isRequired, field.label))
.map(CompletionItem.fromField)
.toList,
examples ++
fields
// todo: filter out present fields
.sortBy(field => (field.isRequired, field.label))
.map(CompletionItem.fromField)
.toList,
inValue =
(
h,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ object SimpleHttpBuilder {
service: Service[Alg],
backend: Client[F],
): Either[UnsupportedProtocolError, FunctorAlgebra[Alg, F]] =
builder(service).client(backend).use
builder(service).client(backend).make

}

Expand Down

0 comments on commit 76f2673

Please sign in to comment.