[Editor] Add support for Prolog language as Logic card
This commit is contained in:
@@ -36,6 +36,7 @@ class DefaultProjectAssembler : ProjectAssembler {
|
||||
packager.pack(project.fontsDirectory, targetJar, "BOOT-INF/classes/project/fonts")
|
||||
packager.pack(project.widgetsDirectory, targetJar, "BOOT-INF/classes/project/widgets")
|
||||
packager.pack(project.audioDirectory, targetJar, "BOOT-INF/classes/project/audio")
|
||||
packager.pack(project.logicDirectory, targetJar, "BOOT-INF/classes/project/logic")
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.bartlomiejpluta.base.editor.code.component
|
||||
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileNode
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileType
|
||||
import javafx.scene.control.ContextMenu
|
||||
import javafx.scene.control.cell.TextFieldTreeCell
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.action
|
||||
import tornadofx.enableWhen
|
||||
import tornadofx.item
|
||||
import tornadofx.toProperty
|
||||
|
||||
class PrologFileTreeCell(onCreate: (FileNode) -> Unit, onDelete: (FileNode) -> Unit) :
|
||||
TextFieldTreeCell<FileNode>() {
|
||||
private val isRoot = true.toProperty()
|
||||
private val isNotRoot = isRoot.not()
|
||||
|
||||
private val fileMenu = ContextMenu().apply {
|
||||
item("Rename") {
|
||||
enableWhen(isNotRoot)
|
||||
|
||||
action {
|
||||
treeView.isEditable = true
|
||||
startEdit()
|
||||
treeView.isEditable = false
|
||||
}
|
||||
}
|
||||
|
||||
item("Delete") {
|
||||
enableWhen(isNotRoot)
|
||||
|
||||
action {
|
||||
item.delete()
|
||||
onDelete(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val directoryMenu = ContextMenu().apply {
|
||||
item("New File...") {
|
||||
action { onCreate(item) }
|
||||
}
|
||||
|
||||
item("Refresh") {
|
||||
action { item.refresh() }
|
||||
}
|
||||
|
||||
item("Rename") {
|
||||
enableWhen(isNotRoot)
|
||||
|
||||
action {
|
||||
treeView.isEditable = true
|
||||
startEdit()
|
||||
treeView.isEditable = false
|
||||
}
|
||||
}
|
||||
|
||||
item("Delete") {
|
||||
enableWhen(isNotRoot)
|
||||
|
||||
action {
|
||||
item.delete()
|
||||
onDelete(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
converter = ScriptFileStringConverter(this, this::renameFile)
|
||||
}
|
||||
|
||||
private fun renameFile(file: FileNode, name: String) = file.apply {
|
||||
file.rename(name)
|
||||
}
|
||||
|
||||
override fun updateItem(item: FileNode?, empty: Boolean) {
|
||||
super.updateItem(item, empty)
|
||||
|
||||
if (empty || item == null) {
|
||||
text = null
|
||||
graphic = null
|
||||
contextMenu = null
|
||||
isRoot.value = true
|
||||
return
|
||||
}
|
||||
|
||||
text = item.name
|
||||
graphic = FontIcon(getFileNodeIcon(item))
|
||||
|
||||
contextMenu = when {
|
||||
isEditing -> null
|
||||
item !is FileSystemNode -> null
|
||||
item.type == FileType.FILE -> fileMenu
|
||||
item.type == FileType.DIRECTORY -> directoryMenu
|
||||
else -> null
|
||||
}
|
||||
|
||||
isRoot.value = (item.parent == null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun getFileNodeIcon(file: FileNode): String {
|
||||
if (file.type == FileType.DIRECTORY) {
|
||||
return "fa-folder"
|
||||
}
|
||||
|
||||
return when (file.extension.toLowerCase()) {
|
||||
"java" -> "fa-code"
|
||||
else -> "fa-file"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.bartlomiejpluta.base.editor.code.highlighting
|
||||
|
||||
import com.bartlomiejpluta.base.editor.code.stylesheet.PrologSyntaxHighlightingStylesheet
|
||||
import org.fxmisc.richtext.model.StyleSpans
|
||||
import org.fxmisc.richtext.model.StyleSpansBuilder
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class PrologSyntaxHighlighter : SyntaxHighlighter {
|
||||
override fun highlight(code: String): StyleSpans<Collection<String>> = StyleSpansBuilder<Collection<String>>().let {
|
||||
val lastKeywordEnd = PATTERN.findAll(code).fold(0) { lastKeywordEnd, result ->
|
||||
val styleClass = when {
|
||||
result.groups["VARIABLE"] != null -> "variable"
|
||||
result.groups["PAREN"] != null -> "paren"
|
||||
result.groups["BRACE"] != null -> "brace"
|
||||
result.groups["BRACKET"] != null -> "bracket"
|
||||
result.groups["STRING"] != null -> "string"
|
||||
result.groups["NUMBER"] != null -> "number"
|
||||
result.groups["OPERATOR"] != null -> "operator"
|
||||
result.groups["COMMENT"] != null -> "comment"
|
||||
else -> throw IllegalStateException("Unsupported regex group")
|
||||
}
|
||||
|
||||
it.add(emptyList(), result.range.first - lastKeywordEnd)
|
||||
it.add(listOf(styleClass), result.range.last - result.range.first + 1)
|
||||
|
||||
result.range.last + 1
|
||||
}
|
||||
|
||||
it.add(emptyList(), code.length - lastKeywordEnd)
|
||||
|
||||
it.create()
|
||||
}
|
||||
|
||||
override val stylesheet = PrologSyntaxHighlightingStylesheet()
|
||||
|
||||
companion object {
|
||||
private val VARIABLE_PATTERN = "([A-Z]\\w*)"
|
||||
private val PAREN_PATTERN = "\\(|\\)"
|
||||
private val BRACE_PATTERN = "\\{|\\}"
|
||||
private val BRACKET_PATTERN = "\\[|\\]"
|
||||
private val STRING_PATTERN = "((\"([^\"\\\\]|\\\\.)*\")|('([^'\\\\]|\\\\.)*'))"
|
||||
private val NUMBER_PATTERN = "\\b-?([0-9]*\\.[0-9]+|[0-9]+)\\w?\\b"
|
||||
private val OPERATOR_PATTERN = "[+-/*:|&?<>=!;]"
|
||||
private val COMMENT_PATTERN = """
|
||||
%[^
|
||||
]*|/\*(.|\R)*?\*/
|
||||
""".trimIndent()
|
||||
|
||||
private val PATTERN = (
|
||||
"(?<VARIABLE>$VARIABLE_PATTERN)"
|
||||
+ "|(?<PAREN>$PAREN_PATTERN)"
|
||||
+ "|(?<BRACE>$BRACE_PATTERN)"
|
||||
+ "|(?<BRACKET>$BRACKET_PATTERN)"
|
||||
+ "|(?<STRING>$STRING_PATTERN)"
|
||||
+ "|(?<NUMBER>$NUMBER_PATTERN)"
|
||||
+ "|(?<COMMENT>$COMMENT_PATTERN)"
|
||||
+ "|(?<OPERATOR>$OPERATOR_PATTERN)"
|
||||
).toRegex()
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,6 @@ package com.bartlomiejpluta.base.editor.code.model
|
||||
enum class CodeType {
|
||||
JAVA,
|
||||
XML,
|
||||
SQL
|
||||
SQL,
|
||||
PROLOG
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.bartlomiejpluta.base.editor.code.service
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.stereotype.Component
|
||||
import java.nio.file.Path
|
||||
|
||||
@Component
|
||||
class PrologFileService {
|
||||
|
||||
@Autowired
|
||||
private lateinit var appContext: ApplicationContext
|
||||
|
||||
fun toPathString(className: String) = toPath(className).toString() + ".pl"
|
||||
fun toPath(className: String) = Path.of("", *className.split(".").toTypedArray())
|
||||
|
||||
fun ofPath(path: String): String = ofPath(Path.of(path))
|
||||
fun ofPath(path: Path): String = path.joinToString(".")
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.bartlomiejpluta.base.editor.code.stylesheet
|
||||
|
||||
import javafx.scene.text.FontPosture
|
||||
import javafx.scene.text.FontWeight
|
||||
import tornadofx.*
|
||||
|
||||
class PrologSyntaxHighlightingStylesheet : CodeEditorStylesheet() {
|
||||
companion object {
|
||||
val variable by cssclass()
|
||||
val argument by cssclass()
|
||||
val paren by cssclass()
|
||||
val bracket by cssclass()
|
||||
val brace by cssclass()
|
||||
val string by cssclass()
|
||||
val number by cssclass()
|
||||
val operator by cssclass()
|
||||
val field by cssclass()
|
||||
val comment by cssclass()
|
||||
val paragraphBox by cssclass()
|
||||
val paragraphText by cssclass()
|
||||
|
||||
val hasCaret by csspseudoclass()
|
||||
|
||||
val tabSize by cssproperty<Int>("-fx-tab-size")
|
||||
}
|
||||
|
||||
init {
|
||||
paren {
|
||||
fill = c("cadetblue")
|
||||
fontWeight = FontWeight.BOLD
|
||||
}
|
||||
|
||||
bracket {
|
||||
fill = c("darkgreen")
|
||||
fontWeight = FontWeight.BOLD
|
||||
}
|
||||
|
||||
brace {
|
||||
fill = c("teal")
|
||||
fontWeight = FontWeight.BOLD
|
||||
}
|
||||
|
||||
string {
|
||||
fill = c("#008000")
|
||||
}
|
||||
|
||||
number {
|
||||
fill = c("#0000FF")
|
||||
}
|
||||
|
||||
operator {
|
||||
fill = c("#CC7832")
|
||||
}
|
||||
|
||||
variable {
|
||||
fill = c("#BBB529")
|
||||
fontWeight = FontWeight.BOLD
|
||||
}
|
||||
|
||||
argument {
|
||||
fill = c("#000080")
|
||||
fontWeight = FontWeight.BOLD
|
||||
}
|
||||
|
||||
comment {
|
||||
fill = c("#808080")
|
||||
fontStyle = FontPosture.ITALIC
|
||||
}
|
||||
|
||||
paragraphBox and hasCaret {
|
||||
backgroundColor = multi(c("#f2f9fc"))
|
||||
}
|
||||
|
||||
paragraphText {
|
||||
tabSize.value = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.code.view.editor
|
||||
|
||||
import com.bartlomiejpluta.base.editor.code.component.CodeEditor
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.JavaSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.PrologSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.SqlSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.XmlSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.model.CodeScope
|
||||
@@ -23,6 +24,7 @@ class CodeEditorView : View() {
|
||||
private val javaSyntaxHighlighter: JavaSyntaxHighlighter by di()
|
||||
private val xmlSyntaxHighlighter: XmlSyntaxHighlighter by di()
|
||||
private val sqlSyntaxHighlighter: SqlSyntaxHighlighter by di()
|
||||
private val prologSyntaxHighlighter: PrologSyntaxHighlighter by di()
|
||||
|
||||
private val codeVM = find<CodeVM>()
|
||||
|
||||
@@ -31,6 +33,7 @@ class CodeEditorView : View() {
|
||||
CodeType.JAVA -> javaSyntaxHighlighter
|
||||
CodeType.XML -> xmlSyntaxHighlighter
|
||||
CodeType.SQL -> sqlSyntaxHighlighter
|
||||
CodeType.PROLOG -> prologSyntaxHighlighter
|
||||
}
|
||||
}, codeVM.typeProperty)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.code.view.editor
|
||||
|
||||
import com.bartlomiejpluta.base.editor.code.component.CodeEditor
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.JavaSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.PrologSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.SqlSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.highlighting.XmlSyntaxHighlighter
|
||||
import com.bartlomiejpluta.base.editor.code.model.CodeScope
|
||||
@@ -21,6 +22,7 @@ class CodeSnippetView : View() {
|
||||
private val javaSyntaxHighlighter: JavaSyntaxHighlighter by di()
|
||||
private val xmlSyntaxHighlighter: XmlSyntaxHighlighter by di()
|
||||
private val sqlSyntaxHighlighter: SqlSyntaxHighlighter by di()
|
||||
private val prologSyntaxHighlighter: PrologSyntaxHighlighter by di()
|
||||
|
||||
private val codeVM = find<CodeVM>()
|
||||
|
||||
@@ -29,6 +31,7 @@ class CodeSnippetView : View() {
|
||||
CodeType.JAVA -> javaSyntaxHighlighter
|
||||
CodeType.XML -> xmlSyntaxHighlighter
|
||||
CodeType.SQL -> sqlSyntaxHighlighter
|
||||
CodeType.PROLOG -> prologSyntaxHighlighter
|
||||
}
|
||||
}, codeVM.typeProperty)
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.bartlomiejpluta.base.editor.code.view.list
|
||||
|
||||
import com.bartlomiejpluta.base.editor.code.api.APIProvider
|
||||
import com.bartlomiejpluta.base.editor.code.component.PrologFileTreeCell
|
||||
import com.bartlomiejpluta.base.editor.code.component.ScriptFileTreeCell
|
||||
import com.bartlomiejpluta.base.editor.code.service.PrologFileService
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileNode
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileType
|
||||
import com.bartlomiejpluta.base.editor.file.model.PseudoFileNode
|
||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
|
||||
import javafx.scene.control.TextInputDialog
|
||||
import javafx.scene.control.TreeItem
|
||||
import javafx.scene.control.TreeView
|
||||
import javafx.scene.input.MouseButton
|
||||
import tornadofx.View
|
||||
import tornadofx.expandAll
|
||||
import tornadofx.populate
|
||||
import tornadofx.treeview
|
||||
|
||||
class LogicFilesView : View() {
|
||||
private val projectContext: ProjectContext by di()
|
||||
private val mainController: MainController by di()
|
||||
private val prologFileService: PrologFileService by di()
|
||||
|
||||
init {
|
||||
projectContext.projectProperty.addListener { _, _, project ->
|
||||
project?.let {
|
||||
val rootNode = PseudoFileNode.emptyRoot().apply {
|
||||
children += it.logicFSNode
|
||||
}
|
||||
|
||||
treeView.root = TreeItem(rootNode)
|
||||
treeView.populate { item -> item.value?.children }
|
||||
root.root.children[0].expandAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val treeView: TreeView<FileNode> = treeview {
|
||||
isShowRoot = false
|
||||
|
||||
setCellFactory {
|
||||
PrologFileTreeCell(this@LogicFilesView::onCreate, mainController::closeScript)
|
||||
}
|
||||
|
||||
setOnMouseClicked { event ->
|
||||
if (event.button == MouseButton.PRIMARY && event.clickCount == 2) {
|
||||
selectionModel?.selectedItem?.value
|
||||
.takeIf { it?.type == FileType.FILE }
|
||||
?.let { mainController.openScript(it) }
|
||||
|
||||
event.consume()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val root = treeView
|
||||
|
||||
private fun onCreate(fsNode: FileNode) {
|
||||
TextInputDialog().apply {
|
||||
width = 300.0
|
||||
contentText = "File name"
|
||||
title = "New file"
|
||||
}
|
||||
.showAndWait()
|
||||
.map(prologFileService::toPathString)
|
||||
.map { fsNode.createNode(it) }
|
||||
.ifPresent { mainController.openScript(it) }
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.bartlomiejpluta.base.editor.asset.view.list.AssetsListView
|
||||
import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM
|
||||
import com.bartlomiejpluta.base.editor.code.view.build.BuildLogsView
|
||||
import com.bartlomiejpluta.base.editor.code.view.editor.CodeEditorFragment
|
||||
import com.bartlomiejpluta.base.editor.code.view.list.LogicFilesView
|
||||
import com.bartlomiejpluta.base.editor.code.view.list.ScriptFilesView
|
||||
import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
|
||||
import com.bartlomiejpluta.base.editor.database.view.list.TablesListView
|
||||
@@ -34,6 +35,7 @@ class MainView : View("BASE Game Editor") {
|
||||
private val mainMenuView = find<MainMenuView>()
|
||||
private val assetsView = find<AssetsListView>()
|
||||
private val scriptFilesView = find<ScriptFilesView>()
|
||||
private val logicFilesView = find<LogicFilesView>()
|
||||
private val buildLogsView = find<BuildLogsView>()
|
||||
private val processLogsView = find<ProcessLogsView>()
|
||||
private val projectPropertiesView = find<ProjectParametersView>()
|
||||
@@ -113,6 +115,10 @@ class MainView : View("BASE Game Editor") {
|
||||
this += scriptFilesView
|
||||
}
|
||||
|
||||
item("Logic", expanded = false) {
|
||||
this += logicFilesView
|
||||
}
|
||||
|
||||
item("Assets", expanded = false) {
|
||||
this += assetsView
|
||||
}
|
||||
|
||||
@@ -363,6 +363,7 @@ class DefaultProjectContext : ProjectContext {
|
||||
"java" -> CodeType.JAVA
|
||||
"xml" -> CodeType.XML
|
||||
"sql" -> CodeType.SQL
|
||||
"pl" -> CodeType.PROLOG
|
||||
else -> throw IllegalStateException("Unsupported script type")
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -95,6 +95,12 @@ class Project {
|
||||
val codeFSNodeProperty = createObjectBinding({ FileSystemNode(codeDirectory) }, codeDirectoryProperty)
|
||||
val codeFSNode by codeFSNodeProperty
|
||||
|
||||
val logicDirectoryProperty = SimpleObjectProperty<File>()
|
||||
var logicDirectory by logicDirectoryProperty
|
||||
private set
|
||||
val logicFSNodeProperty = createObjectBinding({ FileSystemNode(logicDirectory) }, logicDirectoryProperty)
|
||||
val logicFSNode by logicFSNodeProperty
|
||||
|
||||
// Build directories
|
||||
val buildDirectoryProperty = SimpleObjectProperty<File>()
|
||||
var buildDirectory by buildDirectoryProperty
|
||||
@@ -154,6 +160,7 @@ class Project {
|
||||
widgetsDirectory = File(it, WIDGETS_DIR)
|
||||
audioDirectory = File(it, AUDIO_DIR)
|
||||
codeDirectory = File(it, CODE_DIR)
|
||||
logicDirectory = File(it, LOGIC_DIR)
|
||||
buildDirectory = File(it, BUILD_DIR)
|
||||
buildClassesDirectory = File(it, BUILD_CLASSES_DIR)
|
||||
buildDependenciesDirectory = File(it, BUILD_DEPENDENCIES_DIR)
|
||||
@@ -187,6 +194,7 @@ class Project {
|
||||
widgetsDirectory?.mkdirs()
|
||||
audioDirectory?.mkdirs()
|
||||
codeDirectory?.mkdirs()
|
||||
logicDirectory?.mkdirs()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -207,6 +215,7 @@ class Project {
|
||||
const val WIDGETS_DIR = "widgets"
|
||||
const val AUDIO_DIR = "audio"
|
||||
const val CODE_DIR = "src/main/java"
|
||||
const val LOGIC_DIR = "src/main/prolog"
|
||||
const val BUILD_DIR = "build"
|
||||
const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes"
|
||||
const val BUILD_OUT_DIR = "$BUILD_DIR/out"
|
||||
|
||||
Reference in New Issue
Block a user