KTNB-908: Kotlin Notebooks on Welcome Screen

KTNB-908: Use old API in release

KTNB-908: Refactorings

(cherry picked from commit b6553e0c435a9be43ef1387419c29822f94b612a)

KTNB-908: Improve listeners lifetime

(cherry picked from commit 3aefb6e91bd410f823cc54bfb7c57e64804e44e5)

KTNB-908: Process feedback: no sophisticated logic related to locating a project, texts changes

(cherry picked from commit c0d27982d0bd8ebc2894d4680bac18008984c314)

KTNB-908: Streamline work with segmented buttons, remove toolwindow leftovers

(cherry picked from commit 597a9ea2791951981df089ff862d2acc381360af)

KTNB-908: Rework Welcome Screen

Refactor Kotlin Notebook project wizard and actions

Simplified and modularized the Kotlin Notebook creation flow by introducing a new `NewNotebookDialog` and removing the deprecated `KotlinNotebookGeneratorNewProjectWizard`. Added support for recent notebook tracking. Add Open action to the tab.

(cherry picked from commit 5ce728cf3adf2cd9dc7393858a1a3bc79ddf9ba5)

KTNB-908: move static method to more relevant class

(cherry picked from commit 37e1fee22f2ca71523432a7cfe0d091073012f71)

KTNB, minor: fix warnings

(cherry picked from commit 8ff83e4db3bee73f9bb2526cdd08f308e54e16bc)

KTNB-908: Create Scratch Kotlin Notebooks in another scratch root

(cherry picked from commit fd7227253d7d6b928bd9f106dab2198d0b98c8fe)

Add IDEA Dev build with AIA and Python plugins

(cherry picked from commit a6ca8bb509f2534d0d5a3ba83bebab3143498ae5)


Co-authored-by: Nikolay Egorov <Nikolay.Egorov@jetbrains.com>

Merge-request: IJ-MR-158051
Merged-by: Ilya Muradyan <Ilya.Muradyan@jetbrains.com>

GitOrigin-RevId: bb3c707db8d02076021ef0f518eaba7055b5f6fa
This commit is contained in:
Ilya Muradyan
2025-03-24 21:22:29 +00:00
committed by intellij-monorepo-bot
parent f09be76d50
commit 3da9ba225e
6 changed files with 60 additions and 42 deletions

View File

@@ -10962,6 +10962,7 @@ a:com.intellij.ide.scratch.ScratchFileCreationHelper
f:com.intellij.ide.scratch.ScratchFileCreationHelper$Context
- caretOffset:I
- createOption:com.intellij.ide.scratch.ScratchFileService$Option
- defaultRootType:com.intellij.ide.scratch.RootType
- fileCounter:com.intellij.openapi.util.Factory
- fileExtension:java.lang.String
- filePrefix:java.lang.String

View File

@@ -14,6 +14,7 @@ import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.command.undo.UnexpectedUndoException;
import com.intellij.openapi.editor.Caret;
@@ -28,18 +29,17 @@ import com.intellij.openapi.fileEditor.impl.text.TextEditorState;
import com.intellij.openapi.fileTypes.*;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.NaturalComparator;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.openapi.vfs.*;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.UIBundle;
import com.intellij.util.*;
import com.intellij.util.concurrency.SynchronizedClearableLazy;
import com.intellij.util.containers.ContainerUtil;
@@ -50,6 +50,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.io.IOException;
import java.util.List;
import java.util.*;
@@ -253,15 +254,16 @@ public final class ScratchFileActions {
VirtualFile dir = context.ideView != null ? PsiUtilCore.getVirtualFile(ArrayUtil.getFirstElement(context.ideView.getDirectories())) : null;
RootType rootType = dir == null ? null : ScratchFileService.findRootType(dir);
String relativePath = rootType != ScratchRootType.getInstance() ? "" :
String relativePath = rootType != context.defaultRootType ? "" :
FileUtil.getRelativePath(ScratchFileService.getInstance().getRootPath(rootType), dir.getPath(), '/');
String fileName = (StringUtil.isEmpty(relativePath) ? "" : relativePath + "/") +
PathUtil.makeFileName(ObjectUtils.notNull(context.filePrefix, "scratch") +
(context.fileCounter != null ? context.fileCounter.create() : ""),
context.fileExtension);
VirtualFile file = ScratchRootType.getInstance().createScratchFile(
project, fileName, context.language, context.text, context.createOption);
VirtualFile file = createScratchFile(
project, fileName, context.language, context.text, context.createOption, context.defaultRootType
);
if (file == null) return null;
Navigatable navigatable = PsiNavigationSupport.getInstance().createNavigatable(project, file, context.caretOffset);
@@ -273,6 +275,36 @@ public final class ScratchFileActions {
return psiFile;
}
static @Nullable VirtualFile createScratchFile(@Nullable Project project,
@NotNull String fileName,
@Nullable Language language,
@NotNull String text,
@NotNull ScratchFileService.Option option,
@NotNull RootType rootType) {
try {
return
WriteCommandAction.writeCommandAction(project).withName(UIBundle.message("file.chooser.create.new.scratch.file.command.name"))
.withGlobalUndo().shouldRecordActionForActiveDocument(false)
.withUndoConfirmationPolicy(UndoConfirmationPolicy.REQUEST_CONFIRMATION).compute(() -> {
ScratchFileService fileService = ScratchFileService.getInstance();
VirtualFile file = fileService.findFile(rootType, fileName, option);
// save text should go before any other manipulations that load document,
// otherwise undo will be broken
VfsUtil.saveText(file, text);
if (language != null) {
Language fileLanguage = LanguageUtil.getFileLanguage(file);
fileService.getScratchesMapping().setMapping(file, fileLanguage == null || language == fileLanguage ? null : language);
}
return file;
});
}
catch (IOException e) {
Messages.showMessageDialog(UIBundle.message("create.new.file.could.not.create.file.error.message", fileName),
UIBundle.message("error.dialog.title"), Messages.getErrorIcon());
return null;
}
}
private static void checkLanguageAndTryToFixText(@NotNull Project project,
@NotNull ScratchFileCreationHelper.Context context,
@NotNull DataContext dataContext) {

View File

@@ -45,6 +45,7 @@ public abstract class ScratchFileCreationHelper {
public String filePrefix;
public Factory<Integer> fileCounter;
public String fileExtension;
public @NotNull RootType defaultRootType = ScratchRootType.getInstance();
public ScratchFileService.Option createOption = ScratchFileService.Option.create_new_always;
public IdeView ideView;

View File

@@ -3,19 +3,12 @@ package com.intellij.ide.scratch;
import com.intellij.lang.LangBundle;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageUtil;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.UIBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.IOException;
/**
* Root for files placed under the "Scratches" folder in the
@@ -53,27 +46,6 @@ public final class ScratchRootType extends RootType {
@Nullable Language language,
@NotNull String text,
@NotNull ScratchFileService.Option option) {
try {
return
WriteCommandAction.writeCommandAction(project).withName(UIBundle.message("file.chooser.create.new.scratch.file.command.name"))
.withGlobalUndo().shouldRecordActionForActiveDocument(false)
.withUndoConfirmationPolicy(UndoConfirmationPolicy.REQUEST_CONFIRMATION).compute(() -> {
ScratchFileService fileService = ScratchFileService.getInstance();
VirtualFile file = fileService.findFile(this, fileName, option);
// save text should go before any other manipulations that load document,
// otherwise undo will be broken
VfsUtil.saveText(file, text);
if (language != null) {
Language fileLanguage = LanguageUtil.getFileLanguage(file);
fileService.getScratchesMapping().setMapping(file, fileLanguage == null || language == fileLanguage ? null : language);
}
return file;
});
}
catch (IOException e) {
Messages.showMessageDialog(UIBundle.message("create.new.file.could.not.create.file.error.message", fileName),
UIBundle.message("error.dialog.title"), Messages.getErrorIcon());
return null;
}
return ScratchFileActions.createScratchFile(project, fileName, language, text, option, this);
}
}

View File

@@ -2095,6 +2095,8 @@ c:com.intellij.ide.actions.OpenFileAction
- sf:Companion:com.intellij.ide.actions.OpenFileAction$Companion
- <init>():V
- actionPerformed(com.intellij.openapi.actionSystem.AnActionEvent):V
- p:createFileChooserDescriptor(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile):com.intellij.openapi.fileChooser.FileChooserDescriptor
- p:doOpenFile(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile,kotlin.coroutines.Continuation):java.lang.Object
- getActionUpdateThread():com.intellij.openapi.actionSystem.ActionUpdateThread
- pf:getPathToSelect():com.intellij.openapi.vfs.VirtualFile
- sf:openFile(com.intellij.openapi.vfs.VirtualFile,com.intellij.openapi.project.Project):V

View File

@@ -18,6 +18,7 @@ import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.readAction
import com.intellij.openapi.components.service
import com.intellij.openapi.fileChooser.FileChooser
import com.intellij.openapi.fileChooser.FileChooserDescriptor
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.fileChooser.PathChooserDialog
import com.intellij.openapi.fileChooser.impl.FileChooserUtil
@@ -71,16 +72,12 @@ open class OpenFileAction : AnAction(), DumbAware, LightEditCompatible, ActionRe
override fun actionPerformed(e: AnActionEvent) {
val project = e.project
val showFiles = project != null || PlatformProjectOpenProcessor.getInstanceIfItExists() != null
val descriptor =
if (showFiles) ProjectOrFileChooserDescriptor()
else OpenProjectFileChooserDescriptor(true).withTitle(IdeBundle.message("title.open.project"))
var toSelect: VirtualFile? = null
val defaultProjectDirectory = GeneralLocalSettings.getInstance().defaultProjectDirectory
if (defaultProjectDirectory.isNotEmpty()) {
toSelect = VfsUtil.findFileByIoFile(File(defaultProjectDirectory), true)
}
descriptor.putUserData(PathChooserDialog.PREFER_LAST_OVER_EXPLICIT, toSelect == null && showFiles)
val descriptor = createFileChooserDescriptor(project, toSelect)
FileChooser.chooseFiles(descriptor, project, toSelect ?: pathToSelect) { files ->
for (file in files) {
if (!descriptor.isFileSelectable(file)) {
@@ -97,6 +94,19 @@ open class OpenFileAction : AnAction(), DumbAware, LightEditCompatible, ActionRe
}
}
protected open fun createFileChooserDescriptor(
project: Project?,
fileToSelect: VirtualFile?
): FileChooserDescriptor {
val showFiles = project != null || PlatformProjectOpenProcessor.getInstanceIfItExists() != null
val descriptor =
if (showFiles) ProjectOrFileChooserDescriptor()
else OpenProjectFileChooserDescriptor(true).withTitle(IdeBundle.message("title.open.project"))
descriptor.putUserData(PathChooserDialog.PREFER_LAST_OVER_EXPLICIT, fileToSelect == null && showFiles)
return descriptor
}
@Suppress("unused")
private class OnWelcomeScreen : OpenFileAction() {
override fun update(e: AnActionEvent) {
@@ -147,7 +157,7 @@ open class OpenFileAction : AnAction(), DumbAware, LightEditCompatible, ActionRe
override fun isChooseMultiple() = true
}
private suspend fun doOpenFile(project: Project?, virtualFile: VirtualFile) {
protected open suspend fun doOpenFile(project: Project?, virtualFile: VirtualFile) {
val file = virtualFile.toNioPath()
if (Files.isDirectory(file)) {
@Suppress("TestOnlyProblems")