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

@examples trait for completions #339

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
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 */
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: a proper solution for this would probably be to type-match the encoded InputNode against a struct node, then format it using FormattingVisitor, with a new method suited specifically to structs.

.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