Merge branch 'merge-idea-203' into merge-idea-202
|
|
@ -23,6 +23,15 @@ intellij {
|
||||||
}
|
}
|
||||||
tasks.getByName<org.jetbrains.intellij.tasks.PatchPluginXmlTask>("patchPluginXml") {
|
tasks.getByName<org.jetbrains.intellij.tasks.PatchPluginXmlTask>("patchPluginXml") {
|
||||||
changeNotes("""
|
changeNotes("""
|
||||||
|
<h3>[1.2]</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Single New menu action to access filename template configurations</li>
|
||||||
|
<li>Simplify template configuration with placeholder auto completion</li>
|
||||||
|
<li>New templates are active by default</li>
|
||||||
|
<li>Combine name and description into title</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h3>[1.1]</h3>
|
<h3>[1.1]</h3>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 72 KiB |
BIN
filename-template-new-menu.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
|
||||||
pluginVersion = 1.1.0-202
|
pluginVersion = 1.2.0-202
|
||||||
platformVersion = 2020.2
|
platformVersion = 2020.2
|
||||||
|
|
|
||||||
|
|
@ -4,38 +4,64 @@ import com.intellij.icons.AllIcons
|
||||||
import com.intellij.ide.IdeBundle
|
import com.intellij.ide.IdeBundle
|
||||||
import com.intellij.ide.actions.CreateFileAction
|
import com.intellij.ide.actions.CreateFileAction
|
||||||
import com.intellij.ide.ui.newItemPopup.NewItemPopupUtil
|
import com.intellij.ide.ui.newItemPopup.NewItemPopupUtil
|
||||||
import com.intellij.ide.ui.newItemPopup.NewItemSimplePopupPanel
|
|
||||||
import com.intellij.lang.LangBundle
|
import com.intellij.lang.LangBundle
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.ui.InputValidatorEx
|
import com.intellij.openapi.ui.InputValidatorEx
|
||||||
|
import com.intellij.openapi.util.Trinity
|
||||||
import com.intellij.psi.PsiDirectory
|
import com.intellij.psi.PsiDirectory
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import de.idetools.filename_template.placeholders.PlaceholderProcessor
|
import de.idetools.filename_template.placeholders.*
|
||||||
|
import de.idetools.filename_template.settings.FilenameTemplateSettingsState
|
||||||
import java.awt.event.InputEvent
|
import java.awt.event.InputEvent
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class CreateFileWithFilenameTemplateAction(
|
class CreateFileWithFilenameTemplateAction :
|
||||||
text: String,
|
CreateFileAction("Filename Template", "Create a new file based on template", AllIcons.FileTypes.AddAny) {
|
||||||
description: String,
|
|
||||||
private val placeholderProcessor: PlaceholderProcessor
|
private val placeholders: List<Placeholder> = listOf(
|
||||||
) :
|
EpochPlaceholder(),
|
||||||
CreateFileAction(text, description, AllIcons.FileTypes.Unknown) {
|
DatePlaceholder(),
|
||||||
|
ProjectPlaceholder(),
|
||||||
|
SequencePlaceholder(),
|
||||||
|
HostPlaceholder(),
|
||||||
|
UserPlaceholder(),
|
||||||
|
DefaultPlaceholder()
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun update(e: AnActionEvent) {
|
||||||
|
if (FilenameTemplateSettingsState.instance.filenameTemplates.isEmpty()) {
|
||||||
|
e.presentation.isEnabledAndVisible = false
|
||||||
|
} else {
|
||||||
|
super.update(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun invokeDialog(
|
override fun invokeDialog(
|
||||||
project: Project,
|
project: Project,
|
||||||
directory: PsiDirectory,
|
directory: PsiDirectory,
|
||||||
elementsConsumer: Consumer<Array<PsiElement?>?>
|
elementsConsumer: Consumer<Array<PsiElement?>?>
|
||||||
) {
|
) {
|
||||||
|
val settings: FilenameTemplateSettingsState = FilenameTemplateSettingsState.instance
|
||||||
|
settings.filenameTemplates.forEach {
|
||||||
|
if (it.title.isBlank()) {
|
||||||
|
it.title = if (it.description.isBlank()) it.name else "${it.name} - ${it.description}"
|
||||||
|
}
|
||||||
|
it.name = ""
|
||||||
|
it.description = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val templates = settings.filenameTemplates
|
||||||
|
.filter { it.isActive }
|
||||||
|
.map {
|
||||||
|
Trinity(it.title, AllIcons.FileTypes.AddAny, processTemplate(it.template, project, directory))
|
||||||
|
}
|
||||||
val validator: MyInputValidator = MyValidator(project, directory)
|
val validator: MyInputValidator = MyValidator(project, directory)
|
||||||
val contentPanel = NewItemSimplePopupPanel()
|
val contentPanel = CreateWithFilenameTemplateDialogPanel(templates)
|
||||||
val nameField = contentPanel.textField
|
val nameField = contentPanel.textField
|
||||||
|
|
||||||
val (filename, caretPosition) = placeholderProcessor.processTemplate(project, directory)
|
|
||||||
|
|
||||||
nameField.text = filename
|
|
||||||
nameField.caretPosition = caretPosition
|
|
||||||
|
|
||||||
val popup = NewItemPopupUtil.createNewItemPopup(IdeBundle.message("title.new.file"), contentPanel, nameField)
|
val popup = NewItemPopupUtil.createNewItemPopup(IdeBundle.message("title.new.file"), contentPanel, nameField)
|
||||||
|
|
||||||
contentPanel.setApplyAction { event: InputEvent? ->
|
contentPanel.setApplyAction { event: InputEvent? ->
|
||||||
val name = nameField.text
|
val name = nameField.text
|
||||||
if (validator.checkInput(name) && validator.canClose(name)) {
|
if (validator.checkInput(name) && validator.canClose(name)) {
|
||||||
|
|
@ -52,4 +78,46 @@ class CreateFileWithFilenameTemplateAction(
|
||||||
}
|
}
|
||||||
popup.showCenteredInCurrentWindow(project)
|
popup.showCenteredInCurrentWindow(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processTemplate(template: String, project: Project, directory: PsiDirectory): String {
|
||||||
|
var placeholderLevel = 0
|
||||||
|
var placeholder = ""
|
||||||
|
|
||||||
|
val context = PlaceholderContext(project, directory)
|
||||||
|
|
||||||
|
for (character in template) {
|
||||||
|
when (character) {
|
||||||
|
'{' -> {
|
||||||
|
if (0 < placeholderLevel) {
|
||||||
|
placeholder += character
|
||||||
|
}
|
||||||
|
|
||||||
|
placeholderLevel += 1
|
||||||
|
}
|
||||||
|
'}' -> {
|
||||||
|
if (placeholderLevel == 1) {
|
||||||
|
context.filename += placeholders
|
||||||
|
.first { it.supports(placeholder) }
|
||||||
|
.process(placeholder, context)
|
||||||
|
placeholder = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
placeholderLevel = max(0, placeholderLevel - 1)
|
||||||
|
|
||||||
|
if (0 < placeholderLevel) {
|
||||||
|
placeholder += character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (0 < placeholderLevel) {
|
||||||
|
placeholder += character
|
||||||
|
} else {
|
||||||
|
context.filename += character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.filename
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package de.idetools.filename_template
|
||||||
|
|
||||||
|
import com.intellij.ide.actions.newclass.CreateWithTemplatesDialogPanel
|
||||||
|
import com.intellij.openapi.util.Trinity
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class CreateWithFilenameTemplateDialogPanel(templates: List<Trinity<String, Icon, String>>) :
|
||||||
|
CreateWithTemplatesDialogPanel(templates, templates.first().first) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
updateSelectedText()
|
||||||
|
myTemplatesList.addListSelectionListener { updateSelectedText() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateSelectedText() {
|
||||||
|
val selectedValue = myTemplatesList.selectedValue
|
||||||
|
if (selectedValue != null) {
|
||||||
|
var filename = selectedValue.third
|
||||||
|
val caretPosition = determineCaretPosition(filename)
|
||||||
|
filename = filename.replace("{|}", "")
|
||||||
|
|
||||||
|
myTextField.text = filename
|
||||||
|
nameField.caretPosition = caretPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun determineCaretPosition(filename: String): Int = when {
|
||||||
|
filename.indexOf("{|}") != -1 -> filename.indexOf("{|}")
|
||||||
|
filename.indexOfFirst { it == '.' } != -1 -> filename.indexOfFirst { it == '.' }
|
||||||
|
else -> filename.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
package de.idetools.filename_template
|
|
||||||
|
|
||||||
import com.intellij.openapi.actionSystem.ActionManager
|
|
||||||
import com.intellij.openapi.actionSystem.Anchor
|
|
||||||
import com.intellij.openapi.actionSystem.Constraints
|
|
||||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.startup.StartupActivity
|
|
||||||
import de.idetools.filename_template.placeholders.DatePlaceholder
|
|
||||||
import de.idetools.filename_template.placeholders.DefaultPlaceholder
|
|
||||||
import de.idetools.filename_template.placeholders.EpochPlaceholder
|
|
||||||
import de.idetools.filename_template.placeholders.HostPlaceholder
|
|
||||||
import de.idetools.filename_template.placeholders.PlaceholderProcessor
|
|
||||||
import de.idetools.filename_template.placeholders.ProjectPlaceholder
|
|
||||||
import de.idetools.filename_template.placeholders.SequencePlaceholder
|
|
||||||
import de.idetools.filename_template.placeholders.UserPlaceholder
|
|
||||||
import de.idetools.filename_template.settings.FilenameTemplateSettingsState
|
|
||||||
|
|
||||||
class InitializeFilenameTemplateActivity : StartupActivity {
|
|
||||||
override fun runActivity(project: Project) {
|
|
||||||
initializeActions()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun initializeActions() {
|
|
||||||
val settings: FilenameTemplateSettingsState = FilenameTemplateSettingsState.instance
|
|
||||||
|
|
||||||
val placeholders = listOf(
|
|
||||||
EpochPlaceholder(),
|
|
||||||
DatePlaceholder(),
|
|
||||||
ProjectPlaceholder(),
|
|
||||||
HostPlaceholder(),
|
|
||||||
SequencePlaceholder(),
|
|
||||||
UserPlaceholder(),
|
|
||||||
DefaultPlaceholder()
|
|
||||||
)
|
|
||||||
|
|
||||||
val actionManager = ActionManager.getInstance()
|
|
||||||
val newGroup = actionManager.getAction("NewGroup") as DefaultActionGroup
|
|
||||||
|
|
||||||
actionManager.getActionIds("FilenameTemplate").forEach {
|
|
||||||
newGroup.remove(actionManager.getAction(it))
|
|
||||||
actionManager.unregisterAction(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
var anchorId = "NewFile"
|
|
||||||
settings.filenameTemplates.filter { it.isActive }.forEach {
|
|
||||||
val action = CreateFileWithFilenameTemplateAction(
|
|
||||||
it.name,
|
|
||||||
it.description,
|
|
||||||
PlaceholderProcessor(it.template, placeholders)
|
|
||||||
)
|
|
||||||
val actionId = "FilenameTemplate.${it.name}"
|
|
||||||
actionManager.registerAction(actionId, action)
|
|
||||||
newGroup.addAction(action, Constraints(Anchor.AFTER, anchorId))
|
|
||||||
anchorId = actionId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
package de.idetools.filename_template.placeholders
|
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.psi.PsiDirectory
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
class PlaceholderProcessor(private val template: String, private val placeholders: List<Placeholder>) {
|
|
||||||
|
|
||||||
fun processTemplate(project: Project, directory: PsiDirectory): ProcessedTemplate {
|
|
||||||
var placeholderLevel = 0
|
|
||||||
var placeholder = ""
|
|
||||||
|
|
||||||
val context = PlaceholderContext(project, directory)
|
|
||||||
|
|
||||||
for (character in template) {
|
|
||||||
when (character) {
|
|
||||||
'{' -> {
|
|
||||||
if (0 < placeholderLevel) {
|
|
||||||
placeholder += character
|
|
||||||
}
|
|
||||||
|
|
||||||
placeholderLevel += 1
|
|
||||||
}
|
|
||||||
'}' -> {
|
|
||||||
if (placeholderLevel == 1) {
|
|
||||||
context.filename += placeholders
|
|
||||||
.first { it.supports(placeholder) }
|
|
||||||
.process(placeholder, context)
|
|
||||||
placeholder = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
placeholderLevel = max(0, placeholderLevel - 1)
|
|
||||||
|
|
||||||
if (0 < placeholderLevel) {
|
|
||||||
placeholder += character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
if (0 < placeholderLevel) {
|
|
||||||
placeholder += character
|
|
||||||
} else {
|
|
||||||
context.filename += character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val caretPosition = when {
|
|
||||||
context.filename.indexOf("{|}") != -1 -> context.filename.indexOf("{|}")
|
|
||||||
context.filename.indexOfFirst { it == '.' } != -1 -> context.filename.indexOfFirst { it == '.' }
|
|
||||||
else -> context.filename.length
|
|
||||||
}
|
|
||||||
context.filename = context.filename.replace("{|}", "")
|
|
||||||
|
|
||||||
return ProcessedTemplate(context.filename, caretPosition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,7 +2,6 @@ package de.idetools.filename_template.settings
|
||||||
|
|
||||||
import com.intellij.openapi.options.Configurable
|
import com.intellij.openapi.options.Configurable
|
||||||
import com.intellij.openapi.options.ConfigurationException
|
import com.intellij.openapi.options.ConfigurationException
|
||||||
import de.idetools.filename_template.InitializeFilenameTemplateActivity
|
|
||||||
import org.jetbrains.annotations.Nls
|
import org.jetbrains.annotations.Nls
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
|
@ -12,8 +11,16 @@ class FilenameTemplateConfigurable : Configurable {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val settings: FilenameTemplateSettingsState = FilenameTemplateSettingsState.instance
|
val settings: FilenameTemplateSettingsState = FilenameTemplateSettingsState.instance
|
||||||
|
settings.filenameTemplates.forEach {
|
||||||
|
if (it.title.isBlank()) {
|
||||||
|
it.title = if (it.description.isBlank()) it.name else "${it.name} - ${it.description}"
|
||||||
|
}
|
||||||
|
it.name = ""
|
||||||
|
it.description = ""
|
||||||
|
}
|
||||||
|
|
||||||
component = FilenameTemplateSettingsComponent(ArrayList(settings.filenameTemplates.map {
|
component = FilenameTemplateSettingsComponent(ArrayList(settings.filenameTemplates.map {
|
||||||
FilenameTemplateModel(it.isActive, it.name, it.description, it.template)
|
FilenameTemplateModel(it.isActive, it.title, it.name, it.description, it.template)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,9 +39,8 @@ class FilenameTemplateConfigurable : Configurable {
|
||||||
return settings.filenameTemplates.size != component.filenameTemplates.size ||
|
return settings.filenameTemplates.size != component.filenameTemplates.size ||
|
||||||
settings.filenameTemplates.withIndex().any {
|
settings.filenameTemplates.withIndex().any {
|
||||||
component.filenameTemplateTable.getValueAt(it.index, 0) != it.value.isActive
|
component.filenameTemplateTable.getValueAt(it.index, 0) != it.value.isActive
|
||||||
|| component.filenameTemplateTable.getValueAt(it.index, 1) != it.value.name
|
|| component.filenameTemplateTable.getValueAt(it.index, 1) != it.value.title
|
||||||
|| component.filenameTemplateTable.getValueAt(it.index, 2) != it.value.description
|
|| component.filenameTemplateTable.getValueAt(it.index, 2) != it.value.template
|
||||||
|| component.filenameTemplateTable.getValueAt(it.index, 3) != it.value.template
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,12 +51,12 @@ class FilenameTemplateConfigurable : Configurable {
|
||||||
settings.filenameTemplates.addAll(component.filenameTemplates.map {
|
settings.filenameTemplates.addAll(component.filenameTemplates.map {
|
||||||
FilenameTemplateModel(
|
FilenameTemplateModel(
|
||||||
it.isActive,
|
it.isActive,
|
||||||
|
it.title,
|
||||||
it.name,
|
it.name,
|
||||||
it.description,
|
it.description,
|
||||||
it.template
|
it.template
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
InitializeFilenameTemplateActivity().initializeActions()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
|
|
@ -59,6 +65,7 @@ class FilenameTemplateConfigurable : Configurable {
|
||||||
component.filenameTemplates.addAll(settings.filenameTemplates.map {
|
component.filenameTemplates.addAll(settings.filenameTemplates.map {
|
||||||
FilenameTemplateModel(
|
FilenameTemplateModel(
|
||||||
it.isActive,
|
it.isActive,
|
||||||
|
it.title,
|
||||||
it.name,
|
it.name,
|
||||||
it.description,
|
it.description,
|
||||||
it.template
|
it.template
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package de.idetools.filename_template.settings
|
package de.idetools.filename_template.settings
|
||||||
|
|
||||||
data class FilenameTemplateModel(
|
data class FilenameTemplateModel(
|
||||||
var isActive: Boolean = false,
|
var isActive: Boolean = true,
|
||||||
|
var title: String = "",
|
||||||
var name: String = "",
|
var name: String = "",
|
||||||
var description: String = "",
|
var description: String = "",
|
||||||
var template: String = ""
|
var template: String = ""
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import com.intellij.ui.table.JBTable
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import java.awt.FlowLayout
|
import java.awt.FlowLayout
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
|
import javax.swing.table.TableColumn
|
||||||
|
|
||||||
class FilenameTemplateSettingsComponent(val filenameTemplates: ArrayList<FilenameTemplateModel>) {
|
class FilenameTemplateSettingsComponent(val filenameTemplates: ArrayList<FilenameTemplateModel>) {
|
||||||
private var filenameTemplateTableModel: FilenameTemplateTableModel = FilenameTemplateTableModel(filenameTemplates)
|
private var filenameTemplateTableModel: FilenameTemplateTableModel = FilenameTemplateTableModel(filenameTemplates)
|
||||||
|
|
@ -21,12 +22,29 @@ class FilenameTemplateSettingsComponent(val filenameTemplates: ArrayList<Filenam
|
||||||
|
|
||||||
filenameTemplateTable = JBTable(filenameTemplateTableModel)
|
filenameTemplateTable = JBTable(filenameTemplateTableModel)
|
||||||
filenameTemplateTable.autoCreateRowSorter = false
|
filenameTemplateTable.autoCreateRowSorter = false
|
||||||
|
val activeColumn = filenameTemplateTable.columnModel.getColumn(0)
|
||||||
|
activeColumn.resizable = false
|
||||||
|
activeColumn.maxWidth = determineRequiredWidth(activeColumn)
|
||||||
|
|
||||||
|
val templateColumn = filenameTemplateTable.columnModel.getColumn(2)
|
||||||
|
templateColumn.cellEditor = PlaceholderCompletionCellEditor()
|
||||||
|
|
||||||
val filenameTemplateTableScrollPane = JBScrollPane(filenameTemplateTable)
|
val filenameTemplateTableScrollPane = JBScrollPane(filenameTemplateTable)
|
||||||
|
|
||||||
panel.add(filenameTemplateTableScrollPane, BorderLayout.CENTER)
|
panel.add(filenameTemplateTableScrollPane, BorderLayout.CENTER)
|
||||||
panel.add(createToolbar(filenameTemplateTable), BorderLayout.EAST)
|
panel.add(createToolbar(filenameTemplateTable), BorderLayout.EAST)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun determineRequiredWidth(column: TableColumn): Int =
|
||||||
|
filenameTemplateTable.tableHeader.defaultRenderer.getTableCellRendererComponent(
|
||||||
|
filenameTemplateTable,
|
||||||
|
column.headerValue,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
).preferredSize.width + 8
|
||||||
|
|
||||||
private fun createToolbar(table: JBTable): JPanel {
|
private fun createToolbar(table: JBTable): JPanel {
|
||||||
val actionGroup = DefaultActionGroup()
|
val actionGroup = DefaultActionGroup()
|
||||||
actionGroup.add(object : AnAction("Add", "Add new filename template", AllIcons.General.Add) {
|
actionGroup.add(object : AnAction("Add", "Add new filename template", AllIcons.General.Add) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import javax.swing.table.AbstractTableModel
|
||||||
|
|
||||||
class FilenameTemplateTableModel(private val filenameTemplates: ArrayList<FilenameTemplateModel>) :
|
class FilenameTemplateTableModel(private val filenameTemplates: ArrayList<FilenameTemplateModel>) :
|
||||||
AbstractTableModel() {
|
AbstractTableModel() {
|
||||||
private val header: List<String> = listOf("Active", "Name", "Description", "Template")
|
private val header: List<String> = listOf("Active", "Title", "Template")
|
||||||
|
|
||||||
override fun getRowCount(): Int = filenameTemplates.size
|
override fun getRowCount(): Int = filenameTemplates.size
|
||||||
|
|
||||||
|
|
@ -14,9 +14,8 @@ class FilenameTemplateTableModel(private val filenameTemplates: ArrayList<Filena
|
||||||
override fun getValueAt(row: Int, column: Int): Any {
|
override fun getValueAt(row: Int, column: Int): Any {
|
||||||
return when (column) {
|
return when (column) {
|
||||||
0 -> filenameTemplates[row].isActive
|
0 -> filenameTemplates[row].isActive
|
||||||
1 -> filenameTemplates[row].name
|
1 -> filenameTemplates[row].title
|
||||||
2 -> filenameTemplates[row].description
|
2 -> filenameTemplates[row].template
|
||||||
3 -> filenameTemplates[row].template
|
|
||||||
else -> throw ArrayIndexOutOfBoundsException()
|
else -> throw ArrayIndexOutOfBoundsException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,9 +23,8 @@ class FilenameTemplateTableModel(private val filenameTemplates: ArrayList<Filena
|
||||||
override fun setValueAt(value: Any?, row: Int, column: Int) {
|
override fun setValueAt(value: Any?, row: Int, column: Int) {
|
||||||
when (column) {
|
when (column) {
|
||||||
0 -> filenameTemplates[row].isActive = value as Boolean
|
0 -> filenameTemplates[row].isActive = value as Boolean
|
||||||
1 -> filenameTemplates[row].name = value as String
|
1 -> filenameTemplates[row].title = value as String
|
||||||
2 -> filenameTemplates[row].description = value as String
|
2 -> filenameTemplates[row].template = value as String
|
||||||
3 -> filenameTemplates[row].template = value as String
|
|
||||||
else -> throw ArrayIndexOutOfBoundsException()
|
else -> throw ArrayIndexOutOfBoundsException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package de.idetools.filename_template.settings
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||||
|
import com.intellij.codeInsight.completion.InsertHandler
|
||||||
|
import com.intellij.codeInsight.completion.InsertionContext
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
|
import com.intellij.openapi.project.ProjectManager
|
||||||
|
import com.intellij.util.TextFieldCompletionProviderDumbAware
|
||||||
|
import com.intellij.util.textCompletion.TextFieldWithCompletion
|
||||||
|
import java.awt.Component
|
||||||
|
import javax.swing.AbstractCellEditor
|
||||||
|
import javax.swing.JTable
|
||||||
|
import javax.swing.table.TableCellEditor
|
||||||
|
|
||||||
|
internal class PlaceholderCompletionCellEditor : AbstractCellEditor(), TableCellEditor {
|
||||||
|
|
||||||
|
private var component = TextFieldWithCompletion(
|
||||||
|
ProjectManager.getInstance().defaultProject,
|
||||||
|
PlaceholderCompletionProvider(),
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getCellEditorValue(): Any {
|
||||||
|
return component.text
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTableCellEditorComponent(
|
||||||
|
table: JTable,
|
||||||
|
value: Any,
|
||||||
|
isSelected: Boolean,
|
||||||
|
rowIndex: Int,
|
||||||
|
vColIndex: Int
|
||||||
|
): Component {
|
||||||
|
component.text = value as String
|
||||||
|
return component
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlaceholderCompletionProvider : TextFieldCompletionProviderDumbAware(true) {
|
||||||
|
object PlaceholderInsertHandler : InsertHandler<LookupElement> {
|
||||||
|
override fun handleInsert(context: InsertionContext, lookupElement: LookupElement) {
|
||||||
|
val text = context.document.text
|
||||||
|
if (context.tailOffset < text.length && text[context.tailOffset] == '}') {
|
||||||
|
context.document.replaceString(context.tailOffset - 1, context.tailOffset + 1, "}")
|
||||||
|
}
|
||||||
|
if (0 < context.startOffset && text[context.startOffset - 1] == '{') {
|
||||||
|
context.document.replaceString(context.startOffset - 1, context.startOffset + 1, "{")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPrefix(currentTextPrefix: String): String {
|
||||||
|
if (-1 < currentTextPrefix.indexOf('{')) {
|
||||||
|
return currentTextPrefix.removeRange(0, currentTextPrefix.lastIndexOf('{'))
|
||||||
|
}
|
||||||
|
return currentTextPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addCompletionVariants(text: String, offset: Int, prefix: String, result: CompletionResultSet) {
|
||||||
|
listOf("|", "0", "DATE", "EPOCH", "HOST", "PROJECT", "USER").forEach {
|
||||||
|
result.addElement(LookupElementBuilder.create("{${it}}").withInsertHandler(PlaceholderInsertHandler))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
<ol>
|
<ol>
|
||||||
<li>Settings -> Tools -> Filename Template</li>
|
<li>Settings -> Tools -> Filename Template</li>
|
||||||
<li>Configure filename templates</li>
|
<li>Configure filename templates</li>
|
||||||
<li>Create new file: New -> <i>Template name</i></li>
|
<li>Create new file: New -> Filename Template</li>
|
||||||
|
<li>Choose filename template</li>
|
||||||
<li>Complete the file name with return</li>
|
<li>Complete the file name with return</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
|
@ -21,13 +22,10 @@
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Active</dt>
|
<dt>Active</dt>
|
||||||
<dd>Only active filename templates will be shown in the menu.</dd>
|
<dd>Only active filename templates are available in the template selection list.</dd>
|
||||||
|
|
||||||
<dt>Name</dt>
|
<dt>Title</dt>
|
||||||
<dd>The name will be shown in the menu.</dd>
|
<dd>The title is displayed in the template selection list below the file name input field.</dd>
|
||||||
|
|
||||||
<dt>Description</dt>
|
|
||||||
<dd>The description will be shown in the status bar when hovering the menu entry.</dd>
|
|
||||||
|
|
||||||
<dt>Template</dt>
|
<dt>Template</dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
@ -92,11 +90,13 @@
|
||||||
instance="de.idetools.filename_template.settings.FilenameTemplateConfigurable"
|
instance="de.idetools.filename_template.settings.FilenameTemplateConfigurable"
|
||||||
id="de.idetools.filename_template.settings.FilenameTemplateConfigurable"
|
id="de.idetools.filename_template.settings.FilenameTemplateConfigurable"
|
||||||
displayName="Filename Template"/>
|
displayName="Filename Template"/>
|
||||||
<backgroundPostStartupActivity
|
|
||||||
implementation="de.idetools.filename_template.InitializeFilenameTemplateActivity"/>
|
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<actions>
|
<actions>
|
||||||
<!-- Add your actions here -->
|
<action id="de.idetools.filename_template.CreateFileWithFilenameTemplateAction"
|
||||||
|
class="de.idetools.filename_template.CreateFileWithFilenameTemplateAction" text="NewFilenameTemplate"
|
||||||
|
description="Create a new file based on a filename template" icon="/META-INF/pluginIcon-small.png">
|
||||||
|
<add-to-group group-id="NewGroup" anchor="after" relative-to-action="NewFile"/>
|
||||||
|
</action>
|
||||||
</actions>
|
</actions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
|
|
||||||
BIN
src/main/resources/META-INF/pluginIcon-small.png
Normal file
|
After Width: | Height: | Size: 369 B |
BIN
src/main/resources/META-INF/pluginIcon-small_dark.png
Normal file
|
After Width: | Height: | Size: 365 B |