mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
[find in files] IJ-CR-168030 IJPL-186012 Introduce FrontendScopeChooserCombo for remote development
- Added APIs and services to allow the backend to expose available search scopes to the frontend (ScopeModelService) - created ScopesStateService that keeps map scopeId to ScopeDescriptor - added scopeId to FindModel for getting scope on the backend using ScopesStateService - refactored FindPopupScopeUIImpl for using FrontendScopeChooserCombo instead of ScopeChooserCombo in case when FindKey is enabled (cherry picked from commit 4d44d7aaadff23a0a3bb4262ea4d6f5a7dfe1f85) GitOrigin-RevId: 7a1174256fc723c3373c7924a4d028fd6e3d1285
This commit is contained in:
committed by
intellij-monorepo-bot
parent
88830c6ae4
commit
4648976c82
@@ -12,6 +12,7 @@ import com.intellij.find.replaceInProject.ReplaceInProjectManager
|
||||
import com.intellij.ide.ui.colors.rpcId
|
||||
import com.intellij.ide.ui.icons.rpcId
|
||||
import com.intellij.ide.ui.toSerializableTextChunk
|
||||
import com.intellij.ide.util.scopeChooser.ScopesStateService
|
||||
import com.intellij.ide.vfs.VirtualFileId
|
||||
import com.intellij.ide.vfs.rpcId
|
||||
import com.intellij.ide.vfs.virtualFile
|
||||
@@ -56,6 +57,12 @@ internal class FindRemoteApiImpl : FindRemoteApi {
|
||||
return@coroutineScope
|
||||
}
|
||||
val filesToScanInitially = filesToScanInitially.mapNotNull { it.virtualFile() }.toSet()
|
||||
// SearchScope is not serializable, so we will get it by id from the client
|
||||
findModel.customScopeId?.let { scopeId ->
|
||||
ScopesStateService.getInstance(project).getScopeById(scopeId)?.let {
|
||||
findModel.customScope = it
|
||||
}
|
||||
}
|
||||
//read action is necessary in case of the loading from a directory
|
||||
val scope = readAction { FindInProjectUtil.getGlobalSearchScope(project, findModel) }
|
||||
FindInProjectUtil.findUsages(findModel, project, progressIndicator, presentation, filesToScanInitially) { usageInfo ->
|
||||
|
||||
@@ -3,7 +3,7 @@ c:com.intellij.find.FindModel
|
||||
- java.lang.Cloneable
|
||||
- sf:Companion:com.intellij.find.FindModel$Companion
|
||||
- <init>():V
|
||||
- b:<init>(I,java.lang.String,java.lang.String,Z,Z,Z,com.intellij.find.FindModel$SearchContext,Z,Z,Z,Z,I,Z,Z,Z,Z,Z,Z,Z,java.lang.String,java.lang.String,Z,java.lang.String,java.lang.String,Z,Z,Z,Z,kotlinx.serialization.internal.SerializationConstructorMarker):V
|
||||
- b:<init>(I,java.lang.String,java.lang.String,Z,Z,Z,com.intellij.find.FindModel$SearchContext,Z,Z,Z,Z,I,Z,Z,Z,Z,Z,Z,Z,java.lang.String,java.lang.String,Z,java.lang.String,java.lang.String,java.lang.String,Z,Z,Z,Z,kotlinx.serialization.internal.SerializationConstructorMarker):V
|
||||
- f:addObserver(com.intellij.find.FindModel$FindModelObserver):V
|
||||
- clone():com.intellij.find.FindModel
|
||||
- f:compileRegExp():java.util.regex.Pattern
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.intellij.util.containers.ContainerUtil
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import org.intellij.lang.annotations.MagicConstant
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.UnknownNullability
|
||||
import java.util.regex.Pattern
|
||||
@@ -371,6 +372,15 @@ open class FindModel : UserDataHolder, Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
var customScopeId: String? = null
|
||||
set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
notifyObservers()
|
||||
}
|
||||
}
|
||||
|
||||
@get:JvmName("isCustomScope")
|
||||
@set:JvmName("setCustomScope")
|
||||
var isCustomScope: Boolean = false
|
||||
@@ -581,6 +591,7 @@ open class FindModel : UserDataHolder, Cloneable {
|
||||
moduleName = model.moduleName
|
||||
customScopeName = model.customScopeName
|
||||
customScope = model.customScope
|
||||
customScopeId = model.customScopeId
|
||||
isCustomScope = model.isCustomScope
|
||||
isFindAll = model.isFindAll
|
||||
searchContext = model.searchContext
|
||||
@@ -622,6 +633,7 @@ open class FindModel : UserDataHolder, Cloneable {
|
||||
if (isWholeWordsOnly != findModel.isWholeWordsOnly) return false
|
||||
if (isWithSubdirectories != findModel.isWithSubdirectories) return false
|
||||
if (if (customScope != null) (customScope != findModel.customScope) else findModel.customScope != null) return false
|
||||
if (if (customScopeId != null) (customScopeId != findModel.customScopeId) else findModel.customScopeId != null) return false
|
||||
if (if (customScopeName != null) (customScopeName != findModel.customScopeName) else findModel.customScopeName != null) return false
|
||||
if (if (directoryName != null) (directoryName != findModel.directoryName) else findModel.directoryName != null) return false
|
||||
if (if (fileFilter != null) (fileFilter != findModel.fileFilter) else findModel.fileFilter != null) return false
|
||||
@@ -663,6 +675,7 @@ open class FindModel : UserDataHolder, Cloneable {
|
||||
result = 31 * result + (fileFilter?.hashCode() ?: 0)
|
||||
result = 31 * result + (customScopeName?.hashCode() ?: 0)
|
||||
result = 31 * result + (customScope?.hashCode() ?: 0)
|
||||
result = 31 * result + (customScopeId?.hashCode() ?: 0)
|
||||
result = 31 * result + (if (isCustomScope) 1 else 0)
|
||||
result = 31 * result + (if (isMultiline) 1 else 0)
|
||||
result = 31 * result + (if (isPreserveCase) 1 else 0)
|
||||
|
||||
@@ -1628,6 +1628,7 @@ public final class FindPopupPanel extends JBPanel<FindPopupPanel> implements Fin
|
||||
model.setModuleName(null);
|
||||
model.setCustomScopeName(null);
|
||||
model.setCustomScope(null);
|
||||
model.setCustomScopeId(null);
|
||||
model.setCustomScope(false);
|
||||
myScopeUI.applyTo(model, mySelectedScope);
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.find.impl;
|
||||
|
||||
import com.intellij.find.FindBundle;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindSettings;
|
||||
import com.intellij.ide.util.scopeChooser.FrontendScopeChooserCombo;
|
||||
import com.intellij.ide.util.scopeChooser.ScopeChooserCombo;
|
||||
import com.intellij.ide.util.scopeChooser.ScopeDescriptor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -48,6 +49,7 @@ final class FindPopupScopeUIImpl implements FindPopupScopeUI {
|
||||
private ComboBox<String> myModuleComboBox;
|
||||
private FindPopupDirectoryChooser myDirectoryChooser;
|
||||
private ScopeChooserCombo myScopeCombo;
|
||||
private FrontendScopeChooserCombo newScopeCombo;
|
||||
|
||||
FindPopupScopeUIImpl(@NotNull FindPopupPanel panel) {
|
||||
myHelper = panel.getHelper();
|
||||
@@ -61,8 +63,8 @@ final class FindPopupScopeUIImpl implements FindPopupScopeUI {
|
||||
? ContainerUtil.ar(new Pair<>(PROJECT, new JLabel()),
|
||||
new Pair<>(MODULE, shrink(myModuleComboBox)),
|
||||
new Pair<>(DIRECTORY, myDirectoryChooser),
|
||||
new Pair<>(SCOPE, shrink(myScopeCombo)))
|
||||
: ContainerUtil.ar(new Pair<>(SCOPE, shrink(myScopeCombo)),
|
||||
new Pair<>(SCOPE, shrink(getScopeChooser())))
|
||||
: ContainerUtil.ar(new Pair<>(SCOPE, shrink(getScopeChooser())),
|
||||
new Pair<>(DIRECTORY, myDirectoryChooser));
|
||||
}
|
||||
|
||||
@@ -80,47 +82,85 @@ final class FindPopupScopeUIImpl implements FindPopupScopeUI {
|
||||
|
||||
myDirectoryChooser = new FindPopupDirectoryChooser(myFindPopupPanel);
|
||||
|
||||
myScopeCombo = new ScopeChooserCombo();
|
||||
Object selection = ObjectUtils.coalesce(myHelper.getModel().getCustomScopeName(), FindSettings.getInstance().getDefaultScopeName());
|
||||
myScopeCombo.init(myProject, true, true, selection, new Condition<>() {
|
||||
//final String projectFilesScopeName = PsiBundle.message("psi.search.scope.project");
|
||||
final String moduleFilesScopeName;
|
||||
initScopeCombo(restartSearchListener);
|
||||
}
|
||||
|
||||
{
|
||||
String moduleScopeName = IndexingBundle.message("search.scope.module", "");
|
||||
final int ind = moduleScopeName.indexOf(' ');
|
||||
moduleFilesScopeName = moduleScopeName.substring(0, ind + 1);
|
||||
}
|
||||
private JComponent getScopeChooser() {
|
||||
return FindKey.isEnabled() ? newScopeCombo : myScopeCombo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean value(ScopeDescriptor descriptor) {
|
||||
final String display = descriptor.getDisplayName();
|
||||
return /*!projectFilesScopeName.equals(display) &&*/ !display.startsWith(moduleFilesScopeName);
|
||||
}
|
||||
});
|
||||
myScopeCombo.setBrowseListener(new ScopeChooserCombo.BrowseListener() {
|
||||
private ComboBox<ScopeDescriptor> getScopeCombo() {
|
||||
return FindKey.isEnabled() ? newScopeCombo: myScopeCombo.getComboBox();
|
||||
}
|
||||
|
||||
private FindModel myModelSnapshot;
|
||||
private void initScopeCombo(ActionListener restartSearchListener) {
|
||||
if (FindKey.isEnabled()) {
|
||||
newScopeCombo = new FrontendScopeChooserCombo(myProject);
|
||||
Disposer.register(myFindPopupPanel.getDisposable(), newScopeCombo);
|
||||
}
|
||||
else {
|
||||
myScopeCombo = new ScopeChooserCombo();
|
||||
Object selection = ObjectUtils.coalesce(myHelper.getModel().getCustomScopeName(), FindSettings.getInstance().getDefaultScopeName());
|
||||
myScopeCombo.init(myProject, true, true, selection, new Condition<>() {
|
||||
//final String projectFilesScopeName = PsiBundle.message("psi.search.scope.project");
|
||||
final String moduleFilesScopeName;
|
||||
|
||||
@Override
|
||||
public void onBeforeBrowseStarted() {
|
||||
myModelSnapshot = myHelper.getModel();
|
||||
myFindPopupPanel.getCanClose().set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterBrowseFinished() {
|
||||
if (myModelSnapshot != null) {
|
||||
SearchScope scope = myScopeCombo.getSelectedScope();
|
||||
if (scope != null) {
|
||||
myModelSnapshot.setCustomScope(scope);
|
||||
}
|
||||
myFindPopupPanel.getCanClose().set(true);
|
||||
{
|
||||
String moduleScopeName = IndexingBundle.message("search.scope.module", "");
|
||||
final int ind = moduleScopeName.indexOf(' ');
|
||||
moduleFilesScopeName = moduleScopeName.substring(0, ind + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
myScopeCombo.getComboBox().addActionListener(restartSearchListener);
|
||||
Disposer.register(myFindPopupPanel.getDisposable(), myScopeCombo);
|
||||
|
||||
@Override
|
||||
public boolean value(ScopeDescriptor descriptor) {
|
||||
final String display = descriptor.getDisplayName();
|
||||
return /*!projectFilesScopeName.equals(display) &&*/ !display.startsWith(moduleFilesScopeName);
|
||||
}
|
||||
});
|
||||
myScopeCombo.setBrowseListener(new ScopeChooserCombo.BrowseListener() {
|
||||
|
||||
private FindModel myModelSnapshot;
|
||||
|
||||
@Override
|
||||
public void onBeforeBrowseStarted() {
|
||||
myModelSnapshot = myHelper.getModel();
|
||||
myFindPopupPanel.getCanClose().set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterBrowseFinished() {
|
||||
if (myModelSnapshot != null) {
|
||||
SearchScope scope = myScopeCombo.getSelectedScope();
|
||||
if (scope != null) {
|
||||
myModelSnapshot.setCustomScope(scope);
|
||||
}
|
||||
myFindPopupPanel.getCanClose().set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
Disposer.register(myFindPopupPanel.getDisposable(), myScopeCombo);
|
||||
}
|
||||
getScopeCombo().addActionListener(restartSearchListener);
|
||||
}
|
||||
|
||||
private String getSelectedScopeName() {
|
||||
if (FindKey.isEnabled()) {
|
||||
return newScopeCombo.getSelectedScopeName();
|
||||
}
|
||||
return myScopeCombo.getSelectedScopeName();
|
||||
}
|
||||
|
||||
private void applyScopeTo(FindModel findModel) {
|
||||
if (FindKey.isEnabled()) {
|
||||
findModel.setCustomScopeId(newScopeCombo.getSelectedScopeId());
|
||||
findModel.setCustomScopeName(newScopeCombo.getSelectedScopeName());
|
||||
}
|
||||
else {
|
||||
SearchScope selectedCustomScope = myScopeCombo.getSelectedScope();
|
||||
String customScopeName = selectedCustomScope == null ? null : selectedCustomScope.getDisplayName();
|
||||
findModel.setCustomScopeName(customScopeName);
|
||||
findModel.setCustomScope(selectedCustomScope);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,7 +170,7 @@ final class FindPopupScopeUIImpl implements FindPopupScopeUI {
|
||||
|
||||
@Override
|
||||
public void applyTo(@NotNull FindSettings findSettings, @NotNull FindPopupScopeUI.ScopeType selectedScope) {
|
||||
findSettings.setDefaultScopeName(myScopeCombo.getSelectedScopeName());
|
||||
findSettings.setDefaultScopeName(getSelectedScopeName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,10 +186,7 @@ final class FindPopupScopeUIImpl implements FindPopupScopeUI {
|
||||
findModel.setModuleName((String)myModuleComboBox.getSelectedItem());
|
||||
}
|
||||
else if (selectedScope == SCOPE) {
|
||||
SearchScope selectedCustomScope = myScopeCombo.getSelectedScope();
|
||||
String customScopeName = selectedCustomScope == null ? null : selectedCustomScope.getDisplayName();
|
||||
findModel.setCustomScopeName(customScopeName);
|
||||
findModel.setCustomScope(selectedCustomScope);
|
||||
applyScopeTo(findModel);
|
||||
findModel.setCustomScope(true);
|
||||
}
|
||||
}
|
||||
@@ -164,7 +201,7 @@ final class FindPopupScopeUIImpl implements FindPopupScopeUI {
|
||||
|
||||
@Override
|
||||
public boolean hideAllPopups() {
|
||||
final JComboBox[] candidates = { myModuleComboBox, myScopeCombo.getComboBox(), myDirectoryChooser.getComboBox() };
|
||||
final JComboBox[] candidates = { myModuleComboBox, getScopeCombo(), myDirectoryChooser.getComboBox() };
|
||||
for (JComboBox candidate : candidates) {
|
||||
if (candidate.isPopupVisible()) {
|
||||
candidate.hidePopup();
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.util.scopeChooser
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.ui.popup.ListSeparator
|
||||
import com.intellij.ui.AnimatedIcon
|
||||
import com.intellij.ui.components.fields.ExtendableTextComponent
|
||||
import com.intellij.ui.components.fields.ExtendableTextField
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.Dimension
|
||||
import java.util.*
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JTextField
|
||||
import javax.swing.plaf.basic.BasicComboBoxEditor
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Instances of `ScopeChooserCombo` **must be disposed** when the corresponding dialog or settings page is closed. Otherwise,
|
||||
* listeners registered in `init()` cause memory leak.<br></br><br></br>
|
||||
* Example: if `ScopeChooserCombo` is used in a
|
||||
* `DialogWrapper` subclass, call `Disposer.register(getDisposable(), myScopeChooserCombo)`, where
|
||||
* `getDisposable()` is `DialogWrapper`'s method.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
class FrontendScopeChooserCombo(project: Project) : ComboBox<ScopeDescriptor>(), Disposable {
|
||||
private val scopeService = ScopeModelService.getInstance(project)
|
||||
private val modelId = UUID.randomUUID().toString()
|
||||
private var loadingTextComponent: ExtendableTextField? = null
|
||||
private var scopesMap: Map<String, ScopeDescriptor> = emptyMap()
|
||||
private val scopeToSeparator: MutableMap<ScopeDescriptor, ListSeparator> = mutableMapOf()
|
||||
|
||||
private val browseExtension: ExtendableTextComponent.Extension = ExtendableTextComponent.Extension.create(AllIcons.General.ArrowDown, "", //TODO()
|
||||
{ TODO() })
|
||||
private val loadingExtension: ExtendableTextComponent.Extension = ExtendableTextComponent.Extension.create(AnimatedIcon.Default(), "", { TODO() })
|
||||
|
||||
|
||||
init {
|
||||
loadItemsAsync()
|
||||
setEditor(object : BasicComboBoxEditor() {
|
||||
override fun createEditorComponent(): JTextField {
|
||||
val ecbEditor = ExtendableTextField()
|
||||
ecbEditor.addExtension(browseExtension)
|
||||
ecbEditor.setBorder(null)
|
||||
loadingTextComponent = ecbEditor
|
||||
return ecbEditor
|
||||
}
|
||||
}.apply {
|
||||
renderer = createScopeDescriptorRenderer { descriptor -> scopeToSeparator[descriptor] }
|
||||
})
|
||||
}
|
||||
|
||||
private fun setLoading(loading: Boolean) {
|
||||
isEnabled = !loading
|
||||
|
||||
loadingTextComponent?.let { editor ->
|
||||
|
||||
editor.removeExtension(loadingExtension)
|
||||
editor.removeExtension(browseExtension)
|
||||
if (loading) { // Add loading indicator extension
|
||||
editor.addExtension(loadingExtension)
|
||||
}
|
||||
editor.addExtension(browseExtension)
|
||||
editor.repaint()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadItemsAsync() {
|
||||
setLoading(true)
|
||||
|
||||
scopeService.loadItemsAsync(modelId, onFinished = { scopeIdToScopeDescriptor ->
|
||||
scopesMap = scopeIdToScopeDescriptor ?: emptyMap()
|
||||
val items = scopesMap.values
|
||||
withContext(Dispatchers.EDT) {
|
||||
removeAllItems()
|
||||
items.filterOutSeparators().forEach { addItem(it) }
|
||||
setLoading(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun Collection<ScopeDescriptor>.filterOutSeparators(): List<ScopeDescriptor> {
|
||||
var lastItem: ScopeDescriptor? = null
|
||||
|
||||
return this.filter { item ->
|
||||
if (item is ScopeSeparator) {
|
||||
if (lastItem != null) {
|
||||
scopeToSeparator[lastItem] = ListSeparator(item.text)
|
||||
}
|
||||
}
|
||||
lastItem = item
|
||||
item !is ScopeSeparator
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPreferredSize(): Dimension? {
|
||||
if (isPreferredSizeSet) {
|
||||
return super.getPreferredSize()
|
||||
}
|
||||
val preferredSize = super.getPreferredSize()
|
||||
return Dimension(min(400, preferredSize.width), preferredSize.height)
|
||||
}
|
||||
|
||||
fun getSelectedScopeId(): String? {
|
||||
val scopeDescriptor = selectedItem as? ScopeDescriptor
|
||||
return scopesMap.entries.firstOrNull { it.value == scopeDescriptor }?.key
|
||||
}
|
||||
|
||||
@Nls
|
||||
fun getSelectedScopeName(): String? {
|
||||
return (selectedItem as? ScopeDescriptor)?.displayName
|
||||
}
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
scopeService.disposeModel(modelId) // ActionListener[] listeners = myBrowseButton.getActionListeners();
|
||||
// for (ActionListener listener : listeners) {
|
||||
// myBrowseButton.removeActionListener(listener);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ApiStatus.Internal
|
||||
data class SearchScopeUiInfo(val id: String, val name: String, val icon: Icon?, val isSeparator: Boolean)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.util.scopeChooser;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
@@ -107,7 +107,8 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo
|
||||
|
||||
ComboBox<ScopeDescriptor> combo = getComboBox();
|
||||
combo.setMinimumAndPreferredWidth(JBUIScale.scale(300));
|
||||
combo.setRenderer(ScopeSeparatorKt.createScopeDescriptorRenderer(() -> scopes));
|
||||
combo.setRenderer(
|
||||
ScopeSeparatorKt.createScopeDescriptorRenderer(scopes == null ? null : (descriptor) -> scopes.getSeparatorFor(descriptor)));
|
||||
combo.setSwingPopup(false);
|
||||
|
||||
if (selection != null) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.util.scopeChooser
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface ScopeModelService {
|
||||
|
||||
fun loadItemsAsync(modelId: String, onFinished: suspend (Map<String, ScopeDescriptor>?) -> Unit)
|
||||
|
||||
fun disposeModel(modelId: String)
|
||||
|
||||
fun getScopeById(scopeId: String): ScopeDescriptor?
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ScopeModelService {
|
||||
return project.service<ScopeModelService>()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.util.scopeChooser
|
||||
|
||||
import com.intellij.openapi.ui.popup.ListSeparator
|
||||
import com.intellij.ui.dsl.listCellRenderer.listCellRenderer
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.util.function.Supplier
|
||||
import javax.swing.ListCellRenderer
|
||||
|
||||
@ApiStatus.Internal
|
||||
@@ -15,15 +15,14 @@ class ScopeSeparator @ApiStatus.Internal constructor(@Nls val text: String) : Sc
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createScopeDescriptorRenderer(scopesSupplier: Supplier<ScopesSnapshot?>): ListCellRenderer<ScopeDescriptor?> {
|
||||
internal fun createScopeDescriptorRenderer(separatorProvider: ((ScopeDescriptor) -> ListSeparator?)?): ListCellRenderer<ScopeDescriptor?> {
|
||||
return listCellRenderer("") {
|
||||
value.icon?.let {
|
||||
icon(it)
|
||||
}
|
||||
text(value.displayName ?: "")
|
||||
|
||||
val scopes = scopesSupplier.get()
|
||||
scopes?.getSeparatorFor(value)?.let {
|
||||
separatorProvider?.invoke(value)?.let {
|
||||
separator {
|
||||
text = it.text
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.util.scopeChooser
|
||||
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Service(Service.Level.PROJECT)
|
||||
class ScopesStateService(val project: Project) {
|
||||
private var scopesState: ScopesState? = null
|
||||
|
||||
fun getScopeById(scopeId: String): SearchScope? {
|
||||
return scopesState?.scopeIdToDescriptor[scopeId]?.let { return it.scope }
|
||||
}
|
||||
|
||||
fun getOrCreateScopesState(): ScopesState {
|
||||
if (scopesState != null) return scopesState!!
|
||||
val state = ScopesState(project)
|
||||
scopesState = state
|
||||
return state
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ScopesStateService {
|
||||
return project.service<ScopesStateService>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
class ScopesState internal constructor(val project: Project) {
|
||||
var scopeIdToDescriptor: Map<String, ScopeDescriptor> = mapOf()
|
||||
|
||||
fun updateScopes(scopesStateMap: Map<String, ScopeDescriptor>) {
|
||||
scopeIdToDescriptor = scopesStateMap
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,10 @@ jvm_library(
|
||||
"@lib//:kotlinx-serialization-core",
|
||||
"@lib//:kotlinx-serialization-json",
|
||||
"//platform/lang-impl",
|
||||
"//platform/util:util-ui",
|
||||
"//platform/project/shared:project",
|
||||
"//platform/kernel/shared:kernel",
|
||||
"//platform/util/coroutines",
|
||||
],
|
||||
runtime_deps = [":scopes_resources"]
|
||||
)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
c:com.intellij.ide.util.scopeChooser.ScopeDescriptor
|
||||
- com.intellij.openapi.util.ColoredItem
|
||||
- <init>(com.intellij.psi.search.SearchScope):V
|
||||
- getColor():java.awt.Color
|
||||
- getDisplayName():java.lang.String
|
||||
- getIcon():javax.swing.Icon
|
||||
- getScope():com.intellij.psi.search.SearchScope
|
||||
- scopeEquals(com.intellij.psi.search.SearchScope):Z
|
||||
|
||||
@@ -12,7 +12,17 @@ jvm_library(
|
||||
module_name = "intellij.platform.scopes.backend",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["src/**/*.kt", "src/**/*.java"], allow_empty = True),
|
||||
deps = ["@lib//:kotlin-stdlib"],
|
||||
deps = [
|
||||
"@lib//:kotlin-stdlib",
|
||||
"//platform/scopes",
|
||||
"//platform/project/shared:project",
|
||||
"//platform/kernel/backend",
|
||||
"//platform/core-api:core",
|
||||
"//platform/util",
|
||||
"//platform/lang-impl",
|
||||
"//platform/core-ui",
|
||||
"//platform/util/coroutines",
|
||||
],
|
||||
runtime_deps = [
|
||||
":backend_resources",
|
||||
"//platform/backend",
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
</stringArguments>
|
||||
<arrayArguments>
|
||||
<arrayArg name="pluginClasspaths">
|
||||
<args>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</args>
|
||||
<args>
|
||||
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
|
||||
<arg>$MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/2.2.0-RC2-0.2/rhizomedb-compiler-plugin-2.2.0-RC2-0.2.jar</arg>
|
||||
<arg>$MAVEN_REPOSITORY$/com/jetbrains/fleet/rpc-compiler-plugin/2.2.0-RC2-0.1/rpc-compiler-plugin-2.2.0-RC2-0.1.jar</arg>
|
||||
</args>
|
||||
</arrayArg>
|
||||
<arrayArg name="pluginOptions" />
|
||||
</arrayArguments>
|
||||
@@ -32,5 +36,13 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.backend" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.platform.scopes" />
|
||||
<orderEntry type="module" module-name="intellij.platform.project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.kernel.backend" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -2,5 +2,9 @@
|
||||
<dependencies>
|
||||
<module name="intellij.platform.backend"/>
|
||||
<module name="intellij.platform.scopes"/>
|
||||
<module name="intellij.platform.kernel.backend"/>
|
||||
</dependencies>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<platform.rpc.backend.remoteApiProvider implementation="com.intellij.platform.scopes.backend.ScopesStateApiProvider"/>/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
95
platform/scopes/backend/src/ScopeModelApiImpl.kt
Normal file
95
platform/scopes/backend/src/ScopeModelApiImpl.kt
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.scopes.backend
|
||||
|
||||
import com.intellij.ide.util.scopeChooser.*
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.platform.project.ProjectId
|
||||
import com.intellij.platform.project.findProjectOrNull
|
||||
import com.intellij.platform.rpc.backend.RemoteApiProvider
|
||||
import com.intellij.platform.scopes.ScopeModelApi
|
||||
import com.intellij.platform.scopes.SearchScopeData
|
||||
import com.intellij.platform.scopes.SearchScopesInfo
|
||||
import fleet.rpc.remoteApiDescriptor
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
private val LOG = logger<ScopesModelApiImpl>()
|
||||
|
||||
internal class ScopesModelApiImpl : ScopeModelApi {
|
||||
private val modelIdToModel = mutableMapOf<String, AbstractScopeModel>()
|
||||
private val modelIdToScopes = mutableMapOf<String, ScopesState>()
|
||||
|
||||
override suspend fun createModelAndSubscribe(projectId: ProjectId, modelId: String): Flow<SearchScopesInfo>? {
|
||||
val project = projectId.findProjectOrNull()
|
||||
if (project == null) {
|
||||
LOG.warn("Project not found for projectId: $projectId")
|
||||
return null
|
||||
}
|
||||
val model = project.getService(ScopeService::class.java)
|
||||
.createModel(EnumSet.of(
|
||||
ScopeOption.FROM_SELECTION,
|
||||
ScopeOption.USAGE_VIEW,
|
||||
ScopeOption.LIBRARIES,
|
||||
ScopeOption.SEARCH_RESULTS
|
||||
))
|
||||
modelIdToModel[modelId] = model
|
||||
val flow = subscribeToModelUpdates(model, modelId, project)
|
||||
model.refreshScopes(null)
|
||||
return flow
|
||||
}
|
||||
|
||||
|
||||
private fun subscribeToModelUpdates(model: AbstractScopeModel, modelId: String, project: Project): Flow<SearchScopesInfo> {
|
||||
val flow = channelFlow {
|
||||
model.addScopeModelListener(object : ScopeModelListener {
|
||||
override fun scopesUpdated(scopes: ScopesSnapshot) {
|
||||
val scopesStateMap = mutableMapOf<String, ScopeDescriptor>()
|
||||
val scopesData = scopes.scopeDescriptors.mapNotNull { descriptor ->
|
||||
val scopeId = UUID.randomUUID().toString()
|
||||
val scopeData = SearchScopeData.from(descriptor, scopeId) ?: return@mapNotNull null
|
||||
scopesStateMap[scopeData.scopeId] = descriptor
|
||||
scopeData
|
||||
}
|
||||
var scopeState = modelIdToScopes[modelId]
|
||||
if (scopeState == null) {
|
||||
scopeState = ScopesStateService.getInstance(project).getOrCreateScopesState(project)
|
||||
modelIdToScopes[modelId] = scopeState
|
||||
}
|
||||
scopeState.updateScopes(scopesStateMap)
|
||||
|
||||
val searchScopesInfo = SearchScopesInfo(scopesData, null, null, null)
|
||||
launch {
|
||||
send(searchScopesInfo)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
awaitClose {}
|
||||
}
|
||||
return flow
|
||||
}
|
||||
|
||||
override suspend fun updateModel(modelId: String, scopesInfo: SearchScopesInfo): Flow<SearchScopesInfo> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun dispose(modelId: String) {
|
||||
modelIdToScopes.remove(modelId)
|
||||
val model = modelIdToModel[modelId] ?: return
|
||||
Disposer.dispose(model)
|
||||
modelIdToModel.remove(modelId)
|
||||
}
|
||||
}
|
||||
|
||||
private class ScopesStateApiProvider : RemoteApiProvider {
|
||||
override fun RemoteApiProvider.Sink.remoteApis() {
|
||||
remoteApi(remoteApiDescriptor<ScopeModelApi>()) {
|
||||
ScopesModelApiImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,11 @@
|
||||
</stringArguments>
|
||||
<arrayArguments>
|
||||
<arrayArg name="pluginClasspaths">
|
||||
<args>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</args>
|
||||
<args>
|
||||
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
|
||||
<arg>$MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/2.2.0-RC2-0.2/rhizomedb-compiler-plugin-2.2.0-RC2-0.2.jar</arg>
|
||||
<arg>$MAVEN_REPOSITORY$/com/jetbrains/fleet/rpc-compiler-plugin/2.2.0-RC2-0.1/rpc-compiler-plugin-2.2.0-RC2-0.1.jar</arg>
|
||||
</args>
|
||||
</arrayArg>
|
||||
<arrayArg name="pluginOptions" />
|
||||
</arrayArguments>
|
||||
@@ -39,5 +43,9 @@
|
||||
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
|
||||
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.kernel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,2 +1,8 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<!--suppress PluginXmlRegistrationCheck -->
|
||||
<projectService serviceInterface="com.intellij.ide.util.scopeChooser.ScopeModelService"
|
||||
serviceImplementation="com.intellij.platform.scopes.service.ScopeModelServiceImpl"/>
|
||||
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.scopes
|
||||
|
||||
import com.intellij.platform.project.ProjectId
|
||||
import com.intellij.platform.rpc.RemoteApiProviderService
|
||||
import fleet.rpc.RemoteApi
|
||||
import fleet.rpc.Rpc
|
||||
import fleet.rpc.remoteApiDescriptor
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Rpc
|
||||
interface ScopeModelApi : RemoteApi<Unit> {
|
||||
suspend fun createModelAndSubscribe(projectId: ProjectId, modelId: String): Flow<SearchScopesInfo>?
|
||||
|
||||
suspend fun updateModel(modelId: String, scopesInfo: SearchScopesInfo): Flow<SearchScopesInfo>
|
||||
suspend fun dispose(modelId: String)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
suspend fun getInstance(): ScopeModelApi {
|
||||
return RemoteApiProviderService.resolve(remoteApiDescriptor<ScopeModelApi>())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,22 @@
|
||||
package com.intellij.platform.scopes
|
||||
|
||||
import com.intellij.ide.ui.colors.ColorId
|
||||
import com.intellij.ide.ui.colors.color
|
||||
import com.intellij.ide.ui.colors.rpcId
|
||||
import com.intellij.ide.ui.icons.IconId
|
||||
import com.intellij.ide.ui.icons.icon
|
||||
import com.intellij.ide.ui.icons.rpcId
|
||||
import com.intellij.ide.util.scopeChooser.ScopeDescriptor
|
||||
import com.intellij.ide.util.scopeChooser.ScopeSeparator
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.Color
|
||||
import java.util.*
|
||||
import javax.swing.Icon
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Serializable
|
||||
@@ -31,4 +39,22 @@ class SearchScopeData(val scopeId: String, val name: @Nls String, val iconId: Ic
|
||||
class SearchScopesInfo(val scopes: List<SearchScopeData>,
|
||||
val selectedScopeId: String?,
|
||||
val projectScopeId: String?,
|
||||
val everywhereScopeId: String?)
|
||||
val everywhereScopeId: String?) {
|
||||
fun getScopeDescriptors(): Map<String, ScopeDescriptor> {
|
||||
return scopes.associate {
|
||||
val descriptor =
|
||||
if (it.isSeparator) ScopeSeparator(it.name)
|
||||
else object : ScopeDescriptor(object : GlobalSearchScope() {
|
||||
override fun contains(file: VirtualFile): Boolean = throw IllegalStateException("Should not be called")
|
||||
override fun isSearchInModuleContent(aModule: Module): Boolean = throw IllegalStateException("Should not be called")
|
||||
override fun isSearchInLibraries(): Boolean = throw IllegalStateException("Should not be called")
|
||||
}) {
|
||||
override fun getColor(): Color? = it.colorId?.color()
|
||||
override fun getDisplayName(): @Nls(capitalization = Nls.Capitalization.Sentence) String = it.name
|
||||
override fun getIcon(): Icon? = it.iconId?.icon()
|
||||
}
|
||||
|
||||
it.scopeId to descriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.scopes.service
|
||||
|
||||
import com.intellij.ide.util.scopeChooser.ScopeDescriptor
|
||||
import com.intellij.ide.util.scopeChooser.ScopeModelService
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.project.projectId
|
||||
import com.intellij.platform.scopes.ScopeModelApi
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import fleet.rpc.client.RpcTimeoutException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
|
||||
private val LOG = logger<ScopeModelServiceImpl>()
|
||||
|
||||
@ApiStatus.Internal
|
||||
private class ScopeModelServiceImpl(private val project: Project, private val coroutineScope: CoroutineScope) : ScopeModelService {
|
||||
private var scopeIdToDescriptor = mapOf<String, ScopeDescriptor>()
|
||||
|
||||
override fun loadItemsAsync(modelId: String, onFinished: suspend (Map<String, ScopeDescriptor>?) -> Unit) {
|
||||
coroutineScope.childScope("ScopesStateService.subscribeToScopeStates").launch {
|
||||
try {
|
||||
val scopesFlow = ScopeModelApi.getInstance().createModelAndSubscribe(project.projectId(), modelId)
|
||||
if (scopesFlow == null) {
|
||||
LOG.warn("Failed to subscribe to model updates for modelId: $modelId")
|
||||
onFinished(null)
|
||||
return@launch
|
||||
}
|
||||
scopesFlow.collect { scopesInfo ->
|
||||
val fetchedScopes = scopesInfo.getScopeDescriptors()
|
||||
onFinished(fetchedScopes)
|
||||
scopeIdToDescriptor = fetchedScopes
|
||||
}
|
||||
}
|
||||
catch (e: RpcTimeoutException) {
|
||||
LOG.warn("Failed to subscribe to model updates for modelId: $modelId", e)
|
||||
onFinished(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun disposeModel(modelId: String) {
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
ScopeModelApi.getInstance().dispose(modelId)
|
||||
}
|
||||
catch (e: RpcTimeoutException) {
|
||||
LOG.warn("Failed to dispose model for modelId: $modelId", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScopeById(scopeId: String): ScopeDescriptor? {
|
||||
scopeIdToDescriptor.get(scopeId)?.let { return it }
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -2,39 +2,17 @@
|
||||
package com.intellij.platform.searchEverywhere.frontend.tabs.target
|
||||
|
||||
import com.intellij.ide.actions.searcheverywhere.ScopeChooserAction
|
||||
import com.intellij.ide.ui.colors.color
|
||||
import com.intellij.ide.ui.icons.icon
|
||||
import com.intellij.ide.util.scopeChooser.ScopeDescriptor
|
||||
import com.intellij.ide.util.scopeChooser.ScopeSeparator
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.scopes.SearchScopesInfo
|
||||
import com.intellij.platform.searchEverywhere.frontend.AutoToggleAction
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.Color
|
||||
import javax.swing.Icon
|
||||
|
||||
@ApiStatus.Internal
|
||||
class SeScopeChooserActionProvider(val scopesInfo: SearchScopesInfo, private val onSelectedScopeChanged: (String?) -> Unit) {
|
||||
private val descriptors: Map<String, ScopeDescriptor> = scopesInfo.scopes.associate {
|
||||
val descriptor =
|
||||
if (it.isSeparator) ScopeSeparator(it.name)
|
||||
else object : ScopeDescriptor(object : GlobalSearchScope() {
|
||||
override fun contains(file: VirtualFile): Boolean = throw IllegalStateException("Should not be called")
|
||||
override fun isSearchInModuleContent(aModule: Module): Boolean = throw IllegalStateException("Should not be called")
|
||||
override fun isSearchInLibraries(): Boolean = throw IllegalStateException("Should not be called")
|
||||
}) {
|
||||
override fun getColor(): Color? = it.colorId?.color()
|
||||
override fun getDisplayName(): @Nls(capitalization = Nls.Capitalization.Sentence) String = it.name
|
||||
override fun getIcon(): Icon? = it.iconId?.icon()
|
||||
}
|
||||
|
||||
it.scopeId to descriptor
|
||||
}
|
||||
private val descriptors: Map<String, ScopeDescriptor> = scopesInfo.getScopeDescriptors()
|
||||
|
||||
var selectedScopeId: String? = scopesInfo.selectedScopeId
|
||||
private set(value) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<idea-plugin package="com.intellij.platform.searchEverywhere">
|
||||
<dependencies>
|
||||
<module name="intellij.platform.scopes"/>
|
||||
</dependencies>
|
||||
<extensionPoints>
|
||||
<extensionPoint name="searchEverywhere.itemsProviderFactory"
|
||||
interface="com.intellij.platform.searchEverywhere.SeItemsProviderFactory"
|
||||
|
||||
Reference in New Issue
Block a user