Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new features #16

Merged
merged 1 commit into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

### Added
- Added an action to create a new empty file
- Added folding imports
- Added a handler for brackets and buckets

### Fixed
- Fixed linear marker preview
Expand Down
18 changes: 9 additions & 9 deletions src/main/grammars/SlintParser.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private ExportComponentDefinition ::= '{' Expression (',' (Expression | &'}'))*
}


private ImportDefinition ::= IMPORT ImportElementDefinitionBlock? ImportPathDeclaration ';'
ImportDefinition ::= IMPORT ImportElementDefinitionBlock? ImportPathDeclaration ';'
private ImportPathDeclaration ::= STRING_LITERAL
private ImportElementDefinitionBlock ::= '{' (ComponentName ','?)* '}' FROM

Expand All @@ -142,7 +142,7 @@ ComponentDefinition ::= COMPONENT ComponentName ComponentInheritsDeclaration? Co
private ComponentInheritsDeclaration ::= INHERITS ComponentName {
pin=2
}
private ComponentBody ::= '{' ComponentMembers '}' {
ComponentBody ::= '{' ComponentMembers '}' {
pin=1
}
private ComponentMembers ::= ComponentMemberDefinition* {
Expand Down Expand Up @@ -185,7 +185,7 @@ private ComponentMember_recover ::=
)

private InternalComponentDeclaration ::= ComponentName InternalComponentBody
private InternalComponentBody ::= '{' ComponentMembers '}' {
InternalComponentBody ::= '{' ComponentMembers '}' {
pin=1
}

Expand Down Expand Up @@ -217,7 +217,7 @@ private CallbackBindingDeclaration ::= '<=>' PropertyExpression
private CallbackDeclaration ::= Identifier CallArgumentList? '=>' CallbackBody {
pin=3
}
private CallbackBody ::= '{' CallbackMembers '}'
CallbackBody ::= '{' CallbackMembers '}'
private CallbackMembers ::= FunctionMemberDefinition* {
recoverWhile="simple_scope_recover"
}
Expand All @@ -229,7 +229,7 @@ private AnimateDeclaration ::= ANIMATE AnimatePropertyName AnimateBody {
private AnimatePropertyName ::= (PropertyExpression | '*' ) (',' Expression)* {
pin(".*")=1
}
private AnimateBody ::= '{' AnimateMembers '}' {
AnimateBody ::= '{' AnimateMembers '}' {
pin=1
}
private AnimateMembers ::= AnimateMemberDefinition* {
Expand All @@ -244,7 +244,7 @@ private AnimateMember_recover ::= !(Identifier | '}')

// States
private StatesDefinition ::= STATES StatesBody
private StatesBody ::= '[' StateMembers ']' {
StatesBody ::= '[' StateMembers ']' {
pin=1
}
private StateMembers ::= StateMemberDefinition* {
Expand Down Expand Up @@ -294,7 +294,7 @@ private FunctionDefinitionArgumentList ::= '(' FunctionArgument? (',' (FunctionA
}
private FunctionArgument ::= Identifier ':' Type

private FunctionBody ::= '{' FunctionMembers '}' {
FunctionBody ::= '{' FunctionMembers '}' {
pin=1
}
private FunctionMembers ::= FunctionMemberDefinition* {
Expand Down Expand Up @@ -343,7 +343,7 @@ EnumDefinition ::= ENUM ComponentName '{' Identifier (',' Identifier)* '}' {
// Struct
///////////////////////////////////////////////////////////////////////////////////////////////////
StructDefinition ::= STRUCT ComponentName StructBody
private StructBody ::= '{' StructMembers '}' { pin=1 }
StructBody ::= '{' StructMembers '}' { pin=1 }
private StructMembers ::= StructMemberDefinition* {
recoverWhile="simple_scope_recover"
}
Expand All @@ -360,7 +360,7 @@ private StructFieldDeclaration ::= FieldIdentifier Type ','? { pin=2 }
private AnonymousStructDefinition ::= StructBody

private AnonymousStructDeclaration ::= AnonymousStructBody
private AnonymousStructBody ::= '{' AnonymousStructMembers '}' { pin=1 }
AnonymousStructBody ::= '{' AnonymousStructMembers '}' { pin=1 }
private AnonymousStructMembers ::= AnonymousStructMemberDefinition* {
recoverWhile="simple_scope_recover"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.slint.ideaplugin.ide.editor

import com.intellij.lang.BracePair
import com.intellij.lang.PairedBraceMatcher
import com.intellij.psi.PsiFile
import com.intellij.psi.tree.IElementType
import dev.slint.ideaplugin.lang.psi.SlintElementTypes

class SlintBraceMatcher: PairedBraceMatcher {
override fun getPairs(): Array<BracePair> = braces

override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, contextType: IElementType?): Boolean = true

override fun getCodeConstructStart(file: PsiFile, openingBraceOffset: Int): Int = openingBraceOffset

companion object {
private val braces = arrayOf(
BracePair(SlintElementTypes.LBRACE, SlintElementTypes.RBRACE, true),
BracePair(SlintElementTypes.LBRACKET, SlintElementTypes.RBRACKET, false),
BracePair(SlintElementTypes.LPAREN, SlintElementTypes.RPAREN, false),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.slint.ideaplugin.ide.editor

import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler
import dev.slint.ideaplugin.lang.psi.SLINT_STRINGS

class SlintQuoteHandler: SimpleTokenSetQuoteHandler(SLINT_STRINGS)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dev.slint.ideaplugin.ide.folding

import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilderEx
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.editor.Document
import com.intellij.openapi.project.DumbAware
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import dev.slint.ideaplugin.lang.psi.*

class SlintBlockFoldingBuilder : FoldingBuilderEx(), DumbAware {
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> {
val blocks = PsiTreeUtil.findChildrenOfAnyType(
root,
SlintComponentBody::class.java,
SlintInternalComponentBody::class.java,
SlintCallbackBody::class.java,
SlintAnimateBody::class.java,
SlintStatesBody::class.java,
SlintFunctionBody::class.java,
SlintStructBody::class.java,
SlintAnonymousStructBody::class.java,
)
return blocks.map { FoldingDescriptor(it, it.textRange) }.toTypedArray()
}

override fun getPlaceholderText(node: ASTNode): String = "{...}"

override fun isCollapsedByDefault(node: ASTNode): Boolean = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package dev.slint.ideaplugin.ide.folding

import com.intellij.lang.ASTNode
import com.intellij.lang.folding.CustomFoldingBuilder
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.editor.Document
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.refactoring.suggested.endOffset
import com.intellij.refactoring.suggested.startOffset
import dev.slint.ideaplugin.lang.psi.SlintFile
import dev.slint.ideaplugin.lang.psi.SlintImportDefinition
import dev.slint.ideaplugin.util.parser.childrenOfType

class SlintImportFoldingBuilder : CustomFoldingBuilder(), DumbAware {
override fun buildLanguageFoldRegions(
descriptors: MutableList<FoldingDescriptor>,
root: PsiElement,
document: Document,
quick: Boolean
) {
if (root !is SlintFile) {
return
}

val covered = HashSet<SlintImportDefinition>()
val imports = root.allImports()

for (import in imports) {
if (import in covered) {
continue
}

var next: SlintImportDefinition? = import
var last: SlintImportDefinition = import
while (next != null) {

Check warning on line 39 in src/main/kotlin/dev/slint/ideaplugin/ide/folding/SlintImportFoldingBuilder.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Constant conditions

Condition 'next != null' is always true
covered += next
last = next
next = next.nextImport()
}

descriptors += FoldingDescriptor(import, TextRange(import.startOffset, last.endOffset))
}
}

override fun getLanguagePlaceholderText(node: ASTNode, textRange: TextRange): String = "import ..."

override fun isRegionCollapsedByDefault(node: ASTNode): Boolean = false

}

private fun PsiElement.allImports() = childrenOfType(SlintImportDefinition::class).toList()

private fun PsiElement.nextImport(): SlintImportDefinition? {
val next = this.nextSibling

if (next is PsiWhiteSpace) {
return next.nextImport()
}

if (next is PsiComment) {
return next.nextImport()
}

return next as? SlintImportDefinition
}
34 changes: 34 additions & 0 deletions src/main/kotlin/dev/slint/ideaplugin/util/parser/Psi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dev.slint.ideaplugin.util.parser

import com.intellij.openapi.application.runReadAction
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import kotlin.reflect.KClass

/**
* @see [PsiTreeUtil.getChildrenOfType]
*/
fun <T : PsiElement> PsiElement.childrenOfType(clazz: KClass<T>): Collection<T> {
if (project.isDisposed || !this.isValid) return emptyList()
return runReadAction { PsiTreeUtil.findChildrenOfType(this, clazz.java) }
}

/**
* Finds the first child of a certain type.
*/
@Suppress("UNCHECKED_CAST")
fun <T : PsiElement> PsiElement.firstChildOfType(clazz: KClass<T>): T? {
val children = runReadAction { this.children }
for (child in children) {
if (clazz.java.isAssignableFrom(child.javaClass)) {
return child as? T
}

val first = child.firstChildOfType(clazz)
if (first != null) {
return first
}
}

return null
}
8 changes: 8 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,16 @@
<!-- <colorSettingsPage implementation="dev.slint.ideaplugin.highlighting.SlintColorSettingsPage"/>-->

<!-- Editor -->
<lang.braceMatcher language="Slint"
implementationClass="dev.slint.ideaplugin.ide.editor.SlintBraceMatcher"/>
<lang.commenter language="Slint"
implementationClass="dev.slint.ideaplugin.ide.editor.SlintCommenter"/>
<lang.quoteHandler language="Slint"
implementationClass="dev.slint.ideaplugin.ide.editor.SlintQuoteHandler"/>
<lang.foldingBuilder language="Slint"
implementationClass="dev.slint.ideaplugin.ide.folding.SlintBlockFoldingBuilder"/>
<lang.foldingBuilder language="Slint"
implementationClass="dev.slint.ideaplugin.ide.folding.SlintImportFoldingBuilder"/>

<!-- Settings -->
<applicationConfigurable groupId="language" id="slint.settings"
Expand Down
Loading