mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
IJPL-156789 Rework the Language Services widget to show icons of running services
GitOrigin-RevId: 4250a3b436f9dc1c43f805b1f626f349d21bf32a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
629421de59
commit
73145926fc
@@ -3710,8 +3710,8 @@ e:com.intellij.platform.lang.lsWidget.LanguageServicePopupSection
|
||||
- f:createWidgetAction():com.intellij.openapi.actionSystem.AnAction
|
||||
- p:createWidgetInlineActions():java.util.List
|
||||
- pa:createWidgetMainAction():com.intellij.openapi.actionSystem.AnAction
|
||||
- getStatusBarText():java.lang.String
|
||||
- getStatusBarTooltip():java.lang.String
|
||||
- a:getStatusBarIcon():javax.swing.Icon
|
||||
- a:getStatusBarTooltip():java.lang.String
|
||||
- a:getWidgetActionLocation():com.intellij.platform.lang.lsWidget.LanguageServicePopupSection
|
||||
- isError():Z
|
||||
*a:com.intellij.platform.lang.lsWidget.LanguageServiceWidgetItemsProvider
|
||||
|
||||
@@ -620,6 +620,7 @@ show.more=Show more
|
||||
show.less=Show less
|
||||
|
||||
language.services.widget=Language Services
|
||||
language.services.widget.tooltip.running.on.current.file.list=<html>Language Services running on current file:<ul>{0}</ul></html>
|
||||
language.services.widget.section.running.on.current.file=Running on Current File
|
||||
language.services.widget.section.running.on.other.files=Running on Other Files
|
||||
language.services.widget.no.services=No Services
|
||||
|
||||
@@ -10,38 +10,26 @@ import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||
import com.intellij.openapi.options.Configurable
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.util.NlsActions
|
||||
import com.intellij.openapi.util.NlsContexts
|
||||
import com.intellij.platform.lang.lsWidget.internal.LanguageServiceWidgetActionsService
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.LayeredIcon.Companion.layeredIcon
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import javax.swing.Icon
|
||||
|
||||
@ApiStatus.Experimental
|
||||
abstract class LanguageServiceWidgetItem {
|
||||
/**
|
||||
* The default label for the status bar widget is the generic one: "Language Services".
|
||||
*
|
||||
* But if
|
||||
* - this [LanguageServiceWidgetItem] is the only one in the [LanguageServicePopupSection.ForCurrentFile] popup section
|
||||
* (only for this item the [widgetActionLocation] value is [LanguageServicePopupSection.ForCurrentFile])
|
||||
* - and the [statusBarText] value is not `null`
|
||||
*
|
||||
* then the service-specific text will be shown in the status bar.
|
||||
*
|
||||
* If this item is not the only one in the [LanguageServicePopupSection.ForCurrentFile] popup section,
|
||||
* or it is not in the [LanguageServicePopupSection.ForCurrentFile] popup section at all,
|
||||
* then the [statusBarText] value is ignored.
|
||||
* An icon to show in the status bar (size: 16x16).
|
||||
* The Platform will colorize the icon to be status-bar-friendly in the current UI theme.
|
||||
* The Platform will add an error mark to the icon if [isError] is `true`.
|
||||
*/
|
||||
open val statusBarText: @NlsContexts.StatusBarText String? = null
|
||||
abstract val statusBarIcon: Icon
|
||||
|
||||
/**
|
||||
* A tooltip for the status bar widget label.
|
||||
* Used only if this item appears to be the only one in the [LanguageServicePopupSection.ForCurrentFile] popup section.
|
||||
* Otherwise, it's ignored.
|
||||
* @see statusBarText
|
||||
* A tooltip for the status bar widget icon.
|
||||
*/
|
||||
open val statusBarTooltip: @NlsContexts.Tooltip String? = null
|
||||
abstract val statusBarTooltip: @Nls String
|
||||
|
||||
/**
|
||||
* If `true` then the Platform will add the error mark to the icon in the status bar,
|
||||
@@ -55,7 +43,8 @@ abstract class LanguageServiceWidgetItem {
|
||||
val mainAction = createWidgetMainAction()
|
||||
if (isError) {
|
||||
mainAction.templatePresentation.icon = mainAction.templatePresentation.icon?.let {
|
||||
layeredIcon(arrayOf(it, AllIcons.Nodes.ErrorMark)) }
|
||||
layeredIcon(arrayOf(it, AllIcons.Nodes.ErrorMark))
|
||||
}
|
||||
}
|
||||
|
||||
if (ExperimentalUI.isNewUI()) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.platform.lang.lsWidget.impl
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.ui.LafManager
|
||||
import com.intellij.lang.LangBundle
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
@@ -9,7 +10,6 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.ui.popup.ListPopup
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.wm.StatusBarWidget
|
||||
import com.intellij.openapi.wm.impl.status.EditorBasedStatusBarPopup
|
||||
@@ -17,8 +17,12 @@ import com.intellij.platform.lang.lsWidget.LanguageServicePopupSection.ForCurren
|
||||
import com.intellij.platform.lang.lsWidget.LanguageServiceWidgetItem
|
||||
import com.intellij.platform.lang.lsWidget.LanguageServiceWidgetItemsProvider
|
||||
import com.intellij.ui.LayeredIcon
|
||||
import com.intellij.ui.RowIcon
|
||||
import com.intellij.util.IconUtil
|
||||
import com.intellij.util.messages.MessageBusConnection
|
||||
import com.intellij.util.ui.EmptyIcon
|
||||
import com.intellij.util.ui.JBDimension
|
||||
import com.intellij.util.ui.JBUI
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import javax.swing.Icon
|
||||
|
||||
@@ -42,20 +46,55 @@ internal class LanguageServiceWidget(project: Project, scope: CoroutineScope) :
|
||||
override fun getWidgetState(file: VirtualFile?): WidgetState {
|
||||
if (!Registry.`is`("language.service.status.bar.widget")) return WidgetState.HIDDEN
|
||||
|
||||
val allItems = LanguageServiceWidgetItemsProvider.EP_NAME.extensionList.flatMap { it.createWidgetItems(project, file) }
|
||||
// If there are more than maxIconsInStatusBar services, then not all icons show up in the status bar.
|
||||
// Sorting helps to make sure that icons with an error marker go first.
|
||||
val allItems = LanguageServiceWidgetItemsProvider.EP_NAME.extensionList
|
||||
.flatMap { it.createWidgetItems(project, file) }
|
||||
.sortedByDescending { it.isError }
|
||||
cachedWidgetItems = allItems
|
||||
if (allItems.isEmpty()) return WidgetState.HIDDEN
|
||||
|
||||
val fileSpecificItems = file?.let { allItems.filter { it.widgetActionLocation == ForCurrentFile } } ?: emptyList()
|
||||
val singleFileSpecificItem = fileSpecificItems.singleOrNull()
|
||||
val text = singleFileSpecificItem?.statusBarText ?: LangBundle.message("language.services.widget")
|
||||
val maxToolbarTextLength = 30
|
||||
val shortenedText = StringUtil.shortenTextWithEllipsis(text, maxToolbarTextLength, 0, true)
|
||||
val tooltip = singleFileSpecificItem?.statusBarTooltip ?: if (text.length > maxToolbarTextLength) text else null
|
||||
val isError = fileSpecificItems.any { it.isError } // or maybe `allItems.any { it.isError }`?
|
||||
|
||||
return WidgetState(tooltip, shortenedText, true).apply {
|
||||
icon = if (isError) Icons.errorIcon else Icons.normalIcon
|
||||
val widgetIcon = fileSpecificItems.takeIf { it.isNotEmpty() }?.let { createStatusBarIcon(it) }
|
||||
?: AllIcons.Json.Object
|
||||
|
||||
val widgetText = when {
|
||||
fileSpecificItems.size > maxIconsInStatusBar -> "+${fileSpecificItems.size - maxIconsInStatusBar + 1}"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
@Suppress("DialogTitleCapitalization")
|
||||
val tooltip = when {
|
||||
fileSpecificItems.isEmpty() -> LangBundle.message("language.services.widget")
|
||||
else -> LangBundle.message("language.services.widget.tooltip.running.on.current.file.list",
|
||||
fileSpecificItems.joinToString(separator = "") { "<li>${it.statusBarTooltip}</li>" })
|
||||
}
|
||||
|
||||
return WidgetState(tooltip, widgetText, true).apply {
|
||||
icon = widgetIcon
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStatusBarIcon(widgetItems: List<LanguageServiceWidgetItem>): Icon {
|
||||
// either up to 3 icons or 2 icons and "+N" text
|
||||
val items = if (widgetItems.size <= maxIconsInStatusBar) widgetItems else widgetItems.subList(0, maxIconsInStatusBar - 1)
|
||||
if (items.size == 1) return getStatusBarFriendlyIcon(items[0])
|
||||
|
||||
val separatorIcon = EmptyIcon.create(3, 16)
|
||||
val icons = items.flatMap { listOf(getStatusBarFriendlyIcon(it), separatorIcon) }.dropLast(1)
|
||||
return RowIcon(*icons.toTypedArray())
|
||||
}
|
||||
|
||||
private fun getStatusBarFriendlyIcon(item: LanguageServiceWidgetItem): Icon {
|
||||
val statusBarFriendlyColor = when {
|
||||
LafManager.getInstance().currentUIThemeLookAndFeel.isDark -> JBUI.CurrentTheme.StatusBar.Widget.FOREGROUND
|
||||
else -> JBUI.CurrentTheme.StatusBar.Widget.FOREGROUND.brighter() // without `brighter()` icons are too noisy in light themes
|
||||
}
|
||||
val statusBarFriendlyIcon = IconUtil.colorize(item.statusBarIcon, statusBarFriendlyColor)
|
||||
return when {
|
||||
item.isError -> LayeredIcon.layeredIcon(arrayOf(statusBarFriendlyIcon, AllIcons.Nodes.ErrorMark))
|
||||
else -> statusBarFriendlyIcon
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +140,7 @@ internal class LanguageServiceWidget(project: Project, scope: CoroutineScope) :
|
||||
override fun actionPerformed(e: AnActionEvent) {}
|
||||
}
|
||||
|
||||
private object Icons {
|
||||
val normalIcon: Icon = AllIcons.Json.Object
|
||||
val errorIcon: Icon = LayeredIcon.layeredIcon(arrayOf(AllIcons.Json.Object, AllIcons.Nodes.ErrorMark))
|
||||
private companion object {
|
||||
const val maxIconsInStatusBar = 3
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user