From 9b9c0f0594209b8c4ecdb7901293734ccf567437 Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Thu, 9 May 2024 18:09:24 +0300 Subject: Finished implementing all the settings, mapping menu, trident list menu, and fixed all the bugs/issues. Added more index actions for a total of 10 actions (compared to the original 4). Updated README.md and TODO.md. Changed version to 2.0.0. Versions now follow the semver standard. which means that for each major version there will be backwards incompatible changes. for minor versions there will be new features and bug fixes. and for patch versions there will be bug fixes only. --- .../me/kyren223/trident/actions/AppendAction.kt | 16 -- .../me/kyren223/trident/actions/SelectAction.kt | 44 ----- .../trident/actions/TridentAppendAction.kt | 16 ++ .../kyren223/trident/actions/TridentListAction.kt | 20 --- .../trident/actions/TridentListSelectAction.kt | 5 +- .../trident/actions/TridentSelectAction.kt | 44 +++++ .../kotlin/me/kyren223/trident/data/Settings.kt | 27 +++ .../me/kyren223/trident/data/SettingsData.kt | 27 ++- .../me/kyren223/trident/data/SettingsState.kt | 33 ---- .../me/kyren223/trident/data/TridentState.kt | 181 --------------------- .../me/kyren223/trident/ui/SettingsConfigurable.kt | 11 +- .../me/kyren223/trident/ui/TridentListMenu.kt | 36 ++-- .../me/kyren223/trident/ui/TridentMappingsMenu.kt | 12 +- .../me/kyren223/trident/utils/TridentUtils.kt | 88 +++++++--- src/main/kotlin/me/kyren223/trident/utils/Utils.kt | 12 +- 15 files changed, 224 insertions(+), 348 deletions(-) delete mode 100644 src/main/kotlin/me/kyren223/trident/actions/AppendAction.kt delete mode 100644 src/main/kotlin/me/kyren223/trident/actions/SelectAction.kt create mode 100644 src/main/kotlin/me/kyren223/trident/actions/TridentAppendAction.kt create mode 100644 src/main/kotlin/me/kyren223/trident/actions/TridentSelectAction.kt create mode 100644 src/main/kotlin/me/kyren223/trident/data/Settings.kt delete mode 100644 src/main/kotlin/me/kyren223/trident/data/SettingsState.kt delete mode 100644 src/main/kotlin/me/kyren223/trident/data/TridentState.kt (limited to 'src/main/kotlin/me/kyren223/trident') diff --git a/src/main/kotlin/me/kyren223/trident/actions/AppendAction.kt b/src/main/kotlin/me/kyren223/trident/actions/AppendAction.kt deleted file mode 100644 index 1b9a2b4..0000000 --- a/src/main/kotlin/me/kyren223/trident/actions/AppendAction.kt +++ /dev/null @@ -1,16 +0,0 @@ -package me.kyren223.trident.actions - -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFile -import me.kyren223.trident.utils.TridentList - -class AppendAction : AnAction() { - override fun actionPerformed(e: AnActionEvent) { - val project: Project = e.project ?: return - val file: VirtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return - TridentList.append(project, file) - } -} diff --git a/src/main/kotlin/me/kyren223/trident/actions/SelectAction.kt b/src/main/kotlin/me/kyren223/trident/actions/SelectAction.kt deleted file mode 100644 index 37617c4..0000000 --- a/src/main/kotlin/me/kyren223/trident/actions/SelectAction.kt +++ /dev/null @@ -1,44 +0,0 @@ -package me.kyren223.trident.actions - -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.fileEditor.FileEditorManager -import me.kyren223.trident.utils.TridentList - -class SelectAction : AnAction() { - override fun actionPerformed(e: AnActionEvent) { - val project = e.project ?: return - var index = when (val actionId = e.actionManager.getId(this)) { - NEXT -> { - val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return - val current = TridentList.getIndexOfFile(project, file) ?: return - current + 1 - } - - PREV -> { - val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return - val current = TridentList.getIndexOfFile(project, file) ?: return - current - 1 - } - - else -> { - getIndex(actionId!!) - } - } - - val file = TridentList.select(project, index) ?: return - FileEditorManager.getInstance(project).openFile(file, true) - } - - private fun getIndex(actionId: String): Int { - return actionId.substring(SELECT.length).toInt() - 1 - } - - companion object { - const val NEXT = "TridentSelectNext" - const val PREV = "TridentSelectPrev" - const val SELECT = "TridentSelect" - } -} - diff --git a/src/main/kotlin/me/kyren223/trident/actions/TridentAppendAction.kt b/src/main/kotlin/me/kyren223/trident/actions/TridentAppendAction.kt new file mode 100644 index 0000000..1b0d33a --- /dev/null +++ b/src/main/kotlin/me/kyren223/trident/actions/TridentAppendAction.kt @@ -0,0 +1,16 @@ +package me.kyren223.trident.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import me.kyren223.trident.utils.TridentList + +class TridentAppendAction : AnAction() { + override fun actionPerformed(e: AnActionEvent) { + val project: Project = e.project ?: return + val file: VirtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return + TridentList.append(project, file) + } +} diff --git a/src/main/kotlin/me/kyren223/trident/actions/TridentListAction.kt b/src/main/kotlin/me/kyren223/trident/actions/TridentListAction.kt index cef0bf2..0d733f3 100644 --- a/src/main/kotlin/me/kyren223/trident/actions/TridentListAction.kt +++ b/src/main/kotlin/me/kyren223/trident/actions/TridentListAction.kt @@ -2,32 +2,12 @@ package me.kyren223.trident.actions import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent -import com.maddyhome.idea.vim.api.injector -import com.maddyhome.idea.vim.command.MappingMode -import com.maddyhome.idea.vim.key.MappingOwner -import me.kyren223.trident.data.SettingsState import me.kyren223.trident.ui.TridentListMenu class TridentListAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { - if (!remapped) remap() val project = e.project ?: return TridentListMenu.open(project) } - // TODO move the remap to somewhere else - private fun remap() { - if (!SettingsState.instance.enterToSelect) return - val keys = injector.parser.parseKeys(":action TridentQuickMenuSelect") - val keyGroup = injector.keyGroup - keyGroup.putKeyMapping(MappingMode.NVO, - injector.parser.parseKeys(""), - MappingOwner.Plugin.get("Trident"), keys, false - ) - remapped = true - } - - companion object { - var remapped = false - } } diff --git a/src/main/kotlin/me/kyren223/trident/actions/TridentListSelectAction.kt b/src/main/kotlin/me/kyren223/trident/actions/TridentListSelectAction.kt index d1dfd2d..1b68a59 100644 --- a/src/main/kotlin/me/kyren223/trident/actions/TridentListSelectAction.kt +++ b/src/main/kotlin/me/kyren223/trident/actions/TridentListSelectAction.kt @@ -3,12 +3,9 @@ package me.kyren223.trident.actions import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import me.kyren223.trident.ui.TridentListMenu -import me.kyren223.trident.utils.TridentList class TridentListSelectAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { - val project = e.project ?: return - TridentList.select(project, TridentListMenu.line) + TridentListMenu.instance?.select() } - } diff --git a/src/main/kotlin/me/kyren223/trident/actions/TridentSelectAction.kt b/src/main/kotlin/me/kyren223/trident/actions/TridentSelectAction.kt new file mode 100644 index 0000000..60973f2 --- /dev/null +++ b/src/main/kotlin/me/kyren223/trident/actions/TridentSelectAction.kt @@ -0,0 +1,44 @@ +package me.kyren223.trident.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.fileEditor.FileEditorManager +import me.kyren223.trident.utils.TridentList + +class TridentSelectAction : AnAction() { + override fun actionPerformed(e: AnActionEvent) { + val project = e.project ?: return + val index = when (val actionId = e.actionManager.getId(this)) { + NEXT -> { + val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return + val current = TridentList.getIndexOfFile(project, file) ?: return + current + 1 + } + + PREV -> { + val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return + val current = TridentList.getIndexOfFile(project, file) ?: return + current - 1 + } + + else -> { + getIndex(actionId!!) + } + } + + val file = TridentList.select(project, index) ?: return + FileEditorManager.getInstance(project).openFile(file, true) + } + + private fun getIndex(actionId: String): Int { + return actionId.substring(SELECT.length).toInt() - 1 + } + + companion object { + const val NEXT = "TridentSelectNext" + const val PREV = "TridentSelectPrev" + const val SELECT = "TridentSelect" + } +} + diff --git a/src/main/kotlin/me/kyren223/trident/data/Settings.kt b/src/main/kotlin/me/kyren223/trident/data/Settings.kt new file mode 100644 index 0000000..27a7d2a --- /dev/null +++ b/src/main/kotlin/me/kyren223/trident/data/Settings.kt @@ -0,0 +1,27 @@ +package me.kyren223.trident.data + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.* + +// Copyright 2000-2022 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@Service +@State(name = "me.kyren223.trident.data.SettingsState", storages = [Storage("SdkSettingsPlugin.xml")]) +class Settings : SimplePersistentStateComponent(SettingsState()) { + companion object { + val instance: Settings + get() = ApplicationManager.getApplication().getService(Settings::class.java) + val state: SettingsState + get() = instance.state + } +} + +class SettingsState : BaseState() { + var width = 800 + var height = 400 + var fontSize = 20 + var enterToSelect = true + var automaticMapping = false + 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 2c5c467..eed655e 100644 --- a/src/main/kotlin/me/kyren223/trident/data/SettingsData.kt +++ b/src/main/kotlin/me/kyren223/trident/data/SettingsData.kt @@ -16,14 +16,15 @@ class SettingsData { val panel: JPanel - private val width = JBIntSpinner(SettingsState.instance.width, minValue, maxValue, step) - private val height = JBIntSpinner(SettingsState.instance.height, minValue, maxValue, step) - private val fontSize = JBIntSpinner(SettingsState.instance.fontSize, minValue, maxValue, step) + private val width = JBIntSpinner(Settings.state.width, minValue, maxValue, step) + private val height = JBIntSpinner(Settings.state.height, minValue, maxValue, step) + private val fontSize = JBIntSpinner(Settings.state.fontSize, minValue, maxValue, step) - private val enterToSelect = JBCheckBox(null, SettingsState.instance.enterToSelect) - private val rememberLine = JBCheckBox(null, SettingsState.instance.rememberLine) - private val automaticMapping = JBCheckBox(null, SettingsState.instance.automaticMapping) - private val recursiveMapping = JBCheckBox(null, SettingsState.instance.recursiveMapping) + 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 recursiveMapping = JBCheckBox(null, Settings.state.recursiveMapping) + private val indexCycling = JBCheckBox(null, Settings.state.indexCycling) init { panel = FormBuilder.createFormBuilder() @@ -56,6 +57,10 @@ class SettingsData { "and will be selected when the TridentList is opened.")) .addComponent(desc("Note, this does not persist across restarts, it's run-time only.")) + .addLabeledComponent("Index cycling", indexCycling) + .addComponent(desc("If enabled, indexes will be cyclic, " + + "For example if you have 3 files and hotkey to 4, it'll cycle to 1.")) + .addComponentFillVertically(JPanel(), 0) .panel } @@ -121,4 +126,12 @@ class SettingsData { fun setRecursiveMapping(recursiveMapping: Boolean) { this.recursiveMapping.isSelected = recursiveMapping } + + fun getIndexCycling(): Boolean { + return indexCycling.isSelected + } + + fun setIndexCycling(indexCycling: Boolean) { + this.indexCycling.isSelected = indexCycling + } } diff --git a/src/main/kotlin/me/kyren223/trident/data/SettingsState.kt b/src/main/kotlin/me/kyren223/trident/data/SettingsState.kt deleted file mode 100644 index 16ec372..0000000 --- a/src/main/kotlin/me/kyren223/trident/data/SettingsState.kt +++ /dev/null @@ -1,33 +0,0 @@ -package me.kyren223.trident.data - -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.State -import com.intellij.openapi.components.Storage -import com.intellij.util.xmlb.XmlSerializerUtil - -// Copyright 2000-2022 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -@State(name = "me.kyren223.trident.data.SettingsState", storages = [Storage("SdkSettingsPlugin.xml")]) -class SettingsState : PersistentStateComponent { - - var width = 800 - var height = 400 - var fontSize = 20 - var enterToSelect = true - var automaticMapping = false - var recursiveMapping = false - var rememberLine = false - - override fun getState(): SettingsState { - return this - } - - override fun loadState(state: SettingsState) { - XmlSerializerUtil.copyBean(state, this) - } - - companion object { - val instance: SettingsState - get() = ApplicationManager.getApplication().getService(SettingsState::class.java) - } -} diff --git a/src/main/kotlin/me/kyren223/trident/data/TridentState.kt b/src/main/kotlin/me/kyren223/trident/data/TridentState.kt deleted file mode 100644 index 54529e9..0000000 --- a/src/main/kotlin/me/kyren223/trident/data/TridentState.kt +++ /dev/null @@ -1,181 +0,0 @@ -package me.kyren223.trident.data - -//object TridentState { -// private const val TRIDENT_LIST_KEY = "TridentList" -// private const val TRIDENT_MAPPINGS_KEY = "TridentMappings" -// -// private var list: MutableMap> = mutableMapOf() -// private var mappings: MutableMap> = mutableMapOf() -// -// private var quickMenu: QuickMenu? = null -// var quickMenuSelectedIndex: Int? = null -// var quickMenuContent: String = "" -// private var pathMappingsMenu: PathMappingsMenu? = null -// var pathMappingsContent: String = "" -// -//// fun appendFile(project: Project, file: VirtualFile) { -//// if (!file.isValid) return -//// loadProject(project) -//// val files = list[project.name] -//// files!!.add(file) -//// saveProject(project) -//// } -// -//// fun selectFile(project: Project, index: Int): VirtualFile? { -//// if (index < 0) return null -//// loadProject(project) -//// val files = list[project.name] -//// if (files!!.size <= index) return null -//// return files[index] -//// } -// -//// private fun loadProject(project: Project) { -//// if (project.name in list) return -//// val properties = PropertiesComponent.getInstance(project) -//// -//// val pathMappingsList = properties.getList(TRIDENT_MAPPINGS_KEY) -//// var map = mutableMapOf() -//// if (pathMappingsList == null) { -//// map["..."] = project.basePath!! -//// } else { -//// for (entry in pathMappingsList) { -//// val split = entry.split("=") -//// if (split.size != 2) continue -//// map[split[0]] = split[1] -//// } -//// } -//// mappings[project.name] = map -//// -//// val list = properties.getList(TRIDENT_LIST_KEY) -//// if (list == null) { -//// this.list[project.name] = mutableListOf() -//// } else { -//// val fs = LocalFileSystem.getInstance() -//// val files = list.stream() -//// .map { fs.findFileByPath(it) } -//// .toList() -//// .filterNotNull() -//// .filter { it.isValid } -//// .toMutableList() -//// this.list[project.name] = files -//// } -//// } -// -//// private fun saveProject(project: Project) { -//// if (project.name !in list) return -//// val files = list[project.name] -//// val properties = PropertiesComponent.getInstance(project) -//// -//// val stringList = files!!.stream() -//// .filter { it.isValid } -//// .map { it.path } -//// .toList() -//// properties.setList(TRIDENT_LIST_KEY, stringList) -//// -//// val pathMappingsString = mappings[project.name]!!.entries -//// .joinToString("\n") { "${it.key}=${it.value}" } -//// .split("\n") -//// properties.setList(TRIDENT_MAPPINGS_KEY, pathMappingsString) -//// } -// -//// fun getIndexOfFile(project: Project, data: VirtualFile?): Int { -//// loadProject(project) -//// val files = list[project.name] -//// if (files == null || data == null) return -1 -//// return files.indexOfFirst { it.path == data.path } -//// } -// -//// fun getFileCount(project: Project): Int { -//// loadProject(project) -//// return list[project.name]!!.size -//// } -// -// fun toggleQuickMenu(project: Project) { -// if (quickMenu != null && quickMenu!!.isShowing) { -// quickMenu!!.doCancelAction() -// return -// } -// -//// loadProject(project) -// val content = TridentList.get(project).joinToString("\n") -// quickMenu = QuickMenu(content) -// val result = quickMenu!!.showAndGet() -// -// if (content != quickMenuContent) { -// retrieveProjectFiles(project, quickMenuContent) -//// saveProject(project) -// } -// -// if (!result) return -// val index = quickMenuSelectedIndex ?: return -// quickMenuSelectedIndex = null -// val file = TridentList.select(project, index) ?: return -// FileEditorManager.getInstance(project).openFile(file, true) -// } -// -// fun quickMenuSelect() { -// if (quickMenu == null || !quickMenu!!.isShowing) return -// quickMenu!!.select() -// } -// -//// private fun getProjectContent(project: Project): String { -//// loadProject(project) -//// val map = mappings[project.name] ?: throw IllegalStateException("Path mappings not found") -//// println("map: $map") -//// var content = list[project.name]!! -//// .joinToString("\n") { it.path } -//// .trim() -//// println("content: $content") -//// for ((key, value) in map) { -//// println("key: $key | value: $value") -//// content = content.replace(value, key) -//// } -//// println("content: $content") -//// return content -//// } -// -//// private fun retrieveProjectFiles(project: Project, content: String) { -//// loadProject(project) -//// val files = content -//// .split("\n") -//// .asSequence() -//// .map { it.trim() } -//// .map { line -> -//// mappings[project.name]!!.entries.fold(line) { acc, (key, value) -> -//// acc.replace(key, value) -//// } -//// } -////// .map { -////// pathMappings[project.name]!!.entries.forEach { (key, value) -> it.replace(key, value) } -////// it -////// } -//// .filter { it.isNotBlank() } -//// .map { LocalFileSystem.getInstance().findFileByPath(it) } -//// .filterNotNull() -//// .filter { it.isValid } -//// .toMutableList() -//// list[project.name] = files -//// } -// -// fun togglePathMappingsMenu(project: Project) { -// if (pathMappingsMenu != null && pathMappingsMenu!!.isShowing) { -// pathMappingsMenu!!.doCancelAction() -// return -// } -// -//// loadProject(project) -// val content = mappings[project.name]!!.entries -// .joinToString("\n") { "${it.key}=${it.value}" } -// pathMappingsMenu = PathMappingsMenu(content) -// pathMappingsMenu!!.showAndGet() -// -// if (content != pathMappingsContent) { -// pathMappingsContent.split("\n").forEach { -// val split = it.split("=") -// if (split.size != 2) return@forEach -// mappings[project.name]!![split[0]] = split[1] -// } -//// saveProject(project) -// } -// } -//} \ 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 6283a29..79c4fdc 100644 --- a/src/main/kotlin/me/kyren223/trident/ui/SettingsConfigurable.kt +++ b/src/main/kotlin/me/kyren223/trident/ui/SettingsConfigurable.kt @@ -4,7 +4,7 @@ package me.kyren223.trident.ui import com.intellij.openapi.options.Configurable import com.intellij.openapi.util.NlsContexts.ConfigurableName import me.kyren223.trident.data.SettingsData -import me.kyren223.trident.data.SettingsState +import me.kyren223.trident.data.Settings import javax.swing.JComponent class SettingsConfigurable : Configurable { @@ -21,7 +21,7 @@ class SettingsConfigurable : Configurable { } override fun isModified(): Boolean { - val settings = SettingsState.instance + val settings = Settings.state if (settings.width != this.settings!!.getWidth()) return true if (settings.height != this.settings!!.getHeight()) return true if (settings.fontSize != this.settings!!.getFontSize()) return true @@ -29,11 +29,12 @@ class SettingsConfigurable : Configurable { if (settings.automaticMapping != this.settings!!.getAutomaticMapping()) 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 return false } override fun apply() { - val settings = SettingsState.instance + val settings = Settings.state settings.width = this.settings!!.getWidth() settings.height = this.settings!!.getHeight() settings.fontSize = this.settings!!.getFontSize() @@ -41,10 +42,11 @@ class SettingsConfigurable : Configurable { settings.automaticMapping = this.settings!!.getAutomaticMapping() settings.recursiveMapping = this.settings!!.getRecursiveMapping() settings.rememberLine = this.settings!!.getRememberLine() + settings.indexCycling = this.settings!!.getIndexCycling() } override fun reset() { - val settings = SettingsState.instance + val settings = Settings.state if (this.settings == null) { this.settings = SettingsData() } @@ -55,6 +57,7 @@ class SettingsConfigurable : Configurable { this.settings!!.setAutomaticMapping(settings.automaticMapping) this.settings!!.setRecursiveMapping(settings.recursiveMapping) this.settings!!.setRememberLine(settings.rememberLine) + this.settings!!.setIndexCycling(settings.indexCycling) } override fun disposeUIResources() { diff --git a/src/main/kotlin/me/kyren223/trident/ui/TridentListMenu.kt b/src/main/kotlin/me/kyren223/trident/ui/TridentListMenu.kt index 4062837..af04b7c 100644 --- a/src/main/kotlin/me/kyren223/trident/ui/TridentListMenu.kt +++ b/src/main/kotlin/me/kyren223/trident/ui/TridentListMenu.kt @@ -1,5 +1,3 @@ -@file:Suppress("SameParameterValue") - package me.kyren223.trident.ui import com.intellij.openapi.editor.EditorSettings @@ -10,8 +8,9 @@ import com.intellij.openapi.ui.DialogWrapper import com.intellij.ui.EditorTextField import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.state.mode.Mode -import me.kyren223.trident.data.SettingsState +import me.kyren223.trident.data.Settings import me.kyren223.trident.utils.TridentList +import me.kyren223.trident.utils.injectEnterToSelectMapping import me.kyren223.trident.utils.setEditorMode import java.awt.event.FocusEvent import java.awt.event.FocusListener @@ -23,7 +22,7 @@ class TridentListMenu(private val content: String) : DialogWrapper(true) { init { this.title = "Trident List" - val settings = SettingsState.instance + val settings = Settings.state setSize(settings.width, settings.height) super.init() } @@ -32,9 +31,9 @@ class TridentListMenu(private val content: String) : DialogWrapper(true) { editor = EditorTextField(this.content) editor.setOneLineMode(false) editor.addSettingsProvider { - it.setFontSize(SettingsState.instance.fontSize) + it.setFontSize(Settings.state.fontSize) it.isInsertMode = false - val lineNumber = if (SettingsState.instance.rememberLine) line else 0 + val lineNumber = if (Settings.state.rememberLine) line else 0 it.caretModel.moveToLogicalPosition(LogicalPosition(lineNumber, 0)) it.settings.isLineNumbersShown = true it.settings.lineNumerationType = EditorSettings.LineNumerationType.ABSOLUTE @@ -46,7 +45,8 @@ class TridentListMenu(private val content: String) : DialogWrapper(true) { setEditorMode(editor, Mode.NORMAL()) } - override fun focusLost(e: FocusEvent?) { /* Do nothing */ } + override fun focusLost(e: FocusEvent?) { /* Do nothing */ + } }) return editor @@ -58,10 +58,7 @@ class TridentListMenu(private val content: String) : DialogWrapper(true) { } fun select() { - val project = editor.project doOKAction() - val file = TridentList.select(project, line) ?: return - FileEditorManager.getInstance(project).openFile(file, true) } override fun doOKAction() { @@ -75,8 +72,9 @@ class TridentListMenu(private val content: String) : DialogWrapper(true) { } private fun save() { - TridentList.set(editor.project, editor.text.split("\n")) - line = editor.editor!!.caretModel.logicalPosition.line + instance = null + files = editor.text.split("\n") + line = editor.editor?.caretModel?.logicalPosition?.line ?: 0 } override fun createSouthPanel(): JComponent? { @@ -84,11 +82,21 @@ class TridentListMenu(private val content: String) : DialogWrapper(true) { } companion object { + var instance: TridentListMenu? = null + var files: List? = null var line = 0 fun open(project: Project) { val content = TridentList.get(project).joinToString("\n") - val menu = TridentListMenu(content) - menu.show() + instance = TridentListMenu(content) + injectEnterToSelectMapping() + val selected = instance!!.showAndGet() + + files?.let { TridentList.set(project, it) } + files = null + + if (!selected) return + val file = TridentList.select(project, line) ?: return + FileEditorManager.getInstance(project).openFile(file, true) } } } diff --git a/src/main/kotlin/me/kyren223/trident/ui/TridentMappingsMenu.kt b/src/main/kotlin/me/kyren223/trident/ui/TridentMappingsMenu.kt index a84b561..4a6d859 100644 --- a/src/main/kotlin/me/kyren223/trident/ui/TridentMappingsMenu.kt +++ b/src/main/kotlin/me/kyren223/trident/ui/TridentMappingsMenu.kt @@ -7,7 +7,7 @@ import com.intellij.openapi.ui.DialogWrapper import com.intellij.ui.EditorTextField import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.state.mode.Mode -import me.kyren223.trident.data.SettingsState +import me.kyren223.trident.data.Settings import me.kyren223.trident.utils.TridentMappings import me.kyren223.trident.utils.setEditorMode import java.awt.event.FocusEvent @@ -18,7 +18,7 @@ class TridentMappingsMenu(private val content: String) : DialogWrapper(true) { private lateinit var editor: EditorTextField init { - val settings = SettingsState.instance + val settings = Settings.state this.title = "Trident Mappings" setSize(settings.width, settings.height) super.init() @@ -28,7 +28,7 @@ class TridentMappingsMenu(private val content: String) : DialogWrapper(true) { editor = EditorTextField(this.content) editor.setOneLineMode(false) editor.addSettingsProvider { - it.setFontSize(SettingsState.instance.fontSize) + it.setFontSize(Settings.state.fontSize) it.isInsertMode = false it.caretModel.moveToLogicalPosition(LogicalPosition(0, 0)) it.settings.isLineNumbersShown = true @@ -62,11 +62,10 @@ class TridentMappingsMenu(private val content: String) : DialogWrapper(true) { } private fun save() { - val map = editor.text.split("\n") + map = editor.text.split("\n") .map { entry -> entry.split("=") } .filter { entry -> entry.size == 2 } .associate { it[0] to it[1] } - TridentMappings.set(editor.project, map) } override fun createSouthPanel(): JComponent? { @@ -74,11 +73,14 @@ class TridentMappingsMenu(private val content: String) : DialogWrapper(true) { } companion object { + var map: Map? = null fun open(project: Project) { val content = TridentMappings.get(project).entries .joinToString("\n") { "${it.key}=${it.value}" } val menu = TridentMappingsMenu(content) menu.show() + map?.let { TridentMappings.set(project, it) } + map = null } } } diff --git a/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt b/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt index b7e19ac..b2302d7 100644 --- a/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt +++ b/src/main/kotlin/me/kyren223/trident/utils/TridentUtils.kt @@ -2,9 +2,10 @@ package me.kyren223.trident.utils import com.intellij.ide.util.PropertiesComponent 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.SettingsState +import me.kyren223.trident.data.Settings object TridentList { private const val PROPERTIES_KEY = "TridentList" @@ -16,12 +17,41 @@ 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` + return path.split("/") + .lastOrNull() + ?.let { + it.split(".") + .let { parts -> + when (parts.size) { + 0 -> it + 1, 2 -> parts.firstOrNull() + else -> return null + } + } + } + ?.let { "\$${it}" } + } + fun append(project: Project, file: VirtualFile) { - // TODO add a setting to automatically add an expansion to mappings if it doesn't exist - // Should be `$` for `/.` - // Unless if the file starts with a dot, in which case it should be `$` val files = get(project).toMutableList() - files.add(file.path) + + 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 + + files.add(path) set(project, files) } @@ -37,7 +67,9 @@ object TridentList { } private fun getFiles(project: Project): List { - return get(project).mapNotNull { LocalFileSystem.getInstance().findFileByPath(it) } + return get(project) + .map { TridentMappings.expand(project, it) } + .mapNotNull { LocalFileSystem.getInstance().findFileByPath(it) } } fun getIndexOfFile(project: Project, file: VirtualFile): Int? { @@ -46,9 +78,9 @@ object TridentList { } fun select(project: Project, index: Int): VirtualFile? { - // TODO make this a setting if it should "cycle" or not + val cycle = Settings.state.indexCycling val count = getFiles(project).size - val i = ((index % count) + count) % count + val i = if (cycle) ((index % count) + count) % count else index val files = getFiles(project) return files.getOrNull(i) } @@ -58,14 +90,13 @@ object TridentMappings { private const val PROPERTIES_KEY = "TridentMappings" private fun isValidEntry(key: String, value: String): Boolean { - // TODO change requirements, key should be alphanumeric and must only have 1 $ as the first character // Requirements: // - Key and value must not be blank - // - key must only contain alphanumeric characters and $ + // - key must only contain alphanumeric characters and start with $ // - value must not contain = return key.isNotBlank() && value.isNotBlank() && - key.matches(Regex("^[a-zA-Z0-9\$]+$")) && - value.matches(Regex("^[^=]+$")) + key.matches(Regex("""^\$[a-zA-Z0-9]+$""")) && + value.matches(Regex("""^[^=]+$""")) } fun append(project: Project, key: String, value: String, overwrite: Boolean = false) { @@ -89,18 +120,37 @@ object TridentMappings { fun get(project: Project): Map { val properties = PropertiesComponent.getInstance(project) val list = properties.getList(PROPERTIES_KEY) ?: return emptyMap() - return list.map { it.split("=") }.associate { it[0] to it[1] } + val map = list + .map { it.split("=") } + .associate { it[0] to it[1] } + .toMutableMap() + project.guessProjectDir()?.let { + map["..."] = it.path + map["\$project"] = it.path + } + return map } fun expand(project: Project, path: String): String { - val recursive = SettingsState.instance.recursiveMapping + val recursive = Settings.state.recursiveMapping val mappings = get(project).toList().sortedByDescending { it.first.length } - var expanded = path - - mappings.forEach { (key, value) -> - expanded = expanded.replace(key, if (recursive) expand(project, value) else value) + var expandedPath = path + while (true) { + var expanded = false + mappings.forEach { (key, value) -> + val expansion = expandedPath.replace(key, value) + if (expansion != expandedPath) { + expandedPath = expansion + expanded = true + } + } + if (!recursive || !expanded) break } - return expanded + return expandedPath + } + + fun exists(project: Project, key: String): Boolean { + return get(project).containsKey(key) } } \ No newline at end of file diff --git a/src/main/kotlin/me/kyren223/trident/utils/Utils.kt b/src/main/kotlin/me/kyren223/trident/utils/Utils.kt index 7e6b80c..e688dd8 100644 --- a/src/main/kotlin/me/kyren223/trident/utils/Utils.kt +++ b/src/main/kotlin/me/kyren223/trident/utils/Utils.kt @@ -2,7 +2,9 @@ package me.kyren223.trident.utils import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector +import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.OperatorArguments +import com.maddyhome.idea.vim.key.MappingOwner import com.maddyhome.idea.vim.state.mode.Mode fun setEditorMode(editor: VimEditor, mode: Mode) { @@ -12,5 +14,13 @@ fun setEditorMode(editor: VimEditor, mode: Mode) { editor.vimChangeActionSwitchMode = Mode.NORMAL() } - +fun injectEnterToSelectMapping() { + injector.keyGroup.putKeyMapping( + MappingMode.NV, + injector.parser.parseKeys(""), + MappingOwner.Plugin.get("Trident"), + injector.parser.parseKeys(":action TridentListSelect"), + false + ) +} -- cgit v1.3.1