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 Inline Anonymous Function/Lambda refactoring: place the caret in an immediately invoked Kotlin lambda or anonymous function, press **Ctrl+Alt+N** or choose **Refactor → Inline...**, preview the one-call rewrite, and apply the IntelliJ IDEA K2-generated substitution; **Undo Last Refactoring** restores the original document.
- 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.
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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-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.252-SNAPSHOT</version>
<version>0.11.256-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>netbeans-plugin-kotlin-refactoring</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright 2000-2024 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.refactoring

import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.k2.refactoring.inline.KotlinInlineAnonymousFunctionProcessor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtNamedFunction

/**
* Prepared IDEA-engine data for a Kotlin **Inline Anonymous Function** refactoring.
*
* @param function lambda or anonymous function selected at the invocation caret
* @param call immediate invocation accepted by IDEA's anonymous-function processor
*/
data class KaInlineAnonymousFunctionResult(
val function: KtFunction,
val call: KtExpression,
)

/**
* Prepares an immediately invoked lambda or anonymous function for IDEA's K2 inline processor.
*
* IDEA remains responsible for recognising supported invocation shapes through
* [KotlinInlineAnonymousFunctionProcessor.findCallExpression]. The NetBeans adapter owns UI,
* preview, document persistence, and undo.
*
* @param cursorKtFile session-managed Kotlin file containing the invocation caret
* @param offset caret offset within [cursorKtFile]
*/
class KaInlineAnonymousFunctionComputer(
private val cursorKtFile: KtFile,
private val offset: Int,
) {

/** Result of [compute]. */
sealed class Outcome {
/** The lambda/anonymous function and its IDEA-supported immediate call are ready. */
data class Ready(val result: KaInlineAnonymousFunctionResult) : Outcome()

/** A lambda/anonymous function was selected but is not immediately invoked. */
data class Error(val message: String) : Outcome()

/** The caret does not select a lambda or anonymous function. */
data object NotApplicable : Outcome()
}

/**
* Finds the lambda or anonymous function enclosing the caret and delegates call validation to IDEA.
*
* @return [Outcome.Ready] for an immediately invoked function, [Outcome.Error] for an uninvoked
* lambda/anonymous function, or [Outcome.NotApplicable] for all other caret targets
*/
fun compute(): Outcome {
val element = cursorKtFile.findElementAt(offset) ?: return Outcome.NotApplicable
val function = PsiTreeUtil.getParentOfType(element, KtFunction::class.java, false)
?.takeIf(::isAnonymousFunction)
?: return Outcome.NotApplicable
val call = KotlinInlineAnonymousFunctionProcessor.findCallExpression(function)
?: return Outcome.Error(messageFor(function))
return Outcome.Ready(KaInlineAnonymousFunctionResult(function, call))
}

/** Restricts this route to function literals and unnamed `fun` expressions, not named declarations. */
private fun isAnonymousFunction(function: KtFunction): Boolean =
function is KtFunctionLiteral || function is KtNamedFunction && function.nameIdentifier == null

/** Explains the IDEA eligibility restriction without importing IDEA's modal error UI. */
private fun messageFor(function: KtFunction): String =
if (function is KtFunctionLiteral) {
"Cannot inline this lambda expression because it is not immediately invoked."
} else {
"Cannot inline this anonymous function because it is not immediately invoked."
}
}
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.252-SNAPSHOT</version>
<version>0.11.256-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
@@ -0,0 +1,112 @@
/*******************************************************************************
* 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.refactoring;

import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeListener;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel;
import org.netbeans.modules.refactoring.spi.ui.RefactoringUI;
import org.openide.util.HelpCtx;

/**
* NetBeans UI adapter for Kotlin **Inline Anonymous Function**.
*
* The transformation is limited to the immediately invoked lambda or anonymous function selected
* at the caret. IDEA's K2 processor supplies the actual rewrite; NetBeans supplies its preview
* and confirmation flow.
*
* @param refactoring carrier routed to {@link KotlinInlineAnonymousFunctionPlugin}
*/
public final class KotlinInlineAnonymousFunctionUI implements RefactoringUI {

private final KotlinInlineAnonymousFunctionRefactoring refactoring;

/**
* Creates an Inline Anonymous Function UI.
*
* @param refactoring carrier receiving the active document and caret
*/
public KotlinInlineAnonymousFunctionUI(KotlinInlineAnonymousFunctionRefactoring refactoring) {
this.refactoring = refactoring;
}

@Override
public String getName() {
return "Inline Anonymous Function";
}

@Override
public String getDescription() {
return "Inline immediately invoked lambda or anonymous function";
}

@Override
public boolean isQuery() {
return false;
}

@Override
public CustomRefactoringPanel getPanel(ChangeListener parent) {
return new DescriptionPanel(getDescription());
}

@Override
public Problem setParameters() {
return null;
}

@Override
public Problem checkParameters() {
return null;
}

@Override
public boolean hasParameters() {
return true;
}

@Override
public AbstractRefactoring getRefactoring() {
return refactoring;
}

@Override
public HelpCtx getHelpCtx() {
return null;
}

/** Displays the operation description until the user previews or confirms the refactoring. */
private static final class DescriptionPanel implements CustomRefactoringPanel {
private final JPanel component;

DescriptionPanel(String description) {
JLabel label = new JLabel(description);
label.setBorder(BorderFactory.createEmptyBorder(8, 12, 8, 12));
component = new JPanel(new BorderLayout());
component.add(label, BorderLayout.CENTER);
}

@Override public void initialize() {}
@Override public Component getComponent() { return component; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinInlineVariableRefactoring;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinInlineTypeAliasPlugin;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinInlineTypeAliasRefactoring;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinInlineAnonymousFunctionPlugin;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinInlineAnonymousFunctionRefactoring;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinIntroduceConstantPlugin;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinIntroduceConstantRefactoring;
import io.github.nbplugins.kotlin.nbm.refactoring.KotlinCopyDeclarationPlugin;
Expand Down Expand Up @@ -86,6 +88,7 @@
* <li>{@link KotlinInlineVariableRefactoring} — delegates to {@link KotlinInlineVariablePlugin}</li>
* <li>{@link KotlinInlineFunctionRefactoring} — delegates to {@link KotlinInlineFunctionPlugin}</li>
* <li>{@link KotlinInlineTypeAliasRefactoring} — delegates to {@link KotlinInlineTypeAliasPlugin}</li>
* <li>{@link KotlinInlineAnonymousFunctionRefactoring} — delegates to {@link KotlinInlineAnonymousFunctionPlugin}</li>
* <li>{@link KotlinIntroduceVariableRefactoring} — delegates to {@link KotlinIntroduceVariablePlugin}</li>
* <li>{@link KotlinExtractFunctionRefactoring} — delegates to {@link KotlinExtractFunctionPlugin}</li>
* <li>{@link KotlinIntroduceConstantRefactoring} — delegates to {@link KotlinIntroduceConstantPlugin}</li>
Expand Down Expand Up @@ -138,6 +141,9 @@ public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
if (refactoring instanceof KotlinInlineTypeAliasRefactoring) {
return new KotlinInlineTypeAliasPlugin((KotlinInlineTypeAliasRefactoring) refactoring);
}
if (refactoring instanceof KotlinInlineAnonymousFunctionRefactoring) {
return new KotlinInlineAnonymousFunctionPlugin((KotlinInlineAnonymousFunctionRefactoring) refactoring);
}
if (refactoring instanceof KotlinIntroduceVariableRefactoring) {
return new KotlinIntroduceVariablePlugin((KotlinIntroduceVariableRefactoring) refactoring);
}
Expand Down
Loading
Loading