Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mattco98/SerenityOS-DSL-Plugin
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.1.0
Choose a base ref
...
head repository: mattco98/SerenityOS-DSL-Plugin
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
  • 19 commits
  • 75 files changed
  • 2 contributors

Commits on Jan 21, 2024

  1. Changelog update - v1.1.0

    actions-user authored and mattco98 committed Jan 21, 2024
    Copy the full SHA
    ccd4005 View commit details
  2. Add GML support

    mattco98 committed Jan 21, 2024
    Copy the full SHA
    7258d05 View commit details
  3. Copy the full SHA
    97d5354 View commit details

Commits on Jan 26, 2024

  1. Copy the full SHA
    97d065c View commit details

Commits on Jan 27, 2024

  1. Copy the full SHA
    50d9971 View commit details
  2. GML: Add a formatter

    mattco98 committed Jan 27, 2024
    Copy the full SHA
    c767d1b View commit details
  3. Copy the full SHA
    0b11e13 View commit details
  4. Copy the full SHA
    1a79ad4 View commit details
  5. Remove unused mixin class

    mattco98 committed Jan 27, 2024
    Copy the full SHA
    24a7586 View commit details
  6. Copy the full SHA
    d90755d View commit details
  7. Copy the full SHA
    24ec597 View commit details
  8. Copy the full SHA
    7d021cd View commit details
  9. GML: Lint property values

    mattco98 committed Jan 27, 2024
    Copy the full SHA
    5ed9ef9 View commit details
  10. Copy the full SHA
    9d861b5 View commit details
  11. Copy the full SHA
    17c2f52 View commit details
  12. GML: Remove special-cased component names

    Turns out these were in the property-definitions.json file already
    mattco98 committed Jan 27, 2024
    Copy the full SHA
    d8bcf09 View commit details
  13. GML: Add IDENTIFIER as a valid value

    See the comment in the .bnf for an explanation
    mattco98 committed Jan 27, 2024
    Copy the full SHA
    ffc85e2 View commit details
  14. Update the changelog

    mattco98 committed Jan 27, 2024
    Copy the full SHA
    224fd2f View commit details
  15. GML: "Component" -> "Widget"

    mattco98 committed Jan 27, 2024
    Copy the full SHA
    3db561f View commit details
Showing with 1,865 additions and 165 deletions.
  1. +11 −0 CHANGELOG.md
  2. +12 −16 build.gradle.kts
  3. +2 −2 gradle.properties
  4. +4 −1 gradle/libs.versions.toml
  5. +1 −1 gradle/wrapper/gradle-wrapper.properties
  6. +29 −28 src/main/kotlin/me/mattco/serenityos/common/DSLAnnotator.kt
  7. +1 −1 src/main/kotlin/me/mattco/serenityos/common/DSLColorSettingsPage.kt
  8. +2 −2 src/main/kotlin/me/mattco/serenityos/{idl/IDLCommenter.kt → common/DSLCommenter.kt}
  9. +43 −0 src/main/kotlin/me/mattco/serenityos/common/DSLTreeChangeListener.kt
  10. +16 −0 src/main/kotlin/me/mattco/serenityos/common/completions.kt
  11. +83 −0 src/main/kotlin/me/mattco/serenityos/common/formatting/SpacingBuilder.kt
  12. +12 −0 src/main/kotlin/me/mattco/serenityos/common/projectUtils.kt
  13. +9 −5 src/main/kotlin/me/mattco/serenityos/common/psiUtils.kt
  14. +25 −0 src/main/kotlin/me/mattco/serenityos/gml/GML.kt
  15. +45 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLBlockFoldingBuilder.kt
  16. +122 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLColorSettingsPage.kt
  17. +133 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLDocumentationProvider.kt
  18. +11 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLFileStub.kt
  19. +27 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLLineMarkerProvider.kt
  20. +28 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLParserDefinition.kt
  21. +98 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLService.kt
  22. +11 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLStartupActivity.kt
  23. +66 −0 src/main/kotlin/me/mattco/serenityos/gml/GMLSyntaxHighlighterFactory.kt
  24. +93 −0 src/main/kotlin/me/mattco/serenityos/gml/annotators/GMLErrorAnnotator.kt
  25. +32 −0 src/main/kotlin/me/mattco/serenityos/gml/annotators/GMLSyntaxAnnotator.kt
  26. +10 −0 src/main/kotlin/me/mattco/serenityos/gml/completions/GMLCompletion.kt
  27. +14 −0 src/main/kotlin/me/mattco/serenityos/gml/completions/GMLCompletionContributor.kt
  28. +47 −0 src/main/kotlin/me/mattco/serenityos/gml/completions/GMLPropertyCompletion.kt
  29. +34 −0 src/main/kotlin/me/mattco/serenityos/gml/completions/GMLWidgetCompletion.kt
  30. +31 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/GMLBraceMatcher.kt
  31. +36 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/GMLCodeStyleSettingsProvider.kt
  32. +52 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/GMLFormattingBlock.kt
  33. +25 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/GMLFormattingModelBuilder.kt
  34. +12 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/GMLLanguageCodeStyleSettingsProvider.kt
  35. +49 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/GMLLineIndentProvider.kt
  36. +50 −0 src/main/kotlin/me/mattco/serenityos/gml/formatting/rules.kt
  37. +15 −0 src/main/kotlin/me/mattco/serenityos/gml/lexer.kt
  38. +6 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/GMLNameIdentifierOwner.kt
  39. +18 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/GMLNamedElement.kt
  40. +5 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/GMLPsiElement.kt
  41. +28 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/GMLPsiFactory.kt
  42. +38 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/GMLRef.kt
  43. +8 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/interfaces/IGMLProperty.kt
  44. +10 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/interfaces/IGMLWidget.kt
  45. +16 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/mixins/GMLPropertyMixin.kt
  46. +64 −0 src/main/kotlin/me/mattco/serenityos/gml/psi/mixins/GMLWidgetMixin.kt
  47. +145 −0 src/main/kotlin/me/mattco/serenityos/gml/typing.kt
  48. +0 −3 src/main/kotlin/me/mattco/serenityos/idl/IDLColorSettingsPage.kt
  49. +0 −2 src/main/kotlin/me/mattco/serenityos/idl/IDLFindUsagesProvider.kt
  50. +2 −1 src/main/kotlin/me/mattco/serenityos/idl/IDLParserDefinition.kt
  51. +2 −6 src/main/kotlin/me/mattco/serenityos/idl/annotation/IDLErrorAnnotator.kt
  52. +1 −1 src/main/kotlin/me/mattco/serenityos/idl/annotation/IDLSyntaxAnnotator.kt
  53. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/project/IDLProjectService.kt
  54. +2 −2 src/main/kotlin/me/mattco/serenityos/idl/psi/IDLPsiFactory.kt
  55. +0 −5 src/main/kotlin/me/mattco/serenityos/idl/psi/IDLRef.kt
  56. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLCallbackInterfaceMixin.kt
  57. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLCallbackMixin.kt
  58. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLDictionaryMixin.kt
  59. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLEnumMixin.kt
  60. +0 −3 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLIdentMixin.kt
  61. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLImportStatementMixin.kt
  62. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLInterfaceMixin.kt
  63. +0 −1 src/main/kotlin/me/mattco/serenityos/idl/psi/mixins/IDLInterfaceMixinMixin.kt
  64. +0 −15 src/main/kotlin/me/mattco/serenityos/ipc/IPCCommenter.kt
  65. +0 −8 src/main/kotlin/me/mattco/serenityos/ipc/IPCLineMarkerProvider.kt
  66. +2 −1 src/main/kotlin/me/mattco/serenityos/ipc/IPCParserDefinition.kt
  67. +2 −6 src/main/kotlin/me/mattco/serenityos/ipc/IPCSyntaxAnnotator.kt
  68. +1 −1 src/main/kotlin/me/mattco/serenityos/ipc/IPCSyntaxHighlighterFactory.kt
  69. +2 −2 src/main/kotlin/me/mattco/serenityos/ipc/psi/IPCPsiFactory.kt
  70. BIN src/main/resources/META-INF/gml.png
  71. +22 −42 src/main/resources/META-INF/{ipc_without_border.svg → gml.svg}
  72. +74 −2 src/main/resources/META-INF/plugin.xml
  73. +62 −0 src/main/resources/grammar/SerenityOS GML.bnf
  74. +63 −0 src/main/resources/grammar/SerenityOS GML.flex
  75. +1 −1 src/main/resources/grammar/SerenityOS IDL.bnf
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,17 @@
# Changelog

## Unreleased
### Added
- GML support
- Syntax highlighting
- Basic completion: navigate from a component to it's C++ definition
- A formatter which completely supports Serenity's GML styling
- Widget and property autocompletion
- Documentation on element hover for both widgets and properties
- Type linting

## 1.1.0 - 2024-01-21

### Added

- Support for IPC files
28 changes: 12 additions & 16 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ fun environment(key: String) = providers.environmentVariable(key)
plugins {
idea
alias(libs.plugins.kotlin)
alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.grammarkit)
alias(libs.plugins.gradleIntelliJPlugin)
alias(libs.plugins.changelog)
@@ -23,6 +24,9 @@ repositories {
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation(libs.kotlinSerialization)
}

intellij {
@@ -32,14 +36,6 @@ intellij {
plugins = properties("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) }
}

kotlin {
@Suppress("UnstableApiUsage")
jvmToolchain {
languageVersion = JavaLanguageVersion.of(17)
vendor = JvmVendorSpec.JETBRAINS
}
}

changelog {
groups.empty()
repositoryUrl = properties("pluginRepositoryUrl")
@@ -64,7 +60,7 @@ tasks {
generateLexer.configure { enabled = false }
generateParser.configure { enabled = false }

val supportedDSLs = listOf("IDL", "IPC")
val supportedDSLs = listOf("GML", "IDL", "IPC")

for (dsl in supportedDSLs) {
task<GenerateLexerTask>("generate${dsl}Lexer") {
@@ -103,6 +99,13 @@ tasks {
gradleVersion = properties("gradleVersion").get()
}

runIdeForUiTests {
systemProperty("robot-server.port", "8082")
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
systemProperty("jb.consents.confirmation.enabled", "false")
}

patchPluginXml {
version = properties("pluginVersion")
sinceBuild = properties("pluginSinceBuild")
@@ -134,13 +137,6 @@ tasks {
}
}

runIdeForUiTests {
systemProperty("robot-server.port", "8082")
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
systemProperty("jb.consents.confirmation.enabled", "false")
}

publishPlugin {
dependsOn("patchChangelog")
token = environment("PUBLISH_TOKEN")
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -2,13 +2,13 @@ pluginGroup=me.mattco.serenityos
pluginName=SerenityOS-DSL
pluginVersion=1.1.0
pluginSinceBuild=232
pluginUntilBuild=233.2
pluginUntilBuild=233.*
platformType=CL
platformVersion=2023.3.2
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins=com.intellij.clion,com.intellij.cidr.lang,com.intellij.cidr.base
javaVersion=17
gradleVersion=8.4
gradleVersion=8.5
# The platform includes Kotlin, so we don't have to
kotlin.stdlib.default.dependency=false
5 changes: 4 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -6,13 +6,16 @@ annotations = "24.1.0"
kotlin = "1.9.22"
changelog = "2.2.0"
gradleIntelliJPlugin = "1.17.0"
grammarkit = "2022.3.2"
grammarkit = "2022.3.2.1"
kotlinxSerialization = "1.6.2"

[libraries]
annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" }
kotlinSerialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" }

[plugins]
changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" }
gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
grammarkit = { id = "org.jetbrains.grammarkit", version.ref = "grammarkit" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
57 changes: 29 additions & 28 deletions src/main/kotlin/me/mattco/serenityos/common/DSLAnnotator.kt
Original file line number Diff line number Diff line change
@@ -8,35 +8,36 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement

abstract class DSLAnnotator : Annotator {
final override fun annotate(element: PsiElement, holder: AnnotationHolder) {
annotate(element, Holder(holder))
private lateinit var holder: AnnotationHolder

override fun annotate(element: PsiElement, holder: AnnotationHolder) {
this.holder = holder
annotate(element)
}

abstract fun annotate(element: PsiElement)

private fun newAnnotation(severity: HighlightSeverity, message: String? = null) = if (message == null) {
holder.newSilentAnnotation(severity)
} else holder.newAnnotation(severity, message)

fun PsiElement.highlight(attribute: TextAttributesKey) {
newAnnotation(HighlightSeverity.INFORMATION)
.range(this)
.textAttributes(attribute)
.create()
}

fun TextRange.highlight(attribute: TextAttributesKey) {
newAnnotation(HighlightSeverity.INFORMATION)
.range(this)
.textAttributes(attribute)
.create()
}

protected abstract fun annotate(element: PsiElement, holder: Holder)

data class Holder(private val holder: AnnotationHolder) {
fun newAnnotation(severity: HighlightSeverity, message: String? = null) = if (message == null) {
holder.newSilentAnnotation(severity)
} else holder.newAnnotation(severity, message)

fun PsiElement.highlight(attribute: TextAttributesKey) {
newAnnotation(HighlightSeverity.INFORMATION)
.range(this)
.textAttributes(attribute)
.create()
}

fun TextRange.highlight(attribute: TextAttributesKey) {
newAnnotation(HighlightSeverity.INFORMATION)
.range(this)
.textAttributes(attribute)
.create()
}

fun PsiElement.highlightError(message: String) {
newAnnotation(HighlightSeverity.ERROR, message)
.range(this)
.create()
}
fun PsiElement.highlightError(message: String) {
newAnnotation(HighlightSeverity.ERROR, message)
.range(this)
.create()
}
}
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ abstract class DSLColorSettingsPage(private val language: Language) : ColorSetti

override fun getColorDescriptors(): Array<ColorDescriptor> = ColorDescriptor.EMPTY_ARRAY

override fun getDisplayName() = IPCLanguage.displayName
override fun getDisplayName() = language.displayName

override fun getAttributeDescriptors() =
getAttributes().map { AttributesDescriptor(it.key, it.value) }.toTypedArray()
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package me.mattco.serenityos.idl
package me.mattco.serenityos.common

import com.intellij.lang.Commenter

class IDLCommenter : Commenter {
class DSLCommenter : Commenter {
override fun getLineCommentPrefix() = "// "

override fun getBlockCommentPrefix() = null
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package me.mattco.serenityos.common

import com.intellij.psi.PsiTreeChangeEvent
import com.intellij.psi.PsiTreeChangeListener

// Allows implementers to only override the functions they care about
abstract class DSLTreeChangeListener : PsiTreeChangeListener {
override fun beforeChildAddition(event: PsiTreeChangeEvent) {
}

override fun beforeChildRemoval(event: PsiTreeChangeEvent) {
}

override fun beforeChildReplacement(event: PsiTreeChangeEvent) {
}

override fun beforeChildMovement(event: PsiTreeChangeEvent) {
}

override fun beforeChildrenChange(event: PsiTreeChangeEvent) {
}

override fun beforePropertyChange(event: PsiTreeChangeEvent) {
}

override fun childAdded(event: PsiTreeChangeEvent) {
}

override fun childRemoved(event: PsiTreeChangeEvent) {
}

override fun childReplaced(event: PsiTreeChangeEvent) {
}

override fun childrenChanged(event: PsiTreeChangeEvent) {
}

override fun childMoved(event: PsiTreeChangeEvent) {
}

override fun propertyChanged(event: PsiTreeChangeEvent) {
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/me/mattco/serenityos/common/completions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package me.mattco.serenityos.common

import com.intellij.openapi.util.Key
import com.intellij.patterns.*
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.util.ProcessingContext

typealias PsiPattern = ElementPattern<out PsiElement>

fun psiElement(type: IElementType): PsiElementPattern.Capture<PsiElement> = PlatformPatterns.psiElement(type)

inline fun <reified T : PsiElement> psiElement(): PsiElementPattern.Capture<T> =
PlatformPatterns.psiElement(T::class.java)

inline operator fun <reified T> ProcessingContext.set(key: Key<T>, value: T) = this.put(key, value)
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package me.mattco.serenityos.common.formatting

import com.intellij.formatting.ASTBlock
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.SpacingBuilder
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet

interface Builder {
fun getSpacing(parent: ASTBlock?, left: ASTBlock?, right: ASTBlock?): Spacing?
}

// Heavily inspired by the Kotlin plugin's SpacingBuilder system
class SpacingBuilder(private val settings: CommonCodeStyleSettings) : Builder {
private val builders = mutableListOf<Builder>()

fun simple(block: SpacingBuilder.() -> Unit) {
builders.add(SimpleBuilder(settings).apply(block))
}

fun contextual(
parent: IElementType? = null,
left: IElementType? = null,
right: IElementType? = null,
parents: TokenSet = parent?.let { tokenSetOf(it) } ?: tokenSetOf(),
lefts: TokenSet = left?.let { tokenSetOf(it) } ?: tokenSetOf(),
rights: TokenSet = right?.let { tokenSetOf(it) } ?: tokenSetOf(),
rule: (ASTBlock?, ASTBlock?, ASTBlock?) -> Spacing?,
) {
builders.add(ContextualBuilder(parents, lefts, rights, rule))
}

fun getSpacing(parent: Block?, left: Block?, right: Block?): Spacing? {
if (parent !is ASTBlock || left !is ASTBlock || right !is ASTBlock)
return null
return getSpacing(parent, left, right)
}

override fun getSpacing(parent: ASTBlock?, left: ASTBlock?, right: ASTBlock?): Spacing? {
for (builder in builders)
builder.getSpacing(parent, left, right)?.let { return it }
return null
}

fun makeSpacing(
minSpaces: Int = 1,
maxSpaces: Int = 1,
minLineFeeds: Int = 0,
keepLineBreaks: Boolean = true,
keepBlankLines: Int = 1,
): Spacing = Spacing.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines)

class SimpleBuilder(settings: CommonCodeStyleSettings) : SpacingBuilder(settings), Builder {
override fun getSpacing(parent: ASTBlock?, left: ASTBlock?, right: ASTBlock?): Spacing? {
return super.getSpacing(parent, left, right)
}
}

class ContextualBuilder(
private val parents: TokenSet,
private val lefts: TokenSet,
private val rights: TokenSet,
private val rule: (ASTBlock?, ASTBlock?, ASTBlock?) -> Spacing?,
) : Builder {
override fun getSpacing(parent: ASTBlock?, left: ASTBlock?, right: ASTBlock?): Spacing? {
if (parents.match(parent) && lefts.match(left) && rights.match(right))
return rule(parent, left, right)
return null
}

companion object {
fun TokenSet.match(block: ASTBlock?) =
block == null || types.isEmpty() || this.contains(block.elementType)
}
}
}

val ASTBlock.elementType: IElementType
get() = this.node!!.elementType

fun tokenSetOf(vararg types: IElementType?) = TokenSet.create(*types.filterNotNull().toTypedArray())
12 changes: 12 additions & 0 deletions src/main/kotlin/me/mattco/serenityos/common/projectUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package me.mattco.serenityos.common

import com.intellij.openapi.project.BaseProjectDirectories.Companion.getBaseDirectories
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile

// TODO: Dependent on folder name?
val Project.isSerenity: Boolean
get() = name == "SerenityOS"

val Project.userlandDirectory: VirtualFile?
get() = getBaseDirectories().singleOrNull()?.findChild("Userland")
Loading