Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
InSyncWithFoo authored Nov 20, 2024
2 parents 59cda9e + 1f64d40 commit fb8d381
Show file tree
Hide file tree
Showing 35 changed files with 605 additions and 382 deletions.
11 changes: 5 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ See [the documentation][0.1.0-a4-1] for more information.

Latest tool versions at the time of release:

* Ruff: [0.7.3][0.1.0-a4-2]
* Ruff: [0.7.4][0.1.0-a4-2]
* uv: [0.5.2][0.1.0-a4-3]
* Rye: [0.42.0][0.1.0-a4-4]

Expand Down Expand Up @@ -45,7 +45,7 @@ Latest tool versions at the time of release:
* Groups can be installed by clicking their corresponding line markers.

* Usages of [`uv.dev-dependencies`][0.1.0-a4-a-4] are now reported.
This field is deprecated as of [uv 0.2.27][0.1.0-a4-a-5];
This field is deprecated as of [uv 0.4.27][0.1.0-a4-a-5];
it should be replaced with `dependency-groups.dev`.

* Dependency specifier strings in `pyproject.toml` and `uv.toml`
Expand All @@ -59,9 +59,8 @@ Latest tool versions at the time of release:
* `dependency-groups.*`
* \[`tool.uv`] `dev-dependencies`

* Links to other Ruff options in documentation popups
are now resolved in-place, replacing the current popup content
with the new option's documentation.
* Links to Ruff options in documentation popups are now resolved in-place,
replacing the current popup content with the option's documentation.
Previously, such links would open the browser.


Expand Down Expand Up @@ -99,7 +98,7 @@ Latest tool versions at the time of release:


[0.1.0-a4-1]: https://insyncwithfoo.github.io/ryecharm/
[0.1.0-a4-2]: https://github.com/astral-sh/ruff/releases/tag/0.7.3
[0.1.0-a4-2]: https://github.com/astral-sh/ruff/releases/tag/0.7.4
[0.1.0-a4-3]: https://github.com/astral-sh/uv/releases/tag/0.5.2
[0.1.0-a4-4]: https://github.com/astral-sh/rye/releases/tag/0.42.0
[0.1.0-a4-a-1]: https://peps.python.org/pep-0735/
Expand Down
13 changes: 10 additions & 3 deletions docs/other-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,16 @@ with the corresponding interpreter as argument, if any.

!!! note

Due to technical limitations, this feature will cause a
"synchronous execution under read action" exception to be logged.
If you wish <em>not</em> to ignore this error, disable the feature.
On IntelliJ IDEA, flickering might happen during computation.
The cause of this problem is as of yet unknown.

As a workaround, enable the "Retrieve data for computing dependency version
inlay hints in read action" advanced setting in the <i>uv</i> subpanel.

This workaround has the disadvantage of delaying
the computation of other inlay hint providers,
causing a "synchronous execution under read action" exception.
Unless the delay proves to be a problem, you can safely ignore this warning.


### Dependency groups
Expand Down
9 changes: 9 additions & 0 deletions docs/ruff/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,12 @@ with the key's name as argument.

=== "`ruff.toml`"
![](../assets/ruff-documentation-demo-ruff-toml-setting-keys.png)


## Link resolving

Links to Ruff options (that is, those accepted by `ruff config`)
are resolved in-place.

Clicking on such a link will replace the current popup content
with that option's documentation.
7 changes: 3 additions & 4 deletions docs/uv/generating.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ as [the default (<i>Pure Python</i>) panel][1].
![](../assets/uv-new-project-panel.png)

!!! note
Due to technical limitations, it is currently
not possible to extend the standard panel.
The <i>uv</i> panel cannot be used with existing framework panels.
This is expected to change in PyCharm 2024.3.
Due to technical limitations, it is not possible to
extend the standard panel. In other words,
uv cannot be used to generate framework-based projects.


## Settings
Expand Down
38 changes: 38 additions & 0 deletions src/main/kotlin/insyncwithfoo/ryecharm/DocumentationURI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package insyncwithfoo.ryecharm

import com.intellij.platform.backend.documentation.DocumentationLinkHandler
import insyncwithfoo.ryecharm.ruff.documentation.RuffDocumentationLinkHandler
import java.net.URI
import java.net.URISyntaxException


/**
* A custom RyeCharm URI, as used by documentation popups,
* to be handled by [DocumentationLinkHandler]s.
*
* @property path The URI's path, but without the preceding slash.
*
* @see RuffDocumentationLinkHandler
*/
internal class DocumentationURI(val host: String, val path: String) {

override fun toString() =
"${RyeCharm.ID}://$host/$path"

companion object {
fun parse(text: String): DocumentationURI? {
val uri = try {
URI(text)
} catch (_: URISyntaxException) {
return null
}

if (uri.scheme != RyeCharm.ID) {
return null
}

return DocumentationURI(uri.host, uri.path.removePrefix("/"))
}
}

}
47 changes: 41 additions & 6 deletions src/main/kotlin/insyncwithfoo/ryecharm/NotificationActions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,34 @@ import com.intellij.notification.BrowseNotificationAction
import com.intellij.notification.Notification
import com.intellij.notification.NotificationAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.util.ui.EmptyClipboardOwner
import insyncwithfoo.ryecharm.configurations.PanelBasedConfigurable
import java.awt.Toolkit
import java.awt.datatransfer.StringSelection


internal fun Notification.addOpenPluginIssueTrackerAction(): Notification {
val issueTrackerActionText = message("notificationActions.openPluginIssueTracker")
return addAction(BrowseNotificationAction(issueTrackerActionText, RyeCharm.ISSUE_TRACKER))
}
internal fun Notification.addAction(text: String, action: () -> Unit) =
addAction(NotificationAction.createSimple(text, action))


internal fun Notification.addExpiringAction(text: String, action: () -> Unit) =
addAction(NotificationAction.createSimpleExpiring(text, action))


internal fun Notification.addAction(text: String, action: () -> Unit) =
addAction(NotificationAction.createSimple(text, action))
internal fun Notification.addOpenBrowserAction(text: String, link: String) =
addAction(BrowseNotificationAction(text, link))


internal fun Notification.addOpenPluginIssueTrackerAction() {
val text = message("notificationActions.openPluginIssueTracker")
val link = RyeCharm.ISSUE_TRACKER

addOpenBrowserAction(text, link)
}


internal fun Notification.addCopyTextAction(text: String, content: String) {
Expand Down Expand Up @@ -58,6 +66,33 @@ internal fun Notification.addOpenSettingsAction(
}


private class OpenFileAction(text: String, private val path: String) : NotificationAction(text) {

override fun actionPerformed(event: AnActionEvent, notification: Notification) {
val project = event.project ?: return cannotOpenFile()

val fileSystem = LocalFileSystem.getInstance()
val virtualFile = fileSystem.findFileByPath(path) ?: return cannotOpenFile(project)

project.fileEditorManager.openFileEditor(OpenFileDescriptor(project, virtualFile), true)
}

private fun cannotOpenFile(project: Project? = null) {
val title = message("notifications.cannotOpenFile.title")
val content = message("notifications.cannotOpenFile.body", path)

project.somethingIsWrong(title, content)
}

}


internal fun Notification.addOpenFileAction(text: String? = null, path: String) {
addAction(OpenFileAction(text ?: message("notificationActions.openFile"), path))
}



internal class OpenTemporaryFileAction(
text: String,
private val filename: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ internal abstract class AdaptivePanel<S>(val state: S, private val overrides: Ov
toggleOtherCellsBasedOn(checkbox)
}

@Suppress("DialogTitleCapitalization")
fun Panel.advancedSettingsGroup(init: Panel.() -> Unit) {
collapsibleGroup(message("configurations.groups.advanced"), init = init)
}

@Suppress("DialogTitleCapitalization")
fun <E> Panel.timeoutGroup(timeouts: TimeoutMap, entries: List<E>) where E : Commented, E : Keyed {
collapsibleGroup(message("configurations.timeouts.groupName"), indent = true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ private fun RuffPanel.makeComponent() = panel {
}
}

collapsibleGroup(message("configurations.ruff.groups.advanced")) {
advancedSettingsGroup {
row {
autoRestartServersInput { bindSelected(state::autoRestartServers) }
overrideCheckbox(state::autoRestartServers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal class UVConfigurations : DisplayableState(), HasTimeouts {
var packageManaging by property(true)
var packageManagingNonUVProject by property(false)

var retrieveDependenciesInReadAction by property(false)

override var timeouts by map<SettingName, MillisecondsOrNoLimit>()
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/insyncwithfoo/ryecharm/configurations/uv/Panels.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ private fun Row.packageManagingNonUVProjectInput(block: Cell<JBCheckBox>.() -> U
checkBox(message("configurations.uv.packageManagingNonUVProject.label")).apply(block)


private fun Row.retrieveDependenciesInReadActionInput(block: Cell<JBCheckBox>.() -> Unit) =
checkBox(message("configurations.uv.retrieveDependenciesInReadAction.label")).apply(block)


@Suppress("DialogTitleCapitalization")
private fun UVPanel.makeComponent() = panel {

Expand Down Expand Up @@ -72,6 +76,13 @@ private fun UVPanel.makeComponent() = panel {
}
}

advancedSettingsGroup {
row {
retrieveDependenciesInReadActionInput { bindSelected(state::retrieveDependenciesInReadAction) }
overrideCheckbox(state::retrieveDependenciesInReadAction)
}
}

timeoutGroup(state.timeouts, UVTimeouts.entries)

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package insyncwithfoo.ryecharm.ruff.documentation.noqa
package insyncwithfoo.ryecharm.ruff

import com.intellij.psi.PsiComment


internal typealias RuleCode = String


/**
* Due to some reason, IntelliJ IDEA's memory usage always peaks
* when analyzing this file with injected regex fragments.
Expand Down Expand Up @@ -41,9 +44,6 @@ private val fileNoqaComment = """(?x)
""".toRegexBypassingIDELanguageInjection()


internal typealias RuleCode = String


private data class RuleCodeFragment(
val content: RuleCode,
val range: IntRange
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/insyncwithfoo/ryecharm/ruff/RuffCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import com.intellij.openapi.util.Disposer
import insyncwithfoo.ryecharm.RootDisposable
import insyncwithfoo.ryecharm.RyeCharm
import insyncwithfoo.ryecharm.propertiesComponent
import insyncwithfoo.ryecharm.ruff.documentation.options.OptionDocumentation
import insyncwithfoo.ryecharm.ruff.documentation.options.OptionName
import insyncwithfoo.ryecharm.ruff.documentation.OptionDocumentation
import insyncwithfoo.ryecharm.ruff.documentation.OptionName
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlin.reflect.KMutableProperty1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package insyncwithfoo.ryecharm.ruff.documentation.options
package insyncwithfoo.ryecharm.ruff.documentation

import com.intellij.openapi.util.text.HtmlChunk
import insyncwithfoo.ryecharm.DocumentationURI
import insyncwithfoo.ryecharm.HTML
import insyncwithfoo.ryecharm.Markdown
import insyncwithfoo.ryecharm.popup
import insyncwithfoo.ryecharm.removeSurroundingTag
import insyncwithfoo.ryecharm.toHTML
import insyncwithfoo.ryecharm.wrappedInCodeBlock
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable


private const val FORCE_LINEBREAK = " "


internal const val RUFF_OPTION_URI_PREFIX = "ruff_option://"
internal typealias OptionName = String
internal typealias OptionDocumentation = HTML


private val sectionLinks: Regex
Expand All @@ -33,6 +37,25 @@ private fun String.anchorToTOMLPath() =
this.replace("_", ".")


@Serializable
internal data class OptionDeprecationInfo(
val since: String?,
val message: String?
)


@Serializable
internal data class OptionInfo(
val doc: String,
val default: String,
@SerialName("value_type")
val valueType: String,
val scope: String?,
val example: String,
val deprecated: OptionDeprecationInfo?
)


private fun OptionDeprecationInfo.formattedAsMarkdown(): Markdown {
val since = this.since?.let { "(since $it)$FORCE_LINEBREAK" }
val message = this.message
Expand All @@ -48,7 +71,7 @@ private fun Markdown.replaceSectionLinksWithSpecializedURIs() = this.replace(sec
val text = match.groups["text"]!!.value
val target = match.groups["target"]!!.value

val uri = "${RUFF_OPTION_URI_PREFIX}${target.anchorToTOMLPath()}"
val uri = DocumentationURI(RUFF_OPTION_HOST, target.anchorToTOMLPath())

"[$text]($uri)"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package insyncwithfoo.ryecharm.ruff.documentation

import com.intellij.platform.backend.documentation.DocumentationLinkHandler
import com.intellij.platform.backend.documentation.DocumentationTarget
import com.intellij.platform.backend.documentation.LinkResolveResult
import insyncwithfoo.ryecharm.DocumentationURI
import insyncwithfoo.ryecharm.ruff.documentation.targets.RuffDocumentationTarget
import insyncwithfoo.ryecharm.ruff.documentation.targets.RuffOptionDocumentationTarget


internal const val RUFF_OPTION_HOST = "ruff.option"


private typealias URL = String


private fun URL.toRuffOptionURI() =
DocumentationURI.parse(this)?.takeIf { it.host == RUFF_OPTION_HOST }


/**
* Show a new popup in-place when certain links
* in documentation popups are clicked.
*/
internal class RuffDocumentationLinkHandler : DocumentationLinkHandler {

override fun resolveLink(target: DocumentationTarget, url: String): LinkResolveResult? {
if (target !is RuffDocumentationTarget) {
return null
}

return resolveLink(target, url)?.let {
LinkResolveResult.resolvedTarget(it)
}
}

private fun resolveLink(target: RuffDocumentationTarget, url: URL): RuffDocumentationTarget? {
val newOption = url.toRuffOptionURI()?.path ?: return null

return RuffOptionDocumentationTarget(target.element, newOption)
}

}
Loading

0 comments on commit fb8d381

Please sign in to comment.