mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: support fallback font
This commit is contained in:
@@ -437,6 +437,7 @@ tasks.register<Exec>("jpackage") {
|
|||||||
// NSWindow
|
// NSWindow
|
||||||
options.add("-Dapple.awt.application.appearance=system")
|
options.add("-Dapple.awt.application.appearance=system")
|
||||||
options.add("--add-opens java.desktop/java.awt=ALL-UNNAMED")
|
options.add("--add-opens java.desktop/java.awt=ALL-UNNAMED")
|
||||||
|
options.add("--add-opens java.desktop/sun.font=ALL-UNNAMED")
|
||||||
options.add("--add-opens java.desktop/sun.lwawt=ALL-UNNAMED")
|
options.add("--add-opens java.desktop/sun.lwawt=ALL-UNNAMED")
|
||||||
options.add("--add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED")
|
options.add("--add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED")
|
||||||
options.add("--add-opens java.desktop/sun.lwawt.macosx.concurrent=ALL-UNNAMED")
|
options.add("--add-opens java.desktop/sun.lwawt.macosx.concurrent=ALL-UNNAMED")
|
||||||
|
|||||||
71
src/main/kotlin/app/termora/FontComboBox.kt
Normal file
71
src/main/kotlin/app/termora/FontComboBox.kt
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package app.termora
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.extras.components.FlatComboBox
|
||||||
|
import com.formdev.flatlaf.util.FontUtils
|
||||||
|
import java.awt.Component
|
||||||
|
import java.awt.Dimension
|
||||||
|
import javax.swing.DefaultListCellRenderer
|
||||||
|
import javax.swing.JList
|
||||||
|
import javax.swing.event.PopupMenuEvent
|
||||||
|
import javax.swing.event.PopupMenuListener
|
||||||
|
|
||||||
|
class FontComboBox : FlatComboBox<String>() {
|
||||||
|
private var fontsLoaded = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val fontComboBox = this
|
||||||
|
fontComboBox.renderer = object : DefaultListCellRenderer() {
|
||||||
|
init {
|
||||||
|
preferredSize = Dimension(preferredSize.width, fontComboBox.preferredSize.height - 2)
|
||||||
|
maximumSize = Dimension(preferredSize.width, preferredSize.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getListCellRendererComponent(
|
||||||
|
list: JList<*>?,
|
||||||
|
value: Any?,
|
||||||
|
index: Int,
|
||||||
|
isSelected: Boolean,
|
||||||
|
cellHasFocus: Boolean
|
||||||
|
): Component {
|
||||||
|
var text = value
|
||||||
|
if (text is String) {
|
||||||
|
if (text.isBlank()) {
|
||||||
|
text = "<None>"
|
||||||
|
}
|
||||||
|
return super.getListCellRendererComponent(
|
||||||
|
list,
|
||||||
|
"<html><font face='$text'>$text</font></html>",
|
||||||
|
index,
|
||||||
|
isSelected,
|
||||||
|
cellHasFocus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fontComboBox.maximumSize = fontComboBox.preferredSize
|
||||||
|
|
||||||
|
fontComboBox.addPopupMenuListener(object : PopupMenuListener {
|
||||||
|
override fun popupMenuWillBecomeVisible(e: PopupMenuEvent) {
|
||||||
|
if (fontsLoaded) return
|
||||||
|
val selectedItem = fontComboBox.selectedItem
|
||||||
|
val families = getItems()
|
||||||
|
for (family in FontUtils.getAvailableFontFamilyNames()) {
|
||||||
|
if (families.contains(family).not()) fontComboBox.addItem(family)
|
||||||
|
}
|
||||||
|
fontComboBox.selectedItem = selectedItem
|
||||||
|
fontsLoaded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popupMenuWillBecomeInvisible(e: PopupMenuEvent) {}
|
||||||
|
override fun popupMenuCanceled(e: PopupMenuEvent) {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getItems(): Set<String> {
|
||||||
|
val families = mutableSetOf<String>()
|
||||||
|
for (i in 0 until itemCount) families.add(getItemAt(i))
|
||||||
|
return families
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@ import com.formdev.flatlaf.FlatClientProperties
|
|||||||
import com.formdev.flatlaf.extras.components.FlatComboBox
|
import com.formdev.flatlaf.extras.components.FlatComboBox
|
||||||
import com.formdev.flatlaf.extras.components.FlatPopupMenu
|
import com.formdev.flatlaf.extras.components.FlatPopupMenu
|
||||||
import com.formdev.flatlaf.extras.components.FlatToolBar
|
import com.formdev.flatlaf.extras.components.FlatToolBar
|
||||||
import com.formdev.flatlaf.util.FontUtils
|
|
||||||
import com.formdev.flatlaf.util.SystemInfo
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
import com.jgoodies.forms.builder.FormBuilder
|
import com.jgoodies.forms.builder.FormBuilder
|
||||||
import com.jgoodies.forms.layout.FormLayout
|
import com.jgoodies.forms.layout.FormLayout
|
||||||
@@ -29,7 +28,6 @@ import org.apache.commons.lang3.StringUtils
|
|||||||
import org.apache.commons.lang3.SystemUtils
|
import org.apache.commons.lang3.SystemUtils
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import java.awt.Component
|
import java.awt.Component
|
||||||
import java.awt.Dimension
|
|
||||||
import java.awt.Toolkit
|
import java.awt.Toolkit
|
||||||
import java.awt.event.ActionEvent
|
import java.awt.event.ActionEvent
|
||||||
import java.awt.event.ItemEvent
|
import java.awt.event.ItemEvent
|
||||||
@@ -399,7 +397,8 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
private val debugComboBox = YesOrNoComboBox()
|
private val debugComboBox = YesOrNoComboBox()
|
||||||
private val beepComboBox = YesOrNoComboBox()
|
private val beepComboBox = YesOrNoComboBox()
|
||||||
private val cursorBlinkComboBox = YesOrNoComboBox()
|
private val cursorBlinkComboBox = YesOrNoComboBox()
|
||||||
private val fontComboBox = FlatComboBox<String>()
|
private val fontComboBox = FontComboBox()
|
||||||
|
private val fallbackFontComboBox = FontComboBox()
|
||||||
private val shellComboBox = FlatComboBox<String>()
|
private val shellComboBox = FlatComboBox<String>()
|
||||||
private val maxRowsTextField = IntSpinner(0, 0)
|
private val maxRowsTextField = IntSpinner(0, 0)
|
||||||
private val fontSizeTextField = IntSpinner(0, 9, 99)
|
private val fontSizeTextField = IntSpinner(0, 9, 99)
|
||||||
@@ -418,6 +417,13 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fallbackFontComboBox.addItemListener {
|
||||||
|
if (it.stateChange == ItemEvent.SELECTED) {
|
||||||
|
terminalSetting.fallbackFont = fallbackFontComboBox.selectedItem as String
|
||||||
|
fireFontChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
autoCloseTabComboBox.addItemListener { e ->
|
autoCloseTabComboBox.addItemListener { e ->
|
||||||
if (e.stateChange == ItemEvent.SELECTED) {
|
if (e.stateChange == ItemEvent.SELECTED) {
|
||||||
terminalSetting.autoCloseTabWhenDisconnected = autoCloseTabComboBox.selectedItem as Boolean
|
terminalSetting.autoCloseTabWhenDisconnected = autoCloseTabComboBox.selectedItem as Boolean
|
||||||
@@ -526,33 +532,6 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fontComboBox.renderer = object : DefaultListCellRenderer() {
|
|
||||||
init {
|
|
||||||
preferredSize = Dimension(preferredSize.width, fontComboBox.preferredSize.height - 2)
|
|
||||||
maximumSize = Dimension(preferredSize.width, preferredSize.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getListCellRendererComponent(
|
|
||||||
list: JList<*>?,
|
|
||||||
value: Any?,
|
|
||||||
index: Int,
|
|
||||||
isSelected: Boolean,
|
|
||||||
cellHasFocus: Boolean
|
|
||||||
): Component {
|
|
||||||
if (value is String) {
|
|
||||||
return super.getListCellRendererComponent(
|
|
||||||
list,
|
|
||||||
"<html><font face='$value'>$value</font></html>",
|
|
||||||
index,
|
|
||||||
isSelected,
|
|
||||||
cellHasFocus
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fontComboBox.maximumSize = fontComboBox.preferredSize
|
|
||||||
|
|
||||||
cursorStyleComboBox.addItem(CursorStyle.Block)
|
cursorStyleComboBox.addItem(CursorStyle.Block)
|
||||||
cursorStyleComboBox.addItem(CursorStyle.Bar)
|
cursorStyleComboBox.addItem(CursorStyle.Bar)
|
||||||
cursorStyleComboBox.addItem(CursorStyle.Underline)
|
cursorStyleComboBox.addItem(CursorStyle.Underline)
|
||||||
@@ -566,29 +545,18 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
shellComboBox.selectedItem = terminalSetting.localShell
|
shellComboBox.selectedItem = terminalSetting.localShell
|
||||||
|
|
||||||
fontComboBox.addItem(terminalSetting.font)
|
fontComboBox.addItem(terminalSetting.font)
|
||||||
var fontsLoaded = false
|
val items = fontComboBox.getItems()
|
||||||
|
for (family in listOf("JetBrains Mono", "Source Code Pro", "Monospaced")) {
|
||||||
fontComboBox.addPopupMenuListener(object : PopupMenuListener {
|
if (items.contains(family).not()) fontComboBox.addItem(family)
|
||||||
override fun popupMenuWillBecomeVisible(e: PopupMenuEvent) {
|
|
||||||
if (!fontsLoaded) {
|
|
||||||
val selectedItem = fontComboBox.selectedItem
|
|
||||||
fontComboBox.removeAllItems();
|
|
||||||
fontComboBox.addItem("JetBrains Mono")
|
|
||||||
fontComboBox.addItem("Source Code Pro")
|
|
||||||
fontComboBox.addItem("Monospaced")
|
|
||||||
FontUtils.getAvailableFontFamilyNames().forEach {
|
|
||||||
fontComboBox.addItem(it)
|
|
||||||
}
|
|
||||||
fontComboBox.selectedItem = selectedItem
|
|
||||||
fontsLoaded = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popupMenuWillBecomeInvisible(e: PopupMenuEvent) {}
|
if (terminalSetting.fallbackFont.isNotBlank()) {
|
||||||
override fun popupMenuCanceled(e: PopupMenuEvent) {}
|
fallbackFontComboBox.addItem(StringUtils.EMPTY)
|
||||||
})
|
}
|
||||||
|
fallbackFontComboBox.addItem(terminalSetting.fallbackFont)
|
||||||
|
|
||||||
fontComboBox.selectedItem = terminalSetting.font
|
fontComboBox.selectedItem = terminalSetting.font
|
||||||
|
fallbackFontComboBox.selectedItem = terminalSetting.fallbackFont
|
||||||
debugComboBox.selectedItem = terminalSetting.debug
|
debugComboBox.selectedItem = terminalSetting.debug
|
||||||
beepComboBox.selectedItem = terminalSetting.beep
|
beepComboBox.selectedItem = terminalSetting.beep
|
||||||
hyperlinkComboBox.selectedItem = terminalSetting.hyperlink
|
hyperlinkComboBox.selectedItem = terminalSetting.hyperlink
|
||||||
@@ -627,7 +595,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
private fun getCenterComponent(): JComponent {
|
private fun getCenterComponent(): JComponent {
|
||||||
val layout = FormLayout(
|
val layout = FormLayout(
|
||||||
"left:pref, $FORM_MARGIN, default:grow, $FORM_MARGIN, left:pref, $FORM_MARGIN, pref, default:grow",
|
"left:pref, $FORM_MARGIN, default:grow, $FORM_MARGIN, left:pref, $FORM_MARGIN, pref, default:grow",
|
||||||
"pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref"
|
"pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref"
|
||||||
)
|
)
|
||||||
|
|
||||||
val beepBtn = JButton(Icons.run)
|
val beepBtn = JButton(Icons.run)
|
||||||
@@ -643,6 +611,8 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
.add(fontComboBox).xy(3, rows)
|
.add(fontComboBox).xy(3, rows)
|
||||||
.add("${I18n.getString("termora.settings.terminal.size")}:").xy(5, rows)
|
.add("${I18n.getString("termora.settings.terminal.size")}:").xy(5, rows)
|
||||||
.add(fontSizeTextField).xy(7, rows).apply { rows += step }
|
.add(fontSizeTextField).xy(7, rows).apply { rows += step }
|
||||||
|
.add("${I18n.getString("termora.settings.terminal.fallback-font")}:").xy(1, rows)
|
||||||
|
.add(fallbackFontComboBox).xy(3, rows).apply { rows += step }
|
||||||
.add("${I18n.getString("termora.settings.terminal.max-rows")}:").xy(1, rows)
|
.add("${I18n.getString("termora.settings.terminal.max-rows")}:").xy(1, rows)
|
||||||
.add(maxRowsTextField).xy(3, rows).apply { rows += step }
|
.add(maxRowsTextField).xy(3, rows).apply { rows += step }
|
||||||
.add("${I18n.getString("termora.settings.terminal.debug")}:").xy(1, rows)
|
.add("${I18n.getString("termora.settings.terminal.debug")}:").xy(1, rows)
|
||||||
|
|||||||
@@ -619,6 +619,11 @@ class DatabaseManager private constructor() : Disposable {
|
|||||||
*/
|
*/
|
||||||
var font by StringPropertyDelegate("JetBrains Mono")
|
var font by StringPropertyDelegate("JetBrains Mono")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回退字体
|
||||||
|
*/
|
||||||
|
var fallbackFont by StringPropertyDelegate(StringUtils.EMPTY)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认终端
|
* 默认终端
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import app.termora.assertEventDispatchThread
|
|||||||
import app.termora.database.DatabaseManager
|
import app.termora.database.DatabaseManager
|
||||||
import app.termora.swingCoroutineScope
|
import app.termora.swingCoroutineScope
|
||||||
import app.termora.terminal.*
|
import app.termora.terminal.*
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -23,9 +24,15 @@ class TerminalDisplay(
|
|||||||
private val terminalBlink: TerminalBlink
|
private val terminalBlink: TerminalBlink
|
||||||
) : JComponent() {
|
) : JComponent() {
|
||||||
|
|
||||||
|
enum class RendererFont {
|
||||||
|
Base,
|
||||||
|
Monospaced,
|
||||||
|
Fallback,
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val lru = object : LinkedHashMap<String, Boolean>() {
|
private val lru = object : LinkedHashMap<String, RendererFont>() {
|
||||||
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, Boolean>?): Boolean {
|
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, RendererFont>?): Boolean {
|
||||||
return size > 2048
|
return size > 2048
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,6 +47,7 @@ class TerminalDisplay(
|
|||||||
private var boldFont = font.deriveFont(Font.BOLD)
|
private var boldFont = font.deriveFont(Font.BOLD)
|
||||||
private var italicFont = font.deriveFont(Font.ITALIC)
|
private var italicFont = font.deriveFont(Font.ITALIC)
|
||||||
private var boldItalicFont = font.deriveFont(Font.ITALIC or Font.BOLD)
|
private var boldItalicFont = font.deriveFont(Font.ITALIC or Font.BOLD)
|
||||||
|
private var fallbackFont = getFallbackTerminalFont()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 正在输入的内容
|
* 正在输入的内容
|
||||||
@@ -179,15 +187,22 @@ class TerminalDisplay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkFont() {
|
private fun checkFont() {
|
||||||
// 如果字体已经改变,那么这里刷新字体
|
val terminal = DatabaseManager.getInstance().terminal
|
||||||
if (font.family != DatabaseManager.getInstance().terminal.font
|
|
||||||
|| font.size != DatabaseManager.getInstance().terminal.fontSize
|
if ((terminal.fallbackFont.isNotBlank() && fallbackFont == null) ||
|
||||||
|
(terminal.fallbackFont.isBlank() && fallbackFont != null) ||
|
||||||
|
(terminal.fallbackFont != fallbackFont?.family) ||
|
||||||
|
(font.size != terminal.fontSize)
|
||||||
) {
|
) {
|
||||||
|
fallbackFont = getFallbackTerminalFont()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.family != terminal.font || font.size != terminal.fontSize) {
|
||||||
font = getTerminalFont()
|
font = getTerminalFont()
|
||||||
monospacedFont = Font(Font.MONOSPACED, font.style, font.size)
|
|
||||||
boldFont = font.deriveFont(Font.BOLD)
|
boldFont = font.deriveFont(Font.BOLD)
|
||||||
italicFont = font.deriveFont(Font.ITALIC)
|
italicFont = font.deriveFont(Font.ITALIC)
|
||||||
boldItalicFont = font.deriveFont(Font.ITALIC or Font.BOLD)
|
boldItalicFont = font.deriveFont(Font.ITALIC or Font.BOLD)
|
||||||
|
monospacedFont = Font(Font.MONOSPACED, font.style, font.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +410,7 @@ class TerminalDisplay(
|
|||||||
fun getDisplayFont(text: String, style: TextStyle): Font {
|
fun getDisplayFont(text: String, style: TextStyle): Font {
|
||||||
assertEventDispatchThread()
|
assertEventDispatchThread()
|
||||||
|
|
||||||
var font = if (style.bold && style.italic) {
|
val displayFont = if (style.bold && style.italic) {
|
||||||
boldItalicFont
|
boldItalicFont
|
||||||
} else if (style.italic) {
|
} else if (style.italic) {
|
||||||
italicFont
|
italicFont
|
||||||
@@ -405,16 +420,37 @@ class TerminalDisplay(
|
|||||||
font
|
font
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var font = displayFont
|
||||||
|
|
||||||
val key = "${font.fontName}:${font.style}:${font.size}:${text}"
|
val key = "${font.fontName}:${font.style}:${font.size}:${text}"
|
||||||
if (lru.containsKey(key)) {
|
if (lru.containsKey(key)) {
|
||||||
if (!lru.getValue(key)) {
|
val c = lru.getValue(key)
|
||||||
font = monospacedFont
|
font = when (c) {
|
||||||
|
RendererFont.Base -> font
|
||||||
|
RendererFont.Fallback -> fallbackFont ?: monospacedFont
|
||||||
|
else -> monospacedFont
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((font.canDisplayUpTo(text) != -1).also { lru[key] = !it }) {
|
// >=0 表示不支持
|
||||||
font = monospacedFont
|
if (FontCanDisplay.canDisplayUpTo(font, text) != -1) {
|
||||||
|
val fallbackTerminalFont = fallbackFont ?: monospacedFont
|
||||||
|
font = if (fallbackTerminalFont.fontName == monospacedFont.fontName) {
|
||||||
|
monospacedFont
|
||||||
|
} else if (FontCanDisplay.canDisplayUpTo(fallbackTerminalFont, text) != -1) {
|
||||||
|
monospacedFont
|
||||||
|
} else {
|
||||||
|
fallbackTerminalFont
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// macOS 比较特殊,因为它可以自动选择 PingFang,而 PingFang 在 macOS 效果最好(前提是回退字体可用的情况下)
|
||||||
|
if (SystemInfo.isMacOS) {
|
||||||
|
if (font == monospacedFont) {
|
||||||
|
font = displayFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return font
|
return font
|
||||||
@@ -438,11 +474,17 @@ class TerminalDisplay(
|
|||||||
|
|
||||||
|
|
||||||
private fun getTerminalFont(): Font {
|
private fun getTerminalFont(): Font {
|
||||||
return Font(
|
val terminal = DatabaseManager.getInstance().terminal
|
||||||
DatabaseManager.getInstance().terminal.font,
|
return Font(terminal.font, Font.PLAIN, terminal.fontSize)
|
||||||
Font.PLAIN,
|
}
|
||||||
DatabaseManager.getInstance().terminal.fontSize
|
|
||||||
)
|
private fun getFallbackTerminalFont(): Font? {
|
||||||
|
val terminal = DatabaseManager.getInstance().terminal
|
||||||
|
return if (terminal.fallbackFont.isBlank()) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
Font(terminal.fallbackFont, Font.PLAIN, terminal.fontSize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toast(text: String, duration: Duration) {
|
fun toast(text: String, duration: Duration) {
|
||||||
@@ -509,4 +551,39 @@ class TerminalDisplay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private object FontCanDisplay {
|
||||||
|
fun canDisplayUpTo(font: Font, str: String): Int {
|
||||||
|
|
||||||
|
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||||
|
return font.canDisplayUpTo(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
val getFontMethod = Font::class.java.getDeclaredMethod("getFont2D")
|
||||||
|
getFontMethod.isAccessible = true
|
||||||
|
val font2d = getFontMethod.invoke(font)
|
||||||
|
val getMapperMethod = font2d.javaClass.getDeclaredMethod("getMapper")
|
||||||
|
getMapperMethod.isAccessible = true
|
||||||
|
val mapper = getMapperMethod.invoke(font2d)
|
||||||
|
val charToGlyphMethod = mapper.javaClass.getDeclaredMethod("charToGlyph", Char::class.java)
|
||||||
|
|
||||||
|
val len = str.length
|
||||||
|
var i = 0
|
||||||
|
while (i < len) {
|
||||||
|
val c = str[i]
|
||||||
|
val glyph = charToGlyphMethod.invoke(mapper, c) as Int
|
||||||
|
if (glyph >= 0) {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (!Character.isHighSurrogate(c)
|
||||||
|
|| (charToGlyphMethod.invoke(mapper, str.codePointAt(i)) as Int) < 0
|
||||||
|
) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
i += 2
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -63,6 +63,7 @@ termora.settings.appearance.confirm-tab-close=Confirm tab close
|
|||||||
|
|
||||||
termora.settings.terminal=Terminal
|
termora.settings.terminal=Terminal
|
||||||
termora.settings.terminal.font=Font
|
termora.settings.terminal.font=Font
|
||||||
|
termora.settings.terminal.fallback-font=Fallback Font
|
||||||
termora.settings.terminal.size=Size
|
termora.settings.terminal.size=Size
|
||||||
termora.settings.terminal.max-rows=Max rows
|
termora.settings.terminal.max-rows=Max rows
|
||||||
termora.settings.terminal.debug=Debug mode
|
termora.settings.terminal.debug=Debug mode
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ termora.find-everywhere.quick-command.local-terminal=本地终端
|
|||||||
|
|
||||||
termora.settings.terminal=终端
|
termora.settings.terminal=终端
|
||||||
termora.settings.terminal.font=字体
|
termora.settings.terminal.font=字体
|
||||||
|
termora.settings.terminal.fallback-font=回退字体
|
||||||
termora.settings.terminal.size=大小
|
termora.settings.terminal.size=大小
|
||||||
termora.settings.terminal.max-rows=最大行数
|
termora.settings.terminal.max-rows=最大行数
|
||||||
termora.settings.terminal.debug=调试模式
|
termora.settings.terminal.debug=调试模式
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ termora.find-everywhere.quick-command.local-terminal=本地端
|
|||||||
|
|
||||||
termora.settings.terminal=終端
|
termora.settings.terminal=終端
|
||||||
termora.settings.terminal.font=字體
|
termora.settings.terminal.font=字體
|
||||||
|
termora.settings.terminal.fallback-font=回退字體
|
||||||
termora.settings.terminal.size=大小
|
termora.settings.terminal.size=大小
|
||||||
termora.settings.terminal.max-rows=最大行數
|
termora.settings.terminal.max-rows=最大行數
|
||||||
termora.settings.terminal.debug=偵錯模式
|
termora.settings.terminal.debug=偵錯模式
|
||||||
|
|||||||
Reference in New Issue
Block a user