initial commit
This commit is contained in:
49
.gitignore
vendored
Normal file
49
.gitignore
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
.gradle
|
||||
/.idea/
|
||||
/build/
|
||||
/target
|
||||
/native/target/
|
||||
!/gradle
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
src/main/gen
|
||||
src/main/resources/natives/
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
/src/test/resources/slint/lexer/output.txt
|
||||
/src/test/resources/slint/parser/.txt
|
||||
/idea-sandbox
|
||||
140
build.gradle.kts
Normal file
140
build.gradle.kts
Normal file
@@ -0,0 +1,140 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("org.jetbrains.kotlin.jvm") version "1.9.23"
|
||||
id("org.jetbrains.intellij") version "1.17.2"
|
||||
id("org.jetbrains.grammarkit") version "2022.3.2.2"
|
||||
id("de.undercouch.download") version "5.6.0"
|
||||
}
|
||||
val slintVersion: String by project
|
||||
//github url
|
||||
val slintGithubUrl = "https://github.com/slint-ui/slint/releases/download/v$slintVersion"
|
||||
//download dir
|
||||
val slintViewerDownloadDir = "${layout.buildDirectory.get()}/slint-viewer"
|
||||
//decompression path
|
||||
val slintViewerBinaryDir = "${layout.buildDirectory.get()}/slint-viewer/$slintVersion"
|
||||
|
||||
val grammarGeneratedRoot = "${layout.buildDirectory.get()}/generated/sources/grammar/"
|
||||
//github filename-> decompression name
|
||||
val slintViewerFilenames = arrayOf(
|
||||
"slint-viewer-linux.tar.gz" to "slint-viewer-linux",
|
||||
"slint-viewer-macos.tar.gz" to "slint-viewer-macos",
|
||||
"slint-viewer-windows.zip" to "slint-viewer-windows.exe",
|
||||
)
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs(file("${grammarGeneratedRoot}/main/java"))
|
||||
}
|
||||
}
|
||||
}
|
||||
group = "me.zhouxi"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
intellij {
|
||||
version.set("IC-2023.2.5")
|
||||
sandboxDir.set("idea-sandbox")
|
||||
plugins.set(listOf("java"))
|
||||
}
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok:1.18.32")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
testCompileOnly("org.projectlombok:lombok:1.18.32")
|
||||
testAnnotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
implementation("org.jetbrains:grammar-kit:2022.3.2")
|
||||
}
|
||||
tasks {
|
||||
buildPlugin {
|
||||
//copy slint-viewer to plugin dir
|
||||
from(slintViewerBinaryDir) {
|
||||
into("/slint-viewer")
|
||||
}
|
||||
}
|
||||
withType<JavaExec>().configureEach {
|
||||
if (name.endsWith("main()")) {
|
||||
notCompatibleWithConfigurationCache("JavaExec created by IntelliJ")
|
||||
}
|
||||
}
|
||||
|
||||
runIde {
|
||||
//copy slint-viewer
|
||||
doFirst {
|
||||
copy {
|
||||
from(slintViewerBinaryDir)
|
||||
into("idea-sandbox/plugins/intellij-slint/slint-viewer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withType<JavaCompile> {
|
||||
sourceCompatibility = "17"
|
||||
targetCompatibility = "17"
|
||||
}
|
||||
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "17"
|
||||
}
|
||||
|
||||
patchPluginXml {
|
||||
sinceBuild.set("232")
|
||||
untilBuild.set("242.*")
|
||||
}
|
||||
|
||||
generateParser {
|
||||
purgeOldFiles.set(true)
|
||||
sourceFile.set(file("src/main/grammar/main.bnf"))
|
||||
pathToParser.set("SlintParser")
|
||||
targetRootOutputDir.set(file("${grammarGeneratedRoot}/main/java"))
|
||||
pathToPsiRoot.set("psi")
|
||||
}
|
||||
generateLexer {
|
||||
sourceFile.set(file("src/main/grammar/main.flex"))
|
||||
targetOutputDir.set(file("${grammarGeneratedRoot}/main/java/me/zhouxi/slint/lang/lexer"))
|
||||
purgeOldFiles.set(true)
|
||||
}
|
||||
|
||||
withType<Test> {
|
||||
jvmArgs("-Djava.awt.headless=true")
|
||||
}
|
||||
|
||||
register("downloadSlintViewer") {
|
||||
doFirst {
|
||||
slintViewerFilenames.forEach { fileDesc ->
|
||||
val (filename, renamed) = fileDesc
|
||||
val src = "$slintGithubUrl/$filename"
|
||||
val fileTarget = "$slintViewerDownloadDir/$filename"
|
||||
download.run {
|
||||
src(src)
|
||||
dest(fileTarget)
|
||||
}
|
||||
copy {
|
||||
val fileTree = if (filename.endsWith("zip")) {
|
||||
zipTree(fileTarget)
|
||||
} else {
|
||||
tarTree(fileTarget)
|
||||
}
|
||||
from(fileTree)
|
||||
//include executable file path
|
||||
include("slint-viewer/slint-viewer*")
|
||||
eachFile {
|
||||
//rename to platform name
|
||||
this.relativePath = RelativePath(true, renamed)
|
||||
}
|
||||
into(slintViewerBinaryDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
signPlugin {
|
||||
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
|
||||
privateKey.set(System.getenv("PRIVATE_KEY"))
|
||||
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
|
||||
}
|
||||
|
||||
publishPlugin {
|
||||
token.set(System.getenv("PUBLISH_TOKEN"))
|
||||
}
|
||||
}
|
||||
8
gradle.properties
Normal file
8
gradle.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib
|
||||
kotlin.stdlib.default.dependency=false
|
||||
# Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html
|
||||
org.gradle.configuration-cache=false
|
||||
# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html
|
||||
org.gradle.caching=false
|
||||
# slint version
|
||||
slintVersion=1.6.0
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
234
gradlew
vendored
Normal file
234
gradlew
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
8
settings.gradle.kts
Normal file
8
settings.gradle.kts
Normal file
@@ -0,0 +1,8 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "intellij-slint"
|
||||
568
src/main/grammar/main.bnf
Normal file
568
src/main/grammar/main.bnf
Normal file
@@ -0,0 +1,568 @@
|
||||
{
|
||||
generate=[token-case="as-is" element-case="as-is"]
|
||||
parserClass="me.zhouxi.slint.lang.parser.SlintParser"
|
||||
implements="me.zhouxi.slint.lang.psi.SlintPsiElement"
|
||||
extends="me.zhouxi.slint.lang.psi.SlintPsiElementImpl"
|
||||
elementTypeHolderClass="me.zhouxi.slint.lang.psi.SlintTypes"
|
||||
elementTypeClass="me.zhouxi.slint.lang.SlintElementType"
|
||||
tokenTypeClass="me.zhouxi.slint.lang.SlintTokenType"
|
||||
psiClassPrefix="Slint"
|
||||
psiImplClassSuffix="Impl"
|
||||
psiPackage="me.zhouxi.slint.lang.psi"
|
||||
psiImplPackage="me.zhouxi.slint.lang.psi.impl"
|
||||
tokens=[
|
||||
Comma = ","
|
||||
FatArrow = "=>"
|
||||
DoubleArrow = "<=>"
|
||||
PlusEqual = "+="
|
||||
MinusEqual = "-="
|
||||
StarEqual = "*="
|
||||
DivEqual = "/="
|
||||
LessEqual = "<="
|
||||
GreaterEqual = ">="
|
||||
EqualEqual = "=="
|
||||
NotEqual = "!="
|
||||
ColonEqual = ":="
|
||||
Arrow = "->"
|
||||
OrOr = "||"
|
||||
AndAnd = "&&"
|
||||
LBrace = "{"
|
||||
RBrace = "}"
|
||||
LParent = "("
|
||||
RParent = ")"
|
||||
LAngle = "<"
|
||||
RAngle = ">"
|
||||
LBracket = "["
|
||||
RBracket = "]"
|
||||
Plus = "+"
|
||||
Minus = "-"
|
||||
Star = "*"
|
||||
Div = "/"
|
||||
Equal = "="
|
||||
Colon = ":"
|
||||
Comma = ","
|
||||
Semicolon = ";"
|
||||
Bang = "!"
|
||||
Dot = "."
|
||||
Question = "?"
|
||||
Dollar = "$"
|
||||
At = "@"
|
||||
Pipe = "|"
|
||||
Percent = "%"
|
||||
Whitespace = "regexp:(\s+)"
|
||||
NumberLiteral = "regexp:\d+(\.(\d+)?)?([a-z]+|%)?"
|
||||
Identifier = "regexp:^[a-zA-Z_][A-Za-z0-9\-_]*"
|
||||
ColorLiteral = "regexp:#([a-zA-Z0-9]+)"
|
||||
StringLiteral = 'regexp:(^"[^"\r\n]*")'
|
||||
LineComment = 'regexp:^//[^\r\n]*'
|
||||
BlockComment = 'regexp:/\*[\s\S]*?\*/'
|
||||
|
||||
]
|
||||
extends(".*Expression")=Expression
|
||||
implements(".*Keyword")=[
|
||||
"me.zhouxi.slint.lang.psi.SlintPsiKeywordIdentifier"
|
||||
]
|
||||
}
|
||||
//
|
||||
Document ::= DocumentElement*
|
||||
private recoverTopElement ::= !('component' | 'struct' | 'enum' | 'global'| 'export'|'import' )
|
||||
private DocumentElement ::= Import | Struct |Export | Enum | GlobalSingleton | Component {
|
||||
recoverWhile=recoverTopElement
|
||||
}
|
||||
GlobalSingleton ::= GlobalKeyword ComponentName ComponentBody {
|
||||
pin=1
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
}
|
||||
//import 定义
|
||||
Import ::= ImportKeyword ImportElement? ModuleLocation';'{
|
||||
pin=1
|
||||
}
|
||||
|
||||
private ImportElement ::= '{' ImportedIdentifier (',' ImportedIdentifier)* ','? '}' FromKeyword {
|
||||
pin=1
|
||||
}
|
||||
|
||||
// ABc as Def
|
||||
ImportedIdentifier ::= ReferenceIdentifier ImportAlias?{
|
||||
pin=1
|
||||
recoverWhile=AliasNameRecover
|
||||
}
|
||||
private AliasNameRecover::=!(','|'}'|';')
|
||||
|
||||
private ImportAlias ::= AsKeyword InternalName {
|
||||
pin=1
|
||||
}
|
||||
//Struct 定义
|
||||
Struct ::= StructKeyword TypeName (':=')? StructBody {
|
||||
pin=1
|
||||
}
|
||||
private StructBody ::= '{' FieldDeclarations? '}'{
|
||||
pin=1
|
||||
}
|
||||
//EnumDeclaration
|
||||
Enum ::= EnumKeyword EnumName '{' (EnumValue (','EnumValue)*','? )? '}'{
|
||||
pin=1
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
}
|
||||
//--------------ExportsList -------------------------------------
|
||||
//ExportsList
|
||||
Export ::= ExportKeyword ExportElement {
|
||||
pin=1
|
||||
}
|
||||
private ExportElement ::= ExportType | Struct| Component | ExportModule | GlobalSingleton|Enum
|
||||
|
||||
ExportType ::= '{' ExportIdentifier (','ExportIdentifier)* ','? '}'{
|
||||
pin=1
|
||||
}
|
||||
ExportIdentifier ::= ReferenceIdentifier ExportAlias?{
|
||||
|
||||
}
|
||||
private ExportAlias ::= AsKeyword ExternalName{
|
||||
pin=1
|
||||
}
|
||||
ExportModule ::= '*' FromKeyword ModuleLocation ';'{
|
||||
pin=1
|
||||
}
|
||||
//---------- component ------------------------------------------------------------
|
||||
//Component ::= NewComponent
|
||||
//| LegacyComponent
|
||||
//Old syntax
|
||||
//private LegacyComponent ::=(GlobalKeyword ComponentName ':=' ComponentName? ComponentBody)| ('global'? SubComponent)
|
||||
|
||||
Component ::= ComponentKeyword ComponentName InheritDeclaration? ComponentBody {
|
||||
pin=1
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
}
|
||||
//组件定义
|
||||
//private LegacyComponent ::= (ComponentName|NamedIdentifier ':=' ) ComponentBody
|
||||
InheritDeclaration ::= InheritsKeyword ReferenceIdentifier {
|
||||
pin=1
|
||||
}
|
||||
ComponentBody ::= '{' ComponentElement* '}'{
|
||||
pin=1
|
||||
}
|
||||
//组件元素定义
|
||||
private ComponentElement ::=ChildrenPlaceholder| PropertyDeclaration | CallbackDeclaration
|
||||
| Function | PropertyAnimation | CallbackConnection | Transitions
|
||||
| PropertyChanged
|
||||
| States | TwoWayBinding | PropertyBinding | ConditionalElement
|
||||
| RepetitionElement | SubComponent {
|
||||
recoverWhile=recoverWhileForComponentBody
|
||||
}
|
||||
private recoverWhileForComponentBody::= !(
|
||||
'property'|'callback'|'changed'
|
||||
|'states'|'transitions'|'pure'
|
||||
|'function'|'public'|'protected'|'for'|'if'|'}'|';'|'@'
|
||||
|GenericIdentifier|PropertyModifier)
|
||||
|
||||
ChildrenPlaceholder ::= '@' 'children'{
|
||||
pin=1
|
||||
}
|
||||
//--------------------------------PropertyDeclaration Start----------------------------------------------------
|
||||
// 属性定义 in property <type> name: value / in property <type> name <=> value
|
||||
PropertyDeclaration ::= PropertyModifier? PropertyKeyword ('<' Type '>')? PropertyName(PropertyValue|PropertyTwoWayBindingValue|';'){
|
||||
pin=2
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
}
|
||||
private PropertyModifier ::= InKeyword|OutKeyword|InOutKeyword|PrivateKeyword
|
||||
private PropertyValue::= ':' BindingStatement {
|
||||
pin=1
|
||||
}
|
||||
private PropertyTwoWayBindingValue ::= '<=>' QualifiedPropertyNameReference ';' {
|
||||
pin=1
|
||||
}
|
||||
//--------------------------------PropertyChanged Start----------------------------------------------------
|
||||
PropertyChanged ::= ChangedKeyword LocalVariable '=>' CodeBlock{
|
||||
pin=1
|
||||
}
|
||||
//--------------------------------CallbackDeclaration Start----------------------------------------------------
|
||||
// 回调定义 pure callback abc()->int; callback abc; callback(..);callback()->type;
|
||||
CallbackDeclaration ::= PureKeyword? CallbackKeyword FunctionName CallbackBinding? ';'{
|
||||
pin=2
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
}
|
||||
//回调参数定义
|
||||
CallbackBinding::= CallbackArgument | ('<=>'QualifiedPropertyNameReference)
|
||||
//入参定义
|
||||
CallbackArgument ::= '(' (Type (','Type)* ','? )? ')' ReturnType?{
|
||||
pin=1
|
||||
}
|
||||
private ReturnType ::= '->' (NamedType|ArrayType){
|
||||
pin=1
|
||||
}
|
||||
//--------------------------------TwoWayBindingDeclaration Start----------------------------------------------------
|
||||
//组件双向绑定
|
||||
TwoWayBinding ::= ReferenceIdentifier '<=>' QualifiedPropertyNameReference ';' {
|
||||
pin=2
|
||||
}
|
||||
|
||||
//--------------------------------FunctionDeclaration Start----------------------------------------------------
|
||||
//函数定义 protected? pure? function f()
|
||||
Function ::= FunctionModifiers? FunctionKeyword FunctionName FunctionArguments ReturnType? CodeBlock{
|
||||
pin=2
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
}
|
||||
private FunctionModifiers ::= ((PublicKeyword | ProtectedKeyword) PureKeyword?) | (PureKeyword (PublicKeyword | ProtectedKeyword)?)
|
||||
|
||||
private FunctionArguments ::= '(' FieldDeclarations* ')'{
|
||||
pin=1
|
||||
}
|
||||
|
||||
//--------------------------------CallbackConnectionDeclaration Start---------------------------------------------------
|
||||
//回调绑定定义 abc()=> {}
|
||||
CallbackConnection ::= FunctionReference CallbackConnectionArguments? '=>' CodeBlock ';'?{
|
||||
pin=3
|
||||
}
|
||||
private CallbackConnectionArguments ::= '(' (LocalVariable (',' LocalVariable)* ','?)? ')'
|
||||
|
||||
//--------------------------------ConditionalElementDeclaration Start---------------------------------------------------
|
||||
ConditionalElement ::= IfKeyword Expression ':' SubComponent{
|
||||
pin=1
|
||||
}
|
||||
RepetitionElement ::= ForKeyword RepetitionVariable InKeyword Expression ':' SubComponent {
|
||||
pin=1
|
||||
}
|
||||
private RepetitionVariable ::= LocalVariable RepetitionIndex?{
|
||||
pin=1
|
||||
}
|
||||
RepetitionIndex ::= '[' LocalVariable ']'{
|
||||
pin=1
|
||||
}
|
||||
//--------------------------------SubElementDeclaration Start---------------------------------------------------
|
||||
//子组件结构元素定义
|
||||
SubComponent ::= (PropertyName ':=')? ReferenceIdentifier ComponentBody{
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------TransitionsDeclaration Start---------------------------------------------------
|
||||
//过渡绑定
|
||||
Transitions ::= TransitionsKeyword '[' Transition* ']'{
|
||||
pin=1
|
||||
}
|
||||
//
|
||||
Transition ::= (InKeyword|OutKeyword) LocalVariable ':' '{' PropertyAnimation* '}'{
|
||||
pin=1
|
||||
recoverWhile=recoverForRBracket
|
||||
}
|
||||
//--------------------------------TransitionsDeclaration End---------------------------------------------------
|
||||
// in | out name : { }
|
||||
States ::= StatesKeyword '[' State* ']'{
|
||||
pin=1
|
||||
}
|
||||
// identifier [when] : { ... }
|
||||
State ::= LocalVariable StateCondition? ':' '{' StateItem* '}' {
|
||||
pin=3
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
recoverWhile=recoverForRBracket
|
||||
}
|
||||
private recoverForRBracket::=!(']'|'}'|';'|GenericIdentifier)
|
||||
StateCondition ::= WhenKeyword Expression {
|
||||
pin=1
|
||||
}
|
||||
//状态可以由transition propertyBinding 和 animationBinding组成
|
||||
private StateItem ::= QualifiedNamePropertyBinding | StateTransition
|
||||
StateTransition ::= (InKeyword|OutKeyword) ':' '{' PropertyAnimation* '}'{
|
||||
pin=1
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
//类型定义
|
||||
Type ::= NamedType | UnnamedType | ArrayType
|
||||
private NamedType ::= QualifiedTypeNameReference
|
||||
ArrayType ::= '[' Type ']'
|
||||
UnnamedType ::= '{' FieldDeclarations* '}'
|
||||
private FieldDeclarations ::= FieldDeclaration (',' FieldDeclaration)* ','?
|
||||
private FieldDeclaration ::= PropertyName ':' Type
|
||||
|
||||
|
||||
//代码块
|
||||
CodeBlock ::= '{' Statement* '}'{
|
||||
pin=1
|
||||
}
|
||||
private Statement ::= (ReturnStatement|IfElseStatement|ExpressionStatement) ';'?{
|
||||
recoverWhile=recoverWhileStatement
|
||||
}
|
||||
ExpressionStatement ::= Expression (';' &Statement)?
|
||||
|
||||
private recoverWhileStatement::=!(GenericIdentifier|';'|'}')
|
||||
|
||||
ReturnStatement ::= 'return' (Expression)?{
|
||||
pin=1
|
||||
}
|
||||
private IfElseStatement ::= IfStatement (ElseIfStatement)* ElseStatement?{
|
||||
pin=1
|
||||
}
|
||||
IfStatement ::= IfKeyword Expression CodeBlock {
|
||||
pin=1
|
||||
}
|
||||
ElseIfStatement ::= ElseKeyword IfKeyword Expression CodeBlock{
|
||||
pin=2
|
||||
}
|
||||
ElseStatement ::= ElseKeyword CodeBlock {
|
||||
pin=1
|
||||
}
|
||||
//动画定义
|
||||
PropertyAnimation ::= AnimateKeyword ('*'| (QualifiedPropertyNameReference (',' QualifiedPropertyNameReference)*)) '{' QualifiedNamePropertyBinding*'}'{
|
||||
pin=1
|
||||
}
|
||||
//组件属性绑定 name: xxx ; name : {}; name : {}
|
||||
//只有对象定义和表达式需要 ;
|
||||
private QualifiedNamePropertyBinding::= QualifiedPropertyNameReference ':' BindingStatement{
|
||||
pin=2
|
||||
}
|
||||
PropertyBinding ::= ReferenceIdentifier ':' BindingStatement{
|
||||
pin=2
|
||||
}
|
||||
//优先尝试表达式解析 {}属于代码块 {name:xx}属于表达式,那么需要预测后面两个token,第二个token不是':'的情况下才是代码块
|
||||
//所以优先判断对象创建判断,然后进行代码块判断,最后进行表达式
|
||||
//代码块分号可选
|
||||
//表达式需要分号结尾
|
||||
BindingStatement ::=ObjectCreationExpressionWithSem|(CodeBlock ';'?)| ExpressionWithSem
|
||||
//用于错误的直观化
|
||||
private ObjectCreationExpressionWithSem::=ObjectCreationExpression';'{
|
||||
pin=1
|
||||
}
|
||||
private ExpressionWithSem::= Expression ';'{
|
||||
pin=1
|
||||
}
|
||||
|
||||
//-----------
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//expression
|
||||
Expression ::= AtExpression
|
||||
| TernaryExpression
|
||||
| UnaryExpression
|
||||
| BinaryExpression
|
||||
| AdditiveExpression
|
||||
| MultiplicativeExpression
|
||||
| ArrayAccessExpression
|
||||
| ArrayCreationExpression
|
||||
| ObjectCreationExpression
|
||||
| AssignmentExpression
|
||||
| PropertyExpression
|
||||
| PrimaryExpression
|
||||
{
|
||||
recoverWhile=recoverForExpression
|
||||
}
|
||||
private recoverForExpression ::= !(Expression|GenericIdentifier|';')
|
||||
|
||||
private BinaryExpression ::= SelfAssignExpression | ComparisonExpression | BooleanExpression
|
||||
//加法表达式
|
||||
AdditiveExpression ::= Expression ('+'|'-') Expression{
|
||||
pin=2
|
||||
}
|
||||
//乘法表达式
|
||||
MultiplicativeExpression ::= Expression ('*'|'/')Expression{
|
||||
pin=2
|
||||
}
|
||||
//------------------------------AtExpression---------------------------------------
|
||||
AtExpression ::= '@' (LineGradient|RadialGradient|ImageUrl|Tr) {
|
||||
pin=1
|
||||
}
|
||||
LineGradient ::= 'linear-gradient' '(' LineGradientArgument ')' {
|
||||
pin=1
|
||||
}
|
||||
private LineGradientArgument ::= Expression (',' ColorStops)? {
|
||||
pin=1
|
||||
recoverWhile=recoverForColorStops
|
||||
}
|
||||
private recoverForColorStops::=!(Expression|','|')')
|
||||
RadialGradient ::= 'radial-gradient' '(' RadialGradientArgument ')' {
|
||||
pin=1
|
||||
}
|
||||
private RadialGradientArgument ::= 'circle' (',' ColorStops)?{
|
||||
pin=1
|
||||
recoverWhile=recoverForColorStops
|
||||
}
|
||||
ImageUrl ::= 'image-url' ImageUrlArgs {
|
||||
pin=1
|
||||
}
|
||||
private ImageUrlArgs ::= '(' RawStringLiteral NineSlice? ')'{
|
||||
pin=1
|
||||
recoverWhile=RP
|
||||
}
|
||||
NineSlice ::= ',' 'nine-slice' '('Numbers*')'{
|
||||
// pin=1
|
||||
}
|
||||
private RP::=!(';'|'}'|')')
|
||||
|
||||
ColorStops ::= ColorStop (','ColorStop)* ','?
|
||||
ColorStop::= Expression Expression?
|
||||
|
||||
Tr::='tr' '(' TrArg (','Expression)* ')'{
|
||||
pin=2
|
||||
}
|
||||
TrArg::= ContextTr | Plurals | SimpleTrText
|
||||
ContextTr ::= RawStringLiteral '=>' (Plurals|SimpleTrText){
|
||||
pin=2
|
||||
}
|
||||
SimpleTrText::=RawStringLiteral
|
||||
Plurals ::= RawStringLiteral '|' RawStringLiteral '%' Expression{
|
||||
pin=2
|
||||
}
|
||||
|
||||
//----------------------------TernaryExpression-----------------------------------------
|
||||
TernaryExpression ::= Expression '?' Expression ':' Expression
|
||||
//----------------------------BooleanExpression-----------------------------------------
|
||||
BooleanExpression ::= Expression ('&&' | '||') Expression{
|
||||
pin=2
|
||||
}
|
||||
|
||||
ComparisonExpression ::= Expression ('>='|'<='|'=='|'!='|'>'|'<') Expression{
|
||||
pin=2
|
||||
}
|
||||
AssignmentExpression ::= Expression '=' Expression
|
||||
|
||||
SelfAssignExpression ::= Expression ('+='|'-='|'/='|'*='|'=') Expression
|
||||
|
||||
UnaryExpression ::= ('!' | '+' | '-') Expression{
|
||||
pin=1
|
||||
}
|
||||
|
||||
private PrimaryExpression::=ParenthesizedExpression|FunctionInvocationExpression|LiteralExpression
|
||||
|
||||
ParenthesizedExpression ::= '(' Expression ')'{
|
||||
pin=2
|
||||
}
|
||||
//fake PropertySuffixExpression::= Expression? '.' GenericIdentifier
|
||||
PropertyExpression ::= Expression '.' GenericIdentifier {
|
||||
// pin=2 extends=PropertySuffixExpression elementType=PropertySuffixExpression
|
||||
}
|
||||
FunctionInvocationExpression ::= Expression '(' InvocationArguments? ')'{
|
||||
extends=PropertyExpression
|
||||
}
|
||||
|
||||
InvocationArguments ::= Expression (','Expression)* ','?{
|
||||
recoverWhile=recoverOnRP
|
||||
}
|
||||
private recoverOnRP::=!(')')
|
||||
ArrayAccessExpression ::=Expression '[' Expression ']'
|
||||
|
||||
ArrayCreationExpression ::= '[' ArrayElements* ']'{
|
||||
pin=1
|
||||
}
|
||||
private ArrayElements ::= Expression (','Expression)* ','?
|
||||
|
||||
|
||||
LiteralExpression ::= Numbers | RawStringLiteral | GenericIdentifier | RawColorLiteral
|
||||
|
||||
//-------------------------------------------------
|
||||
|
||||
//-------------------------------------------------
|
||||
ObjectCreationExpression ::= '{' ObjectPropertyBindings '}'{
|
||||
pin=2
|
||||
}
|
||||
|
||||
private ObjectPropertyBindings ::= ObjectPropertyBinding (','ObjectPropertyBinding)* ','?{
|
||||
pin=1
|
||||
}
|
||||
private ObjectPropertyBinding ::= PropertyName ':' Expression{
|
||||
pin=2
|
||||
recoverWhile=recover
|
||||
}
|
||||
private recover::=!(';'|'}'|',')
|
||||
//-------------------------------For Keyword highlighting------------------------------------
|
||||
ComponentKeyword ::= 'component'
|
||||
StructKeyword ::='struct'
|
||||
EnumKeyword::='enum'
|
||||
GlobalKeyword::='global'
|
||||
ExportKeyword::='export'
|
||||
ImportKeyword::='import'
|
||||
AsKeyword::='as'
|
||||
FromKeyword::='from'
|
||||
InheritsKeyword::='inherits'
|
||||
PropertyKeyword::='property'
|
||||
CallbackKeyword::='callback'
|
||||
StatesKeyword::='states'
|
||||
TransitionsKeyword::='transitions'
|
||||
PureKeyword::='pure'
|
||||
FunctionKeyword::='function'
|
||||
PublicKeyword::='public'
|
||||
ProtectedKeyword::='protected'
|
||||
ForKeyword::='for'
|
||||
IfKeyword::='if'
|
||||
ChangedKeyword::='changed'
|
||||
InKeyword::='in'
|
||||
WhenKeyword::='when'
|
||||
ElseKeyword::='else'
|
||||
AnimateKeyword::='animate'
|
||||
OutKeyword::='out'
|
||||
InOutKeyword::='in-out'
|
||||
PrivateKeyword::='private'
|
||||
|
||||
//---------NamedIdentifier ,简化PsiTree-----------------------------------
|
||||
//noinspection BnfUnusedRule 用于标记命名节点对应的identifier
|
||||
Named ::= PropertyName | TypeName |ExternalName | InternalName|ComponentName|FunctionName{
|
||||
pin=1
|
||||
}
|
||||
{
|
||||
extends("PropertyName|TypeName|ComponentName|FunctionName")=Named
|
||||
}
|
||||
LocalVariable ::= GenericIdentifier{
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
}
|
||||
FunctionName ::= GenericIdentifier
|
||||
|
||||
ComponentName ::=GenericIdentifier
|
||||
|
||||
InternalName ::= GenericIdentifier{
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
}
|
||||
|
||||
PropertyName ::= GenericIdentifier
|
||||
|
||||
TypeName ::= GenericIdentifier
|
||||
|
||||
EnumName ::= GenericIdentifier
|
||||
|
||||
EnumValue ::=GenericIdentifier
|
||||
|
||||
ExternalName ::=GenericIdentifier{
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementMixinImpl"
|
||||
implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"]
|
||||
}
|
||||
|
||||
ReferenceIdentifier::=GenericIdentifier{
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintReferencedIdentifierMixinImpl"
|
||||
}
|
||||
|
||||
//----------UnnamedIdentifier------------------
|
||||
|
||||
PropertyNameReference ::= GenericIdentifier{
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintReferencedIdentifierMixinImpl"
|
||||
}
|
||||
FunctionReference ::=GenericIdentifier{
|
||||
|
||||
}
|
||||
QualifiedPropertyNameReference ::= PropertyNameReference ('.' PropertyNameReference)*{
|
||||
extends=PropertyNameReference
|
||||
}
|
||||
TypeNameReference::=GenericIdentifier
|
||||
|
||||
QualifiedTypeNameReference ::= TypeNameReference ('.' TypeNameReference)*{
|
||||
extends=TypeNameReference
|
||||
}
|
||||
|
||||
ModuleLocation ::= RawStringLiteral{
|
||||
mixin="me.zhouxi.slint.lang.psi.impl.SlintReferencedIdentifierMixinImpl"
|
||||
}
|
||||
//
|
||||
//noinspection BnfSuspiciousToken
|
||||
private RawStringLiteral ::= StringLiteral
|
||||
|
||||
//noinspection BnfSuspiciousToken
|
||||
private Numbers ::= NumberLiteral
|
||||
|
||||
//noinspection BnfSuspiciousToken
|
||||
private GenericIdentifier::= Identifier
|
||||
|
||||
//noinspection BnfSuspiciousToken
|
||||
private RawColorLiteral ::= ColorLiteral
|
||||
93
src/main/grammar/main.flex
Normal file
93
src/main/grammar/main.flex
Normal file
@@ -0,0 +1,93 @@
|
||||
package me.zhouxi.slint.lang.lexer;
|
||||
|
||||
import com.intellij.lexer.FlexLexer;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
import static com.intellij.psi.TokenType.BAD_CHARACTER;
|
||||
import static com.intellij.psi.TokenType.WHITE_SPACE;
|
||||
import static me.zhouxi.slint.lang.psi.SlintTypes.*;
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
public SlintLexer() {
|
||||
this((java.io.Reader)null);
|
||||
}
|
||||
%}
|
||||
|
||||
%public
|
||||
%class SlintLexer
|
||||
%implements FlexLexer
|
||||
%function advance
|
||||
%type IElementType
|
||||
%unicode
|
||||
|
||||
WHITE_SPACE=\s+
|
||||
NUMBERLITERAL=[0-9]+(\.([0-9]+)?)?([a-z]+|%)?
|
||||
IDENTIFIER=[a-zA-Z][A-Za-z0-9\-_]*
|
||||
COLORLITERAL=#([a-zA-Z0-9]+)
|
||||
LINECOMMENT=\/\/[^\r\n]*
|
||||
|
||||
%xstate COMMENT STRINGLITERAL
|
||||
|
||||
%%
|
||||
<YYINITIAL> {
|
||||
{WHITE_SPACE} { return WHITE_SPACE; }
|
||||
"/*" { yybegin(COMMENT);}
|
||||
"\"" { yybegin(STRINGLITERAL);}
|
||||
"," { return Comma; }
|
||||
"=>" { return FatArrow; }
|
||||
"<=>" { return DoubleArrow; }
|
||||
"+=" { return PlusEqual; }
|
||||
"-=" { return MinusEqual; }
|
||||
"*=" { return StarEqual; }
|
||||
"/=" { return DivEqual; }
|
||||
"<=" { return LessEqual; }
|
||||
">=" { return GreaterEqual; }
|
||||
"==" { return EqualEqual; }
|
||||
"!=" { return NotEqual; }
|
||||
":=" { return ColonEqual; }
|
||||
"->" { return Arrow; }
|
||||
"||" { return OrOr; }
|
||||
"&&" { return AndAnd; }
|
||||
"{" { return LBrace; }
|
||||
"}" { return RBrace; }
|
||||
"(" { return LParent; }
|
||||
")" { return RParent; }
|
||||
"<" { return LAngle; }
|
||||
">" { return RAngle; }
|
||||
"[" { return LBracket; }
|
||||
"]" { return RBracket; }
|
||||
"+" { return Plus; }
|
||||
"-" { return Minus; }
|
||||
"*" { return Star; }
|
||||
"/" { return Div; }
|
||||
"=" { return Equal; }
|
||||
":" { return Colon; }
|
||||
";" { return Semicolon; }
|
||||
"!" { return Bang; }
|
||||
"." { return Dot; }
|
||||
"?" { return Question; }
|
||||
"$" { return Dollar; }
|
||||
"@" { return At; }
|
||||
"|" { return Pipe; }
|
||||
"%" { return Percent; }
|
||||
{NUMBERLITERAL} { return NumberLiteral; }
|
||||
{IDENTIFIER} { return Identifier; }
|
||||
{COLORLITERAL} { return ColorLiteral; }
|
||||
{LINECOMMENT} { return LineComment; }
|
||||
}
|
||||
|
||||
<COMMENT>{
|
||||
"*/" { yybegin(YYINITIAL);return BlockComment; }
|
||||
[^*]+ {}
|
||||
"*" {}
|
||||
}
|
||||
<STRINGLITERAL>{
|
||||
"\\" { }
|
||||
"\\\"" { }
|
||||
"\"" { yybegin(YYINITIAL); return StringLiteral; }
|
||||
[^\\\"\n]+ { }
|
||||
[\n] {yybegin(YYINITIAL);}
|
||||
}
|
||||
[^] { return BAD_CHARACTER; }
|
||||
21
src/main/java/me/zhouxi/slint/lang/Slint.java
Normal file
21
src/main/java/me/zhouxi/slint/lang/Slint.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package me.zhouxi.slint.lang;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static com.intellij.openapi.util.IconLoader.getIcon;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
public class Slint extends Language {
|
||||
|
||||
public static final Slint INSTANCE = new Slint();
|
||||
|
||||
protected Slint() {
|
||||
super("Slint");
|
||||
}
|
||||
|
||||
public static final Icon ICON = getIcon("META-INF/pluginIcon.svg", Slint.class);
|
||||
}
|
||||
15
src/main/java/me/zhouxi/slint/lang/SlintElementType.java
Normal file
15
src/main/java/me/zhouxi/slint/lang/SlintElementType.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package me.zhouxi.slint.lang;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class SlintElementType extends IElementType {
|
||||
|
||||
|
||||
public SlintElementType(@NonNls @NotNull String rawKind) {
|
||||
super(rawKind, Slint.INSTANCE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package me.zhouxi.slint.lang;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.PsiParser;
|
||||
import com.intellij.lexer.FlexAdapter;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import me.zhouxi.slint.lang.lexer.SlintLexer;
|
||||
import me.zhouxi.slint.lang.parser.SlintParser;
|
||||
import me.zhouxi.slint.lang.psi.SlintFile;
|
||||
import me.zhouxi.slint.lang.psi.SlintTypes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static me.zhouxi.slint.lang.psi.SlintTypes.*;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
public class SlintParserDefinition implements ParserDefinition {
|
||||
@Override
|
||||
public @NotNull Lexer createLexer(Project project) {
|
||||
return new FlexAdapter(new SlintLexer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiParser createParser(Project project) {
|
||||
return new SlintParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IFileElementType getFileNodeType() {
|
||||
return FileType;
|
||||
}
|
||||
|
||||
public static final IFileElementType FileType = new IFileElementType("SlintFile",Slint.INSTANCE);
|
||||
|
||||
@Override
|
||||
public @NotNull TokenSet getCommentTokens() {
|
||||
return TokenSet.create(LineComment, BlockComment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull TokenSet getStringLiteralElements() {
|
||||
return TokenSet.create(StringLiteral);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiElement createElement(ASTNode node) {
|
||||
return SlintTypes.Factory.createElement(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiFile createFile(@NotNull FileViewProvider viewProvider) {
|
||||
return new SlintFile(viewProvider);
|
||||
}
|
||||
}
|
||||
16
src/main/java/me/zhouxi/slint/lang/SlintTokenType.java
Normal file
16
src/main/java/me/zhouxi/slint/lang/SlintTokenType.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package me.zhouxi.slint.lang;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
public class SlintTokenType extends IElementType {
|
||||
|
||||
public SlintTokenType(@NonNls @NotNull String kind) {
|
||||
super(kind, Slint.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/me/zhouxi/slint/lang/psi/SlintFile.java
Normal file
23
src/main/java/me/zhouxi/slint/lang/psi/SlintFile.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
import com.intellij.extapi.psi.PsiFileBase;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import me.zhouxi.slint.lang.Slint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
public class SlintFile extends PsiFileBase implements PsiFile {
|
||||
|
||||
public SlintFile(@NotNull FileViewProvider viewProvider) {
|
||||
super(viewProvider, Slint.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FileType getFileType() {
|
||||
return SlintFileType.INSTANCE;
|
||||
}
|
||||
}
|
||||
42
src/main/java/me/zhouxi/slint/lang/psi/SlintFileType.java
Normal file
42
src/main/java/me/zhouxi/slint/lang/psi/SlintFileType.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import me.zhouxi.slint.lang.Slint;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
public class SlintFileType extends LanguageFileType {
|
||||
|
||||
public static final SlintFileType INSTANCE = new SlintFileType();
|
||||
|
||||
protected SlintFileType() {
|
||||
super(Slint.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNls @NotNull String getName() {
|
||||
return "Slint File";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NlsContexts.Label @NotNull String getDescription() {
|
||||
return "Slint file dsl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NlsSafe @NotNull String getDefaultExtension() {
|
||||
return "slint";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return Slint.ICON;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface SlintPsiElement extends PsiElement {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SlintPsiElementImpl extends ASTWrapperPsiElement implements SlintPsiElement {
|
||||
|
||||
public SlintPsiElementImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
public interface SlintPsiKeywordIdentifier extends SlintPsiElement{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
import com.intellij.psi.NavigatablePsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
|
||||
public interface SlintPsiNamedElement extends SlintPsiElement, PsiNameIdentifierOwner, NavigatablePsiElement {
|
||||
@Override
|
||||
default boolean canNavigate() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
public interface SlintPsiReferencedIdentifier extends SlintPsiElement {
|
||||
|
||||
}
|
||||
28
src/main/java/me/zhouxi/slint/lang/psi/SlintPsiUtils.java
Normal file
28
src/main/java/me/zhouxi/slint/lang/psi/SlintPsiUtils.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package me.zhouxi.slint.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SlintPsiUtils {
|
||||
|
||||
public static final List<String> InternalTypes = List.of(
|
||||
"angle",
|
||||
"bool",
|
||||
"brush",
|
||||
"color",
|
||||
"duration",
|
||||
"easing",
|
||||
"float",
|
||||
"image",
|
||||
"int",
|
||||
"length",
|
||||
"percent",
|
||||
"physical-length",
|
||||
"relative-font-size",
|
||||
"string"
|
||||
);
|
||||
|
||||
public static boolean isInternalType(SlintPsiElement identifier) {
|
||||
return InternalTypes.stream().anyMatch(identifier::textMatches);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.zhouxi.slint.lang.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
|
||||
import me.zhouxi.slint.lang.psi.SlintPsiElementImpl;
|
||||
import me.zhouxi.slint.lang.psi.SlintPsiReferencedIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class SlintReferencedIdentifierMixinImpl extends SlintPsiElementImpl implements SlintPsiReferencedIdentifier {
|
||||
|
||||
public SlintReferencedIdentifierMixinImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PsiReference getReference() {
|
||||
PsiReference[] references = getReferences();
|
||||
return references.length > 0 ? references[0] : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiReference @NotNull [] getReferences() {
|
||||
return ReferenceProvidersRegistry.getReferencesFromProviders(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package me.zhouxi.slint.reference;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.AbstractElementManipulator;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import me.zhouxi.slint.lang.psi.SlintPsiReferencedIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static me.zhouxi.slint.lang.SlintElementFactoryKt.createIdentifier;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/8
|
||||
*/
|
||||
public class SlintElementNameManipulator extends AbstractElementManipulator<SlintPsiReferencedIdentifier> {
|
||||
@Override
|
||||
public @Nullable SlintPsiReferencedIdentifier handleContentChange(@NotNull SlintPsiReferencedIdentifier element, @NotNull TextRange range, String newContent) throws IncorrectOperationException {
|
||||
final var identifier = element.getFirstChild();
|
||||
if (identifier==null){
|
||||
throw new IncorrectOperationException("identifier doesn't exist");
|
||||
}
|
||||
final var newIdentifier = createIdentifier(element.getProject(), newContent);
|
||||
identifier.replace(newIdentifier);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TextRange getRangeInElement(@NotNull final SlintPsiReferencedIdentifier element) {
|
||||
return new TextRange(0,element.getTextLength());
|
||||
}
|
||||
}
|
||||
12
src/main/kotlin/me/zhouxi/slint/Plugin.kt
Normal file
12
src/main/kotlin/me/zhouxi/slint/Plugin.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package me.zhouxi.slint
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import java.nio.file.Path
|
||||
|
||||
object Plugin {
|
||||
val Id = PluginId.findId("me.zhouxi.intellij-slint")
|
||||
|
||||
val Path: Path = PluginManagerCore.getPlugin(Id)!!.pluginPath
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package me.zhouxi.slint.brace
|
||||
|
||||
import com.intellij.lang.BracePair
|
||||
import com.intellij.lang.PairedBraceMatcher
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import me.zhouxi.slint.lang.psi.SlintTypes
|
||||
|
||||
class SlintPairedBraceMatcher : PairedBraceMatcher {
|
||||
override fun getPairs(): Array<BracePair> {
|
||||
return Pair
|
||||
}
|
||||
|
||||
override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, contextType: IElementType?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getCodeConstructStart(file: PsiFile, openingBraceOffset: Int): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Pair: Array<BracePair> = arrayOf(
|
||||
BracePair(SlintTypes.LBrace, SlintTypes.RBrace, true),
|
||||
BracePair(SlintTypes.LParent, SlintTypes.RParent, true),
|
||||
BracePair(SlintTypes.LBracket, SlintTypes.RBracket, true),
|
||||
BracePair(SlintTypes.LAngle, SlintTypes.RAngle, true)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package me.zhouxi.slint.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.ProcessingContext
|
||||
import me.zhouxi.slint.lang.SlintParserDefinition
|
||||
import me.zhouxi.slint.lang.psi.SlintComponent
|
||||
import me.zhouxi.slint.lang.psi.SlintFile
|
||||
import me.zhouxi.slint.lang.psi.SlintImport
|
||||
import me.zhouxi.slint.lang.psi.SlintPsiUtils.InternalTypes
|
||||
import me.zhouxi.slint.lang.psi.SlintTypes
|
||||
import me.zhouxi.slint.lang.psi.utils.exportedElements
|
||||
import me.zhouxi.slint.lang.psi.utils.inheritDeclaredElements
|
||||
|
||||
class SlintCompletionContributor : CompletionContributor() {
|
||||
init {
|
||||
//文件级别
|
||||
extend(
|
||||
CompletionType.BASIC,
|
||||
PlatformPatterns.psiElement().withAncestor(4, PlatformPatterns.psiElement(SlintParserDefinition.FileType)),
|
||||
object : CompletionProvider<CompletionParameters>() {
|
||||
override fun addCompletions(
|
||||
parameters: CompletionParameters,
|
||||
context: ProcessingContext,
|
||||
result: CompletionResultSet
|
||||
) {
|
||||
result.addAllElements(TopKeywords)
|
||||
}
|
||||
})
|
||||
|
||||
//类型定义
|
||||
extend(
|
||||
CompletionType.BASIC,
|
||||
PlatformPatterns.psiElement().withAncestor(3, PlatformPatterns.psiElement(SlintTypes.Type)),
|
||||
object : CompletionProvider<CompletionParameters>() {
|
||||
override fun addCompletions(
|
||||
parameters: CompletionParameters,
|
||||
context: ProcessingContext,
|
||||
result: CompletionResultSet
|
||||
) {
|
||||
result.addAllElements(BasicTypes)
|
||||
}
|
||||
})
|
||||
|
||||
//componentBody
|
||||
extend(
|
||||
CompletionType.BASIC,
|
||||
PlatformPatterns.psiElement().withAncestor(3, PlatformPatterns.psiElement(SlintTypes.ComponentBody)),
|
||||
object : CompletionProvider<CompletionParameters>() {
|
||||
override fun addCompletions(
|
||||
parameters: CompletionParameters,
|
||||
context: ProcessingContext,
|
||||
result: CompletionResultSet
|
||||
) {
|
||||
result.addAllElements(ElementKeywords)
|
||||
val component = parameters.position.parentOfType<SlintComponent>() ?: return
|
||||
val elements = component.inheritDeclaredElements()
|
||||
for (element in elements) {
|
||||
result.addElement(LookupElementBuilder.create(element).withIcon(AllIcons.Nodes.Property))
|
||||
}
|
||||
val file = component.containingFile as SlintFile
|
||||
val array = file.childrenOfType<SlintImport>()
|
||||
.mapNotNull { it.moduleLocation?.reference?.resolve() as SlintFile? }
|
||||
.flatMap { it.exportedElements() }
|
||||
for (element in array) {
|
||||
result.addElement(LookupElementBuilder.create(element).withIcon(AllIcons.Nodes.Class))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val BasicTypes = InternalTypes.map { LookupElementBuilder.create(it) }
|
||||
val TopKeywords = arrayOf("export", "component", "global", "enum", "struct").map { LookupElementBuilder.create(it) }
|
||||
val ElementKeywords = arrayOf(
|
||||
"in", "out", "in-out", "callback",
|
||||
"property", "private", "changed",
|
||||
"states", "transitions", "@children"
|
||||
).map { LookupElementBuilder.create(it) }
|
||||
@@ -0,0 +1,38 @@
|
||||
package me.zhouxi.slint.formatter
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.psi.TokenType
|
||||
import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition.SyntaxElement
|
||||
import com.intellij.psi.impl.source.codeStyle.lineIndent.JavaLikeLangLineIndentProvider
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import me.zhouxi.slint.lang.Slint
|
||||
import me.zhouxi.slint.lang.psi.SlintTypes
|
||||
|
||||
class SlintLineIndentProvider : JavaLikeLangLineIndentProvider() {
|
||||
|
||||
override fun mapType(tokenType: IElementType): SyntaxElement? {
|
||||
return SyntaxMap[tokenType]
|
||||
}
|
||||
|
||||
|
||||
override fun isSuitableForLanguage(language: Language): Boolean {
|
||||
return language.isKindOf(Slint.INSTANCE)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val SyntaxMap: Map<IElementType, SyntaxElement> = java.util.Map.ofEntries<IElementType, SyntaxElement>(
|
||||
java.util.Map.entry(SlintTypes.LBracket, JavaLikeElement.BlockOpeningBrace),
|
||||
java.util.Map.entry(SlintTypes.RBracket, JavaLikeElement.BlockClosingBrace),
|
||||
java.util.Map.entry(SlintTypes.LBrace, JavaLikeElement.BlockOpeningBrace),
|
||||
java.util.Map.entry(SlintTypes.RBrace, JavaLikeElement.BlockClosingBrace),
|
||||
java.util.Map.entry(TokenType.WHITE_SPACE, JavaLikeElement.Whitespace),
|
||||
java.util.Map.entry(SlintTypes.Semicolon, JavaLikeElement.Semicolon),
|
||||
java.util.Map.entry(SlintTypes.LineComment, JavaLikeElement.LineComment),
|
||||
java.util.Map.entry(SlintTypes.BlockComment, JavaLikeElement.BlockComment),
|
||||
java.util.Map.entry(SlintTypes.Colon, JavaLikeElement.Colon),
|
||||
java.util.Map.entry(SlintTypes.Comma, JavaLikeElement.Comma),
|
||||
java.util.Map.entry(SlintTypes.LParent, JavaLikeElement.LeftParenthesis),
|
||||
java.util.Map.entry(SlintTypes.RParent, JavaLikeElement.RightParenthesis)
|
||||
)
|
||||
}
|
||||
}
|
||||
58
src/main/kotlin/me/zhouxi/slint/highlight/Definitions.kt
Normal file
58
src/main/kotlin/me/zhouxi/slint/highlight/Definitions.kt
Normal file
@@ -0,0 +1,58 @@
|
||||
package me.zhouxi.slint.highlight
|
||||
|
||||
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
|
||||
import com.intellij.openapi.editor.HighlighterColors
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey
|
||||
|
||||
object Definitions {
|
||||
@JvmField
|
||||
val _KeyWord: TextAttributesKey =
|
||||
TextAttributesKey.createTextAttributesKey("_KeyWord", DefaultLanguageHighlighterColors.KEYWORD)
|
||||
|
||||
val _StringLiteral: TextAttributesKey =
|
||||
TextAttributesKey.createTextAttributesKey("_StringLiteral", DefaultLanguageHighlighterColors.STRING)
|
||||
|
||||
val _Comment: TextAttributesKey =
|
||||
TextAttributesKey.createTextAttributesKey("_Comment", DefaultLanguageHighlighterColors.LINE_COMMENT)
|
||||
|
||||
val _DeclaredIdentifier: TextAttributesKey = TextAttributesKey.createTextAttributesKey(
|
||||
"_DeclaredIdentifier", DefaultLanguageHighlighterColors.INSTANCE_FIELD
|
||||
)
|
||||
|
||||
val _BadCharacter: TextAttributesKey =
|
||||
TextAttributesKey.createTextAttributesKey("BadCharacter", HighlighterColors.BAD_CHARACTER)
|
||||
|
||||
val _NumberLiteral: TextAttributesKey =
|
||||
TextAttributesKey.createTextAttributesKey("_NumberLiteral", DefaultLanguageHighlighterColors.NUMBER)
|
||||
|
||||
val _SemiColon: TextAttributesKey =
|
||||
TextAttributesKey.createTextAttributesKey("_SemiColon", DefaultLanguageHighlighterColors.SEMICOLON)
|
||||
val _Error: TextAttributesKey = TextAttributesKey.createTextAttributesKey("_Error", HighlighterColors.BAD_CHARACTER)
|
||||
|
||||
|
||||
private val BadCharacter = arrayOf(_BadCharacter)
|
||||
|
||||
@JvmField
|
||||
val KeyWord: Array<TextAttributesKey> = arrayOf(_KeyWord)
|
||||
|
||||
@JvmField
|
||||
val StringLiteral: Array<TextAttributesKey> = arrayOf(_StringLiteral)
|
||||
|
||||
val DeclaredIdentifier: Array<TextAttributesKey> = arrayOf(_DeclaredIdentifier)
|
||||
|
||||
@JvmField
|
||||
val Comment: Array<TextAttributesKey> = arrayOf(_Comment)
|
||||
|
||||
val Empty: Array<TextAttributesKey?> = arrayOfNulls(0)
|
||||
|
||||
@JvmField
|
||||
val NumberLiteral: Array<TextAttributesKey> = arrayOf(_NumberLiteral)
|
||||
|
||||
@JvmField
|
||||
val Brace: Array<TextAttributesKey> = arrayOf(DefaultLanguageHighlighterColors.BRACES)
|
||||
|
||||
@JvmField
|
||||
val SemiColon: Array<TextAttributesKey> = arrayOf(_SemiColon)
|
||||
|
||||
val Error: Array<TextAttributesKey> = arrayOf(_Error)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package me.zhouxi.slint.highlight
|
||||
|
||||
import com.intellij.lang.annotation.AnnotationHolder
|
||||
import com.intellij.lang.annotation.Annotator
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
|
||||
import com.intellij.psi.PsiElement
|
||||
import me.zhouxi.slint.lang.psi.*
|
||||
|
||||
class KeywordHighlightAnnotator : Annotator {
|
||||
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
|
||||
if (element is SlintPsiKeywordIdentifier) {
|
||||
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
|
||||
.range(element)
|
||||
.textAttributes(Definitions._KeyWord)
|
||||
.create()
|
||||
return
|
||||
}
|
||||
if (element is SlintTypeNameReference && SlintPsiUtils.isInternalType(element)) {
|
||||
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
|
||||
.range(element)
|
||||
.textAttributes(Definitions._KeyWord)
|
||||
.create()
|
||||
return
|
||||
}
|
||||
if (element is SlintPropertyName) {
|
||||
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
|
||||
.range(element)
|
||||
.textAttributes(DefaultLanguageHighlighterColors.INSTANCE_FIELD)
|
||||
.create()
|
||||
}
|
||||
if (element is SlintPropertyBinding) {
|
||||
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
|
||||
.range(element.getReferenceIdentifier())
|
||||
.textAttributes(DefaultLanguageHighlighterColors.INSTANCE_FIELD)
|
||||
.create()
|
||||
}
|
||||
if (element is SlintFunctionName || element is SlintFunctionReference) {
|
||||
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
|
||||
.range(element)
|
||||
.textAttributes(DefaultLanguageHighlighterColors.INSTANCE_METHOD)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package me.zhouxi.slint.highlight
|
||||
|
||||
import com.intellij.lexer.FlexAdapter
|
||||
import com.intellij.lexer.Lexer
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import me.zhouxi.slint.lang.lexer.SlintLexer
|
||||
import me.zhouxi.slint.lang.psi.SlintTypes
|
||||
|
||||
class SlintSyntaxHighlighter : SyntaxHighlighterBase() {
|
||||
override fun getHighlightingLexer(): Lexer {
|
||||
return FlexAdapter(SlintLexer())
|
||||
}
|
||||
|
||||
override fun getTokenHighlights(tokenType: IElementType): Array<TextAttributesKey> {
|
||||
if (tokenType === SlintTypes.StringLiteral) {
|
||||
return Definitions.StringLiteral
|
||||
}
|
||||
if (tokenType === SlintTypes.LineComment || tokenType === SlintTypes.BlockComment) {
|
||||
return Definitions.Comment
|
||||
}
|
||||
if (tokenType === SlintTypes.NumberLiteral) {
|
||||
return Definitions.NumberLiteral
|
||||
}
|
||||
if (tokenType === SlintTypes.LBrace || tokenType === SlintTypes.RBrace) {
|
||||
return Definitions.Brace
|
||||
}
|
||||
if (tokenType === SlintTypes.DoubleArrow) {
|
||||
return Definitions.KeyWord
|
||||
}
|
||||
if (tokenType === SlintTypes.Semicolon) {
|
||||
return Definitions.SemiColon
|
||||
}
|
||||
return TextAttributesKey.EMPTY_ARRAY
|
||||
}
|
||||
}
|
||||
18
src/main/kotlin/me/zhouxi/slint/lang/SlintElementFactory.kt
Normal file
18
src/main/kotlin/me/zhouxi/slint/lang/SlintElementFactory.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package me.zhouxi.slint.lang
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import me.zhouxi.slint.lang.psi.SlintComponent
|
||||
import me.zhouxi.slint.lang.psi.SlintFile
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/8
|
||||
*/
|
||||
|
||||
fun createIdentifier(project: Project?, text: String): PsiElement {
|
||||
val factory = PsiFileFactory.getInstance(project)
|
||||
val file = factory.createFileFromText("dummy.slint", Slint.INSTANCE, "component $text{}") as SlintFile
|
||||
return file.findChildByClass(SlintComponent::class.java)!!.componentName!!.identifier
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.zhouxi.slint.lang.psi.impl
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import me.zhouxi.slint.lang.createIdentifier
|
||||
import me.zhouxi.slint.lang.psi.SlintNamed
|
||||
import me.zhouxi.slint.lang.psi.SlintPsiElementImpl
|
||||
import me.zhouxi.slint.lang.psi.SlintPsiNamedElement
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/15
|
||||
*/
|
||||
abstract class SlintPsiNamedElementMixinImpl(node: ASTNode) : SlintPsiElementImpl(node),
|
||||
SlintPsiNamedElement {
|
||||
override fun getNameIdentifier(): PsiElement? {
|
||||
return findChildByClass(SlintNamed::class.java)
|
||||
}
|
||||
|
||||
override fun getName(): String? {
|
||||
return nameIdentifier?.text ?: this.text
|
||||
}
|
||||
|
||||
override fun canNavigate(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getTextOffset(): Int {
|
||||
return nameIdentifier?.textOffset ?: super.getTextOffset()
|
||||
}
|
||||
|
||||
@Throws(IncorrectOperationException::class)
|
||||
override fun setName(name: @NlsSafe String): PsiElement {
|
||||
val element = nameIdentifier ?: throw IncorrectOperationException()
|
||||
element.replace(createIdentifier(project, name))
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package me.zhouxi.slint.lang.psi.utils
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
import me.zhouxi.slint.lang.psi.*
|
||||
|
||||
|
||||
fun SlintExport.exportedElements(): List<SlintPsiNamedElement> {
|
||||
val list = mutableListOf<SlintPsiNamedElement>()
|
||||
this.exportType?.exportIdentifierList?.forEach {
|
||||
if (it.externalName == null) {
|
||||
val component = it.referenceIdentifier.reference?.resolve() as SlintComponent?
|
||||
component?.let { list.add(component) }
|
||||
} else {
|
||||
list.add(it.externalName!!)
|
||||
}
|
||||
}
|
||||
this.component?.let { list.add(it) }
|
||||
this.globalSingleton?.let { list.add(it) }
|
||||
val file = this.exportModule?.moduleLocation?.reference?.resolve() as SlintFile? ?: return list
|
||||
val exports = file.childrenOfType<SlintExport>()
|
||||
//TODO recursion error
|
||||
exports.forEach { list.addAll(it.exportedElements()) }
|
||||
return list
|
||||
}
|
||||
|
||||
fun SlintImport.importedElements(): List<PsiElement> {
|
||||
val list = mutableListOf<PsiElement>()
|
||||
this.importedIdentifierList.forEach { identifier ->
|
||||
list.add(identifier.referenceIdentifier)
|
||||
identifier.internalName?.let { list.add(it) }
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
fun SlintFile.importedElements(): List<PsiElement> {
|
||||
return this.childrenOfType<SlintImport>().flatMap { it.importedElements() }
|
||||
}
|
||||
|
||||
fun SlintFile.exportedElements(): List<SlintPsiNamedElement> {
|
||||
return this.childrenOfType<SlintExport>().flatMap { it.exportedElements() }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package me.zhouxi.slint.lang.psi.utils
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import me.zhouxi.slint.lang.psi.*
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
||||
|
||||
fun resolveComponent(element: SlintReferenceIdentifier?): SlintComponent? {
|
||||
if (element == null) {
|
||||
return null
|
||||
}
|
||||
val maybeComponent = element.reference?.resolve()
|
||||
if (maybeComponent is SlintComponent) {
|
||||
return maybeComponent
|
||||
}
|
||||
return resolveReferencedComponent(maybeComponent ?: return null)
|
||||
}
|
||||
|
||||
fun resolveComponent(element: SlintInternalName): SlintComponent? {
|
||||
//内部名字解析引用
|
||||
val resolve = element.reference?.resolve()
|
||||
if (resolve is SlintComponent) {
|
||||
return resolve
|
||||
}
|
||||
//InternalName解析不到东西,换成External试一下
|
||||
if (resolve == null) {
|
||||
val externalName = PsiTreeUtil.getPrevSiblingOfType(element, SlintExternalName::class.java)
|
||||
if (externalName == null) {
|
||||
val externalName1 = PsiTreeUtil.getNextSiblingOfType(element, SlintExternalName::class.java) ?: return null
|
||||
return resolveReferencedComponent(externalName1)
|
||||
}
|
||||
return resolveReferencedComponent(externalName)
|
||||
}
|
||||
return resolveReferencedComponent(resolve)
|
||||
}
|
||||
|
||||
fun resolveComponent(element: SlintExternalName): SlintComponent? {
|
||||
val resolve = element.reference?.resolve()
|
||||
if (resolve is SlintComponent) {
|
||||
return resolve
|
||||
}
|
||||
//InternalName解析不到东西,换成External试一下
|
||||
if (resolve == null) {
|
||||
val internalName = PsiTreeUtil.getPrevSiblingOfType(element, SlintInternalName::class.java)
|
||||
if (internalName == null) {
|
||||
val internalName1 = PsiTreeUtil.getNextSiblingOfType(element, SlintInternalName::class.java) ?: return null
|
||||
return resolveReferencedComponent(internalName1)
|
||||
}
|
||||
return resolveReferencedComponent(internalName)
|
||||
}
|
||||
return resolveReferencedComponent(resolve)
|
||||
}
|
||||
|
||||
fun resolveReferencedComponent(element: PsiElement?): SlintComponent? {
|
||||
if (element == null) {
|
||||
return null
|
||||
}
|
||||
when (element) {
|
||||
is SlintComponentName -> return element.parent as SlintComponent?
|
||||
is SlintComponent -> return element
|
||||
is SlintReferenceIdentifier -> return resolveComponent(element)
|
||||
is SlintInternalName -> return resolveComponent(element)
|
||||
is SlintExternalName -> return resolveComponent(element)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun searchProperty(
|
||||
component: PsiElement?,
|
||||
predicate: Predicate<SlintPropertyDeclaration>
|
||||
): SlintPropertyDeclaration? {
|
||||
if (component is SlintSubComponent) {
|
||||
return searchProperty(component, predicate)
|
||||
}
|
||||
if (component is SlintComponent) {
|
||||
return searchElementInParents(component, predicate) { it.componentBody?.propertyDeclarationList }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun searchProperty(
|
||||
subComponent: SlintSubComponent?,
|
||||
predicate: Predicate<SlintPropertyDeclaration>
|
||||
): SlintPropertyDeclaration? {
|
||||
val component = resolveComponent(subComponent?.referenceIdentifier) ?: return null
|
||||
return searchElementInParents(component, predicate) { it.componentBody?.propertyDeclarationList }
|
||||
}
|
||||
|
||||
fun searchCallback(
|
||||
subComponent: SlintSubComponent?,
|
||||
predicate: Predicate<SlintCallbackDeclaration>
|
||||
): SlintCallbackDeclaration? {
|
||||
val component = subComponent?.referenceIdentifier?.reference?.resolve() ?: return null
|
||||
return searchElementInParents(
|
||||
component as SlintComponent,
|
||||
predicate
|
||||
) { it.componentBody?.callbackDeclarationList }
|
||||
}
|
||||
|
||||
fun <T> searchElementInParents(
|
||||
component: SlintComponent?,
|
||||
predicate: Predicate<T>,
|
||||
function: Function<SlintComponent, List<T>?>
|
||||
): T? {
|
||||
if (component == null) {
|
||||
return null
|
||||
}
|
||||
val properties = function.apply(component) ?: arrayListOf<T>()
|
||||
for (property in properties) {
|
||||
if (predicate.test(property)) {
|
||||
return property
|
||||
}
|
||||
}
|
||||
val inheritComponent = resolveReferencedComponent(component.inheritDeclaration?.referenceIdentifier)
|
||||
return searchElementInParents(inheritComponent, predicate, function)
|
||||
}
|
||||
|
||||
fun SlintComponent.currentDeclaredElements(): List<SlintPsiNamedElement> {
|
||||
val properties = this.componentBody?.propertyDeclarationList ?: emptyList()
|
||||
val callbacks = this.componentBody?.callbackDeclarationList ?: emptyList()
|
||||
return properties + callbacks
|
||||
}
|
||||
|
||||
fun SlintComponent.inheritDeclaredElements(): List<SlintPsiNamedElement> {
|
||||
val properties = this.componentBody?.propertyDeclarationList ?: emptyList()
|
||||
val callbacks = this.componentBody?.callbackDeclarationList ?: emptyList()
|
||||
val inheritedComponent = resolveReferencedComponent(this.inheritDeclaration?.referenceIdentifier)
|
||||
?: return properties + callbacks
|
||||
return properties + callbacks + inheritedComponent.inheritDeclaredElements()
|
||||
}
|
||||
11
src/main/kotlin/me/zhouxi/slint/preview/CommandOptions.kt
Normal file
11
src/main/kotlin/me/zhouxi/slint/preview/CommandOptions.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.configurations.LocatableRunConfigurationOptions
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
class CommandOptions : LocatableRunConfigurationOptions() {
|
||||
|
||||
var arguments by string()
|
||||
}
|
||||
15
src/main/kotlin/me/zhouxi/slint/preview/PreviewAction.kt
Normal file
15
src/main/kotlin/me/zhouxi/slint/preview/PreviewAction.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.RunManager
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
|
||||
class PreviewAction : AnAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val manager = RunManager.getInstance(e.project!!)
|
||||
// e.si
|
||||
// manager.createConfiguration()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.ConfigurationType
|
||||
import com.intellij.execution.configurations.RunConfiguration
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
class PreviewConfigurationFactory(type: ConfigurationType) : ConfigurationFactory(type) {
|
||||
override fun getOptionsClass(): Class<out BaseState?> {
|
||||
return CommandOptions::class.java
|
||||
}
|
||||
|
||||
override fun getId(): String {
|
||||
return PreviewConfigurationType.id
|
||||
}
|
||||
|
||||
override fun createTemplateConfiguration(
|
||||
project: Project
|
||||
): RunConfiguration {
|
||||
return PreviewRunConfiguration(project, this, "Slint Viewer")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.configurations.ConfigurationTypeBase
|
||||
import com.intellij.openapi.util.NotNullLazyValue
|
||||
import me.zhouxi.slint.lang.Slint
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
object PreviewConfigurationType : ConfigurationTypeBase(
|
||||
"SlintViewerConfiguration",
|
||||
"Slint viewer",
|
||||
"Slint component preview",
|
||||
NotNullLazyValue.createValue { Slint.ICON }
|
||||
) {
|
||||
init {
|
||||
addFactory(PreviewConfigurationFactory(this))
|
||||
}
|
||||
|
||||
val factory: PreviewConfigurationFactory
|
||||
get() = this.configurationFactories[0] as PreviewConfigurationFactory
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.*
|
||||
import com.intellij.execution.process.ColoredProcessHandler
|
||||
import com.intellij.execution.process.ProcessHandler
|
||||
import com.intellij.execution.process.ProcessTerminatedListener
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.options.SettingsEditor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.InvalidDataException
|
||||
import com.intellij.util.io.BaseOutputReader
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.jdom.Element
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
class PreviewRunConfiguration(project: Project, factory: ConfigurationFactory?, name: String?) :
|
||||
LocatableConfigurationBase<CommandOptions?>(project, factory!!, name) {
|
||||
public override fun getOptions(): CommandOptions {
|
||||
return super.getOptions() as CommandOptions
|
||||
}
|
||||
|
||||
override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration?> {
|
||||
return SlintSettingEditor()
|
||||
}
|
||||
|
||||
|
||||
override fun suggestedName(): String? {
|
||||
println(options.arguments)
|
||||
return suggestedName()
|
||||
}
|
||||
|
||||
@Throws(InvalidDataException::class)
|
||||
override fun readExternal(element: Element) {
|
||||
super.readExternal(element)
|
||||
val attribute = element.getAttributeValue("RunArguments")
|
||||
if (StringUtils.isNoneBlank(attribute)) {
|
||||
options.arguments = attribute
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeExternal(element: Element) {
|
||||
super.writeExternal(element)
|
||||
if (StringUtils.isNoneBlank(options.arguments)) {
|
||||
element.setAttribute("RunArguments", options.arguments)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState {
|
||||
return object : CommandLineState(environment) {
|
||||
@Throws(ExecutionException::class)
|
||||
override fun startProcess(): ProcessHandler {
|
||||
val args = options.arguments?.split(" ")?.filter { it.isNotBlank() }?.toTypedArray() ?: arrayOf()
|
||||
val commandLine = GeneralCommandLine(
|
||||
SlintViewer.executable(), *args
|
||||
)
|
||||
val processHandler = object : ColoredProcessHandler(commandLine) {
|
||||
override fun readerOptions(): BaseOutputReader.Options {
|
||||
return BaseOutputReader.Options.forMostlySilentProcess()
|
||||
}
|
||||
}
|
||||
ProcessTerminatedListener.attach(processHandler)
|
||||
return processHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.actions.LazyRunConfigurationProducer
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.PsiElement
|
||||
import me.zhouxi.slint.lang.psi.SlintFile
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
class PreviewRunConfigurationProducer : LazyRunConfigurationProducer<PreviewRunConfiguration>() {
|
||||
override fun getConfigurationFactory(): ConfigurationFactory {
|
||||
return PreviewConfigurationType.factory
|
||||
}
|
||||
|
||||
override fun setupConfigurationFromContext(
|
||||
configuration: PreviewRunConfiguration,
|
||||
context: ConfigurationContext,
|
||||
sourceElement: Ref<PsiElement>
|
||||
): Boolean {
|
||||
val file = sourceElement.get().containingFile
|
||||
if (file !is SlintFile) {
|
||||
return false
|
||||
}
|
||||
configuration.options.arguments = "${file.virtualFile.path} --auto-reload"
|
||||
configuration.name = file.name
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun isConfigurationFromContext(
|
||||
configuration: PreviewRunConfiguration,
|
||||
context: ConfigurationContext
|
||||
): Boolean {
|
||||
val path = context.psiLocation?.context?.containingFile?.virtualFile?.path ?: return false
|
||||
return configuration.options.arguments?.contains(path) == true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.execution.lineMarker.ExecutorAction
|
||||
import com.intellij.execution.lineMarker.RunLineMarkerContributor
|
||||
import com.intellij.psi.PsiElement
|
||||
import me.zhouxi.slint.lang.Slint
|
||||
import me.zhouxi.slint.lang.psi.SlintComponentName
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
class PreviewRunLineMarkerContributor : RunLineMarkerContributor() {
|
||||
override fun getInfo(element: PsiElement): Info? {
|
||||
if (element.parent is SlintComponentName) {
|
||||
return Info(
|
||||
Slint.ICON, null,
|
||||
*ExecutorAction.getActions(1)
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
|
||||
import com.intellij.openapi.options.ConfigurationException
|
||||
import com.intellij.openapi.options.SettingsEditor
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.dsl.builder.*
|
||||
import java.awt.Desktop
|
||||
import java.awt.Font
|
||||
import java.net.URI
|
||||
import javax.swing.JComponent
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/16
|
||||
*/
|
||||
class SlintSettingEditor : SettingsEditor<PreviewRunConfiguration>() {
|
||||
|
||||
private val commandInput = JBTextField()
|
||||
|
||||
override fun resetEditorFrom(config: PreviewRunConfiguration) {
|
||||
commandInput.text = config.options.arguments
|
||||
}
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
override fun applyEditorTo(config: PreviewRunConfiguration) {
|
||||
config.options.arguments = commandInput.text
|
||||
}
|
||||
|
||||
override fun createEditor(): JComponent {
|
||||
return panel {
|
||||
separator()
|
||||
row {
|
||||
label("Slint viewer arguments").also {
|
||||
it.component.font = it.component.font.deriveFont(Font.BOLD)
|
||||
}
|
||||
}
|
||||
row {
|
||||
cell(commandInput).columns(COLUMNS_LARGE).align(Align.FILL)
|
||||
}
|
||||
row {
|
||||
link("Github document") {
|
||||
Desktop.getDesktop().browse(URI("https://github.com/slint-ui/slint/tree/master/tools/viewer"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/main/kotlin/me/zhouxi/slint/preview/SlintViewer.kt
Normal file
27
src/main/kotlin/me/zhouxi/slint/preview/SlintViewer.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package me.zhouxi.slint.preview
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import me.zhouxi.slint.Plugin
|
||||
import java.nio.file.Paths
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/17
|
||||
*/
|
||||
object SlintViewer {
|
||||
|
||||
private val executable = if (SystemInfo.isWindows) {
|
||||
"slint-viewer-windows.exe"
|
||||
} else if (SystemInfo.isLinux) {
|
||||
"slint-viewer-linux"
|
||||
} else if (SystemInfo.isMac) {
|
||||
"slint-viewer-macos"
|
||||
} else {
|
||||
throw RuntimeException("Unsupported OS")
|
||||
}
|
||||
|
||||
fun executable(): String {
|
||||
return Paths.get(Plugin.Path.toAbsolutePath().toString(), "slint-viewer", executable).toString()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package me.zhouxi.slint.reference
|
||||
|
||||
import com.intellij.patterns.PlatformPatterns.psiElement
|
||||
import com.intellij.patterns.StandardPatterns.or
|
||||
import com.intellij.psi.PsiReferenceContributor
|
||||
import com.intellij.psi.PsiReferenceRegistrar
|
||||
import me.zhouxi.slint.lang.psi.SlintTypes.*
|
||||
import me.zhouxi.slint.reference.provider.ComponentReferenceProvider
|
||||
import me.zhouxi.slint.reference.provider.ModuleLocationReferenceProvider
|
||||
import me.zhouxi.slint.reference.provider.PropertyReferenceProvider
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/17
|
||||
*/
|
||||
class SlintReferenceContributor : PsiReferenceContributor() {
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
//component Reference
|
||||
registrar.registerReferenceProvider(
|
||||
psiElement(ReferenceIdentifier)
|
||||
.withParent(
|
||||
or(
|
||||
psiElement(SubComponent),
|
||||
psiElement(Component),
|
||||
psiElement(InheritDeclaration),
|
||||
psiElement(ImportedIdentifier),
|
||||
psiElement(ExportIdentifier)
|
||||
)
|
||||
),
|
||||
ComponentReferenceProvider()
|
||||
)
|
||||
//moduleLocation Reference
|
||||
registrar.registerReferenceProvider(
|
||||
psiElement(ModuleLocation),
|
||||
ModuleLocationReferenceProvider()
|
||||
)
|
||||
//property binding
|
||||
registrar.registerReferenceProvider(
|
||||
psiElement().withParent(
|
||||
or(
|
||||
psiElement(PropertyBinding),
|
||||
psiElement(ComponentBody)
|
||||
)
|
||||
),
|
||||
PropertyReferenceProvider()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package me.zhouxi.slint.reference.provider
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiReferenceBase
|
||||
import com.intellij.psi.PsiReferenceProvider
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.ProcessingContext
|
||||
import me.zhouxi.slint.lang.psi.*
|
||||
import me.zhouxi.slint.lang.psi.utils.exportedElements
|
||||
import me.zhouxi.slint.lang.psi.utils.importedElements
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/17
|
||||
*/
|
||||
class ComponentReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return arrayOf(SlintComponentNameReference(element as SlintReferenceIdentifier))
|
||||
}
|
||||
|
||||
class SlintComponentNameReference(element: SlintReferenceIdentifier) : PsiReferenceBase<PsiElement?>(element) {
|
||||
override fun resolve(): PsiElement? {
|
||||
val file = element.containingFile as SlintFile
|
||||
//优先查找当前文件内的组件定义
|
||||
val component = file.childrenOfType<SlintComponent>()
|
||||
.firstOrNull { it.componentName?.textMatches(element) == true }
|
||||
if (component != null) {
|
||||
return component
|
||||
}
|
||||
// TODO psiTreeUtils
|
||||
//然后是导出的组件 maybe component or externalName
|
||||
val externalElement = file.exportedElements().firstOrNull { it.textMatches(element) }
|
||||
if (externalElement != null) {
|
||||
return externalElement
|
||||
}
|
||||
//maybe internalName or referencedIdentifier;
|
||||
val element = file.importedElements().firstOrNull { it.textMatches(element) } ?: return null
|
||||
if (element is SlintPsiReferencedIdentifier) {
|
||||
val location = element.parentOfType<SlintImport>()?.moduleLocation ?: return null
|
||||
val targetFile = location.reference?.resolve() as SlintFile? ?: return null
|
||||
return targetFile.exportedElements()
|
||||
.firstOrNull { it.nameIdentifier?.textMatches(element) == true }
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
override fun getVariants(): Array<Any> {
|
||||
val file = element.containingFile as SlintFile
|
||||
val array: Array<Any> = file.childrenOfType<SlintImport>()
|
||||
.mapNotNull { it.moduleLocation?.reference?.resolve() as SlintFile? }
|
||||
.flatMap { it.exportedElements() }.toTypedArray()
|
||||
return array
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package me.zhouxi.slint.reference.provider
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiReferenceBase
|
||||
import com.intellij.psi.PsiReferenceProvider
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.ProcessingContext
|
||||
import me.zhouxi.slint.lang.psi.SlintFile
|
||||
import me.zhouxi.slint.lang.psi.SlintImport
|
||||
import me.zhouxi.slint.lang.psi.SlintInternalName
|
||||
import me.zhouxi.slint.lang.psi.utils.exportedElements
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/17
|
||||
*/
|
||||
class InternalNameReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return arrayOf(InternalNameReference(element as SlintInternalName))
|
||||
}
|
||||
|
||||
class InternalNameReference(element: SlintInternalName) : PsiReferenceBase<SlintInternalName?>(element) {
|
||||
override fun resolve(): PsiElement? {
|
||||
val slintImport = element.parentOfType<SlintImport>() ?: return null
|
||||
val slintFile = slintImport.moduleLocation?.reference?.resolve() as? SlintFile ?: return null
|
||||
return slintFile.exportedElements().firstOrNull { it.textMatches(element) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package me.zhouxi.slint.reference.provider
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.util.ProcessingContext
|
||||
import me.zhouxi.slint.lang.psi.SlintModuleLocation
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/5/17
|
||||
*/
|
||||
class ModuleLocationReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return arrayOf(ModuleLocationReference(element))
|
||||
}
|
||||
|
||||
class ModuleLocationReference(element: PsiElement) : PsiReferenceBase<PsiElement?>(element) {
|
||||
override fun resolve(): PsiElement? {
|
||||
val location = element as SlintModuleLocation
|
||||
val filename = location.stringLiteral.text
|
||||
if (filename.length < 3) return null
|
||||
val directory = element.containingFile.originalFile.virtualFile?.parent ?: return null
|
||||
val file = VfsUtil.findRelativeFile(directory, filename.substring(1, filename.length - 1)) ?: return null
|
||||
return PsiManager.getInstance(element.project).findFile(file)
|
||||
}
|
||||
|
||||
override fun calculateDefaultRangeInElement(): TextRange {
|
||||
return TextRange(1, element.textLength - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.zhouxi.slint.reference.provider
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiReferenceBase
|
||||
import com.intellij.psi.PsiReferenceProvider
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.psi.util.parentOfTypes
|
||||
import com.intellij.util.ProcessingContext
|
||||
import me.zhouxi.slint.lang.psi.SlintComponent
|
||||
import me.zhouxi.slint.lang.psi.SlintPropertyBinding
|
||||
import me.zhouxi.slint.lang.psi.SlintSubComponent
|
||||
import me.zhouxi.slint.lang.psi.utils.searchProperty
|
||||
|
||||
class PropertyReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return arrayOf(PropertyReference(element))
|
||||
}
|
||||
|
||||
class PropertyReference(element: PsiElement) : PsiReferenceBase<PsiElement?>(element) {
|
||||
override fun resolve(): PsiElement? {
|
||||
val binding = element.parentOfType<SlintPropertyBinding>() ?: return null
|
||||
val parent = binding.parentOfTypes(SlintSubComponent::class, SlintComponent::class) ?: return null
|
||||
return searchProperty(parent) { it.propertyName?.textMatches(element) == true }
|
||||
}
|
||||
}
|
||||
}
|
||||
56
src/main/resources/META-INF/plugin.xml
Normal file
56
src/main/resources/META-INF/plugin.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
|
||||
<idea-plugin>
|
||||
<id>me.zhouxi.intellij-slint</id>
|
||||
|
||||
<name>intellij-slint</name>
|
||||
|
||||
<vendor email="zhouxi0106@gmail.com" url="https://www.yourcompany.com"/>
|
||||
|
||||
<description><![CDATA[slint language support.]]></description>
|
||||
|
||||
<depends>com.intellij.modules.platform</depends>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<fileType name="Slint File"
|
||||
implementationClass="me.zhouxi.slint.lang.psi.SlintFileType"
|
||||
fieldName="INSTANCE"
|
||||
language="Slint"
|
||||
extensions="slint"/>
|
||||
<lang.parserDefinition language="Slint"
|
||||
implementationClass="me.zhouxi.slint.lang.SlintParserDefinition"/>
|
||||
<lang.syntaxHighlighter language="Slint"
|
||||
implementationClass="me.zhouxi.slint.highlight.SlintSyntaxHighlighter"/>
|
||||
<annotator implementationClass="me.zhouxi.slint.highlight.KeywordHighlightAnnotator"
|
||||
language="Slint"/>
|
||||
|
||||
<lang.braceMatcher language="Slint"
|
||||
implementationClass="me.zhouxi.slint.brace.SlintPairedBraceMatcher"/>
|
||||
|
||||
<lang.elementManipulator forClass="me.zhouxi.slint.lang.psi.SlintPsiReferencedIdentifier"
|
||||
implementationClass="me.zhouxi.slint.reference.SlintElementNameManipulator"/>
|
||||
|
||||
<completion.contributor language="Slint"
|
||||
implementationClass="me.zhouxi.slint.completion.SlintCompletionContributor"/>
|
||||
|
||||
<psi.referenceContributor language="Slint"
|
||||
implementation="me.zhouxi.slint.reference.SlintReferenceContributor"/>
|
||||
|
||||
<lineIndentProvider implementation="me.zhouxi.slint.formatter.SlintLineIndentProvider"/>
|
||||
|
||||
<!-- <codeInsight.lineMarkerProvider language="Slint"-->
|
||||
<!-- implementationClass="me.zhouxi.slint.preview.PreviewLineMarkerProvider"/>-->
|
||||
<configurationType
|
||||
implementation="me.zhouxi.slint.preview.PreviewConfigurationType"/>
|
||||
|
||||
<runConfigurationProducer implementation="me.zhouxi.slint.preview.PreviewRunConfigurationProducer"/>
|
||||
|
||||
<runLineMarkerContributor implementationClass="me.zhouxi.slint.preview.PreviewRunLineMarkerContributor"
|
||||
language="Slint"/>
|
||||
|
||||
</extensions>
|
||||
<actions>
|
||||
<action id="slint.preview" class="me.zhouxi.slint.preview.PreviewAction"
|
||||
text="Slint Viewer" description="Preview current slint file">
|
||||
</action>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
4
src/main/resources/META-INF/pluginIcon.svg
Normal file
4
src/main/resources/META-INF/pluginIcon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.6632 55.828L48.7333 37.0309C48.7333 37.0309 50 36.3278 50 35.2182C50 33.7406 48.3981 33.2599 48.3981 33.2599L32.9557 27.355C32.4047 27.1462 31.6464 27.7312 32.3564 28.4728L37.4689 33.4165C37.4689 33.4165 38.889 34.765 38.889 35.6494C38.889 36.5338 38.017 37.322 38.017 37.322L19.4135 54.6909C18.7517 55.3089 19.6464 56.4294 20.6632 55.828Z" fill="#2379F4"/>
|
||||
<path d="M43.3368 8.17339L15.2667 26.9677C15.2667 26.9677 14 27.6708 14 28.7804C14 30.258 15.6019 30.7387 15.6019 30.7387L31.0443 36.6464C31.5953 36.8524 32.3565 36.2674 31.6436 35.5286L26.5311 30.5684C26.5311 30.5684 25.111 29.2226 25.111 28.3355C25.111 27.4483 25.983 26.6628 25.983 26.6628L44.5752 9.30769C45.2483 8.68973 44.3565 7.56916 43.3368 8.17339Z" fill="#2379F4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 850 B |
BIN
src/main/resources/icons/slint-logo-small-light.png
Normal file
BIN
src/main/resources/icons/slint-logo-small-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
55
src/test/java/LexerTest.java
Normal file
55
src/test/java/LexerTest.java
Normal file
@@ -0,0 +1,55 @@
|
||||
import com.intellij.lexer.FlexAdapter;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.testFramework.LexerTestCase;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhouxi.slint.lang.lexer.SlintLexer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.Stopwatch;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
@Slf4j
|
||||
public class LexerTest extends LexerTestCase {
|
||||
|
||||
@Override
|
||||
protected Lexer createLexer() {
|
||||
return new FlexAdapter(new SlintLexer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDirPath() {
|
||||
return "src/test/resources/slint";
|
||||
}
|
||||
|
||||
|
||||
public void test() throws IOException {
|
||||
var source = Files.readString(Paths.get("src/test/resources/slint/main.slint"));
|
||||
doTest(source);
|
||||
}
|
||||
|
||||
protected @NotNull String getPathToTestDataFile(String extension) {
|
||||
return "src/test/resources/slint/lexer/output" + extension;
|
||||
}
|
||||
|
||||
|
||||
@Rule
|
||||
public Stopwatch stopwatch = new Stopwatch() {
|
||||
@Override
|
||||
protected void succeeded(long nanos, Description description) {
|
||||
log.info("{} succeeded, time taken: {} ms", description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed(long nanos, Throwable e, Description description) {
|
||||
log.info("{} failed, time taken: {} ms", description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos));
|
||||
}
|
||||
};
|
||||
}
|
||||
33
src/test/java/ParserTest.java
Normal file
33
src/test/java/ParserTest.java
Normal file
@@ -0,0 +1,33 @@
|
||||
import com.intellij.testFramework.ParsingTestCase;
|
||||
import me.zhouxi.slint.lang.SlintParserDefinition;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @author zhouxi 2024/4/30
|
||||
*/
|
||||
public class ParserTest extends ParsingTestCase {
|
||||
public ParserTest() {
|
||||
super("", ".slint", new SlintParserDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull String getTestDataPath() {
|
||||
return "src/test/resources/slint/parser";
|
||||
}
|
||||
|
||||
public void test() throws IOException {
|
||||
final var path = Paths.get("src/test/resources/slint/main.slint");
|
||||
var source = Files.readString(path);
|
||||
StopWatch started = StopWatch.createStarted();
|
||||
for (int i = 0; i < 50000; i++) {
|
||||
doCodeTest(source);
|
||||
}
|
||||
started.stop();
|
||||
System.out.println(started.getNanoTime()/50000);
|
||||
}
|
||||
}
|
||||
5
src/test/resources/slint/main.slint
Normal file
5
src/test/resources/slint/main.slint
Normal file
@@ -0,0 +1,5 @@
|
||||
/* dsadas */
|
||||
/* dsadas */
|
||||
"dasdasd\""
|
||||
"dada"
|
||||
"
|
||||
Reference in New Issue
Block a user