mirror of
https://github.com/fcitx5-android/fcitx5-android.git
synced 2026-08-02 04:44:35 +08:00
Add Avro plugin support and integrate Bangla keyboards in KeyboardWindow
This commit is contained in:
parent
736d782bd8
commit
fe8d0894a4
@ -124,6 +124,7 @@ dependencies {
|
||||
implementation(libs.splitties.views.dsl.recyclerview)
|
||||
implementation(libs.splitties.views.recyclerview)
|
||||
implementation(libs.aboutlibraries.core)
|
||||
implementation(project(":plugin:avro"))
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.test.runner)
|
||||
androidTestImplementation(libs.androidx.test.rules)
|
||||
|
||||
@ -24,6 +24,9 @@ import org.fcitx.fcitx5.android.input.dependency.theme
|
||||
import org.fcitx.fcitx5.android.input.picker.PickerWindow
|
||||
import org.fcitx.fcitx5.android.input.popup.PopupActionListener
|
||||
import org.fcitx.fcitx5.android.input.popup.PopupComponent
|
||||
import org.fcitx.fcitx5.android.input.keyboard.bn.BanglaAvroKeyboard
|
||||
import org.fcitx.fcitx5.android.input.keyboard.bn.ProbhatKeyboard
|
||||
import org.fcitx.fcitx5.android.plugin.avro.AvroKeyboardIds
|
||||
import org.fcitx.fcitx5.android.input.wm.EssentialWindow
|
||||
import org.fcitx.fcitx5.android.input.wm.InputWindow
|
||||
import org.fcitx.fcitx5.android.input.wm.InputWindowManager
|
||||
@ -68,7 +71,9 @@ class KeyboardWindow : InputWindow.SimpleInputWindow<KeyboardWindow>(), Essentia
|
||||
private val keyboards: HashMap<String, BaseKeyboard> by lazy {
|
||||
hashMapOf(
|
||||
TextKeyboard.Name to TextKeyboard(context, theme),
|
||||
NumberKeyboard.Name to NumberKeyboard(context, theme)
|
||||
NumberKeyboard.Name to NumberKeyboard(context, theme),
|
||||
BanglaAvroKeyboard.Name to BanglaAvroKeyboard(context, theme),
|
||||
ProbhatKeyboard.Name to ProbhatKeyboard(context, theme),
|
||||
)
|
||||
}
|
||||
private var currentKeyboardName = ""
|
||||
@ -139,7 +144,10 @@ class KeyboardWindow : InputWindow.SimpleInputWindow<KeyboardWindow>(), Essentia
|
||||
}
|
||||
|
||||
override fun onStartInput(info: EditorInfo, capFlags: CapabilityFlags) {
|
||||
val targetLayout = when (info.inputType and InputType.TYPE_MASK_CLASS) {
|
||||
val imeLayout = AvroKeyboardIds.layoutForIme(
|
||||
fcitx.runImmediately { inputMethodEntryCached.uniqueName }
|
||||
)
|
||||
val targetLayout = imeLayout ?: when (info.inputType and InputType.TYPE_MASK_CLASS) {
|
||||
InputType.TYPE_CLASS_NUMBER -> NumberKeyboard.Name
|
||||
InputType.TYPE_CLASS_PHONE -> NumberKeyboard.Name
|
||||
else -> TextKeyboard.Name
|
||||
@ -148,6 +156,14 @@ class KeyboardWindow : InputWindow.SimpleInputWindow<KeyboardWindow>(), Essentia
|
||||
}
|
||||
|
||||
override fun onImeUpdate(ime: InputMethodEntry) {
|
||||
val layout = AvroKeyboardIds.layoutForIme(ime.uniqueName)
|
||||
if (layout != null) {
|
||||
switchLayout(layout, remember = false)
|
||||
} else if (currentKeyboardName == BanglaAvroKeyboard.Name ||
|
||||
currentKeyboardName == ProbhatKeyboard.Name
|
||||
) {
|
||||
switchLayout(TextKeyboard.Name, remember = false)
|
||||
}
|
||||
currentKeyboard?.onInputMethodUpdate(ime)
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.input.keyboard.bn
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.view.allViews
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.InputMethodEntry
|
||||
import org.fcitx.fcitx5.android.core.KeyState
|
||||
import org.fcitx.fcitx5.android.core.KeyStates
|
||||
import org.fcitx.fcitx5.android.core.KeySym
|
||||
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
|
||||
import org.fcitx.fcitx5.android.data.prefs.ManagedPreference
|
||||
import org.fcitx.fcitx5.android.data.theme.Theme
|
||||
import org.fcitx.fcitx5.android.input.keyboard.AlphabetKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.AltTextKeyView
|
||||
import org.fcitx.fcitx5.android.input.keyboard.BackspaceKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.BaseKeyboard
|
||||
import org.fcitx.fcitx5.android.input.keyboard.CapsKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.CommaKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyAction
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyDef
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyDef.Appearance.Variant
|
||||
import org.fcitx.fcitx5.android.input.keyboard.LanguageKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.LayoutSwitchKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.ReturnKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.SpaceKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.SymbolKey
|
||||
import org.fcitx.fcitx5.android.input.popup.PopupAction
|
||||
import org.fcitx.fcitx5.android.plugin.avro.AvroKeyboardIds
|
||||
import splitties.views.imageResource
|
||||
|
||||
/**
|
||||
* Roman QWERTY layout for Bangla Avro phonetic input.
|
||||
* Keys feed the native Avro engine via [KeyAction.FcitxKeyAction].
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class BanglaAvroKeyboard(
|
||||
context: Context,
|
||||
theme: Theme,
|
||||
) : BaseKeyboard(context, theme, Layout) {
|
||||
|
||||
enum class CapsState { None, Once, Lock }
|
||||
|
||||
companion object {
|
||||
const val Name = AvroKeyboardIds.LAYOUT_AVRO
|
||||
|
||||
private val BANGLA_DIGITS = mapOf(
|
||||
'0' to "০", '1' to "১", '2' to "২", '3' to "৩", '4' to "৪",
|
||||
'5' to "৫", '6' to "৬", '7' to "৭", '8' to "৮", '9' to "৯",
|
||||
)
|
||||
|
||||
private val AVRO_PUNCTUATION = mapOf(
|
||||
"0" to "০", "1" to "১", "2" to "২", "3" to "৩", "4" to "৪",
|
||||
"5" to "৫", "6" to "৬", "7" to "৭", "8" to "৮", "9" to "৯",
|
||||
"." to "।",
|
||||
)
|
||||
|
||||
val Layout: List<List<KeyDef>> = listOf(
|
||||
listOf(
|
||||
AlphabetKey("Q", "1"),
|
||||
AlphabetKey("W", "2"),
|
||||
AlphabetKey("E", "3"),
|
||||
AlphabetKey("R", "4"),
|
||||
AlphabetKey("T", "5"),
|
||||
AlphabetKey("Y", "6"),
|
||||
AlphabetKey("U", "7"),
|
||||
AlphabetKey("I", "8"),
|
||||
AlphabetKey("O", "9"),
|
||||
AlphabetKey("P", "0"),
|
||||
),
|
||||
listOf(
|
||||
AlphabetKey("A", "@"),
|
||||
AlphabetKey("S", "#"),
|
||||
AlphabetKey("D", "&"),
|
||||
AlphabetKey("F", "*"),
|
||||
AlphabetKey("G", "-"),
|
||||
AlphabetKey("H", "+"),
|
||||
AlphabetKey("J", "="),
|
||||
AlphabetKey("K", "("),
|
||||
AlphabetKey("L", ")"),
|
||||
),
|
||||
listOf(
|
||||
CapsKey(),
|
||||
AlphabetKey("Z", "_"),
|
||||
AlphabetKey("X", "৳"),
|
||||
AlphabetKey("C", "\""),
|
||||
AlphabetKey("V", "'"),
|
||||
AlphabetKey("B", ":"),
|
||||
AlphabetKey("N", ";"),
|
||||
AlphabetKey("M", "/"),
|
||||
BackspaceKey(),
|
||||
),
|
||||
listOf(
|
||||
LayoutSwitchKey("?123", ""),
|
||||
CommaKey(0.1f, Variant.Alternative),
|
||||
LanguageKey(),
|
||||
SpaceKey(),
|
||||
SymbolKey(".", 0.1f, Variant.Alternative),
|
||||
ReturnKey(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
val caps: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_caps) }
|
||||
val backspace: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_backspace) }
|
||||
val lang: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_lang) }
|
||||
val space: org.fcitx.fcitx5.android.input.keyboard.TextKeyView by lazy { findViewById(R.id.button_space) }
|
||||
val `return`: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_return) }
|
||||
|
||||
private val showLangSwitchKey = AppPrefs.getInstance().keyboard.showLangSwitchKey
|
||||
|
||||
@Keep
|
||||
private val showLangSwitchKeyListener = ManagedPreference.OnChangeListener<Boolean> { _, v ->
|
||||
updateLangSwitchKey(v)
|
||||
}
|
||||
|
||||
private val keepLettersUppercase by AppPrefs.getInstance().keyboard.keepLettersUppercase
|
||||
|
||||
init {
|
||||
updateLangSwitchKey(showLangSwitchKey.getValue())
|
||||
showLangSwitchKey.registerOnChangeListener(showLangSwitchKeyListener)
|
||||
}
|
||||
|
||||
private val textKeys: List<org.fcitx.fcitx5.android.input.keyboard.TextKeyView> by lazy {
|
||||
allViews.filterIsInstance<org.fcitx.fcitx5.android.input.keyboard.TextKeyView>().toList()
|
||||
}
|
||||
|
||||
private var capsState: CapsState = CapsState.None
|
||||
|
||||
private fun transformAlphabet(c: String): String = when (capsState) {
|
||||
CapsState.None -> c.lowercase()
|
||||
else -> c.uppercase()
|
||||
}
|
||||
|
||||
private var punctuationMapping: Map<String, String> = mapOf()
|
||||
private fun transformPunctuation(p: String): String {
|
||||
AVRO_PUNCTUATION[p]?.let { return it }
|
||||
return punctuationMapping.getOrDefault(p, p)
|
||||
}
|
||||
|
||||
override fun onAction(action: KeyAction, source: org.fcitx.fcitx5.android.input.keyboard.KeyActionListener.Source) {
|
||||
var transformed = action
|
||||
when (action) {
|
||||
is KeyAction.FcitxKeyAction -> when (source) {
|
||||
org.fcitx.fcitx5.android.input.keyboard.KeyActionListener.Source.Keyboard -> {
|
||||
val digit = action.act.singleOrNull()?.takeIf(Char::isDigit)
|
||||
if (digit != null) {
|
||||
super.onAction(
|
||||
KeyAction.CommitAction(BANGLA_DIGITS[digit] ?: action.act),
|
||||
source
|
||||
)
|
||||
return
|
||||
}
|
||||
when (capsState) {
|
||||
CapsState.None -> transformed = action.copy(act = action.act.lowercase())
|
||||
CapsState.Once -> {
|
||||
transformed = action.copy(
|
||||
act = action.act.uppercase(),
|
||||
states = KeyStates(KeyState.Virtual, KeyState.Shift),
|
||||
)
|
||||
switchCapsState()
|
||||
}
|
||||
CapsState.Lock -> transformed = action.copy(
|
||||
act = action.act.uppercase(),
|
||||
states = KeyStates(KeyState.Virtual, KeyState.CapsLock),
|
||||
)
|
||||
}
|
||||
}
|
||||
org.fcitx.fcitx5.android.input.keyboard.KeyActionListener.Source.Popup -> {
|
||||
if (capsState == CapsState.Once) switchCapsState()
|
||||
}
|
||||
}
|
||||
is KeyAction.CapsAction -> switchCapsState(action.lock)
|
||||
else -> {}
|
||||
}
|
||||
super.onAction(transformed, source)
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
capsState = CapsState.None
|
||||
updateCapsButtonIcon()
|
||||
updateAlphabetKeys()
|
||||
}
|
||||
|
||||
override fun onReturnDrawableUpdate(returnDrawable: Int) {
|
||||
`return`.img.imageResource = returnDrawable
|
||||
}
|
||||
|
||||
override fun onPunctuationUpdate(mapping: Map<String, String>) {
|
||||
punctuationMapping = mapping
|
||||
updatePunctuationKeys()
|
||||
}
|
||||
|
||||
override fun onInputMethodUpdate(ime: InputMethodEntry) {
|
||||
space.mainText.text = buildString {
|
||||
append(ime.displayName)
|
||||
ime.subMode.run { label.ifEmpty { name.ifEmpty { null } } }?.let { append(" ($it)") }
|
||||
}
|
||||
if (capsState != CapsState.None) switchCapsState()
|
||||
}
|
||||
|
||||
override fun onPopupAction(action: PopupAction) {
|
||||
val newAction = when (action) {
|
||||
is PopupAction.PreviewAction -> action.copy(content = transformPopupPreview(action.content))
|
||||
is PopupAction.PreviewUpdateAction -> action.copy(content = transformPopupPreview(action.content))
|
||||
is PopupAction.ShowKeyboardAction -> {
|
||||
when (action.keyboard) {
|
||||
is KeyDef.Popup.Keyboard.Preset -> {
|
||||
val label = action.keyboard.label
|
||||
if (label.length == 1 && label[0].isLetter()) {
|
||||
action.copy(
|
||||
keyboard = action.keyboard.copy(label = transformAlphabet(label))
|
||||
)
|
||||
} else action
|
||||
}
|
||||
is KeyDef.Popup.Keyboard.Explicit -> action
|
||||
}
|
||||
}
|
||||
else -> action
|
||||
}
|
||||
super.onPopupAction(newAction)
|
||||
}
|
||||
|
||||
private fun transformPopupPreview(c: String): String {
|
||||
if (c.length != 1) return c
|
||||
if (c[0].isLetter()) return transformAlphabet(c)
|
||||
return transformPunctuation(c)
|
||||
}
|
||||
|
||||
private fun switchCapsState(lock: Boolean = false) {
|
||||
capsState = if (lock) {
|
||||
when (capsState) {
|
||||
CapsState.Lock -> CapsState.None
|
||||
else -> CapsState.Lock
|
||||
}
|
||||
} else {
|
||||
when (capsState) {
|
||||
CapsState.None -> CapsState.Once
|
||||
else -> CapsState.None
|
||||
}
|
||||
}
|
||||
updateCapsButtonIcon()
|
||||
updateAlphabetKeys()
|
||||
}
|
||||
|
||||
private fun updateCapsButtonIcon() {
|
||||
caps.img.imageResource = when (capsState) {
|
||||
CapsState.None -> R.drawable.ic_capslock_none
|
||||
CapsState.Once -> R.drawable.ic_capslock_once
|
||||
CapsState.Lock -> R.drawable.ic_capslock_lock
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLangSwitchKey(visible: Boolean) {
|
||||
lang.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun updateAlphabetKeys() {
|
||||
textKeys.forEach {
|
||||
if (it.def !is KeyDef.Appearance.AltText) return
|
||||
it.mainText.text = it.def.displayText.let { str ->
|
||||
if (str.length != 1 || !str[0].isLetter()) return@forEach
|
||||
if (keepLettersUppercase) str.uppercase() else transformAlphabet(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePunctuationKeys() {
|
||||
textKeys.forEach {
|
||||
if (it is AltTextKeyView) {
|
||||
it.def as KeyDef.Appearance.AltText
|
||||
it.altText.text = transformPunctuation(it.def.altText)
|
||||
} else {
|
||||
it.def as KeyDef.Appearance.Text
|
||||
it.mainText.text = it.def.displayText.let { str ->
|
||||
if (str.isEmpty() || str[0].isLetter() || str[0].isWhitespace()) return@forEach
|
||||
transformPunctuation(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.input.keyboard.bn
|
||||
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyAction
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyDef
|
||||
|
||||
/** Key that commits a Bengali (or other) string directly to the editor. */
|
||||
class BengaliCommitKey(
|
||||
displayText: String,
|
||||
commitText: String = displayText,
|
||||
percentWidth: Float = 0.1f,
|
||||
variant: KeyDef.Appearance.Variant = KeyDef.Appearance.Variant.Normal,
|
||||
) : KeyDef(
|
||||
KeyDef.Appearance.Text(
|
||||
displayText = displayText,
|
||||
textSize = 20f,
|
||||
percentWidth = percentWidth,
|
||||
variant = variant,
|
||||
),
|
||||
setOf(
|
||||
KeyDef.Behavior.Press(KeyAction.CommitAction(commitText))
|
||||
),
|
||||
)
|
||||
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.input.keyboard.bn
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.InputMethodEntry
|
||||
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
|
||||
import org.fcitx.fcitx5.android.data.prefs.ManagedPreference
|
||||
import org.fcitx.fcitx5.android.data.theme.Theme
|
||||
import org.fcitx.fcitx5.android.input.keyboard.BackspaceKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.BaseKeyboard
|
||||
import org.fcitx.fcitx5.android.input.keyboard.CommaKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyDef
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyDef.Appearance.Variant
|
||||
import org.fcitx.fcitx5.android.input.keyboard.LanguageKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.LayoutSwitchKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.ReturnKey
|
||||
import org.fcitx.fcitx5.android.input.keyboard.SpaceKey
|
||||
import org.fcitx.fcitx5.android.plugin.avro.AvroKeyboardIds
|
||||
import splitties.views.imageResource
|
||||
|
||||
/**
|
||||
* Probhat fixed-layout Bengali keyboard (Ekushey / OpenBangla normal layer).
|
||||
* Keys commit Bengali characters directly via [KeyAction.CommitAction].
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class ProbhatKeyboard(
|
||||
context: Context,
|
||||
theme: Theme,
|
||||
) : BaseKeyboard(context, theme, Layout) {
|
||||
|
||||
companion object {
|
||||
const val Name = AvroKeyboardIds.LAYOUT_PROBHAT
|
||||
|
||||
// Normal-layer mappings from OpenBangla Probhat.json (Unicode Probhat).
|
||||
private val ROW1 = listOf("দ", "ঊ", "ঈ", "ড়", "ঠ", "ঐ", "উ", "ই", "ঔ", "ফ")
|
||||
private val ROW2 = listOf("অ", "ষ", "ঢ", "থ", "ঘ", "ঃ", "ঝ", "খ", "ং")
|
||||
private val ROW3 = listOf("য", "ঢ়", "ছ", "ঋ", "ভ", "ণ", "ঙ")
|
||||
|
||||
val Layout: List<List<KeyDef>> = listOf(
|
||||
ROW1.map { BengaliCommitKey(it) },
|
||||
ROW2.map { BengaliCommitKey(it) },
|
||||
listOf(
|
||||
BengaliCommitKey("্", variant = Variant.Alternative),
|
||||
*ROW3.map { BengaliCommitKey(it) }.toTypedArray(),
|
||||
BackspaceKey(),
|
||||
),
|
||||
listOf(
|
||||
LayoutSwitchKey("?123", ""),
|
||||
CommaKey(0.1f, Variant.Alternative),
|
||||
LanguageKey(),
|
||||
SpaceKey(),
|
||||
BengaliCommitKey("।", percentWidth = 0.1f, variant = Variant.Alternative),
|
||||
ReturnKey(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
val backspace: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_backspace) }
|
||||
val lang: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_lang) }
|
||||
val space: org.fcitx.fcitx5.android.input.keyboard.TextKeyView by lazy { findViewById(R.id.button_space) }
|
||||
val `return`: org.fcitx.fcitx5.android.input.keyboard.ImageKeyView by lazy { findViewById(R.id.button_return) }
|
||||
|
||||
private val showLangSwitchKey = AppPrefs.getInstance().keyboard.showLangSwitchKey
|
||||
|
||||
@Keep
|
||||
private val showLangSwitchKeyListener = ManagedPreference.OnChangeListener<Boolean> { _, v ->
|
||||
updateLangSwitchKey(v)
|
||||
}
|
||||
|
||||
init {
|
||||
updateLangSwitchKey(showLangSwitchKey.getValue())
|
||||
showLangSwitchKey.registerOnChangeListener(showLangSwitchKeyListener)
|
||||
}
|
||||
|
||||
override fun onAttach() = Unit
|
||||
|
||||
override fun onReturnDrawableUpdate(returnDrawable: Int) {
|
||||
`return`.img.imageResource = returnDrawable
|
||||
}
|
||||
|
||||
override fun onPunctuationUpdate(mapping: Map<String, String>) = Unit
|
||||
|
||||
override fun onInputMethodUpdate(ime: InputMethodEntry) {
|
||||
space.mainText.text = buildString {
|
||||
append(ime.displayName)
|
||||
ime.subMode.run { label.ifEmpty { name.ifEmpty { null } } }?.let { append(" ($it)") }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLangSwitchKey(visible: Boolean) {
|
||||
lang.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
51
plugin/avro/build.gradle.kts
Normal file
51
plugin/avro/build.gradle.kts
Normal file
@ -0,0 +1,51 @@
|
||||
plugins {
|
||||
id("org.fcitx.fcitx5.android.app-convention")
|
||||
id("org.fcitx.fcitx5.android.plugin-app-convention")
|
||||
id("org.fcitx.fcitx5.android.native-app-convention")
|
||||
id("org.fcitx.fcitx5.android.build-metadata")
|
||||
id("org.fcitx.fcitx5.android.data-descriptor")
|
||||
id("org.fcitx.fcitx5.android.fcitx-component")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "org.fcitx.fcitx5.android.plugin.avro"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "org.fcitx.fcitx5.android.plugin.avro"
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
targets("avro")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
resValues = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
resValue("string", "app_name", "@string/app_name_release")
|
||||
proguardFile("proguard-rules.pro")
|
||||
}
|
||||
debug {
|
||||
resValue("string", "app_name", "@string/app_name_debug")
|
||||
}
|
||||
}
|
||||
|
||||
packaging {
|
||||
jniLibs {
|
||||
excludes += setOf(
|
||||
"**/libc++_shared.so",
|
||||
"**/libFcitx5*"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib:fcitx5"))
|
||||
implementation(project(":lib:plugin-base"))
|
||||
}
|
||||
4
plugin/avro/org.fcitx.fcitx5.android.yml
Normal file
4
plugin/avro/org.fcitx.fcitx5.android.yml
Normal file
@ -0,0 +1,4 @@
|
||||
name: Avro Plugin
|
||||
components:
|
||||
- name: plugin
|
||||
type: plugin
|
||||
1
plugin/avro/proguard-rules.pro
vendored
Normal file
1
plugin/avro/proguard-rules.pro
vendored
Normal file
@ -0,0 +1 @@
|
||||
-keep class org.fcitx.fcitx5.android.plugin.avro.** { *; }
|
||||
7
plugin/avro/src/main/AndroidManifest.xml
Normal file
7
plugin/avro/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name" />
|
||||
</manifest>
|
||||
BIN
plugin/avro/src/main/assets/fcitx5/libavro.so
Normal file
BIN
plugin/avro/src/main/assets/fcitx5/libavro.so
Normal file
Binary file not shown.
38
plugin/avro/src/main/cpp/CMakeLists.txt
Normal file
38
plugin/avro/src/main/cpp/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
project(fcitx5-android-plugin-avro VERSION ${VERSION_NAME})
|
||||
|
||||
# For reproducible build
|
||||
add_link_options("LINKER:--hash-style=gnu,--build-id=none")
|
||||
|
||||
# prefab dependency
|
||||
find_package(fcitx5 REQUIRED CONFIG)
|
||||
get_target_property(FCITX5_CMAKE_MODULES fcitx5::cmake INTERFACE_INCLUDE_DIRECTORIES)
|
||||
set(CMAKE_MODULE_PATH ${FCITX5_CMAKE_MODULES} ${CMAKE_MODULE_PATH})
|
||||
|
||||
find_package(ECM MODULE)
|
||||
find_package(Fcitx5Core MODULE)
|
||||
find_package(Fcitx5Module MODULE)
|
||||
|
||||
include("${FCITX_INSTALL_CMAKECONFIG_DIR}/Fcitx5Utils/Fcitx5CompilerSettings.cmake")
|
||||
|
||||
add_fcitx5_addon(avro
|
||||
avro.cpp
|
||||
avro.h
|
||||
avro_parser.cpp
|
||||
avro_parser.h
|
||||
)
|
||||
|
||||
target_link_libraries(avro PRIVATE Fcitx5::Core)
|
||||
|
||||
fcitx5_translate_desktop_file(avro.conf.in avro.conf)
|
||||
fcitx5_translate_desktop_file(probhat.conf.in probhat.conf)
|
||||
configure_file(avro-addon.conf.in.in avro-addon.conf.in COPYONLY)
|
||||
fcitx5_translate_desktop_file("${CMAKE_CURRENT_BINARY_DIR}/avro-addon.conf.in" avro-addon.conf)
|
||||
|
||||
install(TARGETS avro DESTINATION "${CMAKE_INSTALL_LIBDIR}/fcitx5" COMPONENT translation)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avro.conf"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/probhat.conf"
|
||||
DESTINATION "${FCITX_INSTALL_PKGDATADIR}/inputmethod" COMPONENT config)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avro-addon.conf" RENAME avro.conf
|
||||
DESTINATION "${FCITX_INSTALL_PKGDATADIR}/addon" COMPONENT config)
|
||||
7
plugin/avro/src/main/cpp/avro-addon.conf.in.in
Normal file
7
plugin/avro/src/main/cpp/avro-addon.conf.in.in
Normal file
@ -0,0 +1,7 @@
|
||||
[Addon]
|
||||
Name=Avro Bangla Phonetic
|
||||
Category=InputMethod
|
||||
Library=avro
|
||||
Type=SharedLibrary
|
||||
OnDemand=True
|
||||
Configurable=True
|
||||
7
plugin/avro/src/main/cpp/avro.conf.in
Normal file
7
plugin/avro/src/main/cpp/avro.conf.in
Normal file
@ -0,0 +1,7 @@
|
||||
[InputMethod]
|
||||
Name=Avro
|
||||
Icon=fcitx-avro
|
||||
Label=Avro
|
||||
LangCode=bn
|
||||
Addon=avro
|
||||
Configurable=True
|
||||
127
plugin/avro/src/main/cpp/avro.cpp
Normal file
127
plugin/avro/src/main/cpp/avro.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
#include "avro.h"
|
||||
|
||||
#include <fcitx-utils/key.h>
|
||||
#include <fcitx-utils/keysym.h>
|
||||
#include <fcitx/inputpanel.h>
|
||||
#include <fcitx/userinterface.h>
|
||||
|
||||
namespace fcitx {
|
||||
|
||||
FCITX_ADDON_FACTORY(AvroFactory)
|
||||
|
||||
void AvroEngine::activate(const InputMethodEntry &, InputContextEvent &) { buffer_.clear(); }
|
||||
|
||||
void AvroEngine::reset(const InputMethodEntry &, InputContextEvent &) { buffer_.clear(); }
|
||||
|
||||
void AvroEngine::clearBuffer(InputContext *ic) {
|
||||
buffer_.clear();
|
||||
ic->inputPanel().setClientPreedit(Text());
|
||||
ic->updateUserInterface(UserInterfaceComponent::InputPanel);
|
||||
}
|
||||
|
||||
void AvroEngine::updatePreedit(InputContext *ic) {
|
||||
if (buffer_.empty()) {
|
||||
ic->inputPanel().setClientPreedit(Text());
|
||||
} else {
|
||||
ic->inputPanel().setClientPreedit(Text(parser_.parse(buffer_)));
|
||||
}
|
||||
ic->updateUserInterface(UserInterfaceComponent::InputPanel);
|
||||
}
|
||||
|
||||
bool AvroEngine::isProbhatEntry(const InputMethodEntry &entry) {
|
||||
return entry.uniqueName() == "probhat";
|
||||
}
|
||||
|
||||
void AvroEngine::handleProbhatKeyEvent(KeyEvent &keyEvent) {
|
||||
if (keyEvent.isRelease()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const KeyStates modifiers{KeyState::Ctrl, KeyState::Alt};
|
||||
if (keyEvent.key().states() & modifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *ic = keyEvent.inputContext();
|
||||
const auto sym = keyEvent.key().sym();
|
||||
|
||||
if (sym == FcitxKey_BackSpace) {
|
||||
keyEvent.filterAndAccept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sym == FcitxKey_Return) {
|
||||
ic->commitString("\n");
|
||||
keyEvent.filterAndAccept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sym == FcitxKey_space) {
|
||||
ic->commitString(" ");
|
||||
keyEvent.filterAndAccept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyEvent.key().isSimple()) {
|
||||
const auto text = Key::keySymToUTF8(sym);
|
||||
if (!text.empty()) {
|
||||
ic->commitString(text);
|
||||
keyEvent.filterAndAccept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvroEngine::keyEvent(const InputMethodEntry &entry, KeyEvent &keyEvent) {
|
||||
if (isProbhatEntry(entry)) {
|
||||
handleProbhatKeyEvent(keyEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyEvent.isRelease()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const KeyStates modifiers{KeyState::Ctrl, KeyState::Alt};
|
||||
if (keyEvent.key().states() & modifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *ic = keyEvent.inputContext();
|
||||
const auto sym = keyEvent.key().sym();
|
||||
|
||||
if (sym == FcitxKey_BackSpace) {
|
||||
if (buffer_.empty()) {
|
||||
return;
|
||||
}
|
||||
buffer_.pop_back();
|
||||
updatePreedit(ic);
|
||||
keyEvent.filterAndAccept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sym == FcitxKey_Return || sym == FcitxKey_space) {
|
||||
if (!buffer_.empty()) {
|
||||
const auto commit = parser_.parse(buffer_);
|
||||
ic->commitString(commit + (sym == FcitxKey_space ? " " : "\n"));
|
||||
clearBuffer(ic);
|
||||
keyEvent.filterAndAccept();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyEvent.key().isSimple()) {
|
||||
const auto ch = static_cast<char>(sym);
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '`' || ch == '^' ||
|
||||
ch == ',' || ch == '.' || (ch >= '0' && ch <= '9')) {
|
||||
buffer_.push_back(ch);
|
||||
updatePreedit(ic);
|
||||
keyEvent.filterAndAccept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fcitx
|
||||
48
plugin/avro/src/main/cpp/avro.h
Normal file
48
plugin/avro/src/main/cpp/avro.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
#ifndef FCITX_AVRO_AVRO_H
|
||||
#define FCITX_AVRO_AVRO_H
|
||||
|
||||
#include <fcitx/addonfactory.h>
|
||||
#include <fcitx/addonmanager.h>
|
||||
#include <fcitx/inputcontext.h>
|
||||
#include <fcitx/inputmethodengine.h>
|
||||
#include <fcitx/instance.h>
|
||||
#include <fcitx/text.h>
|
||||
#include <fcitx-utils/misc.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "avro_parser.h"
|
||||
|
||||
namespace fcitx {
|
||||
|
||||
class AvroEngine : public InputMethodEngine {
|
||||
public:
|
||||
explicit AvroEngine(Instance *instance) { FCITX_UNUSED(instance); }
|
||||
|
||||
void keyEvent(const InputMethodEntry &entry, KeyEvent &keyEvent) override;
|
||||
void activate(const InputMethodEntry &entry, InputContextEvent &event) override;
|
||||
void reset(const InputMethodEntry &entry, InputContextEvent &event) override;
|
||||
|
||||
private:
|
||||
static bool isProbhatEntry(const InputMethodEntry &entry);
|
||||
void handleProbhatKeyEvent(KeyEvent &keyEvent);
|
||||
void updatePreedit(InputContext *ic);
|
||||
void clearBuffer(InputContext *ic);
|
||||
|
||||
AvroParser parser_;
|
||||
std::string buffer_;
|
||||
};
|
||||
|
||||
class AvroFactory : public AddonFactory {
|
||||
public:
|
||||
AddonInstance *create(AddonManager *manager) override {
|
||||
return new AvroEngine(manager->instance());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fcitx
|
||||
|
||||
#endif
|
||||
150
plugin/avro/src/main/cpp/avro_parser.cpp
Normal file
150
plugin/avro/src/main/cpp/avro_parser.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
#include "avro_parser.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace fcitx {
|
||||
|
||||
namespace {
|
||||
std::vector<AvroPattern> makePatterns();
|
||||
std::string makeVowels();
|
||||
std::string makeConsonants();
|
||||
std::string makeCaseSensitive();
|
||||
} // namespace
|
||||
|
||||
AvroParser::AvroParser()
|
||||
: patterns_(makePatterns()), vowel_(makeVowels()), consonant_(makeConsonants()),
|
||||
caseSensitive_(makeCaseSensitive()) {}
|
||||
|
||||
bool AvroParser::isExact(const std::string &needle, const std::string &haystack, int start,
|
||||
int end, bool negate) {
|
||||
const bool equal = start >= 0 && end <= static_cast<int>(haystack.size()) &&
|
||||
haystack.substr(start, end - start) == needle;
|
||||
return equal ^ negate;
|
||||
}
|
||||
|
||||
bool AvroParser::isVowel(char c) const {
|
||||
const auto lower = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return vowel_.find(lower) != std::string::npos;
|
||||
}
|
||||
|
||||
bool AvroParser::isConsonant(char c) const {
|
||||
const auto lower = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return consonant_.find(lower) != std::string::npos;
|
||||
}
|
||||
|
||||
bool AvroParser::isPunctuation(char c) const { return !(isVowel(c) || isConsonant(c)); }
|
||||
|
||||
bool AvroParser::isCaseSensitive(char c) const {
|
||||
const auto lower = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return caseSensitive_.find(lower) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string AvroParser::fixString(const std::string &input) const {
|
||||
std::string fixed;
|
||||
fixed.reserve(input.size());
|
||||
for (auto c : input) {
|
||||
if (isCaseSensitive(c)) {
|
||||
fixed.push_back(c);
|
||||
} else {
|
||||
fixed.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
|
||||
}
|
||||
}
|
||||
return fixed;
|
||||
}
|
||||
|
||||
std::string AvroParser::parse(const std::string &input) const {
|
||||
const auto fixed = fixString(input);
|
||||
std::string output;
|
||||
output.reserve(fixed.size() * 2);
|
||||
|
||||
int cur = 0;
|
||||
while (cur < static_cast<int>(fixed.size())) {
|
||||
const int start = cur;
|
||||
bool matched = false;
|
||||
|
||||
for (const auto &pattern : patterns_) {
|
||||
const int end = cur + static_cast<int>(pattern.find.size());
|
||||
if (end > static_cast<int>(fixed.size()) ||
|
||||
fixed.substr(start, pattern.find.size()) != pattern.find) {
|
||||
continue;
|
||||
}
|
||||
const int prev = start - 1;
|
||||
|
||||
if (!pattern.rules.empty()) {
|
||||
for (const auto &rule : pattern.rules) {
|
||||
bool replace = true;
|
||||
for (const auto &m : rule.matches) {
|
||||
const int chk = m.type == "suffix" ? end : prev;
|
||||
bool cond = false;
|
||||
if (m.scope == "punctuation") {
|
||||
cond = (chk < 0 && m.type == "prefix") ||
|
||||
(chk >= static_cast<int>(fixed.size()) && m.type == "suffix") ||
|
||||
(chk >= 0 && chk < static_cast<int>(fixed.size()) &&
|
||||
isPunctuation(fixed[chk]));
|
||||
} else if (m.scope == "vowel") {
|
||||
const bool inRange = (chk >= 0 && m.type == "prefix") ||
|
||||
(chk < static_cast<int>(fixed.size()) &&
|
||||
m.type == "suffix");
|
||||
cond = inRange && chk >= 0 && chk < static_cast<int>(fixed.size()) &&
|
||||
isVowel(fixed[chk]);
|
||||
} else if (m.scope == "consonant") {
|
||||
const bool inRange = (chk >= 0 && m.type == "prefix") ||
|
||||
(chk < static_cast<int>(fixed.size()) &&
|
||||
m.type == "suffix");
|
||||
cond = inRange && chk >= 0 && chk < static_cast<int>(fixed.size()) &&
|
||||
isConsonant(fixed[chk]);
|
||||
} else if (m.scope == "exact") {
|
||||
int s = 0;
|
||||
int e = 0;
|
||||
if (m.type == "suffix") {
|
||||
s = end;
|
||||
e = end + static_cast<int>(m.value.size());
|
||||
} else {
|
||||
s = start - static_cast<int>(m.value.size());
|
||||
e = start;
|
||||
}
|
||||
cond = isExact(m.value, fixed, s, e, false);
|
||||
}
|
||||
|
||||
if (((!cond) ^ m.negative)) {
|
||||
replace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
output += rule.replace;
|
||||
cur = end;
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
break;
|
||||
}
|
||||
|
||||
output += pattern.replace;
|
||||
cur = end;
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
output.push_back(fixed[cur]);
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
namespace {
|
||||
#include "avro_rules.inc"
|
||||
} // namespace
|
||||
|
||||
} // namespace fcitx
|
||||
52
plugin/avro/src/main/cpp/avro_parser.h
Normal file
52
plugin/avro/src/main/cpp/avro_parser.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
#ifndef FCITX5_ANDROID_AVRO_PARSER_H
|
||||
#define FCITX5_ANDROID_AVRO_PARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fcitx {
|
||||
|
||||
struct AvroMatchRule {
|
||||
std::string type;
|
||||
std::string scope;
|
||||
std::string value;
|
||||
bool negative;
|
||||
};
|
||||
|
||||
struct AvroRule {
|
||||
std::vector<AvroMatchRule> matches;
|
||||
std::string replace;
|
||||
};
|
||||
|
||||
struct AvroPattern {
|
||||
std::string find;
|
||||
std::string replace;
|
||||
std::vector<AvroRule> rules;
|
||||
};
|
||||
|
||||
class AvroParser {
|
||||
public:
|
||||
AvroParser();
|
||||
std::string parse(const std::string &input) const;
|
||||
|
||||
private:
|
||||
std::vector<AvroPattern> patterns_;
|
||||
std::string vowel_;
|
||||
std::string consonant_;
|
||||
std::string caseSensitive_;
|
||||
|
||||
static bool isExact(const std::string &needle, const std::string &haystack, int start,
|
||||
int end, bool negate);
|
||||
bool isVowel(char c) const;
|
||||
bool isConsonant(char c) const;
|
||||
bool isPunctuation(char c) const;
|
||||
bool isCaseSensitive(char c) const;
|
||||
std::string fixString(const std::string &input) const;
|
||||
};
|
||||
|
||||
} // namespace fcitx
|
||||
|
||||
#endif // FCITX5_ANDROID_AVRO_PARSER_H
|
||||
738
plugin/avro/src/main/cpp/avro_rules.inc
Normal file
738
plugin/avro/src/main/cpp/avro_rules.inc
Normal file
@ -0,0 +1,738 @@
|
||||
std::vector<AvroPattern> makePatterns() {
|
||||
return {
|
||||
AvroPattern{"bhl", "ভ্ল", {
|
||||
}},
|
||||
AvroPattern{"psh", "পশ", {
|
||||
}},
|
||||
AvroPattern{"bdh", "ব্ধ", {
|
||||
}},
|
||||
AvroPattern{"bj", "ব্জ", {
|
||||
}},
|
||||
AvroPattern{"bd", "ব্দ", {
|
||||
}},
|
||||
AvroPattern{"bb", "ব্ব", {
|
||||
}},
|
||||
AvroPattern{"bl", "ব্ল", {
|
||||
}},
|
||||
AvroPattern{"bh", "ভ", {
|
||||
}},
|
||||
AvroPattern{"vl", "ভ্ল", {
|
||||
}},
|
||||
AvroPattern{"b", "ব", {
|
||||
}},
|
||||
AvroPattern{"v", "ভ", {
|
||||
}},
|
||||
AvroPattern{"cNG", "চ্ঞ", {
|
||||
}},
|
||||
AvroPattern{"cch", "চ্ছ", {
|
||||
}},
|
||||
AvroPattern{"cc", "চ্চ", {
|
||||
}},
|
||||
AvroPattern{"ch", "ছ", {
|
||||
}},
|
||||
AvroPattern{"c", "চ", {
|
||||
}},
|
||||
AvroPattern{"dhn", "ধ্ন", {
|
||||
}},
|
||||
AvroPattern{"dhm", "ধ্ম", {
|
||||
}},
|
||||
AvroPattern{"dgh", "দ্ঘ", {
|
||||
}},
|
||||
AvroPattern{"ddh", "দ্ধ", {
|
||||
}},
|
||||
AvroPattern{"dbh", "দ্ভ", {
|
||||
}},
|
||||
AvroPattern{"dv", "দ্ভ", {
|
||||
}},
|
||||
AvroPattern{"dm", "দ্ম", {
|
||||
}},
|
||||
AvroPattern{"DD", "ড্ড", {
|
||||
}},
|
||||
AvroPattern{"Dh", "ঢ", {
|
||||
}},
|
||||
AvroPattern{"dh", "ধ", {
|
||||
}},
|
||||
AvroPattern{"dg", "দ্গ", {
|
||||
}},
|
||||
AvroPattern{"dd", "দ্দ", {
|
||||
}},
|
||||
AvroPattern{"D", "ড", {
|
||||
}},
|
||||
AvroPattern{"d", "দ", {
|
||||
}},
|
||||
AvroPattern{"...", "...", {
|
||||
}},
|
||||
AvroPattern{".`", ".", {
|
||||
}},
|
||||
AvroPattern{"..", "।।", {
|
||||
}},
|
||||
AvroPattern{".", "।", {
|
||||
}},
|
||||
AvroPattern{"ghn", "ঘ্ন", {
|
||||
}},
|
||||
AvroPattern{"Ghn", "ঘ্ন", {
|
||||
}},
|
||||
AvroPattern{"gdh", "গ্ধ", {
|
||||
}},
|
||||
AvroPattern{"Gdh", "গ্ধ", {
|
||||
}},
|
||||
AvroPattern{"gN", "গ্ণ", {
|
||||
}},
|
||||
AvroPattern{"GN", "গ্ণ", {
|
||||
}},
|
||||
AvroPattern{"gn", "গ্ন", {
|
||||
}},
|
||||
AvroPattern{"Gn", "গ্ন", {
|
||||
}},
|
||||
AvroPattern{"gm", "গ্ম", {
|
||||
}},
|
||||
AvroPattern{"Gm", "গ্ম", {
|
||||
}},
|
||||
AvroPattern{"gl", "গ্ল", {
|
||||
}},
|
||||
AvroPattern{"Gl", "গ্ল", {
|
||||
}},
|
||||
AvroPattern{"gg", "জ্ঞ", {
|
||||
}},
|
||||
AvroPattern{"GG", "জ্ঞ", {
|
||||
}},
|
||||
AvroPattern{"Gg", "জ্ঞ", {
|
||||
}},
|
||||
AvroPattern{"gG", "জ্ঞ", {
|
||||
}},
|
||||
AvroPattern{"gh", "ঘ", {
|
||||
}},
|
||||
AvroPattern{"Gh", "ঘ", {
|
||||
}},
|
||||
AvroPattern{"g", "গ", {
|
||||
}},
|
||||
AvroPattern{"G", "গ", {
|
||||
}},
|
||||
AvroPattern{"hN", "হ্ণ", {
|
||||
}},
|
||||
AvroPattern{"hn", "হ্ন", {
|
||||
}},
|
||||
AvroPattern{"hm", "হ্ম", {
|
||||
}},
|
||||
AvroPattern{"hl", "হ্ল", {
|
||||
}},
|
||||
AvroPattern{"h", "হ", {
|
||||
}},
|
||||
AvroPattern{"jjh", "জ্ঝ", {
|
||||
}},
|
||||
AvroPattern{"jNG", "জ্ঞ", {
|
||||
}},
|
||||
AvroPattern{"jh", "ঝ", {
|
||||
}},
|
||||
AvroPattern{"jj", "জ্জ", {
|
||||
}},
|
||||
AvroPattern{"j", "জ", {
|
||||
}},
|
||||
AvroPattern{"J", "জ", {
|
||||
}},
|
||||
AvroPattern{"kkhN", "ক্ষ্ণ", {
|
||||
}},
|
||||
AvroPattern{"kShN", "ক্ষ্ণ", {
|
||||
}},
|
||||
AvroPattern{"kkhm", "ক্ষ্ম", {
|
||||
}},
|
||||
AvroPattern{"kShm", "ক্ষ্ম", {
|
||||
}},
|
||||
AvroPattern{"kxN", "ক্ষ্ণ", {
|
||||
}},
|
||||
AvroPattern{"kxm", "ক্ষ্ম", {
|
||||
}},
|
||||
AvroPattern{"kkh", "ক্ষ", {
|
||||
}},
|
||||
AvroPattern{"kSh", "ক্ষ", {
|
||||
}},
|
||||
AvroPattern{"ksh", "কশ", {
|
||||
}},
|
||||
AvroPattern{"kx", "ক্ষ", {
|
||||
}},
|
||||
AvroPattern{"kk", "ক্ক", {
|
||||
}},
|
||||
AvroPattern{"kT", "ক্ট", {
|
||||
}},
|
||||
AvroPattern{"kt", "ক্ত", {
|
||||
}},
|
||||
AvroPattern{"kl", "ক্ল", {
|
||||
}},
|
||||
AvroPattern{"ks", "ক্স", {
|
||||
}},
|
||||
AvroPattern{"kh", "খ", {
|
||||
}},
|
||||
AvroPattern{"k", "ক", {
|
||||
}},
|
||||
AvroPattern{"lbh", "ল্ভ", {
|
||||
}},
|
||||
AvroPattern{"ldh", "ল্ধ", {
|
||||
}},
|
||||
AvroPattern{"lkh", "লখ", {
|
||||
}},
|
||||
AvroPattern{"lgh", "লঘ", {
|
||||
}},
|
||||
AvroPattern{"lph", "লফ", {
|
||||
}},
|
||||
AvroPattern{"lk", "ল্ক", {
|
||||
}},
|
||||
AvroPattern{"lg", "ল্গ", {
|
||||
}},
|
||||
AvroPattern{"lT", "ল্ট", {
|
||||
}},
|
||||
AvroPattern{"lD", "ল্ড", {
|
||||
}},
|
||||
AvroPattern{"lp", "ল্প", {
|
||||
}},
|
||||
AvroPattern{"lv", "ল্ভ", {
|
||||
}},
|
||||
AvroPattern{"lm", "ল্ম", {
|
||||
}},
|
||||
AvroPattern{"ll", "ল্ল", {
|
||||
}},
|
||||
AvroPattern{"lb", "ল্ব", {
|
||||
}},
|
||||
AvroPattern{"l", "ল", {
|
||||
}},
|
||||
AvroPattern{"mth", "ম্থ", {
|
||||
}},
|
||||
AvroPattern{"mph", "ম্ফ", {
|
||||
}},
|
||||
AvroPattern{"mbh", "ম্ভ", {
|
||||
}},
|
||||
AvroPattern{"mpl", "মপ্ল", {
|
||||
}},
|
||||
AvroPattern{"mn", "ম্ন", {
|
||||
}},
|
||||
AvroPattern{"mp", "ম্প", {
|
||||
}},
|
||||
AvroPattern{"mv", "ম্ভ", {
|
||||
}},
|
||||
AvroPattern{"mm", "ম্ম", {
|
||||
}},
|
||||
AvroPattern{"ml", "ম্ল", {
|
||||
}},
|
||||
AvroPattern{"mb", "ম্ব", {
|
||||
}},
|
||||
AvroPattern{"mf", "ম্ফ", {
|
||||
}},
|
||||
AvroPattern{"m", "ম", {
|
||||
}},
|
||||
AvroPattern{"0", "০", {
|
||||
}},
|
||||
AvroPattern{"1", "১", {
|
||||
}},
|
||||
AvroPattern{"2", "২", {
|
||||
}},
|
||||
AvroPattern{"3", "৩", {
|
||||
}},
|
||||
AvroPattern{"4", "৪", {
|
||||
}},
|
||||
AvroPattern{"5", "৫", {
|
||||
}},
|
||||
AvroPattern{"6", "৬", {
|
||||
}},
|
||||
AvroPattern{"7", "৭", {
|
||||
}},
|
||||
AvroPattern{"8", "৮", {
|
||||
}},
|
||||
AvroPattern{"9", "৯", {
|
||||
}},
|
||||
AvroPattern{"NgkSh", "ঙ্ক্ষ", {
|
||||
}},
|
||||
AvroPattern{"Ngkkh", "ঙ্ক্ষ", {
|
||||
}},
|
||||
AvroPattern{"NGch", "ঞ্ছ", {
|
||||
}},
|
||||
AvroPattern{"Nggh", "ঙ্ঘ", {
|
||||
}},
|
||||
AvroPattern{"Ngkh", "ঙ্খ", {
|
||||
}},
|
||||
AvroPattern{"NGjh", "ঞ্ঝ", {
|
||||
}},
|
||||
AvroPattern{"ngOU", "ঙ্গৌ", {
|
||||
}},
|
||||
AvroPattern{"ngOI", "ঙ্গৈ", {
|
||||
}},
|
||||
AvroPattern{"Ngkx", "ঙ্ক্ষ", {
|
||||
}},
|
||||
AvroPattern{"NGc", "ঞ্চ", {
|
||||
}},
|
||||
AvroPattern{"nch", "ঞ্ছ", {
|
||||
}},
|
||||
AvroPattern{"njh", "ঞ্ঝ", {
|
||||
}},
|
||||
AvroPattern{"ngh", "ঙ্ঘ", {
|
||||
}},
|
||||
AvroPattern{"Ngk", "ঙ্ক", {
|
||||
}},
|
||||
AvroPattern{"Ngx", "ঙ্ষ", {
|
||||
}},
|
||||
AvroPattern{"Ngg", "ঙ্গ", {
|
||||
}},
|
||||
AvroPattern{"Ngm", "ঙ্ম", {
|
||||
}},
|
||||
AvroPattern{"NGj", "ঞ্জ", {
|
||||
}},
|
||||
AvroPattern{"ndh", "ন্ধ", {
|
||||
}},
|
||||
AvroPattern{"nTh", "ন্ঠ", {
|
||||
}},
|
||||
AvroPattern{"NTh", "ণ্ঠ", {
|
||||
}},
|
||||
AvroPattern{"nth", "ন্থ", {
|
||||
}},
|
||||
AvroPattern{"nkh", "ঙ্খ", {
|
||||
}},
|
||||
AvroPattern{"ngo", "ঙ্গ", {
|
||||
}},
|
||||
AvroPattern{"nga", "ঙ্গা", {
|
||||
}},
|
||||
AvroPattern{"ngi", "ঙ্গি", {
|
||||
}},
|
||||
AvroPattern{"ngI", "ঙ্গী", {
|
||||
}},
|
||||
AvroPattern{"ngu", "ঙ্গু", {
|
||||
}},
|
||||
AvroPattern{"ngU", "ঙ্গূ", {
|
||||
}},
|
||||
AvroPattern{"nge", "ঙ্গে", {
|
||||
}},
|
||||
AvroPattern{"ngO", "ঙ্গো", {
|
||||
}},
|
||||
AvroPattern{"NDh", "ণ্ঢ", {
|
||||
}},
|
||||
AvroPattern{"nsh", "নশ", {
|
||||
}},
|
||||
AvroPattern{"Ngr", "ঙর", {
|
||||
}},
|
||||
AvroPattern{"NGr", "ঞর", {
|
||||
}},
|
||||
AvroPattern{"ngr", "ংর", {
|
||||
}},
|
||||
AvroPattern{"nj", "ঞ্জ", {
|
||||
}},
|
||||
AvroPattern{"Ng", "ঙ", {
|
||||
}},
|
||||
AvroPattern{"NG", "ঞ", {
|
||||
}},
|
||||
AvroPattern{"nk", "ঙ্ক", {
|
||||
}},
|
||||
AvroPattern{"ng", "ং", {
|
||||
}},
|
||||
AvroPattern{"nn", "ন্ন", {
|
||||
}},
|
||||
AvroPattern{"NN", "ণ্ণ", {
|
||||
}},
|
||||
AvroPattern{"Nn", "ণ্ন", {
|
||||
}},
|
||||
AvroPattern{"nm", "ন্ম", {
|
||||
}},
|
||||
AvroPattern{"Nm", "ণ্ম", {
|
||||
}},
|
||||
AvroPattern{"nd", "ন্দ", {
|
||||
}},
|
||||
AvroPattern{"nT", "ন্ট", {
|
||||
}},
|
||||
AvroPattern{"NT", "ণ্ট", {
|
||||
}},
|
||||
AvroPattern{"nD", "ন্ড", {
|
||||
}},
|
||||
AvroPattern{"ND", "ণ্ড", {
|
||||
}},
|
||||
AvroPattern{"nt", "ন্ত", {
|
||||
}},
|
||||
AvroPattern{"ns", "ন্স", {
|
||||
}},
|
||||
AvroPattern{"nc", "ঞ্চ", {
|
||||
}},
|
||||
AvroPattern{"n", "ন", {
|
||||
}},
|
||||
AvroPattern{"N", "ণ", {
|
||||
}},
|
||||
AvroPattern{"OI`", "ৈ", {
|
||||
}},
|
||||
AvroPattern{"OU`", "ৌ", {
|
||||
}},
|
||||
AvroPattern{"O`", "ো", {
|
||||
}},
|
||||
AvroPattern{"OI", "ৈ", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
}, "ঐ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "ঐ"},
|
||||
}},
|
||||
AvroPattern{"OU", "ৌ", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
}, "ঔ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "ঔ"},
|
||||
}},
|
||||
AvroPattern{"O", "ো", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
}, "ও"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "ও"},
|
||||
}},
|
||||
AvroPattern{"phl", "ফ্ল", {
|
||||
}},
|
||||
AvroPattern{"pT", "প্ট", {
|
||||
}},
|
||||
AvroPattern{"pt", "প্ত", {
|
||||
}},
|
||||
AvroPattern{"pn", "প্ন", {
|
||||
}},
|
||||
AvroPattern{"pp", "প্প", {
|
||||
}},
|
||||
AvroPattern{"pl", "প্ল", {
|
||||
}},
|
||||
AvroPattern{"ps", "প্স", {
|
||||
}},
|
||||
AvroPattern{"ph", "ফ", {
|
||||
}},
|
||||
AvroPattern{"fl", "ফ্ল", {
|
||||
}},
|
||||
AvroPattern{"f", "ফ", {
|
||||
}},
|
||||
AvroPattern{"p", "প", {
|
||||
}},
|
||||
AvroPattern{"rri`", "ৃ", {
|
||||
}},
|
||||
AvroPattern{"rri", "ৃ", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
}, "ঋ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "ঋ"},
|
||||
}},
|
||||
AvroPattern{"rrZ", "রর্য", {
|
||||
}},
|
||||
AvroPattern{"rry", "রর্য", {
|
||||
}},
|
||||
AvroPattern{"rZ", "র্য", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", false},
|
||||
AvroMatchRule{"prefix", "exact", "r", true},
|
||||
AvroMatchRule{"prefix", "exact", "y", true},
|
||||
AvroMatchRule{"prefix", "exact", "w", true},
|
||||
AvroMatchRule{"prefix", "exact", "x", true},
|
||||
}, "্র্য"},
|
||||
}},
|
||||
AvroPattern{"ry", "র্য", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", false},
|
||||
AvroMatchRule{"prefix", "exact", "r", true},
|
||||
AvroMatchRule{"prefix", "exact", "y", true},
|
||||
AvroMatchRule{"prefix", "exact", "w", true},
|
||||
AvroMatchRule{"prefix", "exact", "x", true},
|
||||
}, "্র্য"},
|
||||
}},
|
||||
AvroPattern{"rr", "রর", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "vowel", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "r", true},
|
||||
AvroMatchRule{"suffix", "punctuation", "", true},
|
||||
}, "র্"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", false},
|
||||
AvroMatchRule{"prefix", "exact", "r", true},
|
||||
}, "্রর"},
|
||||
}},
|
||||
AvroPattern{"Rg", "ড়্গ", {
|
||||
}},
|
||||
AvroPattern{"Rh", "ঢ়", {
|
||||
}},
|
||||
AvroPattern{"R", "ড়", {
|
||||
}},
|
||||
AvroPattern{"r", "র", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", false},
|
||||
AvroMatchRule{"prefix", "exact", "r", true},
|
||||
AvroMatchRule{"prefix", "exact", "y", true},
|
||||
AvroMatchRule{"prefix", "exact", "w", true},
|
||||
AvroMatchRule{"prefix", "exact", "x", true},
|
||||
AvroMatchRule{"prefix", "exact", "Z", true},
|
||||
}, "্র"},
|
||||
}},
|
||||
AvroPattern{"shch", "শ্ছ", {
|
||||
}},
|
||||
AvroPattern{"ShTh", "ষ্ঠ", {
|
||||
}},
|
||||
AvroPattern{"Shph", "ষ্ফ", {
|
||||
}},
|
||||
AvroPattern{"Sch", "শ্ছ", {
|
||||
}},
|
||||
AvroPattern{"skl", "স্ক্ল", {
|
||||
}},
|
||||
AvroPattern{"skh", "স্খ", {
|
||||
}},
|
||||
AvroPattern{"sth", "স্থ", {
|
||||
}},
|
||||
AvroPattern{"sph", "স্ফ", {
|
||||
}},
|
||||
AvroPattern{"shc", "শ্চ", {
|
||||
}},
|
||||
AvroPattern{"sht", "শ্ত", {
|
||||
}},
|
||||
AvroPattern{"shn", "শ্ন", {
|
||||
}},
|
||||
AvroPattern{"shm", "শ্ম", {
|
||||
}},
|
||||
AvroPattern{"shl", "শ্ল", {
|
||||
}},
|
||||
AvroPattern{"Shk", "ষ্ক", {
|
||||
}},
|
||||
AvroPattern{"ShT", "ষ্ট", {
|
||||
}},
|
||||
AvroPattern{"ShN", "ষ্ণ", {
|
||||
}},
|
||||
AvroPattern{"Shp", "ষ্প", {
|
||||
}},
|
||||
AvroPattern{"Shf", "ষ্ফ", {
|
||||
}},
|
||||
AvroPattern{"Shm", "ষ্ম", {
|
||||
}},
|
||||
AvroPattern{"spl", "স্প্ল", {
|
||||
}},
|
||||
AvroPattern{"sk", "স্ক", {
|
||||
}},
|
||||
AvroPattern{"Sc", "শ্চ", {
|
||||
}},
|
||||
AvroPattern{"sT", "স্ট", {
|
||||
}},
|
||||
AvroPattern{"st", "স্ত", {
|
||||
}},
|
||||
AvroPattern{"sn", "স্ন", {
|
||||
}},
|
||||
AvroPattern{"sp", "স্প", {
|
||||
}},
|
||||
AvroPattern{"sf", "স্ফ", {
|
||||
}},
|
||||
AvroPattern{"sm", "স্ম", {
|
||||
}},
|
||||
AvroPattern{"sl", "স্ল", {
|
||||
}},
|
||||
AvroPattern{"sh", "শ", {
|
||||
}},
|
||||
AvroPattern{"Sc", "শ্চ", {
|
||||
}},
|
||||
AvroPattern{"St", "শ্ত", {
|
||||
}},
|
||||
AvroPattern{"Sn", "শ্ন", {
|
||||
}},
|
||||
AvroPattern{"Sm", "শ্ম", {
|
||||
}},
|
||||
AvroPattern{"Sl", "শ্ল", {
|
||||
}},
|
||||
AvroPattern{"Sh", "ষ", {
|
||||
}},
|
||||
AvroPattern{"s", "স", {
|
||||
}},
|
||||
AvroPattern{"S", "শ", {
|
||||
}},
|
||||
AvroPattern{"oo`", "ু", {
|
||||
}},
|
||||
AvroPattern{"oo", "ু", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "উ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "উ"},
|
||||
}},
|
||||
AvroPattern{"o`", "", {
|
||||
}},
|
||||
AvroPattern{"oZ", "অ্য", {
|
||||
}},
|
||||
AvroPattern{"o", "", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "vowel", "", false},
|
||||
AvroMatchRule{"prefix", "exact", "o", true},
|
||||
}, "ও"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "vowel", "", false},
|
||||
AvroMatchRule{"prefix", "exact", "o", false},
|
||||
}, "অ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "অ"},
|
||||
}},
|
||||
AvroPattern{"tth", "ত্থ", {
|
||||
}},
|
||||
AvroPattern{"t``", "ৎ", {
|
||||
}},
|
||||
AvroPattern{"TT", "ট্ট", {
|
||||
}},
|
||||
AvroPattern{"Tm", "ট্ম", {
|
||||
}},
|
||||
AvroPattern{"Th", "ঠ", {
|
||||
}},
|
||||
AvroPattern{"tn", "ত্ন", {
|
||||
}},
|
||||
AvroPattern{"tm", "ত্ম", {
|
||||
}},
|
||||
AvroPattern{"th", "থ", {
|
||||
}},
|
||||
AvroPattern{"tt", "ত্ত", {
|
||||
}},
|
||||
AvroPattern{"T", "ট", {
|
||||
}},
|
||||
AvroPattern{"t", "ত", {
|
||||
}},
|
||||
AvroPattern{"aZ", "অ্যা", {
|
||||
}},
|
||||
AvroPattern{"AZ", "অ্যা", {
|
||||
}},
|
||||
AvroPattern{"a`", "া", {
|
||||
}},
|
||||
AvroPattern{"A`", "া", {
|
||||
}},
|
||||
AvroPattern{"a", "া", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "আ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"prefix", "exact", "a", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "য়া"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "exact", "a", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "আ"},
|
||||
}},
|
||||
AvroPattern{"i`", "ি", {
|
||||
}},
|
||||
AvroPattern{"i", "ি", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ই"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ই"},
|
||||
}},
|
||||
AvroPattern{"I`", "ী", {
|
||||
}},
|
||||
AvroPattern{"I", "ী", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ঈ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ঈ"},
|
||||
}},
|
||||
AvroPattern{"u`", "ু", {
|
||||
}},
|
||||
AvroPattern{"u", "ু", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "উ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "উ"},
|
||||
}},
|
||||
AvroPattern{"U`", "ূ", {
|
||||
}},
|
||||
AvroPattern{"U", "ূ", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ঊ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ঊ"},
|
||||
}},
|
||||
AvroPattern{"ee`", "ী", {
|
||||
}},
|
||||
AvroPattern{"ee", "ী", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ঈ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "ঈ"},
|
||||
}},
|
||||
AvroPattern{"e`", "ে", {
|
||||
}},
|
||||
AvroPattern{"e", "ে", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "এ"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "exact", "`", true},
|
||||
}, "এ"},
|
||||
}},
|
||||
AvroPattern{"z", "য", {
|
||||
}},
|
||||
AvroPattern{"Z", "্য", {
|
||||
}},
|
||||
AvroPattern{"y", "্য", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", true},
|
||||
AvroMatchRule{"prefix", "punctuation", "", true},
|
||||
}, "য়"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "ইয়"},
|
||||
}},
|
||||
AvroPattern{"Y", "য়", {
|
||||
}},
|
||||
AvroPattern{"q", "ক", {
|
||||
}},
|
||||
AvroPattern{"w", "ও", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
AvroMatchRule{"suffix", "vowel", "", false},
|
||||
}, "ওয়"},
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "consonant", "", false},
|
||||
}, "্ব"},
|
||||
}},
|
||||
AvroPattern{"x", "ক্স", {
|
||||
AvroRule{{
|
||||
AvroMatchRule{"prefix", "punctuation", "", false},
|
||||
}, "এক্স"},
|
||||
}},
|
||||
AvroPattern{":`", ":", {
|
||||
}},
|
||||
AvroPattern{":", "ঃ", {
|
||||
}},
|
||||
AvroPattern{"^`", "^", {
|
||||
}},
|
||||
AvroPattern{"^", "ঁ", {
|
||||
}},
|
||||
AvroPattern{",,", "্", {
|
||||
}},
|
||||
AvroPattern{",", ",", {
|
||||
}},
|
||||
AvroPattern{"$", "৳", {
|
||||
}},
|
||||
AvroPattern{"`", "", {
|
||||
}},
|
||||
};
|
||||
}
|
||||
std::string makeVowels() { return "aeiou"; }
|
||||
std::string makeConsonants() { return "bcdfghjklmnpqrstvwxyz"; }
|
||||
std::string makeCaseSensitive() { return "oiudgjnrstyz"; }
|
||||
7
plugin/avro/src/main/cpp/probhat.conf.in
Normal file
7
plugin/avro/src/main/cpp/probhat.conf.in
Normal file
@ -0,0 +1,7 @@
|
||||
[InputMethod]
|
||||
Name=Probhat
|
||||
Icon=fcitx-avro
|
||||
Label=Probhat
|
||||
LangCode=bn
|
||||
Addon=avro
|
||||
Configurable=True
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.plugin.avro
|
||||
|
||||
/** Shared identifiers for Bangla Avro / Probhat keyboard integration. */
|
||||
object AvroKeyboardIds {
|
||||
/** Fcitx input method unique name for Avro phonetic typing. */
|
||||
const val IME_AVRO = "avro"
|
||||
|
||||
/** Fcitx input method unique name for Probhat fixed layout. */
|
||||
const val IME_PROBHAT = "probhat"
|
||||
|
||||
/** Soft keyboard layout id (roman QWERTY feeding the Avro engine). */
|
||||
const val LAYOUT_AVRO = "keyboard-bn-avro"
|
||||
|
||||
/** Soft keyboard layout id (Probhat Bengali fixed layout). */
|
||||
const val LAYOUT_PROBHAT = "keyboard-bn-probhat"
|
||||
|
||||
fun isBanglaIme(uniqueName: String): Boolean =
|
||||
uniqueName == IME_AVRO || uniqueName == IME_PROBHAT
|
||||
|
||||
fun layoutForIme(uniqueName: String): String? = when (uniqueName) {
|
||||
IME_AVRO -> LAYOUT_AVRO
|
||||
IME_PROBHAT -> LAYOUT_PROBHAT
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:pathData="M69,25 L134.34,90.35 115.73,131.73 39,55C49.93,44.18 58.13,35.88 69,25Z"
|
||||
android:strokeLineJoin="miter"
|
||||
android:strokeLineCap="butt">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="54"
|
||||
android:startY="54"
|
||||
android:endX="85"
|
||||
android:endY="85"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#44000000"/>
|
||||
<item android:offset="1" android:color="#00000000"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M40,26h28v28h-28z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="m53.13,46.15q-2.6,0 -4.54,-0.76 -1.93,-0.78 -3.02,-2.3 -1.06,-1.54 -1.06,-3.78 0,-1.88 0.81,-3.14 0.84,-1.26 2.18,-1.96 0.81,-0.42 1.71,-0.67 0.92,-0.25 2.16,-0.34 1.26,-0.11 3.02,-0.11h1.88q-0.08,-1.32 -0.84,-1.93 -0.73,-0.62 -1.88,-0.62 -1.09,0 -1.65,0.42 -0.56,0.39 -0.56,1.09 0,0.11 0,0.22 0.03,0.11 0.03,0.2l-1.99,0.25q-0.03,-0.25 -0.06,-0.48 0,-0.22 0,-0.39 0,-1.54 1.09,-2.35 1.09,-0.81 3,-0.81 2.91,0 4.03,2.35 0.76,-1.29 2.04,-2.38l1.54,1.23q-0.08,0.14 -0.14,0.25 -0.03,0.11 -0.03,0.34 0,0.31 0.2,0.7 0.2,0.39 0.73,1.23 0.5,0.76 0.81,1.46 0.31,0.67 0.31,1.43 0,1.2 -0.78,2.02 -0.78,0.81 -2.77,0.81 -0.53,0 -1.12,-0.14v5.66q0.5,-0.14 0.98,-0.36 0.5,-0.22 1.04,-0.5l0.73,1.88q-0.67,0.31 -1.37,0.56 -0.67,0.22 -1.37,0.39v5.88h-1.96v-5.54q-0.81,0.11 -1.62,0.14 -0.78,0.06 -1.51,0.06zM58.23,34.95v1.23q0.28,0.06 0.5,0.08 0.25,0.03 0.5,0.03 0.92,0 1.29,-0.31 0.36,-0.31 0.36,-0.9 0,-0.53 -0.22,-0.95 -0.2,-0.45 -0.59,-1.06 -0.31,-0.45 -0.5,-0.81 -0.17,-0.36 -0.25,-0.73 -0.7,0.84 -0.9,1.65 -0.2,0.81 -0.2,1.76zM53.35,44.16q0.76,0 1.48,-0.03 0.73,-0.03 1.43,-0.11v-9.07h-1.68q-1.96,0 -3.14,0.11 -1.15,0.11 -1.85,0.34 -0.7,0.22 -1.29,0.59 -1.68,1.04 -1.68,3.44 0,1.23 0.64,2.32 0.64,1.06 2.1,1.74 1.48,0.67 3.98,0.67z" />
|
||||
</vector>
|
||||
48
plugin/avro/src/main/res/drawable/ic_launcher_background.xml
Normal file
48
plugin/avro/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="1.2"
|
||||
android:scaleY="1.2"
|
||||
android:translateX="-10.8"
|
||||
android:translateY="-10.8">
|
||||
<path
|
||||
android:pathData="M0,0h108v108h-108z"
|
||||
android:fillColor="#696969"/>
|
||||
<path
|
||||
android:pathData="m40,69.8h28a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1H40a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m35.3,61.3h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m43.9,61.3h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m52.5,61.3h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m61.1,61.3h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m69.7,61.3h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m35.3,52.8h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m43.9,52.8h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m52.5,52.8h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m61.1,52.8h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
<path
|
||||
android:pathData="m69.7,52.8h3a1,1 0,0 1,1 1v3a1,1 0,0 1,-1 1h-3a1,1 0,0 1,-1 -1v-3a1,1 0,0 1,1 -1z"
|
||||
android:fillColor="#c5c5c5"/>
|
||||
</group>
|
||||
</vector>
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
6
plugin/avro/src/main/res/values/strings.xml
Normal file
6
plugin/avro/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name_release">Fcitx5 (Avro Plugin)</string>
|
||||
<string name="app_name_debug">Fcitx5 (Avro Plugin | Debug)</string>
|
||||
<string name="description">Avro (Bangla phonetic input method) engine support for Fcitx5</string>
|
||||
</resources>
|
||||
6
plugin/avro/src/main/res/xml/plugin.xml
Normal file
6
plugin/avro/src/main/res/xml/plugin.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<plugin xmlns="../../../../../pluginSchema.xsd">
|
||||
<apiVersion>0.1</apiVersion>
|
||||
<domain>fcitx5-avro</domain>
|
||||
<description>@string/description</description>
|
||||
</plugin>
|
||||
66
plugin/avro/tools/gen_avro_rules_inc.py
Normal file
66
plugin/avro/tools/gen_avro_rules_inc.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
"""Generate avro_rules.inc from avro-phonetic.json for the native C++ parser."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def esc(s: str) -> str:
|
||||
return s.replace("\\", "\\\\").replace('"', '\\"')
|
||||
|
||||
|
||||
def main() -> int:
|
||||
plugin_root = Path(__file__).resolve().parents[1]
|
||||
repo_root = plugin_root.parents[1]
|
||||
json_path = repo_root.parent / "fcitx5" / "data" / "avro" / "avro-phonetic.json"
|
||||
if len(sys.argv) > 1:
|
||||
json_path = Path(sys.argv[1])
|
||||
out_path = plugin_root / "src" / "main" / "cpp" / "avro_rules.inc"
|
||||
|
||||
if not json_path.is_file():
|
||||
print(f"Rules JSON not found: {json_path}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
data = json.loads(json_path.read_text(encoding="utf-8"))
|
||||
lines: list[str] = []
|
||||
lines.append("std::vector<AvroPattern> makePatterns() {")
|
||||
lines.append(" return {")
|
||||
for pattern in data["patterns"]:
|
||||
lines.append(
|
||||
f' AvroPattern{{"{esc(pattern["find"])}", "{esc(pattern["replace"])}", {{'
|
||||
)
|
||||
for rule in pattern.get("rules", []):
|
||||
lines.append(" AvroRule{{")
|
||||
for match in rule.get("matches", []):
|
||||
scope = match.get("scope", "")
|
||||
negative = bool(match.get("negative", False))
|
||||
if scope.startswith("!"):
|
||||
negative = True
|
||||
scope = scope[1:]
|
||||
neg = "true" if negative else "false"
|
||||
lines.append(
|
||||
f' AvroMatchRule{{"{esc(match.get("type", ""))}", '
|
||||
f'"{esc(scope)}", "{esc(match.get("value", ""))}", {neg}}},'
|
||||
)
|
||||
lines.append(f' }}, "{esc(rule.get("replace", ""))}"}},')
|
||||
lines.append(" }},")
|
||||
lines.append(" };")
|
||||
lines.append("}")
|
||||
lines.append(f'std::string makeVowels() {{ return "{esc(data["vowel"])}"; }}')
|
||||
lines.append(f'std::string makeConsonants() {{ return "{esc(data["consonant"])}"; }}')
|
||||
lines.append(
|
||||
f'std::string makeCaseSensitive() {{ return "{esc(data["casesensitive"])}"; }}'
|
||||
)
|
||||
|
||||
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
out_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
print(f"Wrote {out_path} ({len(lines)} lines)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
65
plugin/avro/tools/host_golden_test.cpp
Normal file
65
plugin/avro/tools/host_golden_test.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
#include "../src/main/cpp/avro_parser.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
struct GoldenCase {
|
||||
const char *input;
|
||||
const char *expected;
|
||||
};
|
||||
|
||||
int runGoldenTests() {
|
||||
const std::vector<GoldenCase> cases = {
|
||||
{"ami banglay gan gai", "আমি বাংলায় গান গাই"},
|
||||
{"amader valObasa", "আমাদের ভালোবাসা"},
|
||||
{"bhalo", "ভাল"},
|
||||
{"bhalO", "ভালো"},
|
||||
{"mukh", "মুখ"},
|
||||
{"OI", "ঐ"},
|
||||
{"OU", "ঔ"},
|
||||
{"rry", "রর্য"},
|
||||
{"t``", "ৎ"},
|
||||
{",,", "্"},
|
||||
{"x", "এক্স"},
|
||||
{"kw", "ক্ব"},
|
||||
{"ky", "ক্য"},
|
||||
{"123", "১২৩"},
|
||||
};
|
||||
|
||||
fcitx::AvroParser parser;
|
||||
int failures = 0;
|
||||
for (const auto &testCase : cases) {
|
||||
const std::string input(testCase.input);
|
||||
const std::string expected(testCase.expected);
|
||||
const std::string actual = parser.parse(input);
|
||||
if (actual != expected) {
|
||||
++failures;
|
||||
std::cerr << "FAIL: \"" << input << "\"\n"
|
||||
<< " expected: " << expected << "\n"
|
||||
<< " actual: " << actual << "\n";
|
||||
} else {
|
||||
std::cout << "PASS: \"" << input << "\" -> " << actual << "\n";
|
||||
}
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
const int failures = runGoldenTests();
|
||||
if (failures == 0) {
|
||||
std::cout << "All golden tests passed.\n";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
std::cerr << failures << " golden test(s) failed.\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
BIN
plugin/avro/tools/host_golden_test.exe
Normal file
BIN
plugin/avro/tools/host_golden_test.exe
Normal file
Binary file not shown.
101
plugin/avro/tools/run_golden_tests.py
Normal file
101
plugin/avro/tools/run_golden_tests.py
Normal file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
"""Run Avro parser golden tests (Python reference + optional native host binary)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
GOLDEN_CASES = [
|
||||
("ami banglay gan gai", "আমি বাংলায় গান গাই"),
|
||||
("amader valObasa", "আমাদের ভালোবাসা"),
|
||||
("bhalo", "ভাল"), # lowercase trailing o is literal; use bhalO for o-kar
|
||||
("bhalO", "ভালো"),
|
||||
("mukh", "মুখ"),
|
||||
("OI", "ঐ"),
|
||||
("OU", "ঔ"),
|
||||
("rry", "রর্য"),
|
||||
("t``", "ৎ"),
|
||||
(",,", "্"),
|
||||
("x", "এক্স"),
|
||||
("kw", "ক্ব"),
|
||||
("ky", "ক্য"),
|
||||
("123", "১২৩"),
|
||||
]
|
||||
|
||||
|
||||
def load_python_parser():
|
||||
tools_dir = Path(__file__).resolve().parent
|
||||
fcitx5_tools = tools_dir.parents[2].parent / "fcitx5" / "tools"
|
||||
sys.path.insert(0, str(fcitx5_tools))
|
||||
from avro_phonetic_parser import AvroPhoneticParser # noqa: PLC0415
|
||||
|
||||
json_path = fcitx5_tools.parent / "data" / "avro" / "avro-phonetic.json"
|
||||
data = json.loads(json_path.read_text(encoding="utf-8"))
|
||||
return AvroPhoneticParser(data)
|
||||
|
||||
|
||||
def run_python_golden_tests() -> int:
|
||||
parser = load_python_parser()
|
||||
failures = 0
|
||||
print("=== Python reference golden tests ===")
|
||||
for input_text, expected in GOLDEN_CASES:
|
||||
actual = parser.parse(input_text)
|
||||
if actual != expected:
|
||||
failures += 1
|
||||
print(f'FAIL: "{input_text}"')
|
||||
print(f" expected: {expected}")
|
||||
print(f" actual: {actual}")
|
||||
else:
|
||||
print(f'PASS: "{input_text}" -> {actual}')
|
||||
if failures:
|
||||
print(f"{failures} Python golden test(s) failed.")
|
||||
else:
|
||||
print("All Python golden tests passed.")
|
||||
return failures
|
||||
|
||||
|
||||
def try_run_cpp_golden_tests() -> int | None:
|
||||
tools_dir = Path(__file__).resolve().parent
|
||||
cpp_dir = tools_dir.parent / "src" / "main" / "cpp"
|
||||
source = tools_dir / "host_golden_test.cpp"
|
||||
binary = tools_dir / "host_golden_test"
|
||||
|
||||
compilers = [
|
||||
["g++", "-std=c++17", "-I", str(cpp_dir), str(source), str(cpp_dir / "avro_parser.cpp"), "-o", str(binary)],
|
||||
["clang++", "-std=c++17", "-I", str(cpp_dir), str(source), str(cpp_dir / "avro_parser.cpp"), "-o", str(binary)],
|
||||
]
|
||||
|
||||
for cmd in compilers:
|
||||
try:
|
||||
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||
print(f"\n=== Native C++ golden tests ({cmd[0]}) ===")
|
||||
result = subprocess.run([str(binary)], check=False, text=True, capture_output=True)
|
||||
print(result.stdout, end="")
|
||||
if result.stderr:
|
||||
print(result.stderr, end="", file=sys.stderr)
|
||||
return result.returncode
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
except subprocess.CalledProcessError as exc:
|
||||
print(f"Compile failed with {cmd[0]}:", exc.stderr or exc.stdout, file=sys.stderr)
|
||||
continue
|
||||
|
||||
print("\nSkipping native C++ golden tests (no g++/clang++ found).")
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
failures = run_python_golden_tests()
|
||||
cpp_result = try_run_cpp_golden_tests()
|
||||
if cpp_result is not None:
|
||||
failures += cpp_result
|
||||
return failures
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@ -35,3 +35,4 @@ include(":plugin:chewing")
|
||||
include(":plugin:sayura")
|
||||
include(":plugin:jyutping")
|
||||
include(":plugin:thai")
|
||||
include(":plugin:avro")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user