38e5ad570d
Offline English lexicon suggestions with autocapitalization, plus a same-height Chinese more-candidates grid over the key area.
190 lines
5.9 KiB
Swift
190 lines
5.9 KiB
Swift
// RimeSchemaGenerator.swift
|
||
// OSGKeyboard · Shared
|
||
//
|
||
// Generates OSG-owned schemas from public Microsoft/Sogou key maps.
|
||
// No GPL Rime schema files are copied or distributed.
|
||
|
||
import Foundation
|
||
|
||
public enum RimeSchemaGenerator {
|
||
public static func defaultConfiguration() -> String {
|
||
"""
|
||
# Generated by OSGKeyboard.
|
||
config_version: "1.0"
|
||
schema_list:
|
||
- schema: \(TypingInputSchema.fullPinyin.rawValue)
|
||
- schema: \(TypingInputSchema.microsoftDoublePinyin.rawValue)
|
||
- schema: \(TypingInputSchema.sogouDoublePinyin.rawValue)
|
||
switcher:
|
||
caption: 输入方案
|
||
hotkeys: []
|
||
menu:
|
||
# Large page so librime prepares enough candidates for the expand panel.
|
||
# The bridge also iterates beyond the current page via candidate_list_*.
|
||
page_size: 100
|
||
ascii_composer:
|
||
good_old_caps_lock: true
|
||
switch_key:
|
||
Shift_L: noop
|
||
Shift_R: noop
|
||
Control_L: noop
|
||
Control_R: noop
|
||
key_binder:
|
||
bindings: []
|
||
recognizer:
|
||
patterns: {}
|
||
"""
|
||
}
|
||
|
||
public static func schema(
|
||
for inputSchema: TypingInputSchema,
|
||
fuzzyPairs: Set<PinyinFuzzyPair>
|
||
) -> String {
|
||
let alphabet = inputSchema == .fullPinyin
|
||
? "zyxwvutsrqponmlkjihgfedcba"
|
||
: "zyxwvutsrqponmlkjihgfedcba;"
|
||
let algebra = fuzzyRules(fuzzyPairs) + algebraRules(for: inputSchema)
|
||
let algebraYAML = algebra.map { " - '\($0)'" }.joined(separator: "\n")
|
||
|
||
return """
|
||
# Generated by OSGKeyboard. Do not edit; change settings in the host app.
|
||
schema:
|
||
schema_id: \(inputSchema.rawValue)
|
||
name: \(inputSchema.displayName)
|
||
version: "1.0"
|
||
author:
|
||
- OSGKeyboard contributors
|
||
description: |
|
||
Commercially permissive OSG schema backed by osg_pinyin.
|
||
|
||
switches:
|
||
- name: ascii_mode
|
||
reset: 0
|
||
states: [中, 英]
|
||
|
||
engine:
|
||
processors:
|
||
- ascii_composer
|
||
- recognizer
|
||
- key_binder
|
||
- speller
|
||
- punctuator
|
||
- selector
|
||
- navigator
|
||
- express_editor
|
||
segmentors:
|
||
- ascii_segmentor
|
||
- matcher
|
||
- abc_segmentor
|
||
- punct_segmentor
|
||
- fallback_segmentor
|
||
translators:
|
||
- punct_translator
|
||
- script_translator
|
||
|
||
speller:
|
||
alphabet: "\(alphabet)"
|
||
initials: "\(alphabet.replacingOccurrences(of: ";", with: ""))"
|
||
delimiter: " '"
|
||
algebra:
|
||
\(algebraYAML)
|
||
|
||
translator:
|
||
dictionary: osg_pinyin
|
||
prism: \(inputSchema.rawValue)
|
||
enable_sentence: true
|
||
enable_completion: true
|
||
enable_user_dict: true
|
||
initial_quality: 1.2
|
||
|
||
punctuator:
|
||
half_shape:
|
||
",": ","
|
||
".": "。"
|
||
"?": "?"
|
||
"!": "!"
|
||
|
||
key_binder:
|
||
import_preset: default
|
||
|
||
recognizer:
|
||
import_preset: default
|
||
"""
|
||
}
|
||
|
||
/// Rules run against full-pinyin dictionary codes before double-pinyin
|
||
/// transforms, so fuzzy pairs work consistently in all three schemas.
|
||
public static func fuzzyRules(_ enabled: Set<PinyinFuzzyPair>) -> [String] {
|
||
var rules: [String] = []
|
||
for pair in PinyinFuzzyPair.allCases where enabled.contains(pair) {
|
||
switch pair {
|
||
case .zhZ:
|
||
rules += ["derive/^zh/z/", "derive/^z([^h])/zh$1/"]
|
||
case .chC:
|
||
rules += ["derive/^ch/c/", "derive/^c([^h])/ch$1/"]
|
||
case .shS:
|
||
rules += ["derive/^sh/s/", "derive/^s([^h])/sh$1/"]
|
||
case .nL:
|
||
rules += ["derive/^n/l/", "derive/^l/n/"]
|
||
case .fH:
|
||
rules += ["derive/^f/h/", "derive/^h/f/"]
|
||
case .anAng:
|
||
rules += ["derive/ang$/an/", "derive/an$/ang/"]
|
||
case .enEng:
|
||
rules += ["derive/eng$/en/", "derive/en$/eng/"]
|
||
case .inIng:
|
||
rules += ["derive/ing$/in/", "derive/in$/ing/"]
|
||
}
|
||
}
|
||
return rules
|
||
}
|
||
|
||
private static func algebraRules(for schema: TypingInputSchema) -> [String] {
|
||
switch schema {
|
||
case .fullPinyin:
|
||
return [
|
||
"derive/^([jqxy])u$/$1v/",
|
||
"abbrev/^([a-z]).+$/$1/"
|
||
]
|
||
|
||
case .microsoftDoublePinyin, .sogouDoublePinyin:
|
||
// Microsoft and Sogou's commonly shipped layouts are key-compatible.
|
||
// Uppercase markers prevent transforms from matching each other.
|
||
return [
|
||
"erase/^xx$/",
|
||
"derive/^([jqxy])u$/$1v/",
|
||
"derive/^([aoe].*)$/o$1/",
|
||
"xform/^([ae])(.*)$/$1$1$2/",
|
||
"xform/iu$/Q/",
|
||
"xform/[iu]a$/W/",
|
||
"xform/er$|[uv]an$/R/",
|
||
"xform/[uv]e$/T/",
|
||
"xform/v$|uai$/Y/",
|
||
"xform/^sh/U/",
|
||
"xform/^ch/I/",
|
||
"xform/^zh/V/",
|
||
"xform/uo$/O/",
|
||
"xform/[uv]n$/P/",
|
||
"xform/(.)i?ong$/$1S/",
|
||
"xform/[iu]ang$/D/",
|
||
"xform/(.)en$/$1F/",
|
||
"xform/(.)eng$/$1G/",
|
||
"xform/(.)ang$/$1H/",
|
||
"xform/ian$/M/",
|
||
"xform/(.)an$/$1J/",
|
||
"xform/iao$/C/",
|
||
"xform/(.)ao$/$1K/",
|
||
"xform/(.)ai$/$1L/",
|
||
"xform/(.)ei$/$1Z/",
|
||
"xform/ie$/X/",
|
||
"xform/ui$/V/",
|
||
"derive/T$/V/",
|
||
"xform/(.)ou$/$1B/",
|
||
"xform/in$/N/",
|
||
"xform/ing$/;/",
|
||
"xlit/QWRTYUIOPSDFGHMJCKLZXVBN/qwrtyuiopsdfghmjcklzxvbn/"
|
||
]
|
||
}
|
||
}
|
||
}
|