KT-10974 - add import layout configuration table
This commit is contained in:
+11
-5
@@ -13,8 +13,6 @@ import com.intellij.openapi.util.InvalidDataException;
|
|||||||
import com.intellij.openapi.util.WriteExternalException;
|
import com.intellij.openapi.util.WriteExternalException;
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||||
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
|
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
|
||||||
import com.intellij.psi.codeStyle.PackageEntry;
|
|
||||||
import com.intellij.psi.codeStyle.PackageEntryTable;
|
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -26,7 +24,8 @@ import org.jetbrains.kotlin.idea.util.ReflectionUtil;
|
|||||||
import static com.intellij.util.ReflectionUtil.copyFields;
|
import static com.intellij.util.ReflectionUtil.copyFields;
|
||||||
|
|
||||||
public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
|
public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
|
||||||
public final PackageEntryTable PACKAGES_TO_USE_STAR_IMPORTS = new PackageEntryTable();
|
public final KotlinPackageEntryTable PACKAGES_TO_USE_STAR_IMPORTS = new KotlinPackageEntryTable();
|
||||||
|
public final KotlinPackageEntryTable PACKAGES_IMPORT_LAYOUT = new KotlinPackageEntryTable();
|
||||||
public boolean SPACE_AROUND_RANGE = false;
|
public boolean SPACE_AROUND_RANGE = false;
|
||||||
public boolean SPACE_BEFORE_TYPE_COLON = false;
|
public boolean SPACE_BEFORE_TYPE_COLON = false;
|
||||||
public boolean SPACE_AFTER_TYPE_COLON = true;
|
public boolean SPACE_AFTER_TYPE_COLON = true;
|
||||||
@@ -78,8 +77,14 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
|
|||||||
|
|
||||||
// defaults in IDE but not in tests
|
// defaults in IDE but not in tests
|
||||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||||
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new PackageEntry(false, "java.util", false));
|
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("java.util", false));
|
||||||
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new PackageEntry(false, "kotlinx.android.synthetic", true));
|
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("kotlinx.android.synthetic", true));
|
||||||
|
|
||||||
|
PACKAGES_IMPORT_LAYOUT.addEntry(KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY);
|
||||||
|
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("java", true));
|
||||||
|
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("javax", true));
|
||||||
|
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("kotlin", true));
|
||||||
|
PACKAGES_IMPORT_LAYOUT.addEntry(KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +109,7 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
|
|||||||
private void copyFrom(@NotNull KotlinCodeStyleSettings from) {
|
private void copyFrom(@NotNull KotlinCodeStyleSettings from) {
|
||||||
copyFields(getClass().getFields(), from, this);
|
copyFields(getClass().getFields(), from, this);
|
||||||
PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(from.PACKAGES_TO_USE_STAR_IMPORTS);
|
PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(from.PACKAGES_TO_USE_STAR_IMPORTS);
|
||||||
|
PACKAGES_IMPORT_LAYOUT.copyFrom(from.PACKAGES_IMPORT_LAYOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.core.formatter
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
|
|
||||||
|
data class KotlinPackageEntry(
|
||||||
|
val packageName: String,
|
||||||
|
val withSubpackages: Boolean
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val ALL_OTHER_IMPORTS_ENTRY = KotlinPackageEntry("<all other imports>", withSubpackages = true)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val ALL_OTHER_ALIAS_IMPORTS_ENTRY = KotlinPackageEntry("<all other alias imports>", withSubpackages = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun matchesPackageName(otherPackageName: String): Boolean {
|
||||||
|
if (this == ALL_OTHER_IMPORTS_ENTRY || this == ALL_OTHER_ALIAS_IMPORTS_ENTRY) return true
|
||||||
|
|
||||||
|
if (otherPackageName.startsWith(packageName)) {
|
||||||
|
if (otherPackageName.length == packageName.length) return true
|
||||||
|
if (withSubpackages) {
|
||||||
|
if (otherPackageName[packageName.length] == '.') return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isBetterMatchForPackageThan(entry: KotlinPackageEntry?, path: ImportPath): Boolean {
|
||||||
|
if (!matchesPackageName(path.pathStr)) return false
|
||||||
|
if (entry == null) return true
|
||||||
|
|
||||||
|
if (this == ALL_OTHER_ALIAS_IMPORTS_ENTRY && path.hasAlias()) return true
|
||||||
|
if (entry == ALL_OTHER_ALIAS_IMPORTS_ENTRY && path.hasAlias()) return false
|
||||||
|
|
||||||
|
if (entry == ALL_OTHER_IMPORTS_ENTRY && this != ALL_OTHER_ALIAS_IMPORTS_ENTRY) return true
|
||||||
|
if (this == ALL_OTHER_IMPORTS_ENTRY && entry != ALL_OTHER_ALIAS_IMPORTS_ENTRY) return false
|
||||||
|
if (entry.withSubpackages != withSubpackages) return !withSubpackages
|
||||||
|
|
||||||
|
return entry.packageName.count { it == '.' } < packageName.count { it == '.' }
|
||||||
|
}
|
||||||
|
|
||||||
|
val isSpecial: Boolean get() {
|
||||||
|
return (this == ALL_OTHER_IMPORTS_ENTRY || this == ALL_OTHER_ALIAS_IMPORTS_ENTRY)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return packageName
|
||||||
|
}
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.core.formatter
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.InvalidDataException
|
||||||
|
import com.intellij.openapi.util.JDOMExternalizable
|
||||||
|
import org.jdom.Element
|
||||||
|
|
||||||
|
class KotlinPackageEntryTable: JDOMExternalizable, Cloneable {
|
||||||
|
private val entries = mutableListOf<KotlinPackageEntry>()
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is KotlinPackageEntryTable) return false
|
||||||
|
if (other.entries.size != entries.size) return false
|
||||||
|
|
||||||
|
return entries.zip(other.entries).any { (entry, otherEntry) -> entry != otherEntry }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun clone(): KotlinPackageEntryTable {
|
||||||
|
val clone = KotlinPackageEntryTable()
|
||||||
|
clone.copyFrom(this)
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return entries.firstOrNull()?.hashCode() ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyFrom(packageTable: KotlinPackageEntryTable) {
|
||||||
|
entries.clear()
|
||||||
|
entries.addAll(packageTable.entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEntries(): Array<KotlinPackageEntry> {
|
||||||
|
return entries.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insertEntryAt(entry: KotlinPackageEntry, index: Int) {
|
||||||
|
entries.add(index, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeEntryAt(index: Int) {
|
||||||
|
entries.removeAt(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEntryAt(index: Int): KotlinPackageEntry {
|
||||||
|
return entries[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEntryCount(): Int {
|
||||||
|
return entries.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEntryAt(entry: KotlinPackageEntry, index: Int) {
|
||||||
|
entries[index] = entry
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun contains(packageName: String): Boolean {
|
||||||
|
for (entry in entries) {
|
||||||
|
if (packageName.startsWith(entry.packageName)) {
|
||||||
|
if (packageName.length == entry.packageName.length) return true
|
||||||
|
if (entry.withSubpackages) {
|
||||||
|
if (packageName[entry.packageName.length] == '.') return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeEmptyPackages() {
|
||||||
|
entries.removeAll { it.packageName.isBlank() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addEntry(entry: KotlinPackageEntry) {
|
||||||
|
entries.add(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readExternal(element: Element) {
|
||||||
|
entries.clear()
|
||||||
|
|
||||||
|
element.children.forEach {
|
||||||
|
if (it.name == "package") {
|
||||||
|
val packageName = it.getAttributeValue("name") ?: throw InvalidDataException()
|
||||||
|
val alias = it.getAttributeValue("alias")?.toBoolean() ?: false
|
||||||
|
val withSubpackages = it.getAttributeValue("withSubpackages")?.toBoolean() ?: false
|
||||||
|
|
||||||
|
val entry = when {
|
||||||
|
packageName.isEmpty() && !alias -> KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY
|
||||||
|
packageName.isEmpty() && alias -> KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY
|
||||||
|
else -> KotlinPackageEntry(packageName, withSubpackages)
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.add(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeExternal(parentNode: Element) {
|
||||||
|
for (entry in entries) {
|
||||||
|
val element = Element("package")
|
||||||
|
parentNode.addContent(element)
|
||||||
|
val name = if (entry == KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY || entry == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY) "" else entry.packageName
|
||||||
|
val alias = (entry == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY)
|
||||||
|
|
||||||
|
element.setAttribute("name", name)
|
||||||
|
element.setAttribute("alias", alias.toString())
|
||||||
|
element.setAttribute("withSubpackages", entry.withSubpackages.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,36 +27,12 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
object ImportPathComparator : Comparator<ImportPath> {
|
|
||||||
override fun compare(import1: ImportPath, import2: ImportPath): Int {
|
|
||||||
// alias imports placed last
|
|
||||||
if (import1.hasAlias() != import2.hasAlias()) {
|
|
||||||
return if (import1.hasAlias()) +1 else -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// standard library imports last
|
|
||||||
val stdlib1 = isJavaOrKotlinStdlibImport(import1)
|
|
||||||
val stdlib2 = isJavaOrKotlinStdlibImport(import2)
|
|
||||||
if (stdlib1 != stdlib2) {
|
|
||||||
return if (stdlib1) +1 else -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return import1.toString().compareTo(import2.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isJavaOrKotlinStdlibImport(path: ImportPath): Boolean {
|
|
||||||
val s = path.pathStr
|
|
||||||
return s.startsWith("java.") || s.startsWith("javax.") || s.startsWith("kotlin.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val DeclarationDescriptor.importableFqName: FqName?
|
val DeclarationDescriptor.importableFqName: FqName?
|
||||||
get() {
|
get() {
|
||||||
if (!canBeReferencedViaImport()) return null
|
if (!canBeReferencedViaImport()) return null
|
||||||
|
|||||||
+3
-2
@@ -14,6 +14,7 @@ import junit.framework.TestCase
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntry
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
@@ -61,10 +62,10 @@ abstract class AbstractPerformanceImportTest : KotlinLightCodeInsightFixtureTest
|
|||||||
InTextDirectivesUtils.getPrefixedBoolean(fileText, "// IMPORT_NESTED_CLASSES:") ?: false
|
InTextDirectivesUtils.getPrefixedBoolean(fileText, "// IMPORT_NESTED_CLASSES:") ?: false
|
||||||
|
|
||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGE_TO_USE_STAR_IMPORTS:").forEach {
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGE_TO_USE_STAR_IMPORTS:").forEach {
|
||||||
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), false))
|
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(KotlinPackageEntry(it.trim(), false))
|
||||||
}
|
}
|
||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGES_TO_USE_STAR_IMPORTS:").forEach {
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGES_TO_USE_STAR_IMPORTS:").forEach {
|
||||||
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), true))
|
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(KotlinPackageEntry(it.trim(), true))
|
||||||
}
|
}
|
||||||
|
|
||||||
var descriptorName = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// IMPORT:")
|
var descriptorName = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// IMPORT:")
|
||||||
|
|||||||
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.formatter
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.actionSystem.CommonShortcuts
|
||||||
|
import com.intellij.openapi.actionSystem.ShortcutSet
|
||||||
|
import com.intellij.openapi.application.ApplicationBundle
|
||||||
|
import com.intellij.openapi.wm.IdeFocusManager
|
||||||
|
import com.intellij.ui.*
|
||||||
|
import com.intellij.ui.components.JBCheckBox
|
||||||
|
import com.intellij.ui.layout.selected
|
||||||
|
import com.intellij.ui.table.JBTable
|
||||||
|
import com.intellij.util.IconUtil
|
||||||
|
import com.intellij.util.ui.JBUI
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntry
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntryTable
|
||||||
|
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors
|
||||||
|
import java.awt.BorderLayout
|
||||||
|
import java.awt.Dimension
|
||||||
|
import javax.swing.DefaultCellEditor
|
||||||
|
import javax.swing.JPanel
|
||||||
|
import javax.swing.JTable
|
||||||
|
import javax.swing.ListSelectionModel
|
||||||
|
import javax.swing.table.AbstractTableModel
|
||||||
|
|
||||||
|
open class BaseKotlinImportLayoutPanel(title: String): JPanel(BorderLayout()) {
|
||||||
|
val packageTable = KotlinPackageEntryTable()
|
||||||
|
val layoutTable = createTableForPackageEntries(packageTable)
|
||||||
|
|
||||||
|
init {
|
||||||
|
border = IdeBorderFactory.createTitledBorder(
|
||||||
|
title,
|
||||||
|
false,
|
||||||
|
JBUI.emptyInsets()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun addPackage() {
|
||||||
|
var row = layoutTable.selectedRow + 1
|
||||||
|
if (row < 0) {
|
||||||
|
row = packageTable.getEntryCount()
|
||||||
|
}
|
||||||
|
val entry = KotlinPackageEntry("", true)
|
||||||
|
packageTable.insertEntryAt(entry, row)
|
||||||
|
refreshTableModel(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun removePackage() {
|
||||||
|
var row = layoutTable.selectedRow
|
||||||
|
if (row < 0) return
|
||||||
|
|
||||||
|
val entry = packageTable.getEntryAt(row)
|
||||||
|
if (entry == KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY || entry == KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
TableUtil.stopEditing(layoutTable)
|
||||||
|
packageTable.removeEntryAt(row)
|
||||||
|
|
||||||
|
val model = layoutTable.model as AbstractTableModel
|
||||||
|
model.fireTableRowsDeleted(row, row)
|
||||||
|
|
||||||
|
if (row >= packageTable.getEntryCount()) {
|
||||||
|
row--
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row >= 0) {
|
||||||
|
layoutTable.setRowSelectionInterval(row, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun movePackageUp() {
|
||||||
|
val row = layoutTable.selectedRow
|
||||||
|
if (row < 1) return
|
||||||
|
|
||||||
|
TableUtil.stopEditing(layoutTable)
|
||||||
|
val entry = packageTable.getEntryAt(row)
|
||||||
|
val previousEntry = packageTable.getEntryAt(row - 1)
|
||||||
|
packageTable.setEntryAt(entry, row - 1)
|
||||||
|
packageTable.setEntryAt(previousEntry, row)
|
||||||
|
|
||||||
|
val model = layoutTable.model as AbstractTableModel
|
||||||
|
model.fireTableRowsUpdated(row - 1, row)
|
||||||
|
layoutTable.setRowSelectionInterval(row - 1, row - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun movePackageDown() {
|
||||||
|
val row = layoutTable.selectedRow
|
||||||
|
if (row >= packageTable.getEntryCount() - 1) return
|
||||||
|
|
||||||
|
TableUtil.stopEditing(layoutTable)
|
||||||
|
val entry = packageTable.getEntryAt(row)
|
||||||
|
val nextEntry = packageTable.getEntryAt(row + 1)
|
||||||
|
packageTable.setEntryAt(entry, row + 1)
|
||||||
|
packageTable.setEntryAt(nextEntry, row)
|
||||||
|
|
||||||
|
val model = layoutTable.model as AbstractTableModel
|
||||||
|
model.fireTableRowsUpdated(row, row + 1)
|
||||||
|
layoutTable.setRowSelectionInterval(row + 1, row + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshTableModel(row: Int) {
|
||||||
|
val model = layoutTable.model as AbstractTableModel
|
||||||
|
model.fireTableRowsInserted(row, row)
|
||||||
|
layoutTable.setRowSelectionInterval(row, row)
|
||||||
|
TableUtil.editCellAt(layoutTable, row, 0)
|
||||||
|
val editorComp = layoutTable.editorComponent
|
||||||
|
if (editorComp != null) {
|
||||||
|
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown { IdeFocusManager.getGlobalInstance().requestFocus(editorComp, true) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun resizeColumns() {
|
||||||
|
val packageRenderer: ColoredTableCellRenderer = object : ColoredTableCellRenderer() {
|
||||||
|
override fun customizeCellRenderer(
|
||||||
|
table: JTable,
|
||||||
|
value: Any?,
|
||||||
|
selected: Boolean,
|
||||||
|
hasFocus: Boolean,
|
||||||
|
row: Int,
|
||||||
|
column: Int
|
||||||
|
) {
|
||||||
|
val entry = packageTable.getEntryAt(row)
|
||||||
|
val attributes = KotlinHighlightingColors.KEYWORD.defaultAttributes
|
||||||
|
append("import", SimpleTextAttributes.fromTextAttributes(attributes))
|
||||||
|
append(" ", SimpleTextAttributes.REGULAR_ATTRIBUTES)
|
||||||
|
|
||||||
|
when (entry) {
|
||||||
|
KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY -> append(
|
||||||
|
"all other imports",
|
||||||
|
SimpleTextAttributes.REGULAR_ATTRIBUTES
|
||||||
|
)
|
||||||
|
|
||||||
|
KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY -> append(
|
||||||
|
"all alias imports",
|
||||||
|
SimpleTextAttributes.REGULAR_ATTRIBUTES
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> append(
|
||||||
|
"${entry.packageName}.*",
|
||||||
|
SimpleTextAttributes.REGULAR_ATTRIBUTES
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutTable.columnModel.apply {
|
||||||
|
getColumn(0).cellRenderer = packageRenderer
|
||||||
|
getColumn(1).cellRenderer = BooleanTableCellRenderer()
|
||||||
|
|
||||||
|
fixColumnWidthToHeader(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fixColumnWidthToHeader(columnIndex: Int) {
|
||||||
|
with (layoutTable) {
|
||||||
|
val column = columnModel.getColumn(columnIndex)
|
||||||
|
val width = 15 + tableHeader.getFontMetrics(tableHeader.font).stringWidth(getColumnName(columnIndex))
|
||||||
|
|
||||||
|
column.minWidth = width
|
||||||
|
column.maxWidth = width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinStarImportLayoutPanel: BaseKotlinImportLayoutPanel(ApplicationBundle.message("title.packages.to.use.import.with")) {
|
||||||
|
init {
|
||||||
|
val importLayoutPanel = ToolbarDecorator.createDecorator(layoutTable)
|
||||||
|
.setAddAction { addPackage() }
|
||||||
|
.setRemoveAction { removePackage() }
|
||||||
|
.setButtonComparator(
|
||||||
|
"Add",
|
||||||
|
"Remove"
|
||||||
|
).setPreferredSize(Dimension(-1, 100))
|
||||||
|
.createPanel()
|
||||||
|
|
||||||
|
add(importLayoutPanel, BorderLayout.CENTER)
|
||||||
|
resizeColumns()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinImportOrderLayoutPanel: BaseKotlinImportLayoutPanel(ApplicationBundle.message("title.import.layout")) {
|
||||||
|
private val cbImportAliasesSeparately = JBCheckBox("Import aliases separately")
|
||||||
|
|
||||||
|
init {
|
||||||
|
add(cbImportAliasesSeparately, BorderLayout.NORTH)
|
||||||
|
|
||||||
|
val importLayoutPanel = ToolbarDecorator.createDecorator(layoutTable)
|
||||||
|
.addExtraAction(
|
||||||
|
object: DumbAwareActionButton(ApplicationBundle.message("button.add.package"), IconUtil.getAddPackageIcon()) {
|
||||||
|
override fun actionPerformed(event: AnActionEvent) {
|
||||||
|
addPackage()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getShortcut(): ShortcutSet {
|
||||||
|
return CommonShortcuts.getNewForDialogs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.setRemoveAction { removePackage() }
|
||||||
|
.setMoveUpAction { movePackageUp() }
|
||||||
|
.setMoveDownAction { movePackageDown() }
|
||||||
|
.setRemoveActionUpdater {
|
||||||
|
val selectedRow = layoutTable.selectedRow
|
||||||
|
val entry = if (selectedRow in 0 until packageTable.getEntryCount()) packageTable.getEntryAt(selectedRow) else null
|
||||||
|
|
||||||
|
entry != null && entry != KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY && entry != KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY
|
||||||
|
}.setButtonComparator(
|
||||||
|
ApplicationBundle.message("button.add.package"),
|
||||||
|
"Remove",
|
||||||
|
"Up",
|
||||||
|
"Down"
|
||||||
|
).setPreferredSize(Dimension(-1, 100))
|
||||||
|
.createPanel()
|
||||||
|
|
||||||
|
add(importLayoutPanel, BorderLayout.CENTER)
|
||||||
|
resizeColumns()
|
||||||
|
|
||||||
|
cbImportAliasesSeparately.addItemListener { _ ->
|
||||||
|
if (areImportAliasesEnabled()) {
|
||||||
|
if (packageTable.getEntries().none { it == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY }) {
|
||||||
|
packageTable.addEntry(KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY)
|
||||||
|
val row = packageTable.getEntryCount() - 1
|
||||||
|
val model = layoutTable.model as AbstractTableModel
|
||||||
|
model.fireTableRowsInserted(row, row)
|
||||||
|
layoutTable.setRowSelectionInterval(row, row)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val entryIndex = packageTable.getEntries().indexOfFirst { it == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY }
|
||||||
|
|
||||||
|
if (entryIndex != -1) {
|
||||||
|
val currentIndex = layoutTable.selectedRow
|
||||||
|
packageTable.removeEntryAt(entryIndex)
|
||||||
|
val model = layoutTable.model as AbstractTableModel
|
||||||
|
model.fireTableRowsDeleted(entryIndex, entryIndex)
|
||||||
|
|
||||||
|
if (currentIndex < entryIndex) {
|
||||||
|
layoutTable.setRowSelectionInterval(currentIndex, currentIndex)
|
||||||
|
} else if (entryIndex > 0) {
|
||||||
|
layoutTable.setRowSelectionInterval(entryIndex - 1, entryIndex - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun recomputeAliasesCheckbox() {
|
||||||
|
cbImportAliasesSeparately.isSelected = packageTable.getEntries().any { it == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun areImportAliasesEnabled(): Boolean {
|
||||||
|
return cbImportAliasesSeparately.isSelected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTableForPackageEntries(packageTable: KotlinPackageEntryTable): JBTable {
|
||||||
|
val names = arrayOf(ApplicationBundle.message("listbox.import.package"), ApplicationBundle.message("listbox.import.with.subpackages"))
|
||||||
|
|
||||||
|
val dataModel = object : AbstractTableModel() {
|
||||||
|
override fun getColumnCount(): Int {
|
||||||
|
return names.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRowCount(): Int {
|
||||||
|
return packageTable.getEntryCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValueAt(rowIndex: Int, columnIndex: Int): Any? {
|
||||||
|
val entry = packageTable.getEntryAt(rowIndex)
|
||||||
|
if (!isCellEditable(rowIndex, columnIndex)) return null
|
||||||
|
|
||||||
|
return when (columnIndex) {
|
||||||
|
0 -> entry.packageName
|
||||||
|
1 -> entry.withSubpackages
|
||||||
|
else -> throw IllegalArgumentException(columnIndex.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCellEditable(rowIndex: Int, columnIndex: Int): Boolean {
|
||||||
|
val entry = packageTable.getEntryAt(rowIndex)
|
||||||
|
return !entry.isSpecial
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getColumnName(column: Int): String {
|
||||||
|
return names[column]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getColumnClass(columnIndex: Int): Class<*> {
|
||||||
|
return when (columnIndex) {
|
||||||
|
0 -> String::class.java
|
||||||
|
1 -> Boolean::class.java
|
||||||
|
else -> throw IllegalArgumentException(columnIndex.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValueAt(value: Any, rowIndex: Int, columnIndex: Int) {
|
||||||
|
val entry = packageTable.getEntryAt(rowIndex)
|
||||||
|
|
||||||
|
val newEntry = when (columnIndex) {
|
||||||
|
0 -> KotlinPackageEntry((value as String).trim(), entry.withSubpackages)
|
||||||
|
1 -> KotlinPackageEntry(entry.packageName, (value as Boolean))
|
||||||
|
else -> throw IllegalArgumentException(columnIndex.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
packageTable.setEntryAt(newEntry, rowIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the table
|
||||||
|
val result = JBTable(dataModel)
|
||||||
|
result.selectionModel.selectionMode = ListSelectionModel.SINGLE_SELECTION
|
||||||
|
|
||||||
|
val editor = result.getDefaultEditor(String::class.java)
|
||||||
|
if (editor is DefaultCellEditor) editor.clickCountToStart = 1
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
@@ -11,12 +11,12 @@ import com.intellij.application.options.PackagePanel
|
|||||||
import com.intellij.openapi.application.ApplicationBundle
|
import com.intellij.openapi.application.ApplicationBundle
|
||||||
import com.intellij.openapi.editor.colors.EditorColorsScheme
|
import com.intellij.openapi.editor.colors.EditorColorsScheme
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettings
|
import com.intellij.psi.codeStyle.CodeStyleSettings
|
||||||
import com.intellij.psi.codeStyle.PackageEntryTable
|
|
||||||
import com.intellij.ui.OptionGroup
|
import com.intellij.ui.OptionGroup
|
||||||
import com.intellij.ui.components.JBScrollPane
|
import com.intellij.ui.components.JBScrollPane
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntryTable
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import java.awt.GridBagConstraints
|
import java.awt.GridBagConstraints
|
||||||
import java.awt.GridBagLayout
|
import java.awt.GridBagLayout
|
||||||
@@ -53,12 +53,8 @@ class ImportSettingsPanelWrapper(settings: CodeStyleSettings) : CodeStyleAbstrac
|
|||||||
class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPanel() {
|
class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPanel() {
|
||||||
private val cbImportNestedClasses = JCheckBox(KotlinBundle.message("formatter.checkbox.text.insert.imports.for.nested.classes"))
|
private val cbImportNestedClasses = JCheckBox(KotlinBundle.message("formatter.checkbox.text.insert.imports.for.nested.classes"))
|
||||||
|
|
||||||
private val starImportPackageEntryTable = PackageEntryTable()
|
private val starImportLayoutPanel = KotlinStarImportLayoutPanel()
|
||||||
private val dummyImportLayoutPanel = object : ImportLayoutPanel() {
|
private val importOrderLayoutPanel = KotlinImportOrderLayoutPanel()
|
||||||
override fun areStaticImportsEnabled() = false
|
|
||||||
override fun refresh() {}
|
|
||||||
}
|
|
||||||
private val starImportPackageTable = ImportLayoutPanel.createTableForPackageEntries(starImportPackageEntryTable, dummyImportLayoutPanel)
|
|
||||||
|
|
||||||
private val nameCountToUseStarImportSelector = NameCountToUseStarImportSelector(
|
private val nameCountToUseStarImportSelector = NameCountToUseStarImportSelector(
|
||||||
KotlinBundle.message("formatter.title.top.level.symbols"), KotlinCodeStyleSettings.defaultSettings().NAME_COUNT_TO_USE_STAR_IMPORT
|
KotlinBundle.message("formatter.title.top.level.symbols"), KotlinCodeStyleSettings.defaultSettings().NAME_COUNT_TO_USE_STAR_IMPORT
|
||||||
@@ -88,7 +84,13 @@ class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPane
|
|||||||
KotlinBundle.message("formatter.title.other")).apply { add(cbImportNestedClasses) }.createPanel(),
|
KotlinBundle.message("formatter.title.other")).apply { add(cbImportNestedClasses) }.createPanel(),
|
||||||
constraints.apply { gridy++ })
|
constraints.apply { gridy++ })
|
||||||
|
|
||||||
add(PackagePanel.createPackagesPanel(starImportPackageTable, starImportPackageEntryTable), constraints.apply {
|
add(starImportLayoutPanel, constraints.apply {
|
||||||
|
gridy++
|
||||||
|
fill = GridBagConstraints.BOTH
|
||||||
|
weighty = 1.0
|
||||||
|
})
|
||||||
|
|
||||||
|
add(importOrderLayoutPanel, constraints.apply {
|
||||||
gridy++
|
gridy++
|
||||||
fill = GridBagConstraints.BOTH
|
fill = GridBagConstraints.BOTH
|
||||||
weighty = 1.0
|
weighty = 1.0
|
||||||
@@ -102,18 +104,27 @@ class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPane
|
|||||||
|
|
||||||
cbImportNestedClasses.isSelected = settings.IMPORT_NESTED_CLASSES
|
cbImportNestedClasses.isSelected = settings.IMPORT_NESTED_CLASSES
|
||||||
|
|
||||||
starImportPackageEntryTable.copyFrom(settings.PACKAGES_TO_USE_STAR_IMPORTS)
|
starImportLayoutPanel.packageTable.copyFrom(settings.PACKAGES_TO_USE_STAR_IMPORTS)
|
||||||
(starImportPackageTable.model as AbstractTableModel).fireTableDataChanged()
|
(starImportLayoutPanel.layoutTable.model as AbstractTableModel).fireTableDataChanged()
|
||||||
if (starImportPackageTable.rowCount > 0) {
|
if (starImportLayoutPanel.layoutTable.rowCount > 0) {
|
||||||
starImportPackageTable.selectionModel.setSelectionInterval(0, 0)
|
starImportLayoutPanel.layoutTable.selectionModel.setSelectionInterval(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
importOrderLayoutPanel.packageTable.copyFrom(settings.PACKAGES_IMPORT_LAYOUT)
|
||||||
|
(importOrderLayoutPanel.layoutTable.model as AbstractTableModel).fireTableDataChanged()
|
||||||
|
if (importOrderLayoutPanel.layoutTable.rowCount > 0) {
|
||||||
|
importOrderLayoutPanel.layoutTable.selectionModel.setSelectionInterval(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
importOrderLayoutPanel.recomputeAliasesCheckbox()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun apply(settings: KotlinCodeStyleSettings) {
|
fun apply(settings: KotlinCodeStyleSettings) {
|
||||||
settings.NAME_COUNT_TO_USE_STAR_IMPORT = nameCountToUseStarImportSelector.value
|
settings.NAME_COUNT_TO_USE_STAR_IMPORT = nameCountToUseStarImportSelector.value
|
||||||
settings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = nameCountToUseStarImportForMembersSelector.value
|
settings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = nameCountToUseStarImportForMembersSelector.value
|
||||||
settings.IMPORT_NESTED_CLASSES = cbImportNestedClasses.isSelected
|
settings.IMPORT_NESTED_CLASSES = cbImportNestedClasses.isSelected
|
||||||
settings.PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(getCopyWithoutEmptyPackages(starImportPackageEntryTable))
|
settings.PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(getCopyWithoutEmptyPackages(starImportLayoutPanel.packageTable))
|
||||||
|
settings.PACKAGES_IMPORT_LAYOUT.copyFrom(importOrderLayoutPanel.packageTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isModified(settings: KotlinCodeStyleSettings): Boolean {
|
fun isModified(settings: KotlinCodeStyleSettings): Boolean {
|
||||||
@@ -122,7 +133,8 @@ class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPane
|
|||||||
isModified = isModified || nameCountToUseStarImportSelector.value != NAME_COUNT_TO_USE_STAR_IMPORT
|
isModified = isModified || nameCountToUseStarImportSelector.value != NAME_COUNT_TO_USE_STAR_IMPORT
|
||||||
isModified = isModified || nameCountToUseStarImportForMembersSelector.value != NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS
|
isModified = isModified || nameCountToUseStarImportForMembersSelector.value != NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS
|
||||||
isModified = isModified || isModified(cbImportNestedClasses, IMPORT_NESTED_CLASSES)
|
isModified = isModified || isModified(cbImportNestedClasses, IMPORT_NESTED_CLASSES)
|
||||||
isModified = isModified || isModified(getCopyWithoutEmptyPackages(starImportPackageEntryTable), PACKAGES_TO_USE_STAR_IMPORTS)
|
isModified = isModified || isModified(getCopyWithoutEmptyPackages(starImportLayoutPanel.packageTable), PACKAGES_TO_USE_STAR_IMPORTS)
|
||||||
|
isModified = isModified || isModified(importOrderLayoutPanel.packageTable, PACKAGES_IMPORT_LAYOUT)
|
||||||
|
|
||||||
isModified
|
isModified
|
||||||
}
|
}
|
||||||
@@ -133,12 +145,12 @@ class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPane
|
|||||||
return checkBox.isSelected != value
|
return checkBox.isSelected != value
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isModified(list: PackageEntryTable, table: PackageEntryTable): Boolean {
|
private fun isModified(list: KotlinPackageEntryTable, table: KotlinPackageEntryTable): Boolean {
|
||||||
if (list.entryCount != table.entryCount) {
|
if (list.getEntryCount() != table.getEntryCount()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0 until list.entryCount) {
|
for (i in 0 until list.getEntryCount()) {
|
||||||
val entry1 = list.getEntryAt(i)
|
val entry1 = list.getEntryAt(i)
|
||||||
val entry2 = table.getEntryAt(i)
|
val entry2 = table.getEntryAt(i)
|
||||||
if (entry1 != entry2) {
|
if (entry1 != entry2) {
|
||||||
@@ -149,9 +161,9 @@ class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPane
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCopyWithoutEmptyPackages(table: PackageEntryTable): PackageEntryTable {
|
private fun getCopyWithoutEmptyPackages(table: KotlinPackageEntryTable): KotlinPackageEntryTable {
|
||||||
try {
|
try {
|
||||||
val copy = table.clone() as PackageEntryTable
|
val copy = table.clone()
|
||||||
copy.removeEmptyPackages()
|
copy.removeEmptyPackages()
|
||||||
return copy
|
return copy
|
||||||
} catch (ignored: CloneNotSupportedException) {
|
} catch (ignored: CloneNotSupportedException) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||||
import org.jetbrains.kotlin.idea.core.targetDescriptors
|
import org.jetbrains.kotlin.idea.core.targetDescriptors
|
||||||
import org.jetbrains.kotlin.idea.imports.ImportPathComparator
|
|
||||||
import org.jetbrains.kotlin.idea.imports.getImportableTargets
|
import org.jetbrains.kotlin.idea.imports.getImportableTargets
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||||
@@ -45,7 +44,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
|
|||||||
get() = KotlinCodeStyleSettings.getInstance(project)
|
get() = KotlinCodeStyleSettings.getInstance(project)
|
||||||
|
|
||||||
override val importSortComparator: Comparator<ImportPath>
|
override val importSortComparator: Comparator<ImportPath>
|
||||||
get() = ImportPathComparator
|
get() = ImportPathComparator(codeStyleSettings.PACKAGES_IMPORT_LAYOUT)
|
||||||
|
|
||||||
override fun isImportedWithDefault(importPath: ImportPath, contextFile: KtFile): Boolean {
|
override fun isImportedWithDefault(importPath: ImportPath, contextFile: KtFile): Boolean {
|
||||||
val languageVersionSettings = contextFile.getResolutionFacade().frontendService<LanguageVersionSettings>()
|
val languageVersionSettings = contextFile.getResolutionFacade().frontendService<LanguageVersionSettings>()
|
||||||
@@ -409,10 +408,11 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
|
|||||||
importList.add(psiFactory.createNewLine())
|
importList.add(psiFactory.createNewLine())
|
||||||
importList.add(newDirective) as KtImportDirective
|
importList.add(newDirective) as KtImportDirective
|
||||||
} else {
|
} else {
|
||||||
|
val importPathComparator = ImportInsertHelperImpl(project).importSortComparator
|
||||||
val insertAfter = imports
|
val insertAfter = imports
|
||||||
.lastOrNull {
|
.lastOrNull {
|
||||||
val directivePath = it.importPath
|
val directivePath = it.importPath
|
||||||
directivePath != null && ImportPathComparator.compare(directivePath, importPath) <= 0
|
directivePath != null && importPathComparator.compare(directivePath, importPath) <= 0
|
||||||
}
|
}
|
||||||
importList.addAfter(newDirective, insertAfter) as KtImportDirective
|
importList.addAfter(newDirective, insertAfter) as KtImportDirective
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntry
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntryTable
|
||||||
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
|
import java.util.Comparator
|
||||||
|
|
||||||
|
class ImportPathComparator(
|
||||||
|
private val packageTable: KotlinPackageEntryTable
|
||||||
|
) : Comparator<ImportPath> {
|
||||||
|
override fun compare(import1: ImportPath, import2: ImportPath): Int {
|
||||||
|
val index1 = bestMatchIndex(import1)
|
||||||
|
val index2 = bestMatchIndex(import2)
|
||||||
|
|
||||||
|
return when {
|
||||||
|
index1 == index2 -> import1.toString().compareTo(import2.toString())
|
||||||
|
index1 < index2 -> -1
|
||||||
|
else -> +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bestMatchIndex(path: ImportPath): Int {
|
||||||
|
var bestIndex: Int? = null
|
||||||
|
var bestEntryMatch: KotlinPackageEntry? = null
|
||||||
|
|
||||||
|
for ((index, entry) in packageTable.getEntries().withIndex()) {
|
||||||
|
if (entry.isBetterMatchForPackageThan(bestEntryMatch, path)) {
|
||||||
|
bestEntryMatch = entry
|
||||||
|
bestIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestIndex!!
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,10 +6,10 @@
|
|||||||
package org.jetbrains.kotlin
|
package org.jetbrains.kotlin
|
||||||
|
|
||||||
import com.intellij.application.options.CodeStyle
|
import com.intellij.application.options.CodeStyle
|
||||||
import com.intellij.psi.codeStyle.PackageEntry
|
|
||||||
import com.intellij.testFramework.LightProjectDescriptor
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinPackageEntry
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
@@ -56,10 +56,10 @@ abstract class AbstractImportsTest : KotlinLightCodeInsightFixtureTestCase() {
|
|||||||
InTextDirectivesUtils.getPrefixedBoolean(fileText, "// IMPORT_NESTED_CLASSES:") ?: false
|
InTextDirectivesUtils.getPrefixedBoolean(fileText, "// IMPORT_NESTED_CLASSES:") ?: false
|
||||||
|
|
||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGE_TO_USE_STAR_IMPORTS:").forEach {
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGE_TO_USE_STAR_IMPORTS:").forEach {
|
||||||
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), false))
|
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(KotlinPackageEntry(it.trim(), false))
|
||||||
}
|
}
|
||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGES_TO_USE_STAR_IMPORTS:").forEach {
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGES_TO_USE_STAR_IMPORTS:").forEach {
|
||||||
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), true))
|
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(KotlinPackageEntry(it.trim(), true))
|
||||||
}
|
}
|
||||||
|
|
||||||
val log = project.executeWriteCommand<String?>("") { doTest(file) }
|
val log = project.executeWriteCommand<String?>("") { doTest(file) }
|
||||||
|
|||||||
Reference in New Issue
Block a user