[core] IDEA-347144 Use lightweight language chooser instead of modal window for configurable template languages

GitOrigin-RevId: 42e603961664c9f9cb4da0fa8f43ba971dca9382
This commit is contained in:
Nikita Katkov
2024-02-22 19:18:28 +01:00
committed by intellij-monorepo-bot
parent 73d86e093e
commit 291245bb1a
7 changed files with 132 additions and 21 deletions

View File

@@ -36,6 +36,9 @@ template.data.language.configurable=Template Data Languages
template.data.language.configurable.tree.table.title=Language
template.data.language.override.warning.text=There are template data languages specified for the subdirectories. Override them?
template.data.language.override.warning.title=Override Subdirectory Template Data Languages
template.data.language.chooser.intention.text=Choose Template Data Language
template.data.language.chooser.intention.title=Choose template data language
template.data.language.chooser.intention.family.name=Template language settings
quickfix.change.template.data.language.text=Change {0} template data language to\u2026
incorrect.name=Incorrect name

View File

@@ -6,13 +6,14 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiManager;
import com.intellij.ui.popup.list.ListPopupImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.templateLanguages.TemplateDataLanguageMappings.getTemplateableLanguages;
public final class ChangeTemplateDataLanguageAction extends AnAction {
@Override
@@ -30,9 +31,7 @@ public final class ChangeTemplateDataLanguageAction extends AnAction {
if (project == null) return;
final FileViewProvider provider = PsiManager.getInstance(project).findViewProvider(virtualFile);
if (provider instanceof ConfigurableTemplateLanguageFileViewProvider) {
final TemplateLanguageFileViewProvider viewProvider = (TemplateLanguageFileViewProvider)provider;
if (provider instanceof ConfigurableTemplateLanguageFileViewProvider viewProvider) {
e.getPresentation().setText(LangBundle.messagePointer("quickfix.change.template.data.language.text", viewProvider.getTemplateDataLanguage().getDisplayName()));
e.getPresentation().setEnabledAndVisible(true);
}
@@ -47,17 +46,10 @@ public final class ChangeTemplateDataLanguageAction extends AnAction {
@Override
public void actionPerformed(final @NotNull AnActionEvent e) {
Project project = e.getData(CommonDataKeys.PROJECT);
if (project == null) return;
VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
if (project == null || virtualFile == null) return;
editSettings(project, e.getData(CommonDataKeys.VIRTUAL_FILE));
}
public static void editSettings(@NotNull Project project, final @Nullable VirtualFile virtualFile) {
final TemplateDataLanguageConfigurable configurable = new TemplateDataLanguageConfigurable(project);
ShowSettingsUtil.getInstance().editConfigurable(project, configurable, () -> {
if (virtualFile != null) {
configurable.selectFile(virtualFile);
}
});
new ListPopupImpl(project, new TemplateDataLanguageChooserPopupStep(getTemplateableLanguages(), virtualFile, project))
.showInBestPositionFor(e.getDataContext());
}
}

View File

@@ -0,0 +1,35 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.templateLanguages
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.lang.LangBundle
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.psi.templateLanguages.TemplateDataLanguageMappings.getTemplateableLanguages
import com.intellij.ui.popup.list.ListPopupImpl
internal class ChooseTemplateDataLanguageIntention : IntentionAction {
override fun startInWriteAction(): Boolean {
return false
}
override fun getFamilyName(): String {
return LangBundle.message("template.data.language.chooser.intention.family.name")
}
override fun getText(): String {
return LangBundle.message("template.data.language.chooser.intention.title")
}
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean {
return file?.viewProvider is TemplateLanguageFileViewProvider
}
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
if (file == null || editor == null || file.viewProvider !is ConfigurableTemplateLanguageFileViewProvider) return
ListPopupImpl(project, TemplateDataLanguageChooserPopupStep(getTemplateableLanguages(), file.virtualFile, project))
.showInBestPositionFor(editor)
}
}

View File

@@ -0,0 +1,59 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.templateLanguages
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.lang.LangBundle
import com.intellij.lang.Language
import com.intellij.openapi.application.readAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.fileTypes.FileTypes
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.popup.PopupStep
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.swing.Icon
internal class TemplateDataLanguageChooserPopupStep(languages: List<Language>,
private val currentTemplateFile: VirtualFile,
private val project: Project)
: BaseListPopupStep<Language>(LangBundle.message("template.data.language.chooser.intention.text"), languages) {
override fun isSpeedSearchEnabled(): Boolean {
return true
}
override fun getIconFor(value: Language): Icon? {
val associatedFileType = value.associatedFileType ?: FileTypes.UNKNOWN
return associatedFileType.icon
}
override fun getTextFor(value: Language): String {
return value.displayName
}
override fun onChosen(selectedValue: Language?, finalChoice: Boolean): PopupStep<*>? {
if (selectedValue != null) {
TemplateLanguageCoroutineScopeProvider.getInstance(project).scope.launch {
TemplateDataLanguageMappings.getInstance(project).setMapping(currentTemplateFile, selectedValue)
val psiFile = readAction {
PsiManager.getInstance(project).findFile(currentTemplateFile)
} ?: return@launch
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
}
}
return FINAL_CHOICE
}
}
@Service(Service.Level.PROJECT)
private class TemplateLanguageCoroutineScopeProvider(val scope: CoroutineScope) {
companion object {
fun getInstance(project: Project): TemplateLanguageCoroutineScopeProvider {
return project.service<TemplateLanguageCoroutineScopeProvider>()
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Allows choosing the preferred template data language for the current file.
</body>
</html>

View File

@@ -911,6 +911,14 @@
<bundleName>messages.LangBundle</bundleName>
<categoryKey>intention.category.other</categoryKey>
</intentionAction>
<intentionAction>
<!--Must be available both in data and template language-->
<language/>
<className>com.intellij.psi.templateLanguages.ChooseTemplateDataLanguageIntention</className>
<bundleName>messages.LangBundle</bundleName>
<categoryKey>template.data.language.chooser.intention.title</categoryKey>
<skipBeforeAfter>true</skipBeforeAfter>
</intentionAction>
<intentionMenuContributor implementation="com.intellij.codeInsight.daemon.impl.DoNotShowInspectionIntentionMenuContributor"/>
<intentionMenuContributor implementation="com.intellij.codeInsight.daemon.impl.GutterIntentionMenuContributor"/>

View File

@@ -6,13 +6,14 @@ import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.lang.LangBundle;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.templateLanguages.ChangeTemplateDataLanguageAction;
import com.intellij.psi.templateLanguages.ConfigurableTemplateLanguageFileViewProvider;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.psi.templateLanguages.TemplateDataLanguageConfigurable;
import com.intellij.psi.templateLanguages.TemplateLanguageUtil;
import com.intellij.xml.XmlBundle;
import com.intellij.xml.analysis.XmlAnalysisBundle;
@@ -46,8 +47,7 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase {
if (file != TemplateLanguageUtil.getTemplateFile(file)) return null;
FileViewProvider vp = file.getViewProvider();
if (vp instanceof ConfigurableTemplateLanguageFileViewProvider) {
final TemplateLanguageFileViewProvider viewProvider = (TemplateLanguageFileViewProvider)vp;
if (vp instanceof ConfigurableTemplateLanguageFileViewProvider viewProvider) {
final String text =
LangBundle.message("quickfix.change.template.data.language.text", viewProvider.getTemplateDataLanguage().getDisplayName());
@@ -67,7 +67,7 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase {
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
ChangeTemplateDataLanguageAction.editSettings(project, file.getVirtualFile());
editSettings(project, file.getVirtualFile());
}
@Override
@@ -78,4 +78,13 @@ public class HtmlUnknownTagInspection extends HtmlUnknownTagInspectionBase {
}
return null;
}
private static void editSettings(@NotNull Project project, final @Nullable VirtualFile virtualFile) {
final TemplateDataLanguageConfigurable configurable = new TemplateDataLanguageConfigurable(project);
ShowSettingsUtil.getInstance().editConfigurable(project, configurable, () -> {
if (virtualFile != null) {
configurable.selectFile(virtualFile);
}
});
}
}