mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[python] python-lsp-core
GitOrigin-RevId: e07d457d959a1b589861180c1be06b995218aa2c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d9f3979bbe
commit
4f08c28e9d
@@ -71,6 +71,13 @@
|
||||
displayNameKey="settings.python.group.title"
|
||||
descriptionKey="settings.python.group.description"/>
|
||||
|
||||
<groupConfigurable id="python.tools.group.settings"
|
||||
parentId="python.group.settings"
|
||||
weight="72"
|
||||
bundle="messages.PyBundle"
|
||||
displayNameKey="settings.python.tools.group.title"
|
||||
descriptionKey="settings.python.tools.group.description"/>
|
||||
|
||||
<projectConfigurable groupId="python.group.settings"
|
||||
id="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"
|
||||
bundle="messages.PyBundle"
|
||||
|
||||
+6
-1
@@ -5,6 +5,7 @@ import com.intellij.openapi.options.Configurable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.pycharm.community.ide.impl.settings.PythonMainConfigurable
|
||||
import com.intellij.pycharm.community.ide.impl.settings.PythonToolsConfigurable
|
||||
|
||||
class PyCharmProjectConfigurableStartupActivity : ProjectActivity {
|
||||
|
||||
@@ -37,11 +38,15 @@ class PyCharmProjectConfigurableStartupActivity : ProjectActivity {
|
||||
ep.groupWeight = 40
|
||||
}
|
||||
"com.jetbrains.python.configuration.PyIntegratedToolsModulesConfigurable" -> {
|
||||
ep.groupId = PythonMainConfigurable.ID
|
||||
ep.groupId = PythonToolsConfigurable.ID
|
||||
ep.key = "configurable.PyIntegratedToolsModulesConfigurable.pycharm.display.name"
|
||||
ep.bundle="messages.PyBundle"
|
||||
ep.groupWeight = 20
|
||||
}
|
||||
"com.jetbrains.python.black.configuration.BlackFormatterConfigurable" -> {
|
||||
ep.groupId = PythonToolsConfigurable.ID
|
||||
ep.groupWeight = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// 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.pycharm.community.ide.impl.settings
|
||||
|
||||
internal object PythonToolsConfigurable {
|
||||
const val ID: String = "python.tools.group.settings"
|
||||
}
|
||||
@@ -225,6 +225,10 @@ settings.memory.indicator.row.comment=Displays current memory usage in the statu
|
||||
settings.python.group.title=Python
|
||||
settings.python.group.description=<html><body>Configure key Python development settings to customize your coding, debugging, data visualization, and documentation workflows.
|
||||
|
||||
# Python Tools Settings Group
|
||||
settings.python.tools.group.title=Tools
|
||||
settings.python.tools.group.description=<html><body>Configure external Python tool settings.
|
||||
|
||||
runcfg.autodetect.display_name=Autodetect
|
||||
runcfg.autodetect.parameters.group.name=Python test
|
||||
|
||||
@@ -1517,7 +1521,7 @@ black.executable.not.found=Unable to auto-detect Black executable in {0, choice,
|
||||
black.execution.mode.package=Package
|
||||
black.execution.mode.binary=Binary
|
||||
black.execution.mode.tooltip.text=Use either executable or package installed on the project interpreter
|
||||
black.cli.args.text.field.label=Settings:
|
||||
black.cli.args.text.field.label=Arguments:
|
||||
black.cli.args.comment=List command line arguments separated by whitespace. <a href='https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#command-line-options'>Learn more</a><br>\
|
||||
Settings from pyproject.toml are applied automatically for Black v21.4.0 and higher.
|
||||
black.cli.args.validation.notification=No value passed for parameter {0}
|
||||
@@ -1530,6 +1534,30 @@ black.format.fragments.supported.info=Fragment formatting is supported for Black
|
||||
black.format.fragment.fallback.title=Format Fragment
|
||||
black.getting.black.version=Getting Black version\u2026
|
||||
|
||||
# Python LSP Tools
|
||||
configurable.name=Python Language Services
|
||||
not.installed.error=Package is not installed on the current interpreter
|
||||
remote.sdk.error=Package mode is not available for remote SDKs. Please use Binary mode.
|
||||
install.button.label=Install
|
||||
use.section.label=Use:
|
||||
enable.checkbox.label=Enable
|
||||
enable.on.save.label=On save
|
||||
advanced.settings.panel.title=Advanced settings
|
||||
execution.mode.label=Execution mode:
|
||||
executable.label=Executable:
|
||||
executable.auto.detected.path=Auto-detected: {0}
|
||||
executable.not.found=Unable to auto-detect executable in {0, choice, 0#%PATH%|1#$PATH}
|
||||
execution.mode.package=Interpreter
|
||||
execution.mode.binary=Path
|
||||
cli.args.text.field.label=Arguments:
|
||||
cli.args.comment=List command line arguments separated by whitespace.
|
||||
cli.args.validation.notification=No value passed for parameter {0}
|
||||
sdk.not.configured.error=No project SDK configured for the project {0}
|
||||
sdk.not.configured.error.title=SDK not configured
|
||||
remote.sdk.exception.text=Invocation in Package mode is not allowed on remote SDKs
|
||||
getting.version=Getting version\u2026
|
||||
select.path.to.executable=Select Path to Executable
|
||||
|
||||
inlay.parameters.python.show.class.constructor.call.parameter.names=Class constructor calls
|
||||
inlay.parameters.python.show.hints.for.non-literal.arguments=Non-literal arguments
|
||||
inlay.parameters.python.hints.blacklist.explanation=\
|
||||
@@ -1710,6 +1738,14 @@ pycharm.free.mode.upgrade.button=Purchase Subscription
|
||||
python.packaging.sync.packages=Syncing project dependencies
|
||||
python.sdk.read.only=Python SDK ''{0}'' is read only and operation cannot be performed.
|
||||
read.only.python.sdk.system.wide.read.only.message=Modify packages of System Python is forbidden. To modify use another interpreter.
|
||||
button.install=Install {0}
|
||||
label.features=Features:
|
||||
checkbox.inspections=Inspections
|
||||
checkbox.completions=Completions
|
||||
checkbox.inlay.hints=Inlay hints
|
||||
label.features=Features:
|
||||
label.package.not.installed.in.current.interpreter={0} package is not installed in the current interpreter
|
||||
modal.progress.title.installing=Installing {0}\u2026
|
||||
tracecontext.detecting.poetry.executable=Detecting Poetry Executable
|
||||
tracecontext.detecting.pip.executable=Detecting Pip Executable
|
||||
tracecontext.detecting.uv.executable=Detecting uv Executable
|
||||
|
||||
@@ -551,6 +551,8 @@
|
||||
description="Enables incremental reparse for statement lists"/>
|
||||
<registryKey key="python.strict.type.narrow" defaultValue="false"
|
||||
description="Allows narrowing types exhaustively to Never"/>
|
||||
<registryKey key="python.lsp.tools.enabled" defaultValue="true" restartRequired="true"
|
||||
description="Enables lsp tools"/>
|
||||
|
||||
<virtualFileCustomDataProvider implementation="com.jetbrains.python.formatter.PyCodeStyleSettingsProvider"/>
|
||||
</extensions>
|
||||
|
||||
@@ -3,8 +3,11 @@ package com.jetbrains.python.sdk
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.util.system.OS
|
||||
import com.jetbrains.python.psi.PyFile
|
||||
import com.jetbrains.python.sdk.legacy.PythonSdkUtil
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
||||
val Editor.pythonSdk: Sdk?
|
||||
get() {
|
||||
@@ -14,3 +17,15 @@ val Editor.pythonSdk: Sdk?
|
||||
val pyPsiFile = viewProvider.allFiles.firstOrNull { it is PyFile } ?: return null
|
||||
return PythonSdkUtil.findPythonSdk(pyPsiFile)
|
||||
}
|
||||
|
||||
fun Sdk.getExecutablePath(name: String): Path? = homePath?.let {
|
||||
val base = Path(it)
|
||||
if (OS.CURRENT == OS.Windows) {
|
||||
val candidates = listOf("exe", "bat", "cmd", "com").map { ext -> Path(it + "." + ext) }
|
||||
val found = candidates.firstNotNullOfOrNull { candidate -> PythonSdkUtil.getExecutablePath(candidate, name) }
|
||||
found ?: PythonSdkUtil.getExecutablePath(base, name)
|
||||
}
|
||||
else {
|
||||
PythonSdkUtil.getExecutablePath(base, name)
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import com.jetbrains.python.pathValidation.ValidationRequest
|
||||
import com.jetbrains.python.pathValidation.validateExecutableFile
|
||||
import com.jetbrains.python.pyi.PyiFileType
|
||||
import org.jetbrains.annotations.SystemDependent
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
class BlackFormatterUtil {
|
||||
companion object {
|
||||
@@ -38,12 +38,12 @@ class BlackFormatterUtil {
|
||||
return packageManager?.hasInstalledPackageSnapshot(PACKAGE_NAME) ?: false
|
||||
}
|
||||
|
||||
fun detectBlackExecutable(): File? {
|
||||
fun detectBlackExecutable(): Path? {
|
||||
val name = when {
|
||||
SystemInfo.isWindows -> "black.exe"
|
||||
else -> "black"
|
||||
}
|
||||
return PathEnvironmentVariableUtil.findInPath(name)
|
||||
return PathEnvironmentVariableUtil.findInPath(name)?.toPath()
|
||||
}
|
||||
|
||||
fun isBlackExecutableDetected(): Boolean = detectBlackExecutable() != null
|
||||
|
||||
@@ -32,16 +32,18 @@ import com.jetbrains.python.black.BlackFormatterUtil
|
||||
import com.jetbrains.python.black.BlackFormatterVersionService
|
||||
import com.jetbrains.python.black.BlackFormatterVersionService.Companion.UNKNOWN_VERSION
|
||||
import com.jetbrains.python.black.configuration.BlackFormatterConfiguration.BlackFormatterOption.Companion.toCliOptionFlags
|
||||
import com.jetbrains.python.externaltools.configuration.createPythonSdkComboBox
|
||||
import com.jetbrains.python.packaging.management.ui.PythonPackageManagerUI
|
||||
import com.jetbrains.python.packaging.management.ui.installPackageBackground
|
||||
import com.jetbrains.python.sdk.pythonSdk
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import javax.swing.JButton
|
||||
import javax.swing.JCheckBox
|
||||
import javax.swing.JLabel
|
||||
import kotlin.io.path.absolutePathString
|
||||
|
||||
const val CONFIGURABLE_ID: String = "com.jetbrains.python.black.configuration.BlackFormatterConfigurable"
|
||||
|
||||
@@ -49,7 +51,7 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
private var storedState = BlackFormatterConfiguration.getBlackConfiguration(project)
|
||||
|
||||
private var isBlackFormatterPackageInstalled: Boolean = false
|
||||
private var detectedBlackExecutable: File? = null
|
||||
private var detectedBlackExecutable: Path? = null
|
||||
private var selectedSdk: Sdk? = null
|
||||
private var isLocalSdk = false
|
||||
|
||||
@@ -71,7 +73,8 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
.withTitle(@Suppress("DialogTitleCapitalization") PyBundle.message("black.select.path.to.executable")))
|
||||
}
|
||||
|
||||
private val sdkSelectionComboBox = createPythonSdkComboBox(project.modules.mapNotNull { it.pythonSdk }, null)
|
||||
// TODO: initial should be project default
|
||||
private val sdkSelectionComboBox = createPythonSdkComboBox(project, null)
|
||||
|
||||
private val cliArgumentsTextField = BlackTextFieldWithAutoCompletion(project, object :
|
||||
TextFieldWithAutoCompletionListProvider<BlackFormatterConfiguration.CliOptionFlag>(
|
||||
@@ -91,8 +94,7 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
.applyToComponent { renderer = executionModeComboBoxRenderer }
|
||||
.gap(RightGap.SMALL)
|
||||
.component
|
||||
icon(AllIcons.General.ContextHelp)
|
||||
.applyToComponent { toolTipText = PyBundle.message("black.execution.mode.tooltip.text") }
|
||||
contextHelp(PyBundle.message("black.execution.mode.tooltip.text"))
|
||||
layout(RowLayout.LABEL_ALIGNED)
|
||||
}
|
||||
row {
|
||||
@@ -179,7 +181,6 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
executionModeComboBox.addActionListener { updateUiState() }
|
||||
|
||||
sdkSelectionComboBox.addActionListener {
|
||||
selectedSdk = sdkSelectionComboBox.item
|
||||
updateSdkInfo()
|
||||
updateUiState()
|
||||
}
|
||||
@@ -189,8 +190,7 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
enableOnReformatCheckBox.isSelected = storedState.enabledOnReformat
|
||||
enableOnSaveCheckBox.isSelected = storedState.enabledOnSave
|
||||
executionModeComboBox.item = storedState.executionMode
|
||||
cliArgumentsTextField.text = storedState.cmdArguments ?: ""
|
||||
sdkSelectionComboBox.item = selectedSdk
|
||||
cliArgumentsTextField.text = storedState.cmdArguments
|
||||
|
||||
blackExecutablePathField.emptyText.text = getBlackExecPathPlaceholderMessage()
|
||||
storedState.pathToExecutable?.let {
|
||||
@@ -264,18 +264,18 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
sdkName = selectedSdk?.name
|
||||
|
||||
pathToExecutable = if (blackExecutableValidationInfo() == null) {
|
||||
blackExecutablePathField.text.nullize() ?: BlackFormatterUtil.detectBlackExecutable()?.absolutePath
|
||||
blackExecutablePathField.text.nullize() ?: BlackFormatterUtil.detectBlackExecutable()?.absolutePathString()
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
private fun blackExecutableValidationInfo(): ValidationInfo? =
|
||||
BlackFormatterUtil.validateBlackExecutable(
|
||||
blackExecutablePathField.text.nullize() ?: BlackFormatterUtil.detectBlackExecutable()?.absolutePath)
|
||||
blackExecutablePathField.text.nullize() ?: BlackFormatterUtil.detectBlackExecutable()?.absolutePathString())
|
||||
|
||||
private fun getBlackExecPathPlaceholderMessage(): String {
|
||||
return BlackFormatterUtil.detectBlackExecutable()?.let {
|
||||
PyBundle.message("black.executable.auto.detected.path", it.absolutePath)
|
||||
PyBundle.message("black.executable.auto.detected.path", it.absolutePathString())
|
||||
} ?: PyBundle.message("black.executable.not.found", if (SystemInfo.isWindows) 0 else 1)
|
||||
}
|
||||
|
||||
@@ -309,9 +309,10 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
}
|
||||
|
||||
|
||||
class BlackTextFieldWithAutoCompletion(project: Project,
|
||||
provider: TextFieldWithAutoCompletionListProvider<BlackFormatterConfiguration.CliOptionFlag>)
|
||||
: TextFieldWithCompletion(project, provider, "", true, true, true) {
|
||||
class BlackTextFieldWithAutoCompletion(
|
||||
project: Project,
|
||||
provider: TextFieldWithAutoCompletionListProvider<BlackFormatterConfiguration.CliOptionFlag>,
|
||||
) : TextFieldWithCompletion(project, provider, "", true, true, true) {
|
||||
override fun createEditor(): EditorEx {
|
||||
val editor = super.createEditor()
|
||||
val disableSpellChecking = SpellCheckingEditorCustomizationProvider.getInstance().disabledCustomization
|
||||
@@ -353,7 +354,7 @@ class BlackFormatterConfigurable(val project: Project) : BoundConfigurable(PyBun
|
||||
|
||||
private fun getCommentForBlack(configuration: BlackFormatterConfiguration): ActionOnSaveComment {
|
||||
val version = runWithModalProgressBlocking(project, PyBundle.message("black.getting.black.version")) {
|
||||
BlackFormatterVersionService.getVersion (project)
|
||||
BlackFormatterVersionService.getVersion(project)
|
||||
}
|
||||
|
||||
return when (configuration.executionMode) {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.black.configuration
|
||||
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.ui.CollectionComboBoxModel
|
||||
import com.intellij.ui.ComboboxSpeedSearch
|
||||
import com.jetbrains.python.sdk.PySdkListCellRenderer
|
||||
|
||||
internal fun createPythonSdkComboBox(sdks: List<Sdk>, initialSelection: Sdk?): ComboBox<Sdk> {
|
||||
val comboBox = ComboBox<Sdk>()
|
||||
comboBox.model = CollectionComboBoxModel(sdks.toMutableList(), initialSelection)
|
||||
comboBox.renderer = PySdkListCellRenderer()
|
||||
comboBox.addActionListener { comboBox.updateTooltip() }
|
||||
ComboboxSpeedSearch.installOn(comboBox)
|
||||
comboBox.updateTooltip()
|
||||
return comboBox
|
||||
}
|
||||
|
||||
private fun ComboBox<*>.updateTooltip() {
|
||||
val item: Any? = getSelectedItem()
|
||||
val sdkHomePath = if (item is Sdk) item.homePath else null
|
||||
setToolTipText(if (sdkHomePath != null) FileUtil.toSystemDependentName(sdkHomePath) else null)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.externaltools
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
enum class PyLspTool(@NlsSafe val presentableName: String, val packageName: String) {
|
||||
BASEDPYRIGHT("Basedpyright", "basedpyright"),
|
||||
PYREFLY("Pyrefly", "pyrefly"),
|
||||
PYRIGHT("Pyright", "pyright"),
|
||||
RUFF("Ruff", "ruff"),
|
||||
TY("ty", "ty"),
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.externaltools.configuration
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
||||
abstract class PyLspToolConfiguration<State : PyLspToolConfiguration<State>> : PersistentStateComponent<State> {
|
||||
var enabled: Boolean = false
|
||||
var inspections: Boolean = true
|
||||
open var completions: Boolean? = null
|
||||
|
||||
/**
|
||||
* `null` means: not supported
|
||||
*/
|
||||
open var inlayHints: Boolean? = null
|
||||
var executableDiscoveryMode: ExecutableDiscoveryMode = ExecutableDiscoveryMode.INTERPRETER
|
||||
var pathToExecutable: String? = null
|
||||
val executablePath: Path? = pathToExecutable?.let { Path(it) }
|
||||
var sdkName: String = DEFAULT_ENVIRONMENT
|
||||
|
||||
final override fun getState(): State = this as State
|
||||
|
||||
override fun loadState(state: State): Unit = XmlSerializerUtil.copyBean(state, this as State)
|
||||
}
|
||||
|
||||
/**
|
||||
* Executable discovery mode for LSP tools.
|
||||
*/
|
||||
enum class ExecutableDiscoveryMode {
|
||||
INTERPRETER,
|
||||
PATH,
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.externaltools.configuration
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.modules
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.ui.CollectionComboBoxModel
|
||||
import com.intellij.ui.ComboboxSpeedSearch
|
||||
import com.jetbrains.python.sdk.PySdkListCellRenderer
|
||||
import com.jetbrains.python.sdk.PythonSdkUtil
|
||||
import com.jetbrains.python.sdk.pythonSdk
|
||||
|
||||
const val DEFAULT_ENVIRONMENT: String = "Project Default"
|
||||
|
||||
fun Project.sdkByNameDefaultAware(name: String): Sdk? =
|
||||
if (name == DEFAULT_ENVIRONMENT) pythonSdk else PythonSdkUtil.findSdkByKey(name)
|
||||
|
||||
fun createPythonSdkComboBox(project: Project, initialSelection: Any?): ComboBox<Any> {
|
||||
val sdks = buildList {
|
||||
project.pythonSdk?.let { add(it) }
|
||||
project.modules.mapNotNullTo(this) { it.pythonSdk }
|
||||
}.distinct()
|
||||
return ComboBox<Any>().apply {
|
||||
model = CollectionComboBoxModel(
|
||||
// we use a simple string here, ideally we should introduce some special class for this
|
||||
(listOf(DEFAULT_ENVIRONMENT) + sdks).toMutableList(),
|
||||
initialSelection,
|
||||
)
|
||||
renderer = PySdkListCellRenderer()
|
||||
addActionListener { updateTooltip() }
|
||||
ComboboxSpeedSearch.installOn(this)
|
||||
updateTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ComboBox<*>.updateTooltip() {
|
||||
val item = selectedItem
|
||||
val sdkHomePath = if (item is Sdk) item.homePath else null
|
||||
setToolTipText(if (sdkHomePath != null) FileUtil.toSystemDependentName(sdkHomePath) else null)
|
||||
}
|
||||
Reference in New Issue
Block a user