mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
chore: improve editor
This commit is contained in:
@@ -4,7 +4,7 @@ plugins {
|
||||
|
||||
|
||||
|
||||
project.version = "0.0.4"
|
||||
project.version = "0.0.5"
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -17,15 +17,13 @@ import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.name
|
||||
|
||||
|
||||
class EditorDialog(file: Path, owner: Window, myDisposable: Disposable) : DialogWrapper(null) {
|
||||
class EditorDialog(file: Path, owner: Window, private val myDisposable: Disposable) : DialogWrapper(null) {
|
||||
|
||||
private val filename = file.name
|
||||
private val filepath = File(file.absolutePathString())
|
||||
private val editorPanel = EditorPanel(this, filepath)
|
||||
|
||||
init {
|
||||
Disposer.register(disposable, myDisposable)
|
||||
|
||||
size = Dimension(UIManager.getInt("Dialog.width"), UIManager.getInt("Dialog.height"))
|
||||
isModal = false
|
||||
controlsVisible = true
|
||||
@@ -49,6 +47,18 @@ class EditorDialog(file: Path, owner: Window, myDisposable: Disposable) : Dialog
|
||||
doCancelAction()
|
||||
}
|
||||
})
|
||||
|
||||
Disposer.register(myDisposable, object : Disposable {
|
||||
override fun dispose() {
|
||||
doCancelAction()
|
||||
}
|
||||
})
|
||||
|
||||
Disposer.register(disposable, object : Disposable {
|
||||
override fun dispose() {
|
||||
Disposer.dispose(myDisposable)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun doCancelAction() {
|
||||
|
||||
@@ -2,18 +2,24 @@ package app.termora.plugins.editor
|
||||
|
||||
import app.termora.DocumentAdaptor
|
||||
import app.termora.DynamicColor
|
||||
import app.termora.EnableManager
|
||||
import app.termora.Icons
|
||||
import app.termora.database.DatabaseManager
|
||||
import com.formdev.flatlaf.FlatLaf
|
||||
import com.formdev.flatlaf.extras.components.FlatTextField
|
||||
import com.formdev.flatlaf.extras.components.FlatToolBar
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.apache.commons.io.FilenameUtils
|
||||
import org.dom4j.io.OutputFormat
|
||||
import org.dom4j.io.SAXReader
|
||||
import org.dom4j.io.XMLWriter
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
||||
import org.fife.ui.rsyntaxtextarea.Theme
|
||||
import org.fife.ui.rtextarea.RTextScrollPane
|
||||
import org.fife.ui.rtextarea.SearchContext
|
||||
import org.fife.ui.rtextarea.SearchEngine
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Insets
|
||||
import java.awt.event.ActionEvent
|
||||
@@ -21,22 +27,40 @@ import java.awt.event.KeyEvent
|
||||
import java.awt.event.WindowAdapter
|
||||
import java.awt.event.WindowEvent
|
||||
import java.io.File
|
||||
import java.io.StringReader
|
||||
import java.io.StringWriter
|
||||
import javax.swing.*
|
||||
import javax.swing.SwingConstants.VERTICAL
|
||||
import javax.swing.event.DocumentEvent
|
||||
import kotlin.math.max
|
||||
|
||||
class EditorPanel(private val window: JDialog, private val file: File) : JPanel(BorderLayout()) {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(EditorPanel::class.java)
|
||||
}
|
||||
|
||||
private var text = file.readText(Charsets.UTF_8)
|
||||
private val layeredPane = LayeredPane()
|
||||
|
||||
private val textArea = RSyntaxTextArea()
|
||||
private val scrollPane = RTextScrollPane(textArea)
|
||||
private val findPanel = FlatToolBar().apply { isFloatable = false }
|
||||
private val toolbar = FlatToolBar().apply { isFloatable = false }
|
||||
private val searchTextField = FlatTextField()
|
||||
private val closeFindPanelBtn = JButton(Icons.close)
|
||||
private val nextBtn = JButton(Icons.down)
|
||||
private val prevBtn = JButton(Icons.up)
|
||||
private val context = SearchContext()
|
||||
private val softWrapBtn = JToggleButton(Icons.softWrap)
|
||||
private val scrollUpBtn = JButton(Icons.scrollUp)
|
||||
private val scrollEndBtn = JButton(Icons.scrollDown)
|
||||
private val prettyBtn = JButton(Icons.reformatCode)
|
||||
|
||||
private val enableManager get() = EnableManager.getInstance()
|
||||
private val prettyJson = Json {
|
||||
prettyPrint = true
|
||||
}
|
||||
|
||||
init {
|
||||
initView()
|
||||
@@ -48,6 +72,7 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
textArea.font = textArea.font.deriveFont(DatabaseManager.getInstance().terminal.fontSize.toFloat())
|
||||
textArea.text = text
|
||||
textArea.antiAliasingEnabled = true
|
||||
softWrapBtn.isSelected = enableManager.getFlag("Plugins.editor.softWrap", false)
|
||||
|
||||
val theme = if (FlatLaf.isLafDark())
|
||||
Theme.load(javaClass.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml"))
|
||||
@@ -89,9 +114,13 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
else -> SyntaxConstants.SYNTAX_STYLE_NONE
|
||||
}
|
||||
|
||||
// 只有 JSON 才可以格式化
|
||||
prettyBtn.isVisible = textArea.syntaxEditingStyle == SyntaxConstants.SYNTAX_STYLE_JSON ||
|
||||
textArea.syntaxEditingStyle == SyntaxConstants.SYNTAX_STYLE_XML
|
||||
|
||||
textArea.discardAllEdits()
|
||||
|
||||
scrollPane.border = BorderFactory.createMatteBorder(1, 0, 0, 0, DynamicColor.BorderColor)
|
||||
scrollPane.border = BorderFactory.createMatteBorder(0, 0, 0, 1, DynamicColor.BorderColor)
|
||||
|
||||
findPanel.isVisible = false
|
||||
findPanel.isOpaque = true
|
||||
@@ -110,8 +139,19 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
BorderFactory.createEmptyBorder(2, 2, 2, 2)
|
||||
)
|
||||
|
||||
toolbar.orientation = VERTICAL
|
||||
toolbar.add(scrollUpBtn)
|
||||
toolbar.add(prettyBtn)
|
||||
toolbar.add(softWrapBtn)
|
||||
toolbar.add(scrollEndBtn)
|
||||
|
||||
val viewPanel = JPanel(BorderLayout())
|
||||
viewPanel.add(scrollPane, BorderLayout.CENTER)
|
||||
viewPanel.add(toolbar, BorderLayout.EAST)
|
||||
viewPanel.border = BorderFactory.createMatteBorder(1, 0, 0, 0, DynamicColor.BorderColor)
|
||||
|
||||
layeredPane.add(findPanel, JLayeredPane.MODAL_LAYER as Any)
|
||||
layeredPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER as Any)
|
||||
layeredPane.add(viewPanel, JLayeredPane.DEFAULT_LAYER as Any)
|
||||
|
||||
add(layeredPane, BorderLayout.CENTER)
|
||||
}
|
||||
@@ -126,6 +166,13 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
}
|
||||
})
|
||||
|
||||
softWrapBtn.addActionListener {
|
||||
enableManager.getFlag("Plugins.editor.softWrap", softWrapBtn.isSelected)
|
||||
textArea.lineWrap = softWrapBtn.isSelected
|
||||
}
|
||||
|
||||
scrollUpBtn.addActionListener { scrollPane.verticalScrollBar.value = 0 }
|
||||
scrollEndBtn.addActionListener { scrollPane.verticalScrollBar.value = scrollPane.verticalScrollBar.maximum }
|
||||
|
||||
textArea.inputMap.put(
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_S, toolkit.menuShortcutKeyMaskEx),
|
||||
@@ -135,6 +182,10 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_F, toolkit.menuShortcutKeyMaskEx),
|
||||
"Find"
|
||||
)
|
||||
textArea.inputMap.put(
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_F, toolkit.menuShortcutKeyMaskEx or KeyEvent.SHIFT_DOWN_MASK),
|
||||
"Format"
|
||||
)
|
||||
|
||||
searchTextField.inputMap.put(
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
||||
@@ -159,6 +210,33 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
}
|
||||
})
|
||||
|
||||
textArea.actionMap.put("Format", object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) {
|
||||
if (textArea.syntaxEditingStyle == SyntaxConstants.SYNTAX_STYLE_JSON) {
|
||||
runCatching {
|
||||
val json = prettyJson.parseToJsonElement(textArea.text)
|
||||
textArea.text = prettyJson.encodeToString(json)
|
||||
}.onFailure {
|
||||
if (log.isErrorEnabled) {
|
||||
log.error(it.message, it)
|
||||
}
|
||||
}
|
||||
} else if (textArea.syntaxEditingStyle == SyntaxConstants.SYNTAX_STYLE_XML) {
|
||||
runCatching {
|
||||
val document = SAXReader().read(StringReader(textArea.text))
|
||||
val sw = StringWriter()
|
||||
val writer = XMLWriter(sw, OutputFormat.createPrettyPrint())
|
||||
writer.write(document)
|
||||
textArea.text = sw.toString()
|
||||
}.onFailure {
|
||||
if (log.isErrorEnabled) {
|
||||
log.error(it.message, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
textArea.actionMap.put("Find", object : AbstractAction("Find") {
|
||||
override fun actionPerformed(e: ActionEvent) {
|
||||
findPanel.isVisible = true
|
||||
@@ -185,6 +263,10 @@ class EditorPanel(private val window: JDialog, private val file: File) : JPanel(
|
||||
|
||||
searchTextField.addActionListener { nextBtn.doClick(0) }
|
||||
|
||||
|
||||
|
||||
prettyBtn.addActionListener(searchTextField.actionMap.get("Format"))
|
||||
|
||||
prevBtn.addActionListener { search(false) }
|
||||
nextBtn.addActionListener { search(true) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user