From 256192111877482a2e2ceeda806064920008b59e Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Sun, 12 May 2024 12:52:59 +0300 Subject: Version 2.1.0 Fixed a bunch of issues with the new changes Trident settings are now under "tools" section Updated README.md Renamed some UI elements --- .../kotlin/me/kyren223/trident/data/Settings.kt | 5 +- .../me/kyren223/trident/data/SettingsData.kt | 56 +++++++++-- .../kotlin/me/kyren223/trident/tests/SplitTest.kt | 61 ++++++++++++ .../me/kyren223/trident/ui/SettingsConfigurable.kt | 7 +- .../me/kyren223/trident/utils/TridentUtils.kt | 103 ++++++++++++++------- 5 files changed, 183 insertions(+), 49 deletions(-) create mode 100644 src/main/kotlin/me/kyren223/trident/tests/SplitTest.kt (limited to 'src/main/kotlin/me/kyren223/trident') diff --git a/src/main/kotlin/me/kyren223/trident/data/Settings.kt b/src/main/kotlin/me/kyren223/trident/data/Settings.kt index 27a7d2a..a1a400b 100644 --- a/src/main/kotlin/me/kyren223/trident/data/Settings.kt +++ b/src/main/kotlin/me/kyren223/trident/data/Settings.kt @@ -8,7 +8,7 @@ import com.intellij.openapi.components.* @State(name = "me.kyren223.trident.data.SettingsState", storages = [Storage("SdkSettingsPlugin.xml")]) class Settings : SimplePersistentStateComponent(SettingsState()) { companion object { - val instance: Settings + private val instance: Settings get() = ApplicationManager.getApplication().getService(Settings::class.java) val state: SettingsState get() = instance.state @@ -20,7 +20,8 @@ class SettingsState : BaseState() { var height = 400 var fontSize = 20 var enterToSelect = true - var automaticMapping = false + var automaticMapping = AutomaticMapping.Disabled + var automaticReplacing = AutomaticReplacing.Smart var recursiveMapping = false var rememberLine = false var indexCycling = false diff --git a/src/main/kotlin/me/kyren223/trident/data/SettingsData.kt b/src/main/kotlin/me/kyren223/trident/data/SettingsData.kt index eed655e..b4c48f7 100644 --- a/src/main/kotlin/me/kyren223/trident/data/SettingsData.kt +++ b/src/main/kotlin/me/kyren223/trident/data/SettingsData.kt @@ -1,5 +1,6 @@ package me.kyren223.trident.data +import com.intellij.openapi.ui.ComboBox import com.intellij.ui.JBColor import com.intellij.ui.JBIntSpinner import com.intellij.ui.components.JBCheckBox @@ -9,7 +10,7 @@ import com.intellij.util.ui.JBFont import javax.swing.JPanel class SettingsData { - + private val minValue = 1 private val maxValue = 5000 private val step = 10 @@ -22,11 +23,15 @@ class SettingsData { private val enterToSelect = JBCheckBox(null, Settings.state.enterToSelect) private val rememberLine = JBCheckBox(null, Settings.state.rememberLine) - private val automaticMapping = JBCheckBox(null, Settings.state.automaticMapping) + private val automaticMapping = ComboBox(AutomaticMapping.entries.toTypedArray()) + private val automaticReplacing = ComboBox(AutomaticReplacing.entries.toTypedArray()) private val recursiveMapping = JBCheckBox(null, Settings.state.recursiveMapping) private val indexCycling = JBCheckBox(null, Settings.state.indexCycling) init { + automaticMapping.selectedItem = Settings.state.automaticMapping + automaticReplacing.selectedItem = Settings.state.automaticReplacing + panel = FormBuilder.createFormBuilder() .addComponent(JBLabel("Popup settings").withFont(JBFont.h4())) .addLabeledComponent("Popup width", width) @@ -41,9 +46,16 @@ class SettingsData { .addVerticalGap(step) .addLabeledComponent("Automatic mapping (when possible)", automaticMapping) - .addComponent(desc("If enabled, when using the Append action, " + - "the full file path will be added to the Trident Mappings.")) - .addComponent(desc("Mapping Entry: $=/.")) + .addComponent(desc("Disabled - adds the full file path to the Trident Mappings.")) + .addComponent(desc("Filename - Adds the filename (with extension).")) + .addComponent(desc("Filename (no extension) - Adds the filename (without extension).")) + .addVerticalGap(step) + + .addLabeledComponent("Automatic replacing (when possible)", automaticReplacing) + .addComponent(desc("Disabled - Keeps the full file path.")) + .addComponent(desc("Exact - Replaces the full path if an exact match is found.")) + .addComponent(desc("Smart - Like exact but if no exact match found, " + + "it will try to make the path shorter.")) .addVerticalGap(step) .addLabeledComponent("Recursive mapping", recursiveMapping) @@ -103,12 +115,20 @@ class SettingsData { this.enterToSelect.isSelected = enter } - fun getAutomaticMapping(): Boolean { - return automaticMapping.isSelected + fun getAutomaticMapping(): AutomaticMapping { + return automaticMapping.selectedItem as AutomaticMapping } - fun setAutomaticMapping(automaticMapping: Boolean) { - this.automaticMapping.isSelected = automaticMapping + fun setAutomaticMapping(automaticMapping: AutomaticMapping) { + this.automaticMapping.selectedItem = automaticMapping + } + + fun getAutomaticReplacing(): AutomaticReplacing { + return automaticReplacing.selectedItem as AutomaticReplacing + } + + fun setAutomaticReplacing(automaticReplacing: AutomaticReplacing) { + this.automaticReplacing.selectedItem = automaticReplacing } fun getRememberLine(): Boolean { @@ -135,3 +155,21 @@ class SettingsData { this.indexCycling.isSelected = indexCycling } } + +enum class AutomaticMapping { + Disabled, + Filename, + FilenameNoExtension, + ; + + override fun toString(): String { + if (this == FilenameNoExtension) return "Filename (without extension)" + return super.toString() + } +} + +enum class AutomaticReplacing { + Disabled, + Exact, + Smart, +} diff --git a/src/main/kotlin/me/kyren223/trident/tests/SplitTest.kt b/src/main/kotlin/me/kyren223/trident/tests/SplitTest.kt new file mode 100644 index 0000000..e4ea477 --- /dev/null +++ b/src/main/kotlin/me/kyren223/trident/tests/SplitTest.kt @@ -0,0 +1,61 @@ +package me.kyren223.trident.tests + +import org.junit.Test + +class SplitTest { + + @Test + fun testSplit() { + val filenameAndExtension = "SplitTest.kt" + val filename = "SplitTest" + val dotfile = ".ideavimrc" + + val split = filenameAndExtension.split(".") + assert(split.size == 2) + assert(split[0] == filename) + assert(split[1] == "kt") + + val split2 = filename.split(".") + assert(split2.size == 1) + assert(split2[0] == filename) + + val split3 = dotfile.split(".") + assert(split3.size == 2) + assert(split3[0] == "") + assert(split3[1] == "ideavimrc") + + + } + + @Test + fun testSplit2() { + val path = "C:/Users/Owner/Projects/Trident/src/main/kotlin/me/kyren223/trident/tests/SplitTest.kt" + testPath(path, "SplitTest", "kt") + testPath("SplitTest.kt", "SplitTest", "kt") + testPath("SplitTest", "SplitTest", null) + testPath(".ideavimrc", null, "ideavimrc") + testPath("build.gradle.kts", "build.gradle", "kts") + + } + + private fun testPath(path: String, filename: String?, extension: String?) { + + val fullFilename = path.split("/").last() + println("fullFilename: $fullFilename") + val lastDot = fullFilename.lastIndexOf(".") + val noExtension = lastDot == -1 + + val filename2 = if (noExtension) fullFilename else { + fullFilename.substring(0, lastDot).ifEmpty { null } + } + val extension2 = if (noExtension) null else fullFilename.substring(lastDot + 1) + + println("filename: $filename") + println("extension: $extension") + println("filename2: $filename2") + println("extension2: $extension2") + + assert(filename2 == filename) + assert(extension2 == extension) + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/kyren223/trident/ui/SettingsConfigurable.kt b/src/main/kotlin/me/kyren223/trident/ui/SettingsConfigurable.kt index 79c4fdc..c0d1247 100644 --- a/src/main/kotlin/me/kyren223/trident/ui/SettingsConfigurable.kt +++ b/src/main/kotlin/me/kyren223/trident/ui/SettingsConfigurable.kt @@ -27,6 +27,7 @@ class SettingsConfigurable : Configurable { if (settings.fontSize != this.settings!!.getFontSize()) return true if (settings.enterToSelect != this.settings!!.getEnterToSelect()) return true if (settings.automaticMapping != this.settings!!.getAutomaticMapping()) return true + if (settings.automaticReplacing != this.settings!!.getAutomaticReplacing()) return true if (settings.recursiveMapping != this.settings!!.getRecursiveMapping()) return true if (settings.rememberLine != this.settings!!.getRememberLine()) return true if (settings.indexCycling != this.settings!!.getIndexCycling()) return true @@ -40,6 +41,7 @@ class SettingsConfigurable : Configurable { settings.fontSize = this.settings!!.getFontSize() settings.enterToSelect = this.settings!!.getEnterToSelect() settings.automaticMapping = this.settings!!.getAutomaticMapping() + settings.automaticReplacing = this.settings!!.getAutomaticReplacing() settings.recursiveMapping = this.settings!!.getRecursiveMapping() settings.rememberLine = this.settings!!.getRememberLine() settings.indexCycling = this.settings!!.getIndexCycling() @@ -47,14 +49,13 @@ class SettingsConfigurable : Configurable { override fun reset() { val settings = Settings.state - if (this.settings == null) { - this.settings = SettingsData() - } + if (this.settings == null) this.settings = SettingsData() this.settings!!.setWidth(settings.width) this.settings!!.setHeight(settings.height) this.settings!!.setFontSize(settings.fontSize) this.settings!!.setEnterToSelect(settings.enterToSelect) this.settings!!.setAutomaticMapping(settings.automaticMapping) + this.settings!!.setAutomaticReplacing(settings.automaticReplacing) this.settings!!.setRecursiveMapping(settings.recursiveMapping) this.settings!!.setRememberLine(settings.rememberLine) this.settings!!.setIndexCycling(settings.indexCycling) diff --git a/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt b/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt index b2302d7..f00e568 100644 --- a/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt +++ b/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt @@ -5,6 +5,8 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile +import me.kyren223.trident.data.AutomaticMapping +import me.kyren223.trident.data.AutomaticReplacing import me.kyren223.trident.data.Settings object TridentList { @@ -17,42 +19,72 @@ object TridentList { return expandedPath.isNotBlank() && LocalFileSystem.getInstance().findFileByPath(expandedPath) != null } - private fun getShortPath(path: String): String? { - // For path `/path/to/file.ext` the result should be `$file` - // Unless for dot files, in which case it should be `$ext` - // Examples: - // - `/path/to/TridentUtils.kt` -> `$TridentUtils` - // - `/path/to/someBinary` -> `$someBinary` - // - `/path/to/.ideavimrc` -> `$ideavimrc` + private fun getModifiedPath(project: Project, path: String): String { + val automaticMapping = Settings.state.automaticMapping + val automaticReplacing = Settings.state.automaticReplacing + val mappings = TridentMappings.get(project) + + val hasReplacement = automaticReplacing != AutomaticReplacing.Disabled + && mappings.containsValue(path) + + if (hasReplacement) { + return mappings.filterValues { it == path }.keys.firstOrNull()!! + } + + if (automaticMapping == AutomaticMapping.Disabled) { + return if (automaticReplacing == AutomaticReplacing.Smart) { + return smartReplacement(path, mappings) + } else path + } + return path.split("/") .lastOrNull() ?.let { - it.split(".") - .let { parts -> - when (parts.size) { - 0 -> it - 1, 2 -> parts.firstOrNull() - else -> return null - } - } - } - ?.let { "\$${it}" } + if (automaticMapping == AutomaticMapping.Filename) { + return@let it + } + val dotIndex = it.lastIndexOf(".") + val filename = if (dotIndex == -1) it else it.substring(0, dotIndex).ifBlank { null } + val extension = if (dotIndex == -1) null else it.substring(dotIndex + 1) + return@let (filename ?: extension)!! + }?.let { + val key = "\$$it" + TridentMappings.append(project, key, path) + return@let key + } ?: path } - + + private fun smartReplacement(path: String, mappings: Map): String { + // This is technically redundant, + // The smart path is sorted based on length, so the longest path will be the first + // And the longest path will be the first path that exactly matches + val exactPath = mappings.filter { it.value == path }.keys.firstOrNull() + exactPath?.let { return it } + + var smartPath = path + for ((key, value) in mappings + .toList() + .sortedByDescending { it.second.length } + .associate { it.first to it.second }) { + smartPath = smartPath.replace(value, key) + } + return smartPath + } + fun append(project: Project, file: VirtualFile) { + println("TridentList.append - file: ${file.path}") val files = get(project).toMutableList() - - val automaticMapping = Settings.state.automaticMapping - val path = if (automaticMapping) { - val shortPath = getShortPath(file.path) ?: file.path - if (TridentMappings.exists(project, shortPath)) file.path else { - TridentMappings.append(project, shortPath, file.path) - shortPath - } - } else file.path - + val path = getModifiedPath(project, file.path) + println("TridentList.append - path: $path") files.add(path) + println("TridentList.append - add: " + files.joinToString(", ")) set(project, files) + println("TridentList.append - set") + + println("TridentList.append - TridentList: " + get(project).joinToString(", ")) + println("TridentList.append - TridentMappings: " + TridentMappings.get(project) + .map { "${it.key}=${it.value}" } + .joinToString(", ")) } fun set(project: Project, files: List) { @@ -92,18 +124,23 @@ object TridentMappings { private fun isValidEntry(key: String, value: String): Boolean { // Requirements: // - Key and value must not be blank - // - key must only contain alphanumeric characters and start with $ + // - key must start with $ + // - key must only contain alphanumeric characters, underscores, hyphens, and dots // - value must not contain = return key.isNotBlank() && value.isNotBlank() && - key.matches(Regex("""^\$[a-zA-Z0-9]+$""")) && + key.matches(Regex("""^\$[a-zA-Z0-9_.\-]+$""")) && value.matches(Regex("""^[^=]+$""")) } fun append(project: Project, key: String, value: String, overwrite: Boolean = false) { + println("TridentMappings.append - key: $key, value: $value") val map = get(project).toMutableMap() - if (map.contains(key) && !overwrite) return + if (map.containsKey(key) && !overwrite) return + println("TridentMappings.append - map: $map") map[key] = value + println("TridentMappings.append - map after: $map") set(project, map) + println("TridentMappings.append - set: ${get(project).map { "${it.key}=${it.value}" }.joinToString(", ")}") } fun set(project: Project, mappings: Map) { @@ -149,8 +186,4 @@ object TridentMappings { return expandedPath } - - fun exists(project: Project, key: String): Boolean { - return get(project).containsKey(key) - } } \ No newline at end of file -- cgit v1.3.1