Skip to content

Commit

Permalink
Added autocompletion capability at root level + special case like exe…
Browse files Browse the repository at this point in the history
…cutionMode. Added General Hovering capabilities.
  • Loading branch information
dsalathe committed Sep 19, 2023
1 parent 32bd599 commit 0601f97
Show file tree
Hide file tree
Showing 19 changed files with 241 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.typesafe.config.{Config, ConfigList, ConfigObject, ConfigValue}
import io.smartdatalake.completion.SDLBCompletionEngine
import io.smartdatalake.context.{SDLBContext, TextContext}
import io.smartdatalake.schema.SchemaCollections.{AttributeCollection, TemplateCollection}
import io.smartdatalake.schema.{ItemType, SchemaItem, SchemaReader, SchemaReaderImpl}
import io.smartdatalake.schema.{ItemType, SchemaItem, SchemaReader, SchemaReaderImpl, TemplateType}
import io.smartdatalake.conversions.ScalaJavaConverterAPI.*
import org.eclipse.lsp4j.{CompletionItem, CompletionItemKind}

Expand All @@ -15,19 +15,19 @@ class SDLBCompletionEngineImpl(private val schemaReader: SchemaReader) extends S
override def generateCompletionItems(context: SDLBContext): List[CompletionItem] =
val itemSuggestionsFromSchema = schemaReader.retrieveAttributeOrTemplateCollection(context) match
case AttributeCollection(attributes) => generateAttributeSuggestions(attributes, context.getParentContext)
case TemplateCollection(templates) => generateTemplateSuggestions(templates, context.isInList)
case TemplateCollection(templates, templateType) => generateTemplateSuggestions(templates, templateType, context.isInList)

val itemSuggestionsFromConfig = generateItemSuggestionsFromConfig(context)
val allItems = itemSuggestionsFromConfig ++ itemSuggestionsFromSchema
if allItems.isEmpty then typeList else allItems

private def generateItemSuggestionsFromConfig(context: SDLBContext): List[CompletionItem] = context.parentPath.lastOption match
case Some(value) => value match
case "inputId" | "outputId" => retrieveDataObjectIds(context)
case "inputId" | "outputId" | "inputIds" | "outputIds" => retrieveDataObjectIds(context) //TODO regex?
case _ => List.empty[CompletionItem]
case None => List.empty[CompletionItem]

private def retrieveDataObjectIds(context: SDLBContext): List[CompletionItem] = //TODO test
private def retrieveDataObjectIds(context: SDLBContext): List[CompletionItem] = //TODO test. TODO return List[String] instead?
context.textContext.rootConfig.getValue("dataObjects") match
case asConfigObject: ConfigObject => asConfigObject.unwrapped().keySet().toScala.toList.map(createCompletionItem)

Expand All @@ -38,20 +38,22 @@ class SDLBCompletionEngineImpl(private val schemaReader: SchemaReader) extends S
case _ => attributes
items.map(createCompletionItem).toList

private[completion] def generateTemplateSuggestions(templates: Iterable[(String, Iterable[SchemaItem])], isInList: Boolean): List[CompletionItem] =
private[completion] def generateTemplateSuggestions(templates: Iterable[(String, Iterable[SchemaItem])], templateType: TemplateType, isInList: Boolean): List[CompletionItem] =
templates.map { case (actionType, attributes) =>
val completionItem = new CompletionItem()
completionItem.setLabel(actionType.toLowerCase)
completionItem.setDetail(" template")
val keyName = if isInList then "" else s"${actionType.toLowerCase}_PLACEHOLDER"
completionItem.setInsertText(
s"""$keyName {
val keyName = if templateType == TemplateType.OBJECT then s"${actionType.toLowerCase}_PLACEHOLDER" else ""
val startObject = if templateType != TemplateType.ATTRIBUTES then "{" else ""
val endObject = if templateType != TemplateType.ATTRIBUTES then "}" else ""
completionItem.setInsertText( //TODO handle indentation
s"""$keyName $startObject
|${
def generatePlaceHolderValue(att: SchemaItem) = {
if att.name == "type" then actionType else att.itemType.defaultValue
}
attributes.map(att => "\t\t" + att.name + " = " + generatePlaceHolderValue(att)).mkString("\n")}\n\t}
|""".stripMargin)
attributes.map(att => "\t\t" + att.name + " = " + generatePlaceHolderValue(att)).mkString("\n")}\n\t$endObject
|""".stripMargin) //TODO remove blank lines?
completionItem.setKind(CompletionItemKind.Snippet)
completionItem
}.toList
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/io/smartdatalake/context/SDLBContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ case class SDLBContext private(textContext: TextContext, parentPath: List[String
case asConfigList: ConfigList => findParentContext(asConfigList.get(path.toInt), newRemainingPath)
case _ => None

parentPath.headOption.flatMap(head => findParentContext(textContext.rootConfig.getValue(head), parentPath.tail))
findParentContext(textContext.rootConfig.root(), parentPath)

}

Expand Down
10 changes: 5 additions & 5 deletions src/main/scala/io/smartdatalake/context/hocon/HoconParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ private[context] object HoconParser:
if line <= 0 then
(0, "")
else
val textLine = text.split(Token.NEW_LINE)(line-1).filterNot(c => c.isWhitespace).takeWhile(_ != Token.COMMENT).mkString
val textLine = text.split(Token.NEW_LINE_PATTERN, -1)(line-1).filterNot(c => c.isWhitespace).takeWhile(_ != Token.COMMENT).mkString
val newDepth = depth - textLine.count(_ == Token.START_OBJECT) + textLine.count(_ == Token.END_OBJECT) + textLine.count(_ == Token.END_LIST) - textLine.count(_ == Token.START_LIST)
if textLine.contains(Token.END_OBJECT) || textLine.contains(Token.END_LIST) then retrieveHelper(line-1, newDepth) else
textLine.split(Token.KEY_VAL_SPLIT_REGEX) match
case Array(singleBlock) => if singleBlock.isBlank then retrieveHelper(line-1, newDepth) else if newDepth < 0 then (line, singleBlock) else retrieveHelper(line-1, newDepth)
case _ => retrieveHelper(line-1, newDepth)
}

val textLine = text.split(Token.NEW_LINE)(line-1).takeWhile(_ != Token.COMMENT).mkString
val textLine = text.split(Token.NEW_LINE_PATTERN, -1)(line-1).takeWhile(_ != Token.COMMENT).mkString
val col = math.min(textLine.length, column)
if textLine.count(_ == Token.END_OBJECT) + textLine.count(_ == Token.END_LIST) > textLine.count(_ == Token.START_OBJECT) + textLine.count(_ == Token.START_LIST) then
val depthForObject = if textLine.indexOf(Token.END_OBJECT) != -1 && col > textLine.indexOf(Token.END_OBJECT) then 1 else 0
Expand All @@ -102,7 +102,7 @@ private[context] object HoconParser:
val keyName = keyValSplit(0).trim
@tailrec
def findValidDirectParentName(line: Int): Option[(Int, String)] = if line <= 0 then None else //TODO test
val textLine = text.split(Token.NEW_LINE)(line-1).takeWhile(_ != Token.COMMENT).mkString
val textLine = text.split(Token.NEW_LINE_PATTERN, -1)(line-1).takeWhile(_ != Token.COMMENT).mkString
if textLine.isBlank then findValidDirectParentName(line-1) else
val words = textLine.filterNot(c => c == Token.START_LIST || c == Token.END_LIST || c == Token.START_OBJECT || c == Token.END_OBJECT || c == '=' || c == '"').split(" ")
words match
Expand Down Expand Up @@ -130,7 +130,7 @@ private[context] object HoconParser:
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 textLine = text.split(Token.NEW_LINE_PATTERN, -1)(line-1) + " "
val column = math.min(textLine.length-1, col)
val leadingCharacter = textLine.charAt(column)
column match
Expand Down Expand Up @@ -193,7 +193,7 @@ private[context] object HoconParser:
if startPosition != -1 && endPosition != -1 then Some((startPosition+1, endPosition)) else None // (...+1, ...-1) to exclude list characters themselves

private[hocon] def lineColToAbsolutePosition(text: String, line: Int, column: Int): Int =
val textLine = text.split(Token.NEW_LINE)
val textLine = text.split(Token.NEW_LINE_PATTERN, -1)
val nCharactersBeforeCurrentLine = textLine.take(line-1).map(line => line.length + 1).sum // +1 for \n character
val nCharactersCurrentLine = math.min(textLine(line-1).length, column)
nCharactersCurrentLine + nCharactersBeforeCurrentLine
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object HoconTokens {
val END_OBJECT = '}'
val START_LIST = '['
val END_LIST = ']'
val NEW_LINE = "\n"
val NEW_LINE_PATTERN = "\\R"
val COMMENT = '#'

}
11 changes: 1 addition & 10 deletions src/main/scala/io/smartdatalake/hover/SDLBHoverEngineImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,4 @@ class SDLBHoverEngineImpl(private val schemaReader: SchemaReader) extends SDLBHo
markupContent.setValue(retrieveSchemaDescription(context))
new Hover(markupContent)

private def retrieveSchemaDescription(context: SDLBContext): String = context.parentPath.mkString(".")
// context.parentPath match
// case path if path.startsWith("actions") && path.count(_ == '.') == 1 =>
// val tActionType: Try[String] = Failure(new IllegalStateException()) // Try(context.textContext.rootConfig.getString(context.parentPath + ".type"))
// tActionType match
// case Success(actionType) => schemaReader.retrieveActionPropertyDescription(actionType, context.word)
// case Failure(_) => ""
//
// case _ => ""

private def retrieveSchemaDescription(context: SDLBContext): String = schemaReader.retrieveDescription(context)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import scala.collection.Iterable

object SchemaCollections {
case class AttributeCollection(attributes: Iterable[SchemaItem])
case class TemplateCollection(templates: Iterable[(String, Iterable[SchemaItem])])
case class TemplateCollection(templates: Iterable[(String, Iterable[SchemaItem])], templateType: TemplateType)

}
Loading

0 comments on commit 0601f97

Please sign in to comment.