Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Added separate Java and Kotlin package trees in Project Explorer: conventional `src/main/java` and `src/test/java` remain under **Source Packages** and **Test Packages**, while `src/main/kotlin` and `src/test/kotlin` appear under **Kotlin Source Packages** and **Kotlin Test Packages** in Maven, Gradle, and Ant/J2SE projects.
- Added Inline Type Alias refactoring: place the caret on a Kotlin `typealias` declaration or one of its type uses, press **Ctrl+Alt+N** or choose **Refactor → Inline...**, then expand every supported Kotlin occurrence or only the selected use and optionally retain the alias declaration; generic arguments, imports, and parenthesisation use the IntelliJ IDEA K2 engine, while **Undo Last Refactoring** restores all changed Kotlin files.
- Added Change Kotlin Package refactoring: use **Refactor → Change Kotlin Package...** for the active Kotlin file or a folder's recursive Kotlin descendants to update package directives in place; nested files retain their relative package hierarchy, supported Kotlin code references and direct imports update, and **Undo Last Refactoring** restores the original contents.
- Added Move Kotlin File and Directory refactoring: move the active `.kt` file from **Refactor → Move Kotlin File...**, or right-click a folder and choose **Move Kotlin Directory...** to recursively move its Kotlin files while retaining the selected directory and nested structure below a selected source root/package; matching package directives and supported Kotlin code references are updated, and **Undo Last Refactoring** restores the original locations and contents.
Expand Down
2 changes: 1 addition & 1 deletion CoreImpl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-core-impl</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinCompilerCliBase/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-compiler-cli-base</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinFixesImpl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-fixes-impl</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinFormatter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-formatter</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinHighlighting/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-highlighting</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinIcons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-icons</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinIntentionUtils/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-intention-utils</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion KotlinRefactoring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-refactoring</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion Nbm/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-kotlin</artifactId>
<version>0.11.250-SNAPSHOT</version>
<version>0.11.252-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-nbm</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public Lookup createAdditionalLookup(Lookup lkp) {
Project project = lkp.lookup(Project.class);

return Lookups.fixed(new KotlinPrivilegedTemplates(),
new GradleProjectOpenedHook(project));
new GradleProjectOpenedHook(project),
new io.github.nbplugins.kotlin.nbm.projectsextensions.KotlinProjectSources(project));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ public Lookup createAdditionalLookup(Lookup lkp) {

return Lookups.fixed(
new KotlinPrivilegedTemplates(),
new J2SEExtendedClassPathProvider(j2seProject),
new J2SEProjectOpenedHook(j2seProject)
new J2SEExtendedClassPathProvider(j2seProject),
new J2SEProjectOpenedHook(j2seProject),
new io.github.nbplugins.kotlin.nbm.projectsextensions.KotlinProjectSources(j2seProject)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public Lookup createAdditionalLookup(Lookup lkp) {
Project project = lkp.lookup(Project.class);

return Lookups.fixed(new KotlinPrivilegedTemplates(),
new MavenProjectOpenedHook(project)
new MavenProjectOpenedHook(project),
new io.github.nbplugins.kotlin.nbm.projectsextensions.KotlinProjectSources(project)
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* ******************************************************************************
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2026 nbplugins contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ******************************************************************************
*/
package io.github.nbplugins.kotlin.nbm.projectsextensions

import java.beans.PropertyChangeListener
import javax.swing.Icon
import org.netbeans.api.project.SourceGroup
import org.openide.filesystems.FileObject

/** Hides [excludedFolders] from a broader Java source group without changing project metadata. */
class FilteredSourceGroup(
private val delegate: SourceGroup,
excludedFolders: Collection<FileObject>
) : SourceGroup {
private val excludedPaths = excludedFolders.map(FileObject::getPath).toSet()

/** Returns the delegated root folder. */
override fun getRootFolder(): FileObject = delegate.rootFolder

/** Returns the delegated stable source-group identifier. */
override fun getName(): String = delegate.name

/** Returns the delegated Project Explorer label. */
override fun getDisplayName(): String = delegate.displayName

/** Returns the delegated icon. */
override fun getIcon(opened: Boolean): Icon? = delegate.getIcon(opened)

/** Returns whether [file] belongs to the Java group and is not a Kotlin root or its descendant. */
override fun contains(file: FileObject): Boolean =
delegate.contains(file) && excludedPaths.none { path -> file.path == path || file.path.startsWith("$path/") }

/** Registers [listener] with the delegated group. */
override fun addPropertyChangeListener(listener: PropertyChangeListener?) {
delegate.addPropertyChangeListener(listener)
}

/** Removes [listener] from the delegated group. */
override fun removePropertyChangeListener(listener: PropertyChangeListener?) {
delegate.removePropertyChangeListener(listener)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/**
* ******************************************************************************
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2026 nbplugins contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ******************************************************************************
*/
package io.github.nbplugins.kotlin.nbm.projectsextensions

import javax.swing.event.ChangeEvent
import javax.swing.event.ChangeListener
import org.netbeans.api.java.project.JavaProjectConstants
import org.netbeans.api.project.Project
import org.netbeans.api.project.ProjectUtils
import org.netbeans.api.project.SourceGroup
import org.netbeans.api.project.Sources
import org.netbeans.spi.java.project.support.ui.PackageView
import org.netbeans.spi.project.ui.support.NodeFactory
import org.netbeans.spi.project.ui.support.NodeList
import org.openide.nodes.Node
import org.openide.util.ChangeSupport
import org.openide.util.RequestProcessor

/**
* Adds dedicated Kotlin main and test package nodes to project types whose standard
* node factory already renders Java source groups.
*/
class KotlinProjectNodeFactory : NodeFactory {

/**
* Creates the Kotlin package-node list for [project].
*
* @param project project being rendered in Project Explorer
* @return dynamic list of Kotlin source-root nodes
*/
override fun createNodes(project: Project): NodeList<SourceGroup> =
KotlinSourceNodeList(project, includeJavaGroups = false, includeGradleOtherGroups = false, filterJavaKotlinRoots = false)
}

/** Supplies the missing source nodes for the legacy third-party Gradle integration. */
class KotlinLegacyGradleProjectNodeFactory : NodeFactory {

/**
* Creates a source list for the legacy Gradle project type.
*
* @param project legacy Gradle project being rendered in Project Explorer
* @return Kotlin package-tree nodes for the project
*/
override fun createNodes(project: Project): NodeList<SourceGroup> =
KotlinSourceNodeList(project, includeJavaGroups = true, includeGradleOtherGroups = false, filterJavaKotlinRoots = true)
}

/**
* Replaces the built-in Gradle source node factory, which otherwise merges Java and Kotlin trees.
*/
class KotlinGradleProjectNodeFactory : NodeFactory {

/**
* Creates a source list that preserves Java, resource, and generated nodes while splitting Kotlin.
*
* @param project Gradle project being rendered in Project Explorer
* @return dynamic list of Gradle source-root nodes
*/
override fun createNodes(project: Project): NodeList<SourceGroup> =
KotlinSourceNodeList(project, includeJavaGroups = true, includeGradleOtherGroups = true, filterJavaKotlinRoots = false)
}

/** Replaces the J2SE Java node factory so broad Ant roots do not duplicate Kotlin folders. */
class KotlinJ2SEProjectNodeFactory : NodeFactory {

/**
* Creates a source list with Java package trees filtered to omit conventional Kotlin roots.
*
* @param project J2SE/Ant project being rendered in Project Explorer
* @return dynamic list of separated Java and Kotlin source-root nodes
*/
override fun createNodes(project: Project): NodeList<SourceGroup> =
KotlinSourceNodeList(project, includeJavaGroups = true, includeGradleOtherGroups = false, filterJavaKotlinRoots = true)
}

/**
* Produces PackageView nodes from standard and Kotlin source groups.
*
* The Gradle implementation uses public `Sources` type names deliberately: the Gradle Java
* implementation owns those types but the Kotlin plugin must not take a hard module dependency on it.
*/
private class KotlinSourceNodeList(
private val project: Project,
private val includeJavaGroups: Boolean,
private val includeGradleOtherGroups: Boolean,
private val filterJavaKotlinRoots: Boolean
) : NodeList<SourceGroup>, ChangeListener {

private val changes = ChangeSupport(this)

/**
* Returns ordered source groups for Project Explorer.
*
* @return Java roots when requested, followed by separated Kotlin roots and Gradle auxiliary roots
*/
override fun keys(): List<SourceGroup> {
val sources = ProjectUtils.getSources(project)
val groups = mutableListOf<SourceGroup>()
if (includeJavaGroups) {
val kotlinRoots = KotlinProjectSourceGroups.findRoots(project.projectDirectory).map(KotlinProjectSourceRoot::folder)
groups += sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA)
.map { group -> if (filterJavaKotlinRoots) FilteredSourceGroup(group, kotlinRoots) else group }
}

val projectKotlinGroups = sources.getSourceGroups(KotlinProjectSourceGroups.KOTLIN_SOURCE_TYPE) +
sources.getSourceGroups(KotlinProjectSourceGroups.KOTLIN_TEST_SOURCE_TYPE)
val kotlinGroupPaths = projectKotlinGroups.map { it.rootFolder.path }.toSet()
val gradleKotlinGroups = sources.getSourceGroups("kotlin")
.filterNot { it.rootFolder.path in kotlinGroupPaths }
groups += gradleKotlinGroups.map(::labelKotlinGroup)
groups += projectKotlinGroups

if (includeGradleOtherGroups) {
groups += sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES)
groups += sources.getSourceGroups("generated")
}
return groups.distinctBy { it.rootFolder.path }
}

/**
* Creates a package-view node for [key].
*
* @param key source group to render
* @return package tree rooted at [key]
*/
override fun node(key: SourceGroup): Node = PackageView.createPackageView(key)

/** Starts listening for source-model changes. */
override fun addNotify() {
ProjectUtils.getSources(project).addChangeListener(this)
}

/** Stops listening for source-model changes. */
override fun removeNotify() {
ProjectUtils.getSources(project).removeChangeListener(this)
}

/**
* Schedules an Explorer refresh outside the source-model callback stack.
*
* @param event source-model change event
*/
override fun stateChanged(event: ChangeEvent) {
REFRESH_PROCESSOR.post { changes.fireChange() }
}

/**
* Registers a [listener] for changes in source nodes.
*
* @param listener listener to register
*/
override fun addChangeListener(listener: ChangeListener) {
changes.addChangeListener(listener)
}

/**
* Removes a [listener] from source-node changes.
*
* @param listener listener to remove
*/
override fun removeChangeListener(listener: ChangeListener) {
changes.removeChangeListener(listener)
}

/** Gives a Gradle Kotlin source group a stable language-specific package-tree label. */
private fun labelKotlinGroup(group: SourceGroup): SourceGroup = when {
group.rootFolder.path.endsWith("/src/main/kotlin") ->
NamedSourceGroup(group, KotlinProjectSourceGroups.KOTLIN_SOURCE_PACKAGES)
group.rootFolder.path.endsWith("/src/test/kotlin") ->
NamedSourceGroup(group, KotlinProjectSourceGroups.KOTLIN_TEST_SOURCE_PACKAGES)
else -> group
}

private companion object {
val REFRESH_PROCESSOR = RequestProcessor(KotlinSourceNodeList::class.java)
}
}
Loading
Loading