diff --git a/src/main/scala/io/smartdatalake/completion/SDLBCompletionEngineImpl.scala b/src/main/scala/io/smartdatalake/completion/SDLBCompletionEngineImpl.scala index bf93edc..da7f558 100644 --- a/src/main/scala/io/smartdatalake/completion/SDLBCompletionEngineImpl.scala +++ b/src/main/scala/io/smartdatalake/completion/SDLBCompletionEngineImpl.scala @@ -1,8 +1,8 @@ package io.smartdatalake.completion import io.smartdatalake.completion.SDLBCompletionEngine -import io.smartdatalake.completion.schema.{ItemType, SchemaItem, SchemaReader, SchemaReaderImpl} import io.smartdatalake.context.SDLBContext +import io.smartdatalake.schema.{ItemType, SchemaItem, SchemaReader, SchemaReaderImpl} import org.eclipse.lsp4j.{CompletionItem, CompletionItemKind} import scala.util.{Failure, Success, Try} diff --git a/src/main/scala/io/smartdatalake/context/SDLBContext.scala b/src/main/scala/io/smartdatalake/context/SDLBContext.scala index 6271afe..12be5cb 100644 --- a/src/main/scala/io/smartdatalake/context/SDLBContext.scala +++ b/src/main/scala/io/smartdatalake/context/SDLBContext.scala @@ -6,7 +6,7 @@ import io.smartdatalake.context.TextContext.EMPTY_TEXT_CONTEXT import io.smartdatalake.context.hocon.HoconParser import io.smartdatalake.utils.MultiLineTransformer -case class SDLBContext private(textContext: TextContext, parentPath: String, parentWord: String) { +case class SDLBContext private(textContext: TextContext, parentPath: String, parentWord: String, word: String) { def withText(newText: String): SDLBContext = copy(textContext = textContext.update(newText)) @@ -14,9 +14,10 @@ case class SDLBContext private(textContext: TextContext, parentPath: String, par val TextContext(originalText, configText, config) = textContext if originalLine <= 0 || originalLine > originalText.count(_ == '\n') + 1 || originalCol < 0 then this else val (newLine, newCol) = MultiLineTransformer.computeCorrectedPosition(originalText, originalLine, originalCol) - val (parentLine, word) = HoconParser.retrieveDirectParent(configText, newLine, newCol) + val word = HoconParser.retrieveWordAtPosition(configText, newLine, newCol) + val (parentLine, parentWord) = HoconParser.retrieveDirectParent(configText, newLine, newCol) val path = HoconParser.retrievePath(config, parentLine) - copy(parentPath = path, parentWord = word) + copy(parentPath = path, parentWord = parentWord, word = word) //TODO keep that method? @@ -26,9 +27,9 @@ case class SDLBContext private(textContext: TextContext, parentPath: String, par } object SDLBContext { - val EMPTY_CONTEXT: SDLBContext = SDLBContext(EMPTY_TEXT_CONTEXT, "", "") + val EMPTY_CONTEXT: SDLBContext = SDLBContext(EMPTY_TEXT_CONTEXT, "", "", "") - def fromText(originalText: String): SDLBContext = SDLBContext(TextContext.create(originalText), "", "") + def fromText(originalText: String): SDLBContext = SDLBContext(TextContext.create(originalText), "", "", "") } diff --git a/src/main/scala/io/smartdatalake/context/hocon/HoconParser.scala b/src/main/scala/io/smartdatalake/context/hocon/HoconParser.scala index dfe0d24..5c65e86 100644 --- a/src/main/scala/io/smartdatalake/context/hocon/HoconParser.scala +++ b/src/main/scala/io/smartdatalake/context/hocon/HoconParser.scala @@ -5,6 +5,7 @@ import io.smartdatalake.utils.MultiLineTransformer.{computeCorrectedPosition, fl import scala.annotation.tailrec import scala.util.{Try, Success, Failure} +import io.smartdatalake.context.hocon.{HoconTokens => Token} /** * Utility class to parse HOCON-formatted files @@ -60,7 +61,6 @@ private[context] object HoconParser: * @return The direct parent */ def retrieveDirectParent(text: String, line: Int, column: Int): (Int, String) = - import io.smartdatalake.context.hocon.{HoconTokens => Token} @tailrec /* @@ -88,3 +88,24 @@ private[context] object HoconParser: else retrieveHelper(line-1, 0) + + def retrieveWordAtPosition(text: String, line: Int, col: Int): String = + def getWordAtIndex(textLine: String, index: Int): String = + val (leftPart, rightPart) = textLine.splitAt(index) + val leftPossibleIndex = leftPart.lastIndexOf(" ") + val leftIndex = if leftPossibleIndex == -1 then 0 else leftPossibleIndex + val rightPossibleIndex = rightPart.indexOf(" ") + val rightIndex = if rightPossibleIndex == -1 then textLine.length - 2 else index + rightPossibleIndex + textLine.substring(leftIndex, rightIndex).trim + + val textLine = text.split(Token.NEW_LINE)(line-1) + " " + val column = math.min(textLine.length-1, col) + val leadingCharacter = textLine.charAt(column) + column match + case 0 if leadingCharacter.isWhitespace => "" + case _ if leadingCharacter.isWhitespace => + val precedingCharacter = textLine.charAt(column-1) + if precedingCharacter.isWhitespace then "" else getWordAtIndex(textLine, column-1) + + case _ => getWordAtIndex(textLine, column) + diff --git a/src/main/scala/io/smartdatalake/hover/SDLBHoverEngine.scala b/src/main/scala/io/smartdatalake/hover/SDLBHoverEngine.scala new file mode 100644 index 0000000..51515a4 --- /dev/null +++ b/src/main/scala/io/smartdatalake/hover/SDLBHoverEngine.scala @@ -0,0 +1,7 @@ +package io.smartdatalake.hover + +import io.smartdatalake.context.SDLBContext +import org.eclipse.lsp4j.Hover + +trait SDLBHoverEngine: + def generateHoveringInformation(context: SDLBContext): Hover diff --git a/src/main/scala/io/smartdatalake/hover/SDLBHoverEngineImpl.scala b/src/main/scala/io/smartdatalake/hover/SDLBHoverEngineImpl.scala new file mode 100644 index 0000000..e799e62 --- /dev/null +++ b/src/main/scala/io/smartdatalake/hover/SDLBHoverEngineImpl.scala @@ -0,0 +1,28 @@ +package io.smartdatalake.hover +import io.smartdatalake.context.SDLBContext +import io.smartdatalake.schema.{SchemaReader, SchemaReaderImpl} +import org.eclipse.lsp4j.{Hover, MarkupContent, MarkupKind} + +import scala.util.{Failure, Success, Try} + +class SDLBHoverEngineImpl extends SDLBHoverEngine: + + val schemaReader: SchemaReader = new SchemaReaderImpl("sdl-schema/sdl-schema-2.5.0.json") //TODO should be retrieved from a service keeping its state, object for example + + + override def generateHoveringInformation(context: SDLBContext): Hover = + val markupContent = new MarkupContent() + markupContent.setKind(MarkupKind.MARKDOWN) + markupContent.setValue(retrieveSchemaDescription(context)) + new Hover(markupContent) + + private def retrieveSchemaDescription(context: SDLBContext): String = + context.parentPath match + case path if path.startsWith("actions") && path.count(_ == '.') == 1 => + val tActionType: Try[String] = Try(context.textContext.config.getString(context.parentPath + ".type")) + tActionType match + case Success(actionType) => schemaReader.retrieveActionPropertyDescription(actionType, context.word) + case Failure(_) => "" + + case _ => "" + diff --git a/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServer.scala b/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServer.scala index 11ca5b9..a1e02ac 100644 --- a/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServer.scala +++ b/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServer.scala @@ -18,12 +18,15 @@ class SmartDataLakeLanguageServer extends LanguageServer with LanguageClientAwar initializeResult.getCapabilities.setTextDocumentSync(TextDocumentSyncKind.Full) val completionOptions = new CompletionOptions initializeResult.getCapabilities.setCompletionProvider(completionOptions) + + initializeResult.getCapabilities.setHoverProvider(true) + CompletableFuture.supplyAsync(() => initializeResult) } override def shutdown(): CompletableFuture[AnyRef] = { errorCode = 0 - null + CompletableFuture.completedFuture(null) } override def exit(): Unit = System.exit(errorCode) diff --git a/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentService.scala b/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentService.scala index 849d940..3d4fb6b 100644 --- a/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentService.scala +++ b/src/main/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentService.scala @@ -1,10 +1,11 @@ package io.smartdatalake.languageserver -import io.smartdatalake.completion.SDLBCompletionEngineImpl +import io.smartdatalake.completion.{SDLBCompletionEngine, SDLBCompletionEngineImpl} import io.smartdatalake.context.SDLBContext +import io.smartdatalake.hover.{SDLBHoverEngine, SDLBHoverEngineImpl} import org.eclipse.lsp4j.jsonrpc.messages import org.eclipse.lsp4j.services.TextDocumentService -import org.eclipse.lsp4j.{CodeAction, CodeActionParams, CodeLens, CodeLensParams, Command, CompletionItem, CompletionItemKind, CompletionList, CompletionParams, DefinitionParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFormattingParams, DocumentHighlight, DocumentHighlightParams, DocumentOnTypeFormattingParams, DocumentRangeFormattingParams, DocumentSymbol, DocumentSymbolParams, Hover, HoverParams, InsertReplaceEdit, Location, LocationLink, Position, Range, ReferenceParams, RenameParams, SignatureHelp, SignatureHelpParams, SymbolInformation, TextDocumentPositionParams, TextEdit, WorkspaceEdit} +import org.eclipse.lsp4j.{CodeAction, CodeActionParams, CodeLens, CodeLensParams, Command, CompletionItem, CompletionItemKind, CompletionList, CompletionParams, DefinitionParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFormattingParams, DocumentHighlight, DocumentHighlightParams, DocumentOnTypeFormattingParams, DocumentRangeFormattingParams, DocumentSymbol, DocumentSymbolParams, Hover, HoverParams, InsertReplaceEdit, Location, LocationLink, MarkupContent, MarkupKind, Position, Range, ReferenceParams, RenameParams, SignatureHelp, SignatureHelpParams, SymbolInformation, TextDocumentPositionParams, TextEdit, WorkspaceEdit} import java.util import java.util.concurrent.CompletableFuture @@ -14,6 +15,8 @@ import scala.util.Using class SmartDataLakeTextDocumentService extends TextDocumentService { private var context: SDLBContext = SDLBContext.EMPTY_CONTEXT + private val completionEngine: SDLBCompletionEngine = new SDLBCompletionEngineImpl + private val hoverEngine: SDLBHoverEngine = new SDLBHoverEngineImpl //TODO DI!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! override def completion(params: CompletionParams): CompletableFuture[messages.Either[util.List[CompletionItem], CompletionList]] = { @@ -47,7 +50,12 @@ class SmartDataLakeTextDocumentService extends TextDocumentService { override def resolveCompletionItem(completionItem: CompletionItem): CompletableFuture[CompletionItem] = ??? - override def hover(params: HoverParams): CompletableFuture[Hover] = super.hover(params) //TODO + override def hover(params: HoverParams): CompletableFuture[Hover] = { + CompletableFuture.supplyAsync(() => { + val hoverContext = context.withCaretPosition(params.getPosition.getLine + 1, params.getPosition.getCharacter) + hoverEngine.generateHoveringInformation(hoverContext) + }) + } override def signatureHelp(params: SignatureHelpParams): CompletableFuture[SignatureHelp] = super.signatureHelp(params) diff --git a/src/main/scala/io/smartdatalake/completion/schema/ItemType.scala b/src/main/scala/io/smartdatalake/schema/ItemType.scala similarity index 94% rename from src/main/scala/io/smartdatalake/completion/schema/ItemType.scala rename to src/main/scala/io/smartdatalake/schema/ItemType.scala index c36a777..7f20137 100644 --- a/src/main/scala/io/smartdatalake/completion/schema/ItemType.scala +++ b/src/main/scala/io/smartdatalake/schema/ItemType.scala @@ -1,4 +1,4 @@ -package io.smartdatalake.completion.schema +package io.smartdatalake.schema enum ItemType(val name: String, val defaultValue: String) { case STRING extends ItemType("string", "\"???\"") diff --git a/src/main/scala/io/smartdatalake/completion/schema/SchemaItem.scala b/src/main/scala/io/smartdatalake/schema/SchemaItem.scala similarity index 69% rename from src/main/scala/io/smartdatalake/completion/schema/SchemaItem.scala rename to src/main/scala/io/smartdatalake/schema/SchemaItem.scala index cc51ed5..001c5b2 100644 --- a/src/main/scala/io/smartdatalake/completion/schema/SchemaItem.scala +++ b/src/main/scala/io/smartdatalake/schema/SchemaItem.scala @@ -1,3 +1,3 @@ -package io.smartdatalake.completion.schema +package io.smartdatalake.schema case class SchemaItem(name: String, itemType: ItemType, description: String, required: Boolean) diff --git a/src/main/scala/io/smartdatalake/completion/schema/SchemaReader.scala b/src/main/scala/io/smartdatalake/schema/SchemaReader.scala similarity index 60% rename from src/main/scala/io/smartdatalake/completion/schema/SchemaReader.scala rename to src/main/scala/io/smartdatalake/schema/SchemaReader.scala index 9c743ee..91a6429 100644 --- a/src/main/scala/io/smartdatalake/completion/schema/SchemaReader.scala +++ b/src/main/scala/io/smartdatalake/schema/SchemaReader.scala @@ -1,6 +1,8 @@ -package io.smartdatalake.completion.schema +package io.smartdatalake.schema trait SchemaReader: def retrieveActionProperties(typeName: String): Iterable[SchemaItem] + def retrieveActionPropertyDescription(typeName: String, propertyName: String): String + def retrieveActionTypesWithRequiredAttributes(): Iterable[(String, Iterable[SchemaItem])] diff --git a/src/main/scala/io/smartdatalake/completion/schema/SchemaReaderImpl.scala b/src/main/scala/io/smartdatalake/schema/SchemaReaderImpl.scala similarity index 81% rename from src/main/scala/io/smartdatalake/completion/schema/SchemaReaderImpl.scala rename to src/main/scala/io/smartdatalake/schema/SchemaReaderImpl.scala index 3700d61..40acf76 100644 --- a/src/main/scala/io/smartdatalake/completion/schema/SchemaReaderImpl.scala +++ b/src/main/scala/io/smartdatalake/schema/SchemaReaderImpl.scala @@ -1,4 +1,4 @@ -package io.smartdatalake.completion.schema +package io.smartdatalake.schema import scala.io.Source import scala.util.Using @@ -9,6 +9,12 @@ class SchemaReaderImpl(val schemaPath: String) extends SchemaReader { Source.fromInputStream(inputStream).getLines().mkString("\n").trim }) + + override def retrieveActionPropertyDescription(typeName: String, propertyName: String): String = + schema("definitions")("Action").obj.get(typeName) + .flatMap(typeContext => typeContext("properties").obj.get(propertyName)) + .flatMap(property => property.obj.get("description").map(_.str)).getOrElse("") + override def retrieveActionProperties(typeName: String): Iterable[SchemaItem] = schema("definitions")("Action").obj.get(typeName) match case None => Iterable.empty[SchemaItem] diff --git a/src/test/scala/io/smartdatalake/completion/schema/SchemaReaderSpec.scala b/src/test/scala/io/smartdatalake/completion/schema/SchemaReaderSpec.scala index 686f136..c4c307b 100644 --- a/src/test/scala/io/smartdatalake/completion/schema/SchemaReaderSpec.scala +++ b/src/test/scala/io/smartdatalake/completion/schema/SchemaReaderSpec.scala @@ -1,6 +1,7 @@ package io.smartdatalake.completion.schema import io.smartdatalake.UnitSpec +import io.smartdatalake.schema.{ItemType, SchemaItem, SchemaReaderImpl} import ujson.* import scala.io.Source @@ -58,5 +59,13 @@ class SchemaReaderSpec extends UnitSpec { } + it should "retrieve some action property description" in { + val inputIdDescriptionOfCopyAction = schemaReader.retrieveActionPropertyDescription("CopyAction", "inputId") + inputIdDescriptionOfCopyAction shouldBe "inputs DataObject" + + val overwriteDescriptionOfFileTransferAction = schemaReader.retrieveActionPropertyDescription("FileTransferAction", "overwrite") + overwriteDescriptionOfFileTransferAction shouldBe "Allow existing output file to be overwritten. If false the action will fail if a file to be created already exists. Default is true." + } + } diff --git a/src/test/scala/io/smartdatalake/context/SDLBContextSpec.scala b/src/test/scala/io/smartdatalake/context/SDLBContextSpec.scala index f287bd2..8f0b830 100644 --- a/src/test/scala/io/smartdatalake/context/SDLBContextSpec.scala +++ b/src/test/scala/io/smartdatalake/context/SDLBContextSpec.scala @@ -36,31 +36,37 @@ class SDLBContextSpec extends UnitSpec { val line1Start = SDLBContext.fromText(text).withCaretPosition(1, 0) line1Start.parentPath shouldBe "" line1Start.parentWord shouldBe "" + line1Start.word shouldBe "global" line1Start.getParentContext shouldBe None val line1End = SDLBContext.fromText(text).withCaretPosition(1, 999) line1End.parentPath shouldBe "global" line1End.parentWord shouldBe "global" + line1End.word shouldBe "{" line1End.getParentContext shouldBe defined val line3Start = SDLBContext.fromText(text).withCaretPosition(3, 0) line3Start.parentPath shouldBe "global.spark-options" line3Start.parentWord shouldBe "spark-options" + line3Start.word shouldBe "" line3Start.getParentContext.get.unwrapped().asInstanceOf[java.util.HashMap[String, Int]].get("spark.sql.shuffle.partitions") shouldBe 2 val line3End = SDLBContext.fromText(text).withCaretPosition(3, 999) line3End.parentPath shouldBe "global.spark-options.spark.sql.shuffle.partitions" line3End.parentWord shouldBe "\"spark.sql.shuffle.partitions\"" + line3End.word shouldBe "2" //line3End.getParentContext shouldBe defined //TODO this one is a problem because of the key with dots val line5Start = SDLBContext.fromText(text).withCaretPosition(5, 0) line5Start.parentPath shouldBe "global" line5Start.parentWord shouldBe "global" + line5Start.word shouldBe "}" line5Start.getParentContext shouldBe defined val line5End = SDLBContext.fromText(text).withCaretPosition(5, 1) line5End.parentPath shouldBe "" line5End.parentWord shouldBe "" + line5End.word shouldBe "}" line5End.getParentContext shouldBe None } diff --git a/src/test/scala/io/smartdatalake/context/hocon/HoconParserSpec.scala b/src/test/scala/io/smartdatalake/context/hocon/HoconParserSpec.scala index 3aaae82..0e2ec6f 100644 --- a/src/test/scala/io/smartdatalake/context/hocon/HoconParserSpec.scala +++ b/src/test/scala/io/smartdatalake/context/hocon/HoconParserSpec.scala @@ -238,7 +238,38 @@ class HoconParserSpec extends UnitSpec { it should "parse silently incorrect files" in { HoconParser.parse("blah {") shouldBe None } - + + it should "retrieve correctly hovered word in simple case" in { + val simpleText = "Hello SDLB!" + HoconParser.retrieveWordAtPosition(simpleText, 1, 0) shouldBe "Hello" + HoconParser.retrieveWordAtPosition(simpleText, 1, 4) shouldBe "Hello" + HoconParser.retrieveWordAtPosition(simpleText, 1, 5) shouldBe "Hello" + HoconParser.retrieveWordAtPosition(simpleText, 1, 6) shouldBe "SDLB!" + HoconParser.retrieveWordAtPosition(simpleText, 1, 10) shouldBe "SDLB!" + HoconParser.retrieveWordAtPosition(simpleText, 1, 11) shouldBe "SDLB!" + } + + it should "retrieve correctly hovered word in simple case with multiple spaces" in { + val simpleText = "Hello SDLB!" + HoconParser.retrieveWordAtPosition(simpleText, 1, 0) shouldBe "Hello" + HoconParser.retrieveWordAtPosition(simpleText, 1, 4) shouldBe "Hello" + HoconParser.retrieveWordAtPosition(simpleText, 1, 5) shouldBe "Hello" + HoconParser.retrieveWordAtPosition(simpleText, 1, 6) shouldBe "" + HoconParser.retrieveWordAtPosition(simpleText, 1, 7) shouldBe "SDLB!" + HoconParser.retrieveWordAtPosition(simpleText, 1, 11) shouldBe "SDLB!" + HoconParser.retrieveWordAtPosition(simpleText, 1, 12) shouldBe "SDLB!" + } + + it should "retrieve correctly hovered word in text" in { + val fixture = loadFixture("fixture/hocon/with-comments-example.conf") + val text = fixture.text + HoconParser.retrieveWordAtPosition(text, 4, 0) shouldBe "global" + HoconParser.retrieveWordAtPosition(text, 4, 6) shouldBe "global" + HoconParser.retrieveWordAtPosition(text, 4, 7) shouldBe "{" + HoconParser.retrieveWordAtPosition(text, 6, 7) shouldBe "#\"spark.sql.shuffle.partitions\"" //TODO its a comment line, disable? + HoconParser.retrieveWordAtPosition(text, 7, 7) shouldBe "\"spark.sql.shuffle.partitions\"" //TODO its a string value, disable? + + } private def validateText(fixture: Fixture, column: Int, caretDataList: List[CaretData], positionMap: Option[List[(Int, Int)]]=None): Unit = diff --git a/src/test/scala/io/smartdatalake/hover/SDLBHoverEngineSpec.scala b/src/test/scala/io/smartdatalake/hover/SDLBHoverEngineSpec.scala new file mode 100644 index 0000000..88af61f --- /dev/null +++ b/src/test/scala/io/smartdatalake/hover/SDLBHoverEngineSpec.scala @@ -0,0 +1,25 @@ +package io.smartdatalake.hover + +import io.smartdatalake.UnitSpec +import io.smartdatalake.context.SDLBContext +import ujson.* + +import scala.io.Source +import scala.util.Using + +class SDLBHoverEngineSpec extends UnitSpec { + + val hoveringEngine = new SDLBHoverEngineImpl + + "SDLB Completion engine" should "retrieve all the properties of copyAction" in { + val context = SDLBContext.fromText(loadFile("fixture/hocon/with-multi-lines-flattened-example.conf")) + .withCaretPosition(6, 4) + val expected = + """Configuration of a custom Spark-DataFrame transformation between many inputs and many outputs (n:m). + |Define a transform function which receives a map of input DataObjectIds with DataFrames and a map of options and has + |to return a map of output DataObjectIds with DataFrames, see also trait[[CustomDfsTransformer]] .""".stripMargin + //hoveringEngine.generateHoveringInformation(context).getContents.getRight.getValue shouldBe expected + } + + +} diff --git a/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServerSpec.scala b/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServerSpec.scala index 2d48e92..e292d27 100644 --- a/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServerSpec.scala +++ b/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeLanguageServerSpec.scala @@ -15,6 +15,11 @@ class SmartDataLakeLanguageServerSpec extends UnitSpec { capabilities.get().getCapabilities.getCompletionProvider shouldNot be (null) } + "SDL Language Server" should "have hovering as a capability" in { + val capabilities: CompletableFuture[InitializeResult] = sdlLanguageServer.initialize(null) + capabilities.get().getCapabilities.getHoverProvider.getLeft shouldBe true + } + it should "exit without errors if shutdown before" in { val server = sdlLanguageServer server.shutdown() diff --git a/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentServiceSpec.scala b/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentServiceSpec.scala index dd48c69..ddc5030 100644 --- a/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentServiceSpec.scala +++ b/src/test/scala/io/smartdatalake/languageserver/SmartDataLakeTextDocumentServiceSpec.scala @@ -2,7 +2,7 @@ package io.smartdatalake.languageserver import io.smartdatalake.UnitSpec import io.smartdatalake.languageserver.SmartDataLakeTextDocumentService -import org.eclipse.lsp4j.{CompletionParams, DidOpenTextDocumentParams, Position, TextDocumentItem} +import org.eclipse.lsp4j.{CompletionParams, DidOpenTextDocumentParams, HoverParams, Position, TextDocumentItem} class SmartDataLakeTextDocumentServiceSpec extends UnitSpec { @@ -10,18 +10,32 @@ class SmartDataLakeTextDocumentServiceSpec extends UnitSpec { def params: CompletionParams = val p = new CompletionParams() + // Careful, Position of LSP4J is 0-based p.setPosition(new Position(16, 0)) p "SDL text document service" should "suggest at least one autocompletion item" in { + notifyOpenFile() + val completionResult = textDocumentService.completion(params) + assert(completionResult.get.isLeft) + assert(completionResult.get().getLeft.size() > 0) + } + + it should "provides hovering information" in { + notifyOpenFile() + val params = new HoverParams() + // Careful, Position of LSP4J is 0-based + params.setPosition(new Position(5, 4)) + val hoverInformation = textDocumentService.hover(params) + assert(!hoverInformation.get().getContents.getRight.getValue.isBlank) + } + private def notifyOpenFile(): Unit = { val didOpenTextDocumentParams: DidOpenTextDocumentParams = new DidOpenTextDocumentParams() val textDocumentItem: TextDocumentItem = new TextDocumentItem() textDocumentItem.setText(loadFile("fixture/hocon/with-multi-lines-example.conf")) didOpenTextDocumentParams.setTextDocument(textDocumentItem) textDocumentService.didOpen(didOpenTextDocumentParams) - val completionResult = textDocumentService.completion(params) - assert(completionResult.get.isLeft) - assert(completionResult.get().getLeft.size() > 0) } + }