Skip to content

Commit

Permalink
fixed tag processing order and arg
Browse files Browse the repository at this point in the history
  • Loading branch information
Jolanrensen committed Jan 31, 2023
1 parent c0c1d81 commit 85315ce
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 99 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ These preprocessors can be used to add custom tags to your KDoc / JavaDoc commen
This is not a Dokka plugin, meaning you can actually get a `sources.jar` file with the modified comments instead of just
having the comments modified in a `javadoc.jar` or a Dokka HTML website.

Note: `{@inline tags}` work in KDoc comments too! Plus, `{@tags {@inside tags}}` work too from inside to outside.
Note: `{@inline tags}` work in KDoc comments too! Plus, `{@tags {@inside tags}}` work too.

The processing order is:
- Inline tags
- depth-first
- top-to-bottom
- left-to-right
- Block tags
- top-to-bottom

Examples include:
- `@include` tag to include other comments into your KDoc / JavaDoc, see [@include Processor](#include-processor) (`INCLUDE_DOC_PROCESSOR`)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package nl.jolanrensen.docProcessor

import kotlin.jvm.Throws

abstract class TagDocProcessor : DocProcessor {

/** The tags to be replaced, like "sample" */
Expand Down Expand Up @@ -221,7 +219,7 @@ abstract class TagDocProcessor : DocProcessor {
tagWithContent = tagContent,
path = path,
documentable = documentable,
docContent = docContent,
docContent = text,
filteredDocumentables = filteredDocumentables,
allDocumentables = allDocumentables,
)
Expand All @@ -247,28 +245,6 @@ abstract class TagDocProcessor : DocProcessor {
return@run text
}

// docContent
// .splitDocContentOnInnerTags()
// .joinToString("") { split ->
// val shouldProcess =
// split.startsWith("{@") &&
// split.getTagNameOrNull()
// ?.let(::tagIsSupported) == true
//
// if (shouldProcess) {
// processInnerTagWithContent(
// tagWithContent = split,
// path = path,
// documentable = documentable,
// docContent = docContent,
// filteredDocumentables = filteredDocumentables,
// allDocumentables = allDocumentables,
// )
// } else {
// split
// }
// }

// Then process the normal tags
val processedDoc: DocContent = processedInnerTagsDoc
.splitDocContentPerBlock()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package nl.jolanrensen.docProcessor.defaultProcessors
import nl.jolanrensen.docProcessor.DocumentableWithSource
import nl.jolanrensen.docProcessor.ProcessDocsAction
import nl.jolanrensen.docProcessor.TagDocProcessor
import nl.jolanrensen.docProcessor.findTagNamesInDocContent

/**
* @see IncludeArgDocProcessor
Expand Down Expand Up @@ -43,6 +44,9 @@ const val INCLUDE_ARG_DOC_PROCESSOR = "nl.jolanrensen.docProcessor.defaultProces
* */
* fun update() {}
* ```
*
* NOTE: If there are multiple `@arg` tags with the same name, the last one processed will be used.
* The order is: Inline tags: depth-first, left-to-right. Block tags: top-to-bottom.
*/
class IncludeArgDocProcessor : TagDocProcessor() {

Expand Down Expand Up @@ -132,28 +136,41 @@ class IncludeArgDocProcessor : TagDocProcessor() {
.removeSuffix("}")

val isArgDeclaration = trimmedTagWithContent.startsWith("@$declareArgumentTag")
val argTagsStillPresent = docContent.findTagNamesInDocContent().contains(declareArgumentTag)

return when {
isArgDeclaration -> {
val argDeclaration = trimmedTagWithContent
.removePrefix("@$declareArgumentTag")
.trimStart()
val name = argDeclaration.takeWhile { !it.isWhitespace() }
val value = argDeclaration.removePrefix(name).trimStart()

argMap.getOrPut(documentable) { mutableMapOf() }[name] = value
argsNotFound.getOrPut(documentable) { mutableSetOf() } -= name
""
}

if (isArgDeclaration) {
val argDeclaration = trimmedTagWithContent
.removePrefix("@$declareArgumentTag")
.trimStart()
val name = argDeclaration.takeWhile { !it.isWhitespace() }
val value = argDeclaration.removePrefix(name).trimStart()
argTagsStillPresent -> {
// skip @includeArg tags if there are still @args present
tagWithContent
}

argMap.getOrPut(documentable) { mutableMapOf() }[name] = value
argsNotFound.getOrPut(documentable) { mutableSetOf() } -= name
return ""
} else {
val argTarget = trimmedTagWithContent
.removePrefix("@$useArgumentTag")
.trim()
else -> {
// skip @includeArg tags if there are still @args present

val arg = argMap[documentable]?.get(argTarget)
if (arg == null) {
argsNotFound.getOrPut(documentable) { mutableSetOf() } += argTarget
}

return arg ?: tagWithContent
val argTarget = trimmedTagWithContent
.removePrefix("@$useArgumentTag")
.trim()

val arg = argMap[documentable]?.get(argTarget)
if (arg == null) {
argsNotFound.getOrPut(documentable) { mutableSetOf() } += argTarget
}

arg ?: tagWithContent
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package nl.jolanrensen.docProcessor

import java.util.Comparator

/**
* Just the contents of the comment, without the `*`-stuff.
*/
Expand Down Expand Up @@ -207,77 +209,37 @@ fun DocContent.splitDocContentPerBlock(): List<DocContent> = buildList {
add(currentBlock)
}

/**
* Split doc content in parts being either an inner tag or not.
* For instance, it splits `Hi there {@tag some {@test}}` into `["Hi there ", "{@tag some {@test}}"]`
* You can get the name with [String.getTagNameOrNull].
* Can be joint with "" to get the original content.
*/
//fun DocContent.splitDocContentOnInnerTags(): List<DocContent> = buildList {
// val docContent = this@splitDocContentOnInnerTags
//
// var currentBlock = ""
// val blocksIndicators = mutableListOf<String>()
// for (char in docContent) {
// when (char) {
// '{' -> {
// if (blocksIndicators.isEmpty()) {
// add(currentBlock)
// currentBlock = ""
// }
// currentBlock += char
// blocksIndicators += "{}"
// }
//
// '}' -> {
// currentBlock += char
// blocksIndicators -= "{}"
// if (blocksIndicators.isEmpty()) {
// add(currentBlock)
// currentBlock = ""
// }
// }
//
//// TODO figure out what to do with this
//// '`' -> {
//// if ("``" in blocksIndicators)
//// blocksIndicators -= "``"
//// else
//// blocksIndicators += "``"
//// currentBlock += char
//// }
//
// else -> currentBlock += char
// }
// }
// add(currentBlock)
//}

/** Finds any inline tags, preferring the innermost one. */
private fun DocContent.findInlineTagOrNull(): IntRange? {
/** Finds any inline tag with its depth, preferring the innermost one.*/
private fun DocContent.findInlineTagRangeWithDepthOrNull(): Pair<IntRange, Int>? {
var depth = 0
var start: Int? = null
for ((i, char) in this.withIndex()) {
if (char == '{' && this.getOrNull(i + 1) == '@') {
start = i
depth++
} else if (char == '}') {
if (start != null) {
return start..i
return Pair(start..i, depth)
}
}
}
return null
}

/** Finds all inline tag names, including nested ones, together with their respective range in the doc. */
/**
* Finds all inline tag names, including nested ones,
* together with their respective range in the doc.
* The list is sorted by depth, with the deepest tags first and then by order of appearance.
*/
fun DocContent.findInlineTagNamesInDocContentWithRanges(): List<Pair<String, IntRange>> {
var text = this

return buildList {
while (text.findInlineTagOrNull() != null) {
val range = text.findInlineTagOrNull()!!
return buildMap<Int, MutableList<Pair<String, IntRange>>> {
while (text.findInlineTagRangeWithDepthOrNull() != null) {
val (range, depth) = text.findInlineTagRangeWithDepthOrNull()!!
val comment = text.substring(range)
comment.getTagNameOrNull()?.let { tagName ->
add(tagName to range)
getOrPut(depth) { mutableListOf() } += Pair(tagName, range)
}

text = text.replaceRange(
Expand All @@ -287,7 +249,8 @@ fun DocContent.findInlineTagNamesInDocContentWithRanges(): List<Pair<String, Int
.replace('}', '>'),
)
}
}
}.toSortedMap(Comparator.reverseOrder())
.flatMap { it.value }
}

/** Finds all inline tag names, including nested ones. */
Expand Down

0 comments on commit 85315ce

Please sign in to comment.