diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlArrayDecoder.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlArrayDecoder.kt index 951e4e05..24a254a8 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlArrayDecoder.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlArrayDecoder.kt @@ -46,6 +46,8 @@ public class TomlArrayDecoder( rootNode.key, currentPrimitiveElementOfArray, rootNode.lineNo, + comments = emptyList(), + inlineComment = "", rootNode.key.content, config ) diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/StringUtils.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/StringUtils.kt index b735f098..7e801eec 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/StringUtils.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/StringUtils.kt @@ -7,13 +7,34 @@ package com.akuleshov7.ktoml.parsers import com.akuleshov7.ktoml.exceptions.ParseException /** - * method to find the beginning of the comments in TOML string + * Takes only the text before a comment, searching for a comment after the specified + * [startIndex]. * - * @param startSearchFrom the index after that the search will be done - * @return the index of the first hash symbol or the index of the end of the string + * @param startIndex The index to start the comment search from. + * @return The text before a comment, i.e. + * ```kotlin + * "a = 0 # Comment".takeBeforeComment() == "a = 0" + * ``` */ -internal fun String.findBeginningOfTheComment(startSearchFrom: Int) = - (startSearchFrom until this.length).filter { this[it] == '#' }.minOrNull() ?: this.length +internal fun String.takeBeforeComment(startIndex: Int) = + when (val hashIndex = indexOf('#', startIndex)) { + -1 -> trim() + else -> take(hashIndex).trim() + } + +/** + * Trims a comment of any text before it and its hash token. + * + * @return The comment text, i.e. + * ```kotlin + * "a = 0 # Comment".trimComment() == "Comment" + * ``` + */ +internal fun String.trimComment() = + when (val hashIndex = indexOf('#')) { + -1 -> "" + else -> drop(hashIndex + 1).trim() + } /** * Splitting dot-separated string to the list of tokens: diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt index c7c7bf4a..86d12251 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt @@ -40,18 +40,25 @@ public value class TomlParser(private val config: TomlConfig) { // here we always store the bucket of the latest created array of tables var latestCreatedBucket: TomlArrayOfTablesElement? = null + val comments: MutableList = mutableListOf() + mutableTomlLines.forEachIndexed { index, line -> val lineNo = index + 1 // comments and empty lines can easily be ignored in the TomlTree, but we cannot filter them out in mutableTomlLines // because we need to calculate and save lineNo - if (!line.isComment() && !line.isEmptyLine()) { + if (line.isComment()) { + comments += line.trimComment() + } else if (!line.isEmptyLine()) { + // Parse the inline comment if any + val inlineComment = line.trimComment() + if (line.isTableNode()) { if (line.isArrayOfTables()) { // TomlArrayOfTables contains all information about the ArrayOfTables ([[array of tables]]) val tableArray = TomlArrayOfTables(line, lineNo, config) val arrayOfTables = tomlFileHead.insertTableToTree(tableArray, latestCreatedBucket) // creating a new empty element that will be used as an element in array and the parent for next key-value records - val newArrayElement = TomlArrayOfTablesElement(lineNo, config) + val newArrayElement = TomlArrayOfTablesElement(lineNo, comments, inlineComment, config) // adding this element as a child to the array of tables arrayOfTables.appendChild(newArrayElement) // covering the case when the processed table does not contain nor key-value pairs neither tables (after our insertion) @@ -62,7 +69,7 @@ public value class TomlParser(private val config: TomlConfig) { // here we set the bucket that will be incredibly useful when we will be inserting the next array of tables latestCreatedBucket = newArrayElement } else { - val tableSection = TomlTablePrimitive(line, lineNo, config) + val tableSection = TomlTablePrimitive(line, lineNo, comments, inlineComment, config) // if the table is the last line in toml, then it has no children, and we need to // add at least fake node as a child if (index == mutableTomlLines.lastIndex) { @@ -74,7 +81,7 @@ public value class TomlParser(private val config: TomlConfig) { currentParentalNode = tomlFileHead.insertTableToTree(tableSection) } } else { - val keyValue = line.parseTomlKeyValue(lineNo, config) + val keyValue = line.parseTomlKeyValue(lineNo, comments, inlineComment, config) // inserting the key-value record to the tree when { keyValue is TomlKeyValue && keyValue.key.isDotted -> @@ -93,6 +100,8 @@ public value class TomlParser(private val config: TomlConfig) { else -> currentParentalNode.appendChild(keyValue) } } + + comments.clear() } } return tomlFileHead @@ -134,14 +143,21 @@ public value class TomlParser(private val config: TomlConfig) { * factory adaptor to split the logic of parsing simple values from the logic of parsing collections (like Arrays) * * @param lineNo + * @param comments + * @param inlineComment * @param config * @return parsed toml node */ -public fun String.parseTomlKeyValue(lineNo: Int, config: TomlConfig): TomlNode { +public fun String.parseTomlKeyValue( + lineNo: Int, + comments: List, + inlineComment: String, + config: TomlConfig +): TomlNode { val keyValuePair = this.splitKeyValue(lineNo, config) return when { - keyValuePair.second.startsWith("[") -> TomlKeyValueArray(keyValuePair, lineNo, config) - keyValuePair.second.startsWith("{") -> TomlInlineTable(keyValuePair, lineNo, config) - else -> TomlKeyValuePrimitive(keyValuePair, lineNo, config) + keyValuePair.second.startsWith("[") -> TomlKeyValueArray(keyValuePair, lineNo, comments, inlineComment, config) + keyValuePair.second.startsWith("{") -> TomlInlineTable(keyValuePair, lineNo, comments, inlineComment, config) + else -> TomlKeyValuePrimitive(keyValuePair, lineNo, comments, inlineComment, config) } } diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt index dbcdbde4..f455ce85 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt @@ -6,8 +6,8 @@ package com.akuleshov7.ktoml.tree import com.akuleshov7.ktoml.TomlConfig import com.akuleshov7.ktoml.exceptions.ParseException -import com.akuleshov7.ktoml.parsers.findBeginningOfTheComment import com.akuleshov7.ktoml.parsers.splitKeyToTokens +import com.akuleshov7.ktoml.parsers.takeBeforeComment import com.akuleshov7.ktoml.parsers.trimDoubleBrackets import com.akuleshov7.ktoml.parsers.trimQuotes import com.akuleshov7.ktoml.writers.TomlEmitter @@ -26,6 +26,8 @@ public class TomlArrayOfTables( ) : TomlTable( content, lineNo, + comments = emptyList(), + inlineComment = "", config, isSynthetic ) { @@ -47,11 +49,8 @@ public class TomlArrayOfTables( " It has missing closing brackets: ']]'", lineNo) } - // finding the index of the beginning of the comment (if any) - val firstHash = content.findBeginningOfTheComment(lastIndexOfBrace) - // getting the content inside brackets ([a.b] -> a.b) - val sectionFromContent = content.substring(0, firstHash).trim().trimDoubleBrackets() + val sectionFromContent = content.takeBeforeComment(lastIndexOfBrace).trimDoubleBrackets() .trim() if (sectionFromContent.isBlank()) { @@ -89,7 +88,9 @@ public class TomlArrayOfTables( emitIndent() } + writeChildComments(child) writeHeader(headerKey, config) + writeChildInlineComment(child) if (!child.hasNoChildren()) { emitNewLine() @@ -120,9 +121,16 @@ public class TomlArrayOfTables( /** * This class is used to store elements of array of tables (bucket for key-value records) */ -public class TomlArrayOfTablesElement(lineNo: Int, config: TomlConfig = TomlConfig()) : TomlNode( +public class TomlArrayOfTablesElement( + lineNo: Int, + comments: List, + inlineComment: String, + config: TomlConfig = TomlConfig() +) : TomlNode( EMPTY_TECHNICAL_NODE, lineNo, + comments, + inlineComment, config ) { override val name: String = EMPTY_TECHNICAL_NODE diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt index 3dadd811..9a9615e9 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt @@ -10,6 +10,8 @@ import com.akuleshov7.ktoml.writers.TomlEmitter public class TomlFile(config: TomlConfig = TomlConfig()) : TomlNode( "rootNode", 0, + comments = emptyList(), + inlineComment = "", config ) { override val name: String = "rootNode" diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlInlineTable.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlInlineTable.kt index dc8c8013..5a01cbac 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlInlineTable.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlInlineTable.kt @@ -15,10 +15,14 @@ import com.akuleshov7.ktoml.writers.TomlEmitter public class TomlInlineTable( private val keyValuePair: Pair, lineNo: Int, + comments: List = emptyList(), + inlineComment: String = "", config: TomlConfig = TomlConfig(), ) : TomlNode( "${keyValuePair.first} = ${keyValuePair.second}", lineNo, + comments, + inlineComment, config ) { override val name: String = keyValuePair.first @@ -40,7 +44,7 @@ public class TomlInlineTable( } } .split(",") - .map { it.parseTomlKeyValue(lineNo, config) } + .map { it.parseTomlKeyValue(lineNo, comments = emptyList(), inlineComment = "", config) } return parsedList } @@ -49,6 +53,8 @@ public class TomlInlineTable( val tomlTable = TomlTablePrimitive( "[${if (currentParentalNode is TomlTable) "${currentParentalNode.fullTableName}." else ""}${keyValuePair.first}]", lineNo, + comments, + inlineComment, config ) diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValue.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValue.kt index f1d37e83..2f29fb7d 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValue.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValue.kt @@ -2,7 +2,7 @@ package com.akuleshov7.ktoml.tree import com.akuleshov7.ktoml.TomlConfig import com.akuleshov7.ktoml.exceptions.ParseException -import com.akuleshov7.ktoml.parsers.findBeginningOfTheComment +import com.akuleshov7.ktoml.parsers.takeBeforeComment import com.akuleshov7.ktoml.writers.TomlEmitter private typealias ValueCreator = (String, Int) -> TomlValue @@ -14,6 +14,8 @@ internal interface TomlKeyValue { var key: TomlKey val value: TomlValue val lineNo: Int + val comments: List + val inlineComment: String /** * this is a small hack to support dotted keys @@ -39,6 +41,8 @@ internal interface TomlKeyValue { return TomlTablePrimitive( "[$parentalPrefix${syntheticTablePrefix.joinToString(".")}]", lineNo, + comments, + inlineComment, config, true ) @@ -83,12 +87,12 @@ public fun String.splitKeyValue(lineNo: Int, config: TomlConfig = TomlConfig()): this.lastIndexOf("\"\"\"") ).filterNot { it == -1 }.maxOrNull() ?: 0 - // finding the index of a commented part of the string + // removing the commented part of the string // search starts goes from the closingQuoteIndex to the end of the string - val firstHash = this.findBeginningOfTheComment(closingQuoteIndex) + val pair = takeBeforeComment(closingQuoteIndex) // searching for an equals sign that should be placed main part of the string (not in the comment) - val firstEqualsSign = this.substring(0, firstHash).indexOfFirst { it == '=' } + val firstEqualsSign = pair.indexOfFirst { it == '=' } // equals sign not found in the string if (firstEqualsSign == -1) { @@ -101,8 +105,8 @@ public fun String.splitKeyValue(lineNo: Int, config: TomlConfig = TomlConfig()): } // k = v # comment -> key is `k`, value is `v` - val key = this.substring(0, firstEqualsSign).trim() - val value = this.substring(firstEqualsSign + 1, firstHash).trim() + val key = pair.substring(0, firstEqualsSign).trim() + val value = pair.substring(firstEqualsSign + 1).trim() return Pair( key.checkNotEmpty("key", this, config, lineNo), diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt index 37aa681f..1123755d 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt @@ -14,23 +14,31 @@ public class TomlKeyValueArray( override var key: TomlKey, override val value: TomlValue, override val lineNo: Int, + comments: List, + inlineComment: String, override val name: String, config: TomlConfig = TomlConfig() ) : TomlNode( key, value, lineNo, + comments, + inlineComment, config ), TomlKeyValue { // adaptor for a string pair of key-value public constructor( keyValuePair: Pair, lineNo: Int, + comments: List = emptyList(), + inlineComment: String = "", config: TomlConfig = TomlConfig() ) : this( TomlKey(keyValuePair.first, lineNo), keyValuePair.second.parseList(lineNo, config), lineNo, + comments, + inlineComment, TomlKey(keyValuePair.first, lineNo).content ) diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt index 603eee3a..ea660dc1 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt @@ -14,23 +14,31 @@ public class TomlKeyValuePrimitive( override var key: TomlKey, override val value: TomlValue, override val lineNo: Int, + comments: List, + inlineComment: String, override val name: String, config: TomlConfig = TomlConfig() ) : TomlNode( key, value, lineNo, + comments, + inlineComment, config ), TomlKeyValue { // adaptor for a string pair of key-value public constructor( keyValuePair: Pair, lineNo: Int, + comments: List = emptyList(), + inlineComment: String = "", config: TomlConfig = TomlConfig() ) : this( TomlKey(keyValuePair.first, lineNo), keyValuePair.second.parseValue(lineNo, config), lineNo, + comments, + inlineComment, TomlKey(keyValuePair.first, lineNo).content ) diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt index d291ba3e..d6277e62 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt @@ -15,15 +15,24 @@ public const val EMPTY_TECHNICAL_NODE: String = "technical_node" * Toml specification includes a list of supported data types: * String, Integer, Float, Boolean, Datetime, Array, and Table. * + * @param comments Comments prepended to the current node + * * @property content - original node content (used for logging and tests only) * @property lineNo - the number of a line from TOML that is linked to the current node + * @property inlineComment A comment appended to the end of the line * @property config */ public sealed class TomlNode( public open val content: String, public open val lineNo: Int, + comments: List, + public val inlineComment: String, public open val config: TomlConfig = TomlConfig() ) { + /** + * A list of comments prepended to the node. + */ + public val comments: MutableList = comments.toMutableList() public open val children: MutableList = mutableListOf() public open var parent: TomlNode? = null @@ -38,10 +47,14 @@ public sealed class TomlNode( key: TomlKey, value: TomlValue, lineNo: Int, + comments: List, + inlineComment: String, config: TomlConfig = TomlConfig() ) : this( "${key.content}=${value.content}", lineNo, + comments, + inlineComment, config ) @@ -133,9 +146,21 @@ public sealed class TomlNode( } else { // creating a synthetic (technical) fragment of the table val newChildTableName = if (tomlTable is TomlArrayOfTables) { - TomlArrayOfTables("[[$subTable]]", lineNo, config, true) + TomlArrayOfTables( + "[[$subTable]]", + lineNo, + config, + true + ) } else { - TomlTablePrimitive("[$subTable]", lineNo, config, true) + TomlTablePrimitive( + "[$subTable]", + lineNo, + tomlTable.comments, + tomlTable.inlineComment, + config, + true + ) } previousParent.determineParentAndInsertFragmentOfTable(newChildTableName) newChildTableName @@ -221,9 +246,15 @@ public sealed class TomlNode( val last = children.lastIndex children.forEachIndexed { i, child -> + writeChildComments(child) + emitIndent() child.write(emitter = this, config, multiline) + if (child is TomlKeyValue || child is TomlInlineTable) { + writeChildInlineComment(child) + } + if (i < last) { emitNewLine() @@ -237,6 +268,20 @@ public sealed class TomlNode( } } + protected fun TomlEmitter.writeChildComments(child: TomlNode) { + child.comments.forEach { comment -> + emitIndent() + .emitComment(comment) + .emitNewLine() + } + } + + protected fun TomlEmitter.writeChildInlineComment(child: TomlNode) { + if (child.inlineComment.isNotEmpty()) { + emitComment(child.inlineComment, inline = true) + } + } + public companion object { // number of spaces that is used to indent levels internal const val INDENTING_LEVEL = 4 diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt index b30910fd..1f4186c1 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt @@ -12,6 +12,8 @@ import com.akuleshov7.ktoml.writers.TomlEmitter public class TomlStubEmptyNode(lineNo: Int, config: TomlConfig = TomlConfig()) : TomlNode( EMPTY_TECHNICAL_NODE, lineNo, + comments = emptyList(), + inlineComment = "", config ) { override val name: String = EMPTY_TECHNICAL_NODE diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt index 356a6a28..9d7c64ee 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt @@ -18,11 +18,15 @@ import com.akuleshov7.ktoml.writers.TomlEmitter public abstract class TomlTable( override val content: String, override val lineNo: Int, + comments: List, + inlineComment: String, override val config: TomlConfig = TomlConfig(), public val isSynthetic: Boolean = false ) : TomlNode( content, lineNo, + comments, + inlineComment, config ) { public abstract var fullTableName: String @@ -44,6 +48,10 @@ public abstract class TomlTable( if (isExplicit(firstChild) && type == TableType.PRIMITIVE) { emitter.writeHeader(key, config) + if (inlineComment.isNotEmpty()) { + emitter.emitComment(inlineComment, inline = true) + } + if (firstChild !is TomlStubEmptyNode) { emitter.emitNewLine() } diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt index b7a5cee8..3966b0be 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt @@ -6,10 +6,7 @@ package com.akuleshov7.ktoml.tree import com.akuleshov7.ktoml.TomlConfig import com.akuleshov7.ktoml.exceptions.ParseException -import com.akuleshov7.ktoml.parsers.findBeginningOfTheComment -import com.akuleshov7.ktoml.parsers.splitKeyToTokens -import com.akuleshov7.ktoml.parsers.trimBrackets -import com.akuleshov7.ktoml.parsers.trimQuotes +import com.akuleshov7.ktoml.parsers.* import com.akuleshov7.ktoml.writers.TomlEmitter /** @@ -21,11 +18,15 @@ import com.akuleshov7.ktoml.writers.TomlEmitter public class TomlTablePrimitive( content: String, lineNo: Int, + comments: List = emptyList(), + inlineComment: String = "", config: TomlConfig = TomlConfig(), isSynthetic: Boolean = false ) : TomlTable( content, lineNo, + comments, + inlineComment, config, isSynthetic ) { @@ -47,11 +48,8 @@ public class TomlTablePrimitive( " It has missing closing bracket: ']'", lineNo) } - // finding the index of the beginning of the comment (if any) - val firstHash = content.findBeginningOfTheComment(lastIndexOfBrace) - // getting the content inside brackets ([a.b] -> a.b) - val sectionFromContent = content.substring(0, firstHash).trim().trimBrackets() + val sectionFromContent = content.takeBeforeComment(lastIndexOfBrace).trim().trimBrackets() .trim() if (sectionFromContent.isBlank()) { @@ -93,6 +91,8 @@ public class TomlTablePrimitive( var prevChild: TomlNode? = null children.forEachIndexed { i, child -> + writeChildComments(child) + // Declare the super table after a nested table, to avoid a pair being // a part of the previous table by mistake. if ((child is TomlKeyValue || child is TomlInlineTable) && @@ -112,6 +112,7 @@ public class TomlTablePrimitive( } child.write(emitter = this, config, multiline) + writeChildInlineComment(child) if (i < last) { emitNewLine() diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt index 17ba5efd..263904fb 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt @@ -85,12 +85,12 @@ public abstract class TomlEmitter(config: TomlConfig) { * Emits a [comment], optionally making it end-of-line. * * @param comment - * @param endOfLine Whether the comment is at the end of a line, e.g. after a + * @param inline Whether the comment is at the end of a line, e.g. after a * table header. * @return this instance */ - public fun emitComment(comment: String, endOfLine: Boolean = false): TomlEmitter = - emit(if (endOfLine) " # " else "# ") + public fun emitComment(comment: String, inline: Boolean = false): TomlEmitter = + emit(if (inline) " # " else "# ") .emit(comment) /** diff --git a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/CommentsParsing.kt b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/CommentsParsing.kt index d9d4cc11..8c1a2f79 100644 --- a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/CommentsParsing.kt +++ b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/CommentsParsing.kt @@ -1,7 +1,10 @@ package com.akuleshov7.ktoml.parsers import com.akuleshov7.ktoml.Toml +import com.akuleshov7.ktoml.tree.TomlKeyValuePrimitive import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals class CommentsParsing { @Test @@ -16,5 +19,37 @@ class CommentsParsing { """.trimIndent() val parsedToml = Toml.tomlParser.parseString(string) parsedToml.prettyPrint() + + val tableA = parsedToml.findTableInAstByName("a")!! + val tableB = tableA.findTableInAstByName("a.b")?.getFirstChild()!! + + val pairA = + tableA.children + .first { it is TomlKeyValuePrimitive } + + assertContentEquals( + listOf("comment 1"), + tableA.comments + ) + + assertEquals( + "comment 2", + tableA.inlineComment + ) + + assertContentEquals( + listOf("comment 3"), + pairA.comments + ) + + assertEquals( + "comment 4", + pairA.inlineComment + ) + + assertEquals( + "comment 5", + tableB.inlineComment + ) } } diff --git a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/ValueParserTest.kt b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/ValueParserTest.kt index 48c8da7a..734cdd0d 100644 --- a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/ValueParserTest.kt +++ b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/parsers/ValueParserTest.kt @@ -156,5 +156,5 @@ fun testTomlValue( expectedType: NodeType, config: TomlConfig = TomlConfig() ) { - assertEquals(expectedType, getNodeType(TomlKeyValuePrimitive(keyValuePair, 0, config).value)) + assertEquals(expectedType, getNodeType(TomlKeyValuePrimitive(keyValuePair, 0, config = config).value)) } diff --git a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/CommentWriteTest.kt b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/CommentWriteTest.kt new file mode 100644 index 00000000..a7e2d435 --- /dev/null +++ b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/CommentWriteTest.kt @@ -0,0 +1,27 @@ +package com.akuleshov7.ktoml.writers + +import kotlin.test.Test + +class CommentWriteTest { + @Test + fun commentWriteTest() { + val toml = """ + # Comment + # Comment + x = 0 # Comment + + # Comment + [a] # Comment + b = [ ] # Comment + + # Comment + [a.c] + d = 1 # Comment + + # Comment + [[e]] # Comment + """.trimIndent() + + testTable(toml) + } +} \ No newline at end of file diff --git a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/KeyValueWriteTest.kt b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/KeyValueWriteTest.kt index 351cc8ee..4b625f72 100644 --- a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/KeyValueWriteTest.kt +++ b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/writers/KeyValueWriteTest.kt @@ -95,7 +95,7 @@ fun testTomlPrimitivePair( pair: Pair, config: TomlConfig = TomlConfig() ) = testTomlPair( - TomlKeyValuePrimitive(pair, 0, config), + TomlKeyValuePrimitive(pair, 0, config = config), expectedString = "${pair.first} = ${pair.second}", config, multiline = false @@ -106,7 +106,7 @@ fun testTomlArrayPair( multiline: Boolean, config: TomlConfig = TomlConfig(), ) = testTomlPair( - TomlKeyValueArray(pair, 0, config), + TomlKeyValueArray(pair, 0, config = config), expectedString = "${pair.first} = ${pair.second}", config, multiline @@ -116,7 +116,7 @@ fun testTomlInlineTablePair( pair: Pair, config: TomlConfig = TomlConfig(), ) = testTomlPair( - TomlInlineTable(pair, 0, config), + TomlInlineTable(pair, 0, config = config), expectedString = "${pair.first} = ${pair.second}", config, multiline = false