Skip to content

Commit

Permalink
Merge pull request #110 from tnorbye/1.6.7
Browse files Browse the repository at this point in the history
Version 1.6.7: Fix bugs #105, #106 and fix IDE plugin deprecated usages
  • Loading branch information
tnorbye authored Jan 20, 2025
2 parents 77fa637 + 6be3f4c commit b7cf932
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 31 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

# KDoc Formatter Changelog

## [1.6.7]
- Fix issue #104: Include type parameters in parameter list reordering
- Fix issue #105: Make add punctuation apply to all paragraphs, not just last
- IDE plugin fixes (replaced deprecated API calls)

## [1.6.6]
- IDE-only update: Marked compatible with IntelliJ IDEA 2025.1.
- Updated dependencies
Expand Down Expand Up @@ -249,4 +254,4 @@
- Adds hanging indents for ordered and unordered indents.
- Cleans up the double spaces left by the IntelliJ "Convert to Kotlin"
action right before the closing comment token.
- Removes trailing spaces.
- Removes trailing spaces.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Options:
@<filename>
Read filenames from file.
kdoc-formatter: Version 1.6.6
kdoc-formatter: Version 1.6.7
https://github.com/tnorbye/kdoc-formatter
```

Expand Down
26 changes: 22 additions & 4 deletions cli/src/main/kotlin/kdocformatter/cli/KotlinLexer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,28 @@ class KotlinLexer(private val source: String) {
skipSpace()
val token = nextToken() ?: return null
if (token == "fun") {
// Find beginning of parameter list
val parameters = mutableListOf<String>()

// Find beginning of parameter list, and pick up
// any type parameters in the signature
while (i < length) {
val name = nextToken(matchParens = false) ?: return null
if (name == "(") {
val token = nextToken(matchParens = false) ?: return null
if (token == "<") {
var nextIsVariable = true
while (i < length) {
val varName = nextToken(matchParens = false) ?: return null
if (nextIsVariable && varName.isIdentifier()) {
parameters.add(varName)
}
if (varName == ">") {
break
}
nextIsVariable = varName == ","
}
} else if (token == "(") {
break
}
}
val parameters = mutableListOf<String>()

while (i < length) {
// Name is last symbol before ":"
Expand Down Expand Up @@ -400,6 +414,10 @@ class KotlinLexer(private val source: String) {
return null
}

private fun String.isIdentifier(): Boolean {
return this[0].isJavaIdentifierStart() && this.all { it.isJavaIdentifierPart() }
}

companion object {
private const val PLAIN_TEXT = 1
private const val LINE_COMMENT = 2
Expand Down
94 changes: 94 additions & 0 deletions cli/src/test/kotlin/kdocformatter/cli/KDocFileFormatterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,100 @@ class KDocFileFormatterTest {
reformatted.trim())
}

@Test
fun testKDocOrderingForGenerics() {
// Regression test for https://github.com/tnorbye/kdoc-formatter/issues/104
val source =
"""
class KType
class Test {
/**
* @param type The [KType] representing the type to be instantiated.
* @param T The type of the instance to be created.
* @return An instance of the specified type, or `null` if instantiation fails.
*/
public fun <T : Any> createInstance(type: KType): T? {
return null
}
}
/**
* @param clazz the class
* @param constructor to invoke
* @param T the view
* @param S the stage
*/
fun <S : Stage<*>?, T : StageView<*>?> bind(clazz: Class<S>, constructor: BiFunction<TaskProfilersView?, S, T>) {
}
object Kt {
/**
* Run the loop and wait until condition is true or the retry limit is reached. Returns the
* result afterwards.
*
* @param supplier a function that returns the desired result.
* @param condition tests whether the result is desired.
* @param retryLimit Limit to retry before return the result. If not specified, try forever.
* @param <T> type of the desired result.
* @return the result from the last run (condition met or timeout).
*/
fun <T> waitForAndReturn(
supplier: () -> T,
condition: (T) -> Boolean,
retryLimit: Int = NO_LIMIT,
): T = TODO()
}
"""
.trimIndent()

val reformatted = reformatFile(source, KDocFormattingOptions(72).apply { orderDocTags = true })
assertEquals(
"""
class KType
class Test {
/**
* @param T The type of the instance to be created.
* @param type The [KType] representing the type to be instantiated.
* @return An instance of the specified type, or `null` if
* instantiation fails.
*/
public fun <T : Any> createInstance(type: KType): T? {
return null
}
}
/**
* @param S the stage
* @param T the view
* @param clazz the class
* @param constructor to invoke
*/
fun <S : Stage<*>?, T : StageView<*>?> bind(clazz: Class<S>, constructor: BiFunction<TaskProfilersView?, S, T>) {
}
object Kt {
/**
* Run the loop and wait until condition is true or the retry limit is
* reached. Returns the result afterwards.
*
* @param <T> type of the desired result.
* @param supplier a function that returns the desired result.
* @param condition tests whether the result is desired.
* @param retryLimit Limit to retry before return the result. If not
* specified, try forever.
* @return the result from the last run (condition met or timeout).
*/
fun <T> waitForAndReturn(
supplier: () -> T,
condition: (T) -> Boolean,
retryLimit: Int = NO_LIMIT,
): T = TODO()
}
"""
.trimIndent(),
reformatted.trim())
}

@Test
fun testLineWidth() {
// Perform in KDocFileFormatter test too to make sure we properly account
Expand Down
7 changes: 6 additions & 1 deletion ide-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

# KDoc Formatter Plugin Changelog

## [1.6.7]
- Updated code to replace deprecated API usages
- Fix issue #104: Include type parameters in parameter list reordering
- Fix issue #105: Make add punctuation apply to all paragraphs, not just last

## [1.6.6]
- Add support for 2025.1 EAP, and migrate to 2.x version of IntelliJ gradle plugin.
- Fix https://github.com/tnorbye/kdoc-formatter/issues/106
Expand Down Expand Up @@ -159,4 +164,4 @@
width).

## [1.0.0]
- Initial version
- Initial version
4 changes: 2 additions & 2 deletions ide-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ pluginRepositoryUrl = https://github.com/tnorbye/kdoc-formatter

# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
# for insight into build numbers and IntelliJ Platform versions.
pluginSinceBuild = 232
pluginSinceBuild = 243
pluginUntilBuild = 251.*

# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
platformType = IC
platformVersion = 2024.2
platformVersion = 2024.3
#platformVersion = 251.14649-EAP-CANDIDATE-SNAPSHOT

# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import com.facebook.ktfmt.kdoc.findSamePosition
import com.facebook.ktfmt.kdoc.isLineComment
import com.intellij.application.options.CodeStyle
import com.intellij.lang.Language
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ActionUiKind
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.project.DumbAware
Expand All @@ -39,8 +43,8 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.suggested.endOffset
import com.intellij.refactoring.suggested.startOffset
import com.intellij.psi.util.endOffset
import com.intellij.psi.util.startOffset
import com.intellij.util.ThrowableRunnable
import kotlin.math.min
import org.jetbrains.kotlin.idea.KotlinLanguage
Expand Down Expand Up @@ -263,7 +267,7 @@ class ReformatKDocAction : AnAction(), DumbAware {
val presentation = event.presentation
val type = getApplicableCommentType(event)
val available = type != CommentType.NONE
if (ActionPlaces.isPopupPlace(event.place)) {
if (event.uiKind == ActionUiKind.POPUP) {
presentation.isEnabledAndVisible = available
} else {
presentation.isEnabled = available
Expand Down Expand Up @@ -349,7 +353,9 @@ fun createFormattingTask(
if (task.type == CommentType.KDOC && options.orderDocTags) {
val parent = kdoc.parent
if (parent is KtCallableDeclaration) {
task.orderedParameterNames = parent.valueParameters.mapNotNull { it.name }.toList()
task.orderedParameterNames =
parent.typeParameters.mapNotNull { it.name } +
parent.valueParameters.mapNotNull { it.name }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,28 +826,48 @@ class ParagraphListBuilder(
if (!options.addPunctuation || paragraphs.isEmpty()) {
return
}
val last = paragraphs.last()
if (last.preformatted || last.doc || last.hanging && !last.continuation || last.isEmpty()) {
return
}

val text = last.content
if (!text.startsWithUpperCaseLetter()) {
return
}
for (last in paragraphs) {
if (last.preformatted || last.doc || last.hanging && !last.continuation || last.isEmpty()) {
continue
}

for (i in text.length - 1 downTo 0) {
val c = text[i]
if (c.isWhitespace()) {
val text = last.content
if (!text.startsWithUpperCaseLetter() || text.contentEquals("TODO")) {
continue
}
if (c.isLetterOrDigit() || c.isCloseSquareBracket()) {
text.setLength(i + 1)
text.append('.')

for (i in text.length - 1 downTo 0) {
val c = text[i]
if (c.isWhitespace()) {
continue
}
val isQuoteEnd = c.isCloseSquareBracket() || c == '`'
if (c.isLetterOrDigit() || isQuoteEnd) {
if (!isQuoteEnd && isUrlOrPathEnd(text, i)) {
break
}
text.setLength(i + 1)
text.append('.')
}
break
}
}
}
}

/** Returns true if the given string appears to be the tail end of a URL or path reference. */
private fun isUrlOrPathEnd(s: CharSequence, offset: Int): Boolean {
var i = offset - 1
while (i >= 0) {
val c = s[i]
if (c == '/' || c == '.') {
return true
} else if (c.isWhitespace()) {
break
}
i--
}
return false
}

fun String.containsOnly(vararg s: Char): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ fun String.getParamName(): String? {
}
}

if (start < length && this[start] == '[') {
if (start < length && (this[start] == '[' || this[start] == '<')) {
start++
while (start < length) {
if (this[start].isWhitespace()) {
Expand Down
2 changes: 1 addition & 1 deletion library/src/main/resources/version.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
#

# Release version definition
buildVersion = 1.6.6
buildVersion = 1.6.7
Loading

0 comments on commit b7cf932

Please sign in to comment.