From 7b1d19b59a7f3dfb048df064e85513e0ccb3e4c1 Mon Sep 17 00:00:00 2001 From: Yauheni Slizh Date: Tue, 7 Apr 2026 23:50:45 +0200 Subject: [PATCH 1/2] Add custom logging framework support Allow users to define their own logging templates with {tag} and {message} placeholders for both Kotlin and Java, with an optional import path. Also fix Java import fallback for unresolvable classes. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../services/LogInserterService.kt | 23 +- .../loggingplugin/services/LogStrategy.kt | 43 +- .../loggingplugin/settings/LoggingSettings.kt | 4 + .../toolwindow/LoggingToolWindowFactory.kt | 65 ++- .../services/CustomLogInserterServiceTest.kt | 478 ++++++++++++++++++ 5 files changed, 602 insertions(+), 11 deletions(-) create mode 100644 src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt index f5b7ca8..5063e54 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiCodeBlock import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.PsiExpressionStatement +import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiMethod import com.intellij.psi.PsiWhiteSpace @@ -28,7 +29,7 @@ class LogInserterService(private val project: Project) { logTag: String, framework: LoggingSettings.LoggingFramework = LoggingSettings.LoggingFramework.PRINTLN, ) { - val strategy = LogStrategyFactory.getStrategy(framework) + val strategy = LogStrategyFactory.getStrategy(framework, LoggingSettings.getInstance(project).state) val factory = KtPsiFactory(project) val assignments = PsiTreeUtil.findChildrenOfType( @@ -72,7 +73,7 @@ class LogInserterService(private val project: Project) { logTag: String, framework: LoggingSettings.LoggingFramework = LoggingSettings.LoggingFramework.PRINTLN, ) { - val strategy = LogStrategyFactory.getStrategy(framework) + val strategy = LogStrategyFactory.getStrategy(framework, LoggingSettings.getInstance(project).state) val factory = KtPsiFactory(project) val functions = PsiTreeUtil.findChildrenOfType( @@ -114,7 +115,7 @@ class LogInserterService(private val project: Project) { logTag: String, framework: LoggingSettings.LoggingFramework = LoggingSettings.LoggingFramework.PRINTLN, ) { - val strategy = LogStrategyFactory.getStrategy(framework) + val strategy = LogStrategyFactory.getStrategy(framework, LoggingSettings.getInstance(project).state) val factory = JavaPsiFacade.getElementFactory(project) val methods = PsiTreeUtil.findChildrenOfType(searchScope, PsiMethod::class.java) @@ -146,7 +147,7 @@ class LogInserterService(private val project: Project) { logTag: String, framework: LoggingSettings.LoggingFramework = LoggingSettings.LoggingFramework.PRINTLN, ) { - val strategy = LogStrategyFactory.getStrategy(framework) + val strategy = LogStrategyFactory.getStrategy(framework, LoggingSettings.getInstance(project).state) val factory = JavaPsiFacade.getElementFactory(project) val assignments = PsiTreeUtil.findChildrenOfType( @@ -205,9 +206,15 @@ class LogInserterService(private val project: Project) { val psiClass = JavaPsiFacade.getInstance(project) - .findClass(importPath, file.resolveScope) ?: return - val importStatement = factory.createImportStatement(psiClass) - importList.add(importStatement) + .findClass(importPath, file.resolveScope) + if (psiClass != null) { + val importStatement = factory.createImportStatement(psiClass) + importList.add(importStatement) + } else { + val tempFile = PsiFileFactory.getInstance(project).createFileFromText("Dummy.java", com.intellij.lang.java.JavaLanguage.INSTANCE, "import $importPath;\nclass Dummy {}") as PsiJavaFile + val importStatement = tempFile.importList?.allImportStatements?.firstOrNull() ?: return + importList.add(importStatement) + } } fun removeLogs( @@ -215,7 +222,7 @@ class LogInserterService(private val project: Project) { logTag: String, framework: LoggingSettings.LoggingFramework = LoggingSettings.LoggingFramework.PRINTLN, ) { - val strategy = LogStrategyFactory.getStrategy(framework) + val strategy = LogStrategyFactory.getStrategy(framework, LoggingSettings.getInstance(project).state) val patterns = strategy.getRemovalPatterns(logTag) if (searchScope.containingFile is PsiJavaFile) { diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt index 4604fce..f47cb4c 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt @@ -84,12 +84,53 @@ class NapierStrategy : LogStrategy { override fun getJavaImport(): String? = null } +class CustomLogStrategy( + private val kotlinTemplate: String, + private val javaTemplate: String, + private val importPath: String?, +) : LogStrategy { + override fun createKotlinLog( + factory: KtPsiFactory, + tag: String, + message: String, + ): String = kotlinTemplate.replace("{tag}", tag).replace("{message}", message) + + override fun createJavaLog( + factory: PsiElementFactory, + tag: String, + message: String, + ): String { + val tagReplaced = javaTemplate.replace("{tag}", tag) + return if (message.endsWith(")")) { + // Method-style: message ends with ")", the template's closing " is needed to form the ")" string literal + tagReplaced.replace("{message}", message) + } else { + // Assignment-style: message ends with a variable (e.g. " + x"), no closing " from template needed + tagReplaced.replace("\"{message}\"", "\"$message").replace("{message}", message) + } + } + + override fun getRemovalPatterns(tag: String): List = listOf(tag) + + override fun getKotlinImport(): String? = importPath?.takeIf { it.isNotBlank() } + + override fun getJavaImport(): String? = importPath?.takeIf { it.isNotBlank() } +} + object LogStrategyFactory { - fun getStrategy(framework: LoggingSettings.LoggingFramework): LogStrategy { + fun getStrategy( + framework: LoggingSettings.LoggingFramework, + state: LoggingSettings.State? = null, + ): LogStrategy { return when (framework) { LoggingSettings.LoggingFramework.PRINTLN -> PrintlnStrategy() LoggingSettings.LoggingFramework.TIMBER -> TimberStrategy() LoggingSettings.LoggingFramework.NAPIER -> NapierStrategy() + LoggingSettings.LoggingFramework.CUSTOM -> CustomLogStrategy( + state?.customKotlinTemplate ?: "Log.d(\"{tag}\", \"{message}\")", + state?.customJavaTemplate ?: "Log.d(\"{tag}\", \"{message}\");", + state?.customImport, + ) } } } diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/settings/LoggingSettings.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/settings/LoggingSettings.kt index dc51d2e..f346eaf 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/settings/LoggingSettings.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/settings/LoggingSettings.kt @@ -14,6 +14,7 @@ class LoggingSettings : PersistentStateComponent { PRINTLN("System Println"), TIMBER("Timber"), NAPIER("Napier"), + CUSTOM("Custom"), } data class State( @@ -21,6 +22,9 @@ class LoggingSettings : PersistentStateComponent { var trackAssignments: Boolean = true, var logTag: String = "Myfancy log", var loggingFramework: LoggingFramework = LoggingFramework.PRINTLN, + var customKotlinTemplate: String = "Log.d(\"{tag}\", \"{message}\")", + var customJavaTemplate: String = "Log.d(\"{tag}\", \"{message}\");", + var customImport: String = "", ) private var myState = State() diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt index aa998d3..8d4f707 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt @@ -62,7 +62,7 @@ class LoggingToolWindowFactory : ToolWindowFactory { fun updatePreview() { val state = settings.state val logTag = state.logTag - val strategy = LogStrategyFactory.getStrategy(state.loggingFramework) + val strategy = LogStrategyFactory.getStrategy(state.loggingFramework, state) val preview = StringBuilder() val ktFactory = org.jetbrains.kotlin.psi.KtPsiFactory(project) @@ -92,13 +92,61 @@ class LoggingToolWindowFactory : ToolWindowFactory { previewArea.text = preview.toString() } + val customKotlinTemplateLabel = JBLabel("Kotlin Template ({tag}, {message}):") + val customKotlinTemplateField = + JBTextField(settings.state.customKotlinTemplate).apply { + document.addDocumentListener( + object : DocumentListener { + override fun insertUpdate(e: DocumentEvent) { settings.state.customKotlinTemplate = text; updatePreview() } + override fun removeUpdate(e: DocumentEvent) { settings.state.customKotlinTemplate = text; updatePreview() } + override fun changedUpdate(e: DocumentEvent) { settings.state.customKotlinTemplate = text; updatePreview() } + }, + ) + } + + val customJavaTemplateLabel = JBLabel("Java Template ({tag}, {message}):") + val customJavaTemplateField = + JBTextField(settings.state.customJavaTemplate).apply { + document.addDocumentListener( + object : DocumentListener { + override fun insertUpdate(e: DocumentEvent) { settings.state.customJavaTemplate = text; updatePreview() } + override fun removeUpdate(e: DocumentEvent) { settings.state.customJavaTemplate = text; updatePreview() } + override fun changedUpdate(e: DocumentEvent) { settings.state.customJavaTemplate = text; updatePreview() } + }, + ) + } + + val customImportLabel = JBLabel("Import (optional):") + val customImportField = + JBTextField(settings.state.customImport).apply { + document.addDocumentListener( + object : DocumentListener { + override fun insertUpdate(e: DocumentEvent) { settings.state.customImport = text; updatePreview() } + override fun removeUpdate(e: DocumentEvent) { settings.state.customImport = text; updatePreview() } + override fun changedUpdate(e: DocumentEvent) { settings.state.customImport = text; updatePreview() } + }, + ) + } + + fun updateCustomFieldsVisibility(framework: LoggingSettings.LoggingFramework) { + val isCustom = framework == LoggingSettings.LoggingFramework.CUSTOM + customKotlinTemplateLabel.isVisible = isCustom + customKotlinTemplateField.isVisible = isCustom + customJavaTemplateLabel.isVisible = isCustom + customJavaTemplateField.isVisible = isCustom + customImportLabel.isVisible = isCustom + customImportField.isVisible = isCustom + } + val frameworkModel = CollectionComboBoxModel(LoggingSettings.LoggingFramework.entries) val frameworkCombo = ComboBox(frameworkModel).apply { renderer = SimpleListCellRenderer.create("") { it.displayName } selectedItem = settings.state.loggingFramework addActionListener { - settings.state.loggingFramework = selectedItem as LoggingSettings.LoggingFramework + val selected = selectedItem as LoggingSettings.LoggingFramework + settings.state.loggingFramework = selected + updateCustomFieldsVisibility(selected) updatePreview() } } @@ -144,6 +192,18 @@ class LoggingToolWindowFactory : ToolWindowFactory { constraints.gridy++ settingsPanel.add(frameworkCombo, constraints) constraints.gridy++ + settingsPanel.add(customKotlinTemplateLabel, constraints) + constraints.gridy++ + settingsPanel.add(customKotlinTemplateField, constraints) + constraints.gridy++ + settingsPanel.add(customJavaTemplateLabel, constraints) + constraints.gridy++ + settingsPanel.add(customJavaTemplateField, constraints) + constraints.gridy++ + settingsPanel.add(customImportLabel, constraints) + constraints.gridy++ + settingsPanel.add(customImportField, constraints) + constraints.gridy++ settingsPanel.add(JBLabel("Log Tag:"), constraints) constraints.gridy++ settingsPanel.add(tagField, constraints) @@ -155,6 +215,7 @@ class LoggingToolWindowFactory : ToolWindowFactory { mainPanel.add(settingsPanel, BorderLayout.NORTH) mainPanel.add(previewArea, BorderLayout.CENTER) + updateCustomFieldsVisibility(settings.state.loggingFramework) updatePreview() val content = ContentFactory.getInstance().createContent(mainPanel, "", false) diff --git a/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt b/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt new file mode 100644 index 0000000..56839f6 --- /dev/null +++ b/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt @@ -0,0 +1,478 @@ +package com.github.kiolk.loggingplugin.services + +import com.github.kiolk.loggingplugin.settings.LoggingSettings +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.testFramework.fixtures.BasePlatformTestCase +import org.jetbrains.kotlin.psi.KtFile + +class CustomLogInserterServiceTest : BasePlatformTestCase() { + private lateinit var service: LogInserterService + + override fun setUp() { + super.setUp() + service = LogInserterService.getInstance(project) + val state = LoggingSettings.getInstance(project).state + state.customKotlinTemplate = "MyLogger.log(\"{tag}\", \"{message}\")" + state.customJavaTemplate = "MyLogger.log(\"{tag}\", \"{message}\");" + state.customImport = "com.example.MyLogger" + } + + // region Kotlin — Assignment + + fun testInsertKotlinAssignmentCustomLogs() { + val before = + """ + fun test() { + var x = 1 + x = 2 + } + """.trimIndent() + + val after = + """ + import com.example.MyLogger + + fun test() { + var x = 1 + x = 2 + MyLogger.log("TestTag", "x assigned new value: ${'$'}{x}") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + fun testInsertKotlinAssignmentCustomLogsWithPackage() { + val before = + """ + package com.example + + fun test() { + var x = 1 + x = 2 + } + """.trimIndent() + + val after = + """ + package com.example + + import com.example.MyLogger + + fun test() { + var x = 1 + x = 2 + MyLogger.log("TestTag", "x assigned new value: ${'$'}{x}") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + fun testInsertKotlinAssignmentCustomLogsIdempotency() { + val content = + """ + import com.example.MyLogger + + fun test() { + var x = 1 + x = 2 + MyLogger.log("TestTag", "x assigned new value: ${'$'}{x}") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", content) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(content) + } + + fun testInsertKotlinAssignmentCustomLogsWithExistingImport() { + val content = + """ + import com.example.MyLogger + + fun test() { + var x = 1 + x = 2 + MyLogger.log("TestTag", "x assigned new value: ${'$'}{x}") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", content) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(content) + } + + // endregion + + // region Kotlin — Method + + fun testInsertKotlinMethodCustomLogs() { + val before = + """ + fun test(param: String) { + val y = 0 + } + """.trimIndent() + + val after = + """ + import com.example.MyLogger + + fun test(param: String) { + MyLogger.log("TestTag", "test(param=${'$'}{param})") + val y = 0 + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinMethodLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion + + // region Kotlin — Custom template without import + + fun testInsertKotlinCustomLogsWithoutImport() { + LoggingSettings.getInstance(project).state.customImport = "" + + val before = + """ + fun test() { + var x = 1 + x = 2 + } + """.trimIndent() + + val after = + """ + fun test() { + var x = 1 + x = 2 + MyLogger.log("TestTag", "x assigned new value: ${'$'}{x}") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion + + // region Kotlin — Custom template with only {message} (e.g. Crashlytics style) + + fun testInsertKotlinCrashlyticsStyleCustomLogs() { + val state = LoggingSettings.getInstance(project).state + state.customKotlinTemplate = "Crashlytics.log(\"{message}\")" + state.customImport = "" + + val before = + """ + fun test() { + var x = 1 + x = 2 + } + """.trimIndent() + + val after = + """ + fun test() { + var x = 1 + x = 2 + Crashlytics.log("x assigned new value: ${'$'}{x}") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.insertKotlinAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion + + // region Kotlin — Removal + + fun testRemoveKotlinCustomLogs() { + val before = + """ + fun test() { + MyLogger.log("TestTag", "some log") + var x = 1 + MyLogger.log("OtherTag", "other log") + } + """.trimIndent() + + val after = + """ + fun test() { + var x = 1 + MyLogger.log("OtherTag", "other log") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.removeLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + fun testRemoveKotlinCustomLogsAlsoRemovesImport() { + val before = + """ + import com.example.MyLogger + + fun test() { + MyLogger.log("TestTag", "some log") + var x = 1 + } + """.trimIndent() + + val after = + """ + fun test() { + var x = 1 + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.removeLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + fun testRemoveKotlinCustomLogsKeepsImportWhenOtherLogsRemain() { + val before = + """ + import com.example.MyLogger + + fun test() { + MyLogger.log("TestTag", "some log") + MyLogger.log("OtherTag", "other log") + } + """.trimIndent() + + val after = + """ + import com.example.MyLogger + + fun test() { + MyLogger.log("OtherTag", "other log") + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.removeLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + fun testRemoveCustomLogInsideScopeFunctionKeepsBlock() { + val before = + """ + fun test() { + args.productUUID?.apply { + productUUID = this + MyLogger.log("TestTag", "productUUID assigned new value: ${'$'}{productUUID}") + } + } + """.trimIndent() + + val after = + """ + fun test() { + args.productUUID?.apply { + productUUID = this + } + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.kt", before) as KtFile + + WriteCommandAction.runWriteCommandAction(project) { + service.removeLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion + + // region Java — Assignment + + fun testInsertJavaAssignmentCustomLogs() { + val before = + """ + public class Test { + public void test() { + int x = 1; + x = 2; + } + } + """.trimIndent() + + val after = + """ + import com.example.MyLogger; + + public class Test { + public void test() { + int x = 1; + x = 2; + MyLogger.log("TestTag", "x assigned new value: " + x); + } + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.java", before) + + WriteCommandAction.runWriteCommandAction(project) { + service.insertJavaAssignmentLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion + + // region Java — Method + + fun testInsertJavaMethodCustomLogs() { + val before = + """ + public class Test { + public void test(String param) { + int y = 0; + } + } + """.trimIndent() + + val after = + """ + import com.example.MyLogger; + + public class Test { + public void test(String param) { + MyLogger.log("TestTag", "test(param=" + param + ")"); + int y = 0; + } + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.java", before) + + WriteCommandAction.runWriteCommandAction(project) { + service.insertJavaMethodLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion + + // region Java — Removal + + fun testRemoveJavaCustomLogs() { + val before = + """ + public class Test { + public void test() { + MyLogger.log("TestTag", "log"); + int x = 1; + } + } + """.trimIndent() + + val after = + """ + public class Test { + public void test() { + int x = 1; + } + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.java", before) + + WriteCommandAction.runWriteCommandAction(project) { + service.removeLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + fun testRemoveJavaCustomLogsKeepsOtherTags() { + val before = + """ + public class Test { + public void test() { + MyLogger.log("TestTag", "log"); + MyLogger.log("OtherTag", "other log"); + int x = 1; + } + } + """.trimIndent() + + val after = + """ + public class Test { + public void test() { + MyLogger.log("OtherTag", "other log"); + int x = 1; + } + } + """.trimIndent() + + val psiFile = myFixture.configureByText("Test.java", before) + + WriteCommandAction.runWriteCommandAction(project) { + service.removeLogs(psiFile, "TestTag", LoggingSettings.LoggingFramework.CUSTOM) + } + + myFixture.checkResult(after) + } + + // endregion +} \ No newline at end of file From 1089efc9f9aa3c4f8b695217caa71562cf21f1ed Mon Sep 17 00:00:00 2001 From: Yauheni Slizh Date: Tue, 7 Apr 2026 23:57:16 +0200 Subject: [PATCH 2/2] Fix ktlint violations in custom logging framework code Co-Authored-By: Claude Opus 4.6 (1M context) --- .../services/LogInserterService.kt | 7 ++- .../loggingplugin/services/LogStrategy.kt | 11 ++-- .../toolwindow/LoggingToolWindowFactory.kt | 51 +++++++++++++++---- .../services/CustomLogInserterServiceTest.kt | 2 +- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt index 5063e54..c24a8ba 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogInserterService.kt @@ -211,7 +211,12 @@ class LogInserterService(private val project: Project) { val importStatement = factory.createImportStatement(psiClass) importList.add(importStatement) } else { - val tempFile = PsiFileFactory.getInstance(project).createFileFromText("Dummy.java", com.intellij.lang.java.JavaLanguage.INSTANCE, "import $importPath;\nclass Dummy {}") as PsiJavaFile + val tempFile = + PsiFileFactory.getInstance(project).createFileFromText( + "Dummy.java", + com.intellij.lang.java.JavaLanguage.INSTANCE, + "import $importPath;\nclass Dummy {}", + ) as PsiJavaFile val importStatement = tempFile.importList?.allImportStatements?.firstOrNull() ?: return importList.add(importStatement) } diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt index f47cb4c..e2ce5fd 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/services/LogStrategy.kt @@ -126,11 +126,12 @@ object LogStrategyFactory { LoggingSettings.LoggingFramework.PRINTLN -> PrintlnStrategy() LoggingSettings.LoggingFramework.TIMBER -> TimberStrategy() LoggingSettings.LoggingFramework.NAPIER -> NapierStrategy() - LoggingSettings.LoggingFramework.CUSTOM -> CustomLogStrategy( - state?.customKotlinTemplate ?: "Log.d(\"{tag}\", \"{message}\")", - state?.customJavaTemplate ?: "Log.d(\"{tag}\", \"{message}\");", - state?.customImport, - ) + LoggingSettings.LoggingFramework.CUSTOM -> + CustomLogStrategy( + state?.customKotlinTemplate ?: "Log.d(\"{tag}\", \"{message}\")", + state?.customJavaTemplate ?: "Log.d(\"{tag}\", \"{message}\");", + state?.customImport, + ) } } } diff --git a/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt b/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt index 8d4f707..1ab4fd5 100644 --- a/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt +++ b/src/main/kotlin/com/github/kiolk/loggingplugin/toolwindow/LoggingToolWindowFactory.kt @@ -97,9 +97,20 @@ class LoggingToolWindowFactory : ToolWindowFactory { JBTextField(settings.state.customKotlinTemplate).apply { document.addDocumentListener( object : DocumentListener { - override fun insertUpdate(e: DocumentEvent) { settings.state.customKotlinTemplate = text; updatePreview() } - override fun removeUpdate(e: DocumentEvent) { settings.state.customKotlinTemplate = text; updatePreview() } - override fun changedUpdate(e: DocumentEvent) { settings.state.customKotlinTemplate = text; updatePreview() } + override fun insertUpdate(e: DocumentEvent) { + settings.state.customKotlinTemplate = text + updatePreview() + } + + override fun removeUpdate(e: DocumentEvent) { + settings.state.customKotlinTemplate = text + updatePreview() + } + + override fun changedUpdate(e: DocumentEvent) { + settings.state.customKotlinTemplate = text + updatePreview() + } }, ) } @@ -109,9 +120,20 @@ class LoggingToolWindowFactory : ToolWindowFactory { JBTextField(settings.state.customJavaTemplate).apply { document.addDocumentListener( object : DocumentListener { - override fun insertUpdate(e: DocumentEvent) { settings.state.customJavaTemplate = text; updatePreview() } - override fun removeUpdate(e: DocumentEvent) { settings.state.customJavaTemplate = text; updatePreview() } - override fun changedUpdate(e: DocumentEvent) { settings.state.customJavaTemplate = text; updatePreview() } + override fun insertUpdate(e: DocumentEvent) { + settings.state.customJavaTemplate = text + updatePreview() + } + + override fun removeUpdate(e: DocumentEvent) { + settings.state.customJavaTemplate = text + updatePreview() + } + + override fun changedUpdate(e: DocumentEvent) { + settings.state.customJavaTemplate = text + updatePreview() + } }, ) } @@ -121,9 +143,20 @@ class LoggingToolWindowFactory : ToolWindowFactory { JBTextField(settings.state.customImport).apply { document.addDocumentListener( object : DocumentListener { - override fun insertUpdate(e: DocumentEvent) { settings.state.customImport = text; updatePreview() } - override fun removeUpdate(e: DocumentEvent) { settings.state.customImport = text; updatePreview() } - override fun changedUpdate(e: DocumentEvent) { settings.state.customImport = text; updatePreview() } + override fun insertUpdate(e: DocumentEvent) { + settings.state.customImport = text + updatePreview() + } + + override fun removeUpdate(e: DocumentEvent) { + settings.state.customImport = text + updatePreview() + } + + override fun changedUpdate(e: DocumentEvent) { + settings.state.customImport = text + updatePreview() + } }, ) } diff --git a/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt b/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt index 56839f6..e396f5f 100644 --- a/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt +++ b/src/test/kotlin/com/github/kiolk/loggingplugin/services/CustomLogInserterServiceTest.kt @@ -475,4 +475,4 @@ class CustomLogInserterServiceTest : BasePlatformTestCase() { } // endregion -} \ No newline at end of file +}