chore:新的根节点

This commit is contained in:
amzxyz
2026-01-21 17:43:36 +08:00
commit 274c2e8d00
94 changed files with 3245054 additions and 0 deletions

36
.github/workflows/release-build.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Wanxiang Schema Builds
on:
workflow_dispatch:
workflow_call:
inputs:
tag:
type: string
jobs:
release-build:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "18"
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Release build
run: bash .github/workflows/scripts/release-build.sh
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: rime-wanxiang-dist-${{ github.ref_name }}
if-no-files-found: error
path: dist/rime-wanxiang-*.zip

73
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
on:
push:
branches:
- wanxiang
permissions:
contents: write
pull-requests: write
issues: write
name: Release
jobs:
release-please:
runs-on: ubuntu-22.04
steps:
- uses: googleapis/release-please-action@v4
id: release
- name: Checkout repository
if: ${{ steps.release.outputs.release_created }}
uses: actions/checkout@v4
- name: Release edit to draft
if: ${{ steps.release.outputs.release_created }}
run: |
gh release edit ${TAG_VERSION} --draft
env:
TAG_VERSION: ${{ steps.release.outputs.tag_name }}
GH_TOKEN: ${{ github.token }}
outputs:
release_created: ${{ steps.release.outputs.release_created }}
release_tag_name: ${{ steps.release.outputs.tag_name }}
release-build:
needs: [release-please]
if: needs.release-please.outputs.release_created == 'true'
name: Release build
uses: ./.github/workflows/release-build.yml
permissions:
contents: write
secrets: inherit
release:
runs-on: ubuntu-22.04
needs: [release-please, release-build]
name: Release
env:
TAG_VERSION: ${{ needs.release-please.outputs.release_tag_name }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download build
uses: actions/download-artifact@v4
with:
name: rime-wanxiang-dist-${{ github.ref_name }}
path: ~/artifact
- name: Update release
run: |
# 更新 release title
gh release edit ${TAG_VERSION} --title "${TAG_VERSION} Rime万象拼音输入方案"
# 更新 release note
bash .github/workflows/scripts/generate-release-note.sh
gh release edit ${TAG_VERSION} --notes-file ./release_notes.md
# 更新 Assets
gh release upload ${TAG_VERSION} ~/artifact/rime-wanxiang-*.zip
# 正式发布
gh release edit ${TAG_VERSION} --draft=false --latest
env:
GH_TOKEN: ${{ github.token }}

295
.github/workflows/releases-napshot.yml vendored Normal file
View File

@@ -0,0 +1,295 @@
name: Build release branch snapshot
on:
workflow_dispatch: # 手动触发
push:
branches:
- wanxiang
concurrency:
group: release-branch
cancel-in-progress: true
jobs:
build-release:
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Release build
run: bash .github/workflows/scripts/release-build.sh
# 1. 用 dist/ 里的产物拼出 snapshot 目录
- name: Prepare snapshot tree from dist
run: |
set -euo pipefail
rm -rf snapshot
mkdir -p snapshot
# 使用 dist/ 里的目录构建 snapshot
if ls dist/rime-wanxiang-* 1> /dev/null 2>&1; then
for d in dist/rime-wanxiang-*; do
[ -d "$d" ] || continue
name="$(basename "$d")"
echo "Copying directory $d -> snapshot/$name"
mkdir -p "snapshot/$name"
cp -a "$d"/. "snapshot/$name"/
done
else
echo "Error: no dist/rime-wanxiang-* directories found."
exit 1
fi
echo "Snapshot tree after prepare:"
ls -R snapshot || true
# 2. 检查这次提交是否修改了 dicts 相关文件(控制 3/4/5 是否执行)
- name: Check if dicts changed
id: dicts_changed
run: |
set -euo pipefail
# 手动触发workflow_dispatch直接视为「有变动」强制跑
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# 找到上一条提交(第一次提交可能没有 HEAD^,单独处理)
if git rev-parse HEAD^ >/dev/null 2>&1; then
RANGE="HEAD^ HEAD"
else
echo "Only one commit, treat as changed."
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# 检查本次改动的文件里有没有命中 dicts 目录
if git diff --name-only $RANGE | grep -E '(^dicts/|^rime-wanxiang-.*/dicts/)' >/dev/null 2>&1; then
echo "dicts changed."
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "dicts not changed."
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
# 3. 从 dist 中打出每夜词库 zip不套文件夹只打 dicts/**
- name: Pack nightly dict zips
if: steps.dicts_changed.outputs.changed == 'true'
run: |
set -euo pipefail
mkdir -p dist
pack_dict() {
local src="$1"
local zip_name="$2"
if [[ -d "$src" ]]; then
echo "Packing $src -> dist/${zip_name}"
(cd "$src" && zip -r -q "../../${zip_name}" .)
else
echo "Warning: $src does not exist, skipped."
fi
}
pack_dict "dist/rime-wanxiang-moqi-fuzhu/dicts" "pro-moqi-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-flypy-fuzhu/dicts" "pro-flypy-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-zrm-fuzhu/dicts" "pro-zrm-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-tiger-fuzhu/dicts" "pro-tiger-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-wubi-fuzhu/dicts" "pro-wubi-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-hanxin-fuzhu/dicts" "pro-hanxin-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-shouyou-fuzhu/dicts" "pro-shouyou-fuzhu-dicts.zip"
pack_dict "dist/rime-wanxiang-base/dicts" "base-dicts.zip"
echo "Nightly dict zips in dist/:"
ls -1 dist/*.zip || true
# 4. 删除旧的 Nightly Release 和 Tag
- name: Delete existing Nightly Release and Tag
if: steps.dicts_changed.outputs.changed == 'true'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const tag = "dict-nightly";
try {
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo
});
const existingRelease = releases.data.find(r => r.tag_name === tag);
if (existingRelease) {
console.log(`Deleting existing Release with ID: ${existingRelease.id}`);
await github.rest.repos.deleteRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: existingRelease.id
});
}
console.log(`Deleting tag: ${tag}`);
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `tags/${tag}`
});
} catch (error) {
console.log(`Error deleting Release or Tag: ${error.message}`);
}
- name: Wait for cleanup
if: steps.dicts_changed.outputs.changed == 'true'
run: sleep 10
# 5. 创建新的 Nightly Release上传词库 zips
- name: Create dict-nightly Release
if: steps.dicts_changed.outputs.changed == 'true'
uses: softprops/action-gh-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: dict-nightly
name: "实时提交的词库更新"
body: |
- **base-dicts.zip**:最新的标准版原始中文词库文件
- **pro-moqi-fuzhu-dicts.zip**:携带了墨奇辅助码的词库文件
- **pro-flypy-fuzhu-dicts.zip**:携带了小鹤辅助码的词库文件
- **pro-zrm-fuzhu-dicts.zip**:携带了自然码辅助码的词库文件
- **pro-tiger-fuzhu-dicts.zip**:携带了虎码辅助码的词库文件
- **pro-wubi-fuzhu-dicts.zip**:携带了五笔辅助码的词库文件
- **pro-hanxin-fuzhu-dicts.zip**:携带了汉心辅助码的词库文件
- **pro-shouyou-fuzhu-dicts.zip**:携带了首右辅助码的词库文件
- **[wanxiang-lts-zh-hans.gram](https://github.com/amzxyz/RIME-LMDG/releases/download/LTS/wanxiang-lts-zh-hans.gram)**:与词库同步更新的语法模型
files: |
dist/pro-moqi-fuzhu-dicts.zip
dist/pro-flypy-fuzhu-dicts.zip
dist/pro-zrm-fuzhu-dicts.zip
dist/pro-tiger-fuzhu-dicts.zip
dist/pro-wubi-fuzhu-dicts.zip
dist/pro-hanxin-fuzhu-dicts.zip
dist/pro-shouyou-fuzhu-dicts.zip
dist/base-dicts.zip
draft: false
prerelease: false
make_latest: true
# 6. 为每个方案生成独立分支wanxiang-base / wanxiang-moqi-fuzhu / ...
- name: Commit and force push per-scheme snapshots
env:
GIT_AUTHOR_NAME: ci-bot
GIT_AUTHOR_EMAIL: ci@example.com
GIT_COMMITTER_NAME: ci-bot
GIT_COMMITTER_EMAIL: ci@example.com
run: |
set -euo pipefail
# 当前开发分支(通常是 wanxiang
ORIG_BRANCH="$(git rev-parse --abbrev-ref HEAD || echo 'wanxiang')"
# 方案列表
schemes=("base" "shouyou-fuzhu" "zrm-fuzhu" "tiger-fuzhu" "moqi-fuzhu" "flypy-fuzhu" "wubi-fuzhu" "hanxin-fuzhu")
# 每个方案公共文件清单(在分支根目录使用)
COMMON_FILES=(
"dicts/*.*"
"opencc/*.*"
"custom/*.*"
"lua/*.*"
"lua/lib/*.*"
"lua/tips/*.*"
"default.yaml"
"weasel.yaml"
"wanxiang*.*yaml"
"README.md"
"简纯+.trime.yaml"
"custom_phrase.txt"
)
TAG_NAME="${{ github.event_name == 'release' && github.event.release.tag_name || 'manual-build' }}"
for scheme in "${schemes[@]}"; do
branch="wanxiang-${scheme}" # 分支名wanxiang-moqi-fuzhu
src_dir="snapshot/rime-wanxiang-${scheme}" # 每个方案的源码目录(来自 snapshot
echo "=== Building branch ${branch} from ${src_dir} ==="
if [ ! -d "${src_dir}" ]; then
echo "Warning: ${src_dir} not found, skip ${branch}."
continue
fi
# 切换/创建分支
if git show-ref --verify --quiet "refs/heads/${branch}"; then
git checkout "${branch}"
else
git checkout --orphan "${branch}"
fi
# 清空当前工作区(仅保留 .git 和 snapshot
find . -mindepth 1 -maxdepth 1 ! -name ".git" ! -name "snapshot" -exec rm -rf {} +
# 把这个方案的内容「拍扁」到分支根目录(不保留 rime-wanxiang-xxx 那一层)
cp -a "${src_dir}"/. .
# 在这个分支里生成自己的 plum 配方
mkdir -p plum
#################################
# 生成 plum/full.recipe.yaml
#################################
{
echo "# encoding: utf-8"
echo "---"
echo "recipe:"
echo " Rx: plum/full"
echo " args:"
echo " description: >-"
echo " 万象拼音 ${scheme} 版(整个方案目录)- 分支 ${branch}"
echo "install_files: >-"
for path in "${COMMON_FILES[@]}"; do
echo " ${path}"
done
} > "plum/full.recipe.yaml"
#################################
# 生成 plum/dicts.recipe.yaml
#################################
{
echo "# encoding: utf-8"
echo "---"
echo "recipe:"
echo " Rx: plum/dicts"
echo " args:"
echo " description: >-"
echo " 万象拼音 ${scheme} 版仅词库dicts-only- 分支 ${branch}"
echo "install_files: >-"
echo " dicts/*.*"
} > "plum/dicts.recipe.yaml"
git status
# 注意:不要把 snapshot/ 提交进去
git add .
git reset snapshot || true
git rm -r --cached snapshot 2>/dev/null || true
git commit -m "chore(${branch}): snapshot for ${TAG_NAME}" \
|| echo "Nothing to commit for ${branch}."
git push -f origin "${branch}"
done
# 回到原来的开发分支,并清掉 snapshot只删 CI 本地)
git checkout "${ORIG_BRANCH}" || true
rm -rf snapshot

197
.github/workflows/scripts/aux_go.py vendored Normal file
View File

@@ -0,0 +1,197 @@
import os
import re
# ---------- 在第一个点前插入后缀base.dict.yaml -> base.pro.dict.yaml ----------
def add_suffix_before_extensions(filename: str, suffix: str) -> str:
if not suffix:
return filename
i = filename.find('.')
return (filename + suffix) if i == -1 else (filename[:i] + suffix + filename[i:])
# ========== 1) 从“单个 aux 文件”加载 字 -> 辅助码段列表 ==========
# 行格式:字<TAB>;段1;段2;... (保留空段,不偏移;段内逗号原样保留)
def load_aux_table(aux_file_path):
if not os.path.isfile(aux_file_path):
raise FileNotFoundError(f"aux 文件不存在:{aux_file_path}")
aux_map = {}
print(f'加载辅助码表文件: {os.path.basename(aux_file_path)}')
with open(aux_file_path, 'r', encoding='utf-8') as f:
for raw in f:
line = raw.strip()
if not line or line.startswith('#'):
continue
parts = line.split('\t')
if len(parts) < 2:
continue
ch = parts[0]
aux_list = parts[1].split(';') # 保留空串占位(分号才是边界)
aux_map[ch] = aux_list
return aux_map
# ========== 2) 区间选择(严格:第 N 段 = aux_list[N]N 从 1 起)==========
# 不处理逗号:分号窗口原样拼接
def select_aux_segment(aux_list, start_idx, end_idx=None):
if not aux_list:
return ''
s = max(1, start_idx)
e = end_idx if end_idx is not None else len(aux_list)
e = max(s, min(e, len(aux_list)))
window = aux_list[s:e] # 允许空段
return ''.join(window) if window else ''
DIGIT_RE = re.compile(r'^\d+$')
# ========== 3) 处理单个词库(流式;空也占位“拼音;”)==========
def process_file_for_range_streaming(in_file, out_file, aux_map, start_idx, end_idx, sep=';'):
os.makedirs(os.path.dirname(out_file), exist_ok=True)
try:
fin = open(in_file, 'r', encoding='utf-8')
except Exception as e:
print(f'读取失败 {in_file}: {e}')
return
try:
fout = open(out_file, 'w', encoding='utf-8')
except Exception as e:
fin.close()
print(f'写入失败 {out_file}: {e}')
return
passthrough_set = {
"\td\t1000",
"\tl\t999",
"\tm\t999",
"\tb\t999",
}
processing = False
for line in fin:
if not processing:
fout.write(line)
if '...' in line:
processing = True
continue
raw = line.rstrip('\n')
if (not raw) or raw.lstrip().startswith('#'):
fout.write(line)
continue
parts = raw.split('\t')
if len(parts) == 1:
fout.write(line)
continue
han = parts[0]
col2 = parts[1] if len(parts) > 1 else ''
col3 = parts[2] if len(parts) > 2 else ''
col4 = parts[3] if len(parts) > 3 else ''
# 第二列若是频率(全数字),挪到第三列
if DIGIT_RE.fullmatch(col2 or ''):
col3, col2 = col2, ''
# 特定行直通
if raw.strip() in passthrough_set:
fout.write(raw + '\n')
continue
pinyins = col2.split(' ') if col2 else []
if len(pinyins) != len(han):
warn = f"# 警告: 拼音数与字数不匹配({in_file}) => {raw}"
print(warn)
fout.write(warn + '\n')
continue
_get = aux_map.get
new_cols = []
for i, ch in enumerate(han):
aux_list = _get(ch)
piece = select_aux_segment(aux_list, start_idx, end_idx) if aux_list is not None else ''
new_cols.append(pinyins[i] + sep + piece) # 空也占位:拼音;片段
new_col2 = ' '.join(new_cols)
if col4:
fout.write(f"{han}\t{new_col2}\t{col3}\t{col4}\n" if col3 else f"{han}\t{new_col2}\t\t{col4}\n")
else:
fout.write(f"{han}\t{new_col2}\t{col3}\n" if col3 else f"{han}\t{new_col2}\n")
fin.close()
fout.close()
print(f'已处理: {out_file}')
# ========== 4) 扫目录 + 六套区间(按白名单)==========
def process_batch(input_dir, aux_file_path, base_out_dir, index_mapping, files_whitelist=None,
sep=';', output_suffix=""):
aux_map = load_aux_table(aux_file_path)
print(f'已加载辅助码条目:{len(aux_map)}')
# 收集要处理的文件
to_process = []
for entry in os.scandir(input_dir):
if not entry.is_file():
continue
name = entry.name
if files_whitelist and name not in files_whitelist:
continue
if not (name.endswith('.yaml') or name.endswith('.yml') or name.endswith('.txt')):
continue
to_process.append(entry.path)
if not to_process:
print("输入目录内没有匹配文件")
return
for s_idx, e_idx, subdir in index_mapping:
out_dir = os.path.join(base_out_dir, subdir)
os.makedirs(out_dir, exist_ok=True)
print(f'\n=== 区间 ({s_idx}, {e_idx}) → {subdir} ===')
for in_file in to_process:
fn = os.path.basename(in_file)
out_name = add_suffix_before_extensions(fn, output_suffix)
out_file = os.path.join(out_dir, out_name)
process_file_for_range_streaming(in_file, out_file, aux_map, s_idx, e_idx, sep=sep)
# ========== 5) 入口 ==========
if __name__ == '__main__':
# 六套区间(第 N 段,从 1 起)
index_mapping = [
(1, 2, "pro-moqi-fuzhu-dicts"),
(2, 3, "pro-flypy-fuzhu-dicts"),
(3, 4, "pro-zrm-fuzhu-dicts"),
(4, 5, "pro-tiger-fuzhu-dicts"),
(5, 6, "pro-wubi-fuzhu-dicts"),
(6, 7, "pro-hanxin-fuzhu-dicts"),
(7, None, "pro-shouyou-fuzhu-dicts"),
]
# 路径
AUX_FILE = "custom/aux_code.txt" # ← 单个 aux 文件
INPUT_DIR = "dicts" # ← 词库文件夹
OUT_ROOT = "." # ← 输出根目录
# 仅处理这些文件
FILES = [
"jichu.dict.yaml",
"zi.dict.yaml",
"duoyin.dict.yaml",
"cuoyin.dict.yaml",
"diming.dict.yaml",
"shici.dict.yaml",
"lianxiang.dict.yaml",
"renming.dict.yaml",
"wuzhong.dict.yaml",
"shuxue.dict.yaml",
"dikuang.dict.yaml",
"wu-hua-sheng-yi-yao.dict.yaml",
]
# 输出文件在第一个点前插这个后缀(如 ".pro";设为空串则不加)
OUTPUT_SUFFIX = ".pro"
process_batch(
INPUT_DIR, AUX_FILE, OUT_ROOT,
index_mapping,
files_whitelist=FILES,
sep=';',
output_suffix=OUTPUT_SUFFIX
)

View File

@@ -0,0 +1,78 @@
#!/bin/bash
set -e
# 声明辅助码 zip 包类型显示名
declare -A display_names=(
[zrm]="自然码"
[moqi]="墨奇"
[flypy]="小鹤"
[hanxin]="汉心"
[wubi]="五笔前2"
[tiger]="虎码首末"
[shouyou]="首右"
)
# 仓库和下载地址定义
REPO_URL=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}
DOWNLOAD_URL=${REPO_URL}/releases/download/${TAG_VERSION}
# 获取 changelog标题相同的 commit 合并链接)
CHANGES=$(
gh release view --json body -t "{{.body}}" "${TAG_VERSION}" | sed '1d; /./,$!d'
)
{
echo "## 📝 更新日志"
echo ""
echo "${CHANGES}"
echo ""
echo "## 🚀 下载引导"
echo ""
echo "### 1. 标准版输入方案"
echo ""
echo "✨**适用类型:** 支持全拼、各种双拼"
echo ""
echo "✨**下载地址:** [rime-wanxiang-base.zip](${DOWNLOAD_URL}/rime-wanxiang-base.zip)"
echo ""
echo "### 2. 双拼辅助码增强版输入方案"
echo ""
echo "✨**适用类型:** 支持各种双拼+辅助码的自由组合"
for type in "${!display_names[@]}"; do
name="${display_names[$type]}"
echo " - **${name}辅助版本:** [rime-wanxiang-${type}-fuzhu.zip](${DOWNLOAD_URL}/rime-wanxiang-${type}-fuzhu.zip)"
done
echo ""
echo "### 3. 语法模型"
echo ""
echo "✨**适用类型:** 所有版本皆可用"
echo ""
echo "✨**下载地址:** [wanxiang-lts-zh-hans.gram](https://github.com/amzxyz/RIME-LMDG/releases/download/LTS/wanxiang-lts-zh-hans.gram)"
echo ""
echo "## 📘 使用说明(QQ群11033572 参与讨论)"
echo ""
echo "1. **不使用辅助码的用户:**"
echo ""
echo " 请直接下载标准版,按仓库中的 [README.md](${REPO_URL}/blob/wanxiang/README.md) 配置使用。"
echo ""
echo "2. **使用增强版的用户:**"
echo " - PRO 每一个 zip 是**完整独立配置包**,其差异仅在于词库是否带有特定辅助码。"
echo ' - zrm 仅表示“词库中包含zrm辅助码”并**不代表这是自然码双拼方案,万象支持任意双拼与任意辅助码组合使用**。'
echo " - 若已有目标辅助码类型,只需下载对应 zip解压后根据 README 中提示修改表头(例如双拼方案)即可使用。"
echo ""
echo "3. **语法模型需单独下载**,并放入输入法用户目录根目录(与方案文件放一起),**无需配置**。"
echo ""
echo "4. 💾 飞机盘下载地址(最快更新):[点击访问](https://share.feijipan.com/s/xiGvXdKz)"
echo ""
echo "5. Arch Linux 用户推荐 [启用 Arch Linux CN 仓库](https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/) 或通过 [AUR](https://aur.archlinux.org/pkgbase/rime-wanxiang),按需安装。"
echo " - 基础版包名:\`rime-wanxiang-[拼写方案名]\`,如:自然码方案:\`rime-wanxiang-zrm\`"
echo " - 双拼辅助码增强版包名:\`rime-wanxiang-pro-[拼写方案名]\`,如:自然码方案:\`rime-wanxiang-pro-zrm\`"
echo "6. Deepin Linux v25 用户亦可以通过仓库进行安装。"
echo "### 4. 周边推荐"
echo " - [高度适配万象拼音的仓输入法皮肤](https://github.com/BlackCCCat/ResourceforHamster/tree/main/Skin_Keyboard/)"
echo ""
echo " - [好用的更新脚本,助你优雅管理版本](https://github.com/rimeinn/rime-wanxiang-update-tools)"
echo ""
echo " - [万象cnb仓库无需梯子的类GitHub仓库国内平台](https://cnb.cool/amzxyz/rime-wanxiang)"
} >release_notes.md

View File

@@ -0,0 +1,152 @@
#!/bin/bash
# 打包对用方案到 zip 文件,放到 dist 目录
set -e
ROOT_DIR="$(cd "$(dirname "$0")/../../../" && pwd)"
DIST_DIR="$ROOT_DIR/dist"
CUSTOM_DIR="$ROOT_DIR/custom"
# 成成 PRO 分包文件
echo "▶️ PRO 分包开始"
python3 "$ROOT_DIR/.github/workflows/scripts/aux_go.py"
echo "✅ PRO 分包完毕"
echo
package_schema_base() {
OUT_DIR=$1
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR"
# 1) custom/:仅拷贝 yaml/md/jpg/png排除指定文件保留目录结构
mkdir -p "$OUT_DIR/custom"
rsync -av --prune-empty-dirs \
--include='*/' \
--exclude='wanxiang_chaifen_*.dict.yaml' \
--exclude='wanxiang_chaifen.schema.yaml' \
--exclude='wanxiang_pro.custom.yaml' \
--exclude='wanxiang_pro.dict.yaml' \
--exclude='wanxiang_pro.schema.yaml' \
--include='*.yaml' --include='*.md' --include='*.jpg' --include='*.png' \
--exclude='*' \
"$CUSTOM_DIR/" "$OUT_DIR/custom/"
# 2) 根目录 → $OUT_DIR不排 dicts/),排除若干
OUT_BASE="$(basename "$OUT_DIR")"
rsync -av --ignore-existing \
--exclude='/.*' \
--exclude='/dist/' \
--exclude='/release-please-config.json' \
--exclude='/pro-*-fuzhu-dicts' \
--exclude='/chaifen' \
--exclude='/CHANGELOG.md' \
--exclude='/custom' \
--exclude='/LICENSE' \
--exclude="/$OUT_BASE" \
"$ROOT_DIR/" "$OUT_DIR/"
}
package_schema_pro() {
SCHEMA_NAME="$1"
OUT_DIR="$2"
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR"
# 1) 移动分包后的 dicts
if [[ -d "$ROOT_DIR/pro-$SCHEMA_NAME-fuzhu-dicts" ]]; then
mv "$ROOT_DIR/pro-$SCHEMA_NAME-fuzhu-dicts" "$OUT_DIR/dicts"
fi
# 1.1) 补充必要的附加文件
for f in en.dict.yaml "cn&en.dict.yaml" chengyu.txt people.dict.yaml; do
if [[ -f "$ROOT_DIR/dicts/$f" ]]; then
cp "$ROOT_DIR/dicts/$f" "$OUT_DIR/dicts/"
fi
done
# 2) 复制拆分表并重命名,同时拷贝 schema
src="$ROOT_DIR/custom/wanxiang_chaifen_${SCHEMA_NAME}.dict.yaml"
dst="$OUT_DIR/wanxiang_chaifen.dict.yaml"
[[ -f "$src" ]] && cp "$src" "$dst"
for f in \
wanxiang_pro.dict.yaml \
wanxiang_pro.schema.yaml \
wanxiang_chaifen.schema.yaml
do
src="$ROOT_DIR/custom/$f"
dst="$OUT_DIR/$f"
[[ -f "$src" ]] && cp "$src" "$dst"
done
# 3) custom/:仅拷贝 yaml/md/jpg/png排除若干保留目录结构
mkdir -p "$OUT_DIR/custom"
rsync -av --prune-empty-dirs \
--include='*/' \
--exclude='wanxiang.custom*' \
--exclude='wanxiang_chaifen_*.dict.yaml' \
--exclude='wanxiang_chaifen.schema.yaml' \
--exclude='wanxiang_pro.dict.yaml' \
--exclude='wanxiang_pro.schema.yaml' \
--include='*.yaml' --include='*.md' --include='*.jpg' --include='*.png' \
--exclude='*' \
"$ROOT_DIR/custom/" "$OUT_DIR/custom/"
# 4) 根目录 → $OUT_DIR排除若干
OUT_BASE="$(basename "$OUT_DIR")"
rsync -av --ignore-existing \
--exclude='/.*' \
--exclude='/dist/' \
--exclude='/dicts' \
--exclude='release-please-config.json' \
--exclude='pro-*-fuzhu-dicts' \
--exclude='wanxiang_t9.schema.yaml' \
--exclude='CHANGELOG.md' \
--exclude='wanxiang.dict.yaml' \
--exclude='wanxiang.schema.yaml' \
--exclude='custom' \
--exclude='LICENSE' \
--exclude="/$OUT_BASE" \
"$ROOT_DIR/" "$OUT_DIR/"
# 5) default.yaml: - schema: wanxiang -> - schema: wanxiang_pro
sed -i -E 's/^([[:space:]]*)-\s*schema:\s*wanxiang\s*$/\1- schema: wanxiang_pro/' "$OUT_DIR/default.yaml"
}
package_schema() {
SCHEMA_NAME="$1"
echo "▶️ 开始打包方案:$SCHEMA_NAME"
if [[ "$SCHEMA_NAME" == "base" ]]; then
OUT_DIR="$DIST_DIR/rime-wanxiang-base"
package_schema_base "$OUT_DIR"
ZIP_NAME=rime-wanxiang-"$SCHEMA_NAME".zip
else
OUT_DIR="$DIST_DIR/rime-wanxiang-$SCHEMA_NAME-fuzhu"
package_schema_pro "$SCHEMA_NAME" "$OUT_DIR"
fi
ZIP_NAME=$(basename "$OUT_DIR").zip
(cd "$OUT_DIR" && zip -r -9 -q ../"$ZIP_NAME" . && cd ..)
echo "✅ 完成打包: $ZIP_NAME"
echo
}
SCHEMA_LIST=("base" "flypy" "hanxin" "moqi" "tiger" "wubi" "zrm" "shouyou")
# 如果没有传入参数,则循环 package 所有的
if [[ -z "$SCHEMA_NAME" ]]; then
for name in "${SCHEMA_LIST[@]}"; do
package_schema "$name"
done
exit 0
fi
if [[ ! " ${SCHEMA_LIST[*]} " =~ ${SCHEMA_NAME} ]]; then
echo "参数错误: 只支持 ${SCHEMA_LIST[*]}" >&2
exit 1
fi
package_schema "$SCHEMA_NAME"

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
# lua 目录下动态生成的记录文件,不应被 git 追踪
lua/input_stats.lua
lua/seq_words.lua
# 本地测试打包时的临时文件
dist
pro-*-fuzhu-dicts
release_notes.md

View File

@@ -0,0 +1 @@
{".":"13.6.3"}

2159
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

395
LICENSE Normal file
View File

@@ -0,0 +1,395 @@
Attribution 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of
these terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the
Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted
Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

615
README.md Normal file
View File

@@ -0,0 +1,615 @@
---
# 万象系列方案 [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/amzxyz/rime_wanxiang)
---------------------
## 万象拼音——基于深度优化的词库和语法模型
[万象词库与万象语言模型](https://github.com/amzxyz/RIME-LMDG) 是一种带声调的词库经过AI和大基数语料筛选、加频结合语言模型获得更准确的整句输出。
### 优势
1. 在这里你能找到最为全面的拼音标注数据库,词库词语全部加音调。可应用于多种带声调输入方案,也可将声调作为注释,输入码位置显示,也可直接上屏,是唯一一个支持整句拼音串上屏的方案;
2. 长期死磕首选权重最优解、分词片段最优解,大量应用错位构词法,让语句行云流水,结合语法模型,维护词库与维护模型同时进行,形成完美搭配;
3. 在这里你能找到最为全面的反查数据库现已支持到U17支持两分、多分、笔画三种打法,在生僻字输入、反查的场景中发挥重要作用;
4. 在这里你能找到最为有趣的Lua扩展功能如成对符号包裹首选、tips多类型扩展显示与上屏、手动实时排序以及无感造词不调频的新鲜用法
5. 维护了来自圈内的6种辅助码头部使用全拼编码可以转化为任何双拼编码辅助码有墨奇码鹤形自然码虎码首末五笔前2汉心码因此万象拼音支持拼音和辅助码任意两两组合
6. 万象总结下来,从里到外,是一场翻天覆地的巨变,所涉及之处无不要求做到最优、最精。 这是我们持续的追求!
**万象词库中的带声调拼音标注+词组构成+词频是整个万象项目的核心,是使用体验的基石,方案的其它功能皆可自定义,我希望使用者可以基于词库+转写的方式获得输入体验** [万象词库问题收集反馈表](https://docs.qq.com/smartsheet/DWHZsdnZZaGh5bWJI?viewId=vUQPXH&tab=BB08J2)
---------------------
**效果大赏**
![效果.png](https://storage.deepin.org/thread/202502200358104987_效果.png)
---------------------
|版本差异|标准版|增强版|
|--- | ---- | --- |
|方案文件|wanxiang.schema.yaml|wanxiang_pro.schema.yaml|
|支持类型|全拼、任何双拼|只支持双拼|
|是否调频|默认开启|默认关闭|
|用户词记录|无差别自动记录,词库混乱|需手动造词``引导,词库可控|
|用户词位置|wanxiang.userdb|zc.userdb|
|辅助码|有基于声调的辅助|有7种辅助码可选同时兼容声调辅助|
|简码|全拼开启基于转写的简码,双拼未开启|有携带部分数据但未配置(自己设置的才是自己的)|
|词库格式|你➩nǐ➩1000|你➩nǐ;re➩1000|
### 新手快速入门
不了解rime基础的可以参考友情链接初步了解rime运行的些许特性
[oh my rime](https://www.mintimate.cc/zh/guide/installRime.html)
[rime参数配置](https://xishansnow.github.io/posts/41ac964d.html)
整个rime配置生态都是通的里面有非常完整的使用方法(诸如放到哪里、换个皮肤、什么是用户目录。。。)
**友情提示:** *如果你是第一次使用万象,可以不要用你过往经验来定义万象,按如下的步骤将万象跑起来后,体验一下万象的功能,然后学习一下万象的各项内容之后再考虑。*
#### ①快速运行:
1. 将方案文件置于用户目录中,直接部署,等待部署完成后,
2. 输入以下指令(斜杠引导)切换为对应的双拼/全拼,切换后按照提示重新部署,完成。
3. 这样的指令能帮你一次性完成4个补丁文件的输入类型修改运行逻辑根目录无自定义文件则复制custom文件夹相关文件出来并修改为对应的输入方案如果根目录存在则只修改输入方案不进行复制因此不会被覆盖。
4. ios仓输入法平台特殊需要额外去方案文件管理-使用键盘文件覆盖应用文件,才能完成文件变更,具体操作如下:
- 仓设置首页 -> 输入方案设置 -> 点击右上角 "+" -> 方案下载 -> 下载一套万象输入法方案, 如: 万象拼音标准版
- 仓设置首页 -> 体验输入法 (或者随便找一个可以唤起输入法的场景) - 长按键盘输入"/" (不要上划输入), 然后接想要的方案, 比如 "/flypy", 此时输入法会提示已切换至相应方案
- 仓设置首页 -> 文件管理 -> 拷贝键盘词库至应用
- 仓设置首页 -> RIME -> 重新部署
5. ios元书输入法使用万象改双拼方案的方法从RimeSharedSupport中复制include_keyboard_rime_files.txt到万象方案目录下修改include_keyboard_rime_files.txt在底部新增```^.*[.]custom.*$```的正则表达式然后重新部署即可实现自动复制键盘文件包含custom字符串文件到应用文件
```
/flypy → 小鹤双拼
/mspy → 微软双拼
/zrm → 自然码
/sogou → 搜狗双拼
/znabc → 智能ABC
/ziguang → 紫光双拼
/pyjj → 拼音加加
/gbpy → 国标双拼
/lxsq → 乱序17
/pinyin → 全拼
/wxsp → 万象双拼
/zrlong → 自然龙(反查是全拼)
/hxlong → 汉心龙(反查是全拼)
/jjf → 间接辅助
/zjf → 直接辅助
```
5. 下载语法模型,放置于用户文件夹,无需配置。
但要注意个别安卓前端如小企鹅它的数据位于data这个是受到安卓权限限制的你需要通过安卓文件框架去迁移文件到内部而不是使用MT文件管理迁移这会导致权限异常部署报错现实表现为是不是太大了是不是特别占内存卡成这样。。。如果你清楚Linux权限逻辑实际上不是MT不能用而是是否root并具备修改权限的能力单纯的复制不会与data数据的权限保持一致修改成一致的权限就能用了。
郑重说明模型是一个优秀的大数据遍历能力的模块他能方便的扩展词库数据的不足非100%外显它只消耗一些cpu的算力占用极少的内存而且他是不增大的固定的二进制数据请区别于小而美的热加载数据看待。
#### ②东风破plum
安装环境可用plum命令简单安装与更新在保证安装小狼毫、中州韵、鼠须管等前端的前提下
```
macOS / Linux 已内置 bash无需处理
Windows 需要 Git Bash安装 Git for Windows 时自动提供,)
```
注意:
Windows 的 PowerShell / CMD 不能直接运行东风破,必须用 Git Bash。
<details> <summary><strong>点击展开 / 收起 万象全部安装命令(可一键复制)</strong></summary>
1. 先安装plum这是维护在万象仓库plum分支的版本去掉了默认方案修改了默认路径直接复制2个命令粘贴终端直接执行打开终端的目录由你决定
```base
git clone -b plum --depth 1 https://github.com/amzxyz/rime_wanxiang.git
cd plum
```
2. 配置用户目录变量,检查状态是否正常:
对于小狼毫、鼠须管、Fcitx5已经默认配置了变量
```base
export rime_frontend='rime/weasel'
export rime_frontend='rime/squirrel'
export rime_frontend='fcitx5/fcitx5-rime'
```
但对于Linux、Mac使用ibus、fcitx前端就需要自己设置变量这个变量可以终端执行但最好直接写入~/.zshrc
```base
export rime_frontend=rime/ibus-rime
export rime_frontend=fcitx/fcitx-rime
```
3. 有了上面的工具后你可以切换到刚刚拉取下来的脚本所在目录,执行以下对应的安装目录,即可实现安装和更新
##### 基础版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-base:plum/full
```
##### 基础版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-base:plum/dicts
```
##### 自然码辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-zrm-fuzhu:plum/full
```
##### 自然码辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-zrm-fuzhu:plum/dicts
```
##### 墨奇辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-moqi-fuzhu:plum/full
```
##### 墨奇辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-moqi-fuzhu:plum/dicts
```
##### 小鹤辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-flypy-fuzhu:plum/full
```
##### 小鹤辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-flypy-fuzhu:plum/dicts
```
##### 虎码辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-tiger-fuzhu:plum/full
```
##### 虎码辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-tiger-fuzhu:plum/dicts
```
##### 五笔辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-wubi-fuzhu:plum/full
```
##### 五笔辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-wubi-fuzhu:plum/dicts
```
#### 汉心辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-hanxin-fuzhu:plum/full
```
##### 汉心辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-hanxin-fuzhu:plum/dicts
```
##### 首右辅助版(完整)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-shouyou-fuzhu:plum/full
```
##### 首右辅助版(仅词库)
```bash
bash rime-install amzxyz/rime_wanxiang@wanxiang-shouyou-fuzhu:plum/dicts
```
</details>
**③进阶custom patch法已经尽量为你简化强烈推荐适用于长期稳定使用**
其实快速运行中我们已经完成了custom patch的部署里面还预设了一些示例这些例子只是例子请务必详细阅读每一行保留有用的删除无用的千万不要改完双拼就万事大吉了每一行详细查阅、理解、修改。custom是对对应方案文件的最后一道补丁是真正属于你自己的配置文件他不会被升级所覆盖。
方案提供了custom文件夹预设了一些文件与教程请不要删除相关文件根据文件夹中内容进行相关修改变更
**不要在default.custom写东西,任何patch都要对方案文件进行patchdefault.custom留给前端操作请务必悉知**
```
wanxiang.custom.yaml是对wanxiang.schema.yaml的补丁以此类推
可以打补丁的类型:
schema,default,weasel,squirrel
```
注意不要删除和变更每一个custom的表头。
更详细参照:[🚀 Rime 万象拼音输入方案 新手安装配置指南](https://docs.qq.com/doc/DQ0FqSXBmYVpWVFpy?rtkey=)
**④第三方脚本更新:**
脚本的下载地址 [万象方案更新脚本](https://github.com/rimeinn/rime-wanxiang-update-tools)。这里以win版本的小狼毫为例如果你是**中文系统**请下载更新脚本的 powershell **非utf-8版本**,具体文件名:`rime-wanxiang-update-windows.ps1` 。在使用万象之前,请安装小狼毫,安装小狼毫的过程中,请一切保持默认即可,等你熟悉之后可以自定义。本入门最终会带你一步步设置使用**小鹤双拼+墨奇辅助码**的方案。
1. 下载更新脚本:直接点击上面地址首页右边最新 release 链接,然后下载对应的 `rime-wanxiang-update-windows.ps1` 文件即可。下载完成后直接双击运行刚刚下载的ps1脚本。如果杀毒报错请将你下载的文件恢复后添加到信任文件。如果执行一闪而过、或者遇到乱码再尝试下载 utf-8 版本,具体文件名:`rime-wanxiang-update-windows-utf-8.ps1`。如果提示权限不足,可以在 powershell 终端中执行 `Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser` 再尝试运行下载的 ps1 脚本。
2. 脚本执行后,需要你确认你使用的是全拼还是双拼用户,如果你是全拼用户,请根据提示输入 0 后回车。如果你双拼用户需要你确认你使用的辅助码类型默认的万象方案支持汉心、简单鹤、墨奇、虎码、五笔、自然码共计6种辅助码类型。如果没有你想要的辅助码类型也不要着急可在熟悉万象之后自定义。根据提示输入你使用的辅助码类型的数字后回车即可。这里我按墨奇辅助码输入。更不要着急怎么选择双拼方案后面会告诉你的。
3. 脚本继续执行,提示选择是否全部更新,不要管,你是新手,直接选全部更新,输入 0 回车。然后就默默的等待脚本执行完后,按任意键退出即可。默认情况下,万象的双拼方案为自然码。
4. 在使用脚本更新之前务必使用进阶custom patch法维护好你的配置更新不会覆盖custom.yaml类文件
**⑤自定义数据获取:**
在线custom目录随有三个数据源提供按自己需求自行整理取用这部分数据没有随zip方案包一起供应需在线下载。
- jm_flypy.txt 用于提供小鹤类型的简码下载后复制到根目录custom_phrase.txt自定义库即可使用
- jm_zrm.txt 用于提供自然码类型的简码下载后复制到根目录custom_phrase.txt自定义库即可使用
- tips_user.txt tips用到的“翻译”类型的数据下载后放置于lua/tips里面重新部署。
### 答疑
[为什么PRO版本默认关闭调频的说明](https://github.com/amzxyz/RIME-LMDG/wiki/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%85%B3%E9%97%AD%E8%B0%83%E9%A2%91%E4%BB%A5%E5%8F%8A%E4%B8%8E%E4%B9%8B%E5%85%B3%E8%81%94%E7%9A%84%E6%8E%AA%E6%96%BD%E6%9C%89%E5%93%AA%E4%BA%9B) ```enable_user_dict: false # 是否开启自动调频true为开启```
### 功能一览
#### 辅助码
辅助码可以在输入一个确定得拼音后面继续输入一个部首的读音,使得这个字出现在靠前甚至第一位。这种方式易于理解,无须记忆字根,一切基于拼音得基础上。例如:
![截图_选择区域_20240704121653.png](https://storage.deepin.org/thread/202407041144502563_截图_选择区域_20240704121653.png)
**功能1** **仅PRO** 直接辅助--如果想要 `` 字显示在前面 那么在本方案下提供两种方式,第一种就是辅助码声母,`vf`继续输入`j` 也就是金字旁得声母即可出现结果,如果还是出现不了你要的结果,可以输入另外主体字的声母来继续缩小范围。
![截图_选择区域_20240704121809.png](https://storage.deepin.org/thread/202407041147131421_截图_选择区域_20240704121809.png)
句子中间或者单字输入时需要输入全位辅助码时由于与双拼词语重码因为我们设计的基本辅助码是2位加上双拼共4位由于在整句中我们为了整句输入的顺畅不会将4码聚拢作为优先级较高的选择这样会在很多时候造成你想打的句子缩成一团变成全辅助码的词汇。此时可以通过追加/的方式使其聚拢,这种方式是由于我们是直接辅助码导致的,如果我们通过一个符号引导辅助码,那么在输入时要每一个都用到符号,而采用这种方式我们只需要在必要的时候使用/节省了输入的按键开支,下面由两个图片说明问题:
![截图_选择区域_20240821093644.png](https://storage.deepin.org/thread/202408210142513354_截图_选择区域_20240821093644.png)
![截图_选择区域_20240821093701.png](https://storage.deepin.org/thread/202408210143144721_截图_选择区域_20240821093701.png)
**功能2** **仅PRO** 间接辅助--除以上直接使用辅助外,我们还支持中间加入/来引导辅助码的输入,即:功能1是"nire/" 在有需求的时候末尾增加斜杠能让系统侧重于单字,平时则永远在动态切分,这个模式也是比较吃词库的,当你的词组完整,遇到的异常就少,当词组不完整,你想输入三个字2+2=2编码结构,恰好辅助码与双拼编码重合就会出现3+3的聚拢,此时将你想输入的三个字放入词库中,这个问题就得到了解决,还有得项目通过Lua重新切分来解决,看似巧妙,实际上比较吃操作,影响节奏,无疑万象在很多选择上面选择了更加难的路线,用词库的全面性来托举.
而在功能2中是"ni/re",也就是说辅助码必须经过/来引导,如果你不输入/它将与普通双拼无异,优点是类似vsg能够派生出"中国",更适用于新手辅助码或者叫辅助码轻量使用者.
**功能3** 第二种方式是通过反查字库来定位,只是通过不同的方案实现,在输入主要拼音后,通过符号``` ` ``` 来引导进入反查状态,引导后继续输入`jn`金 则包含金的字就会被选出来;
![截图_选择区域_20240704121635.png](https://storage.deepin.org/thread/202407041149125588_截图_选择区域_20240704121635.png)
引导后继续输入`mu 木`则带``的字就会被选出来
![截图_选择区域_20240704121611.png](https://storage.deepin.org/thread/202407041149524870_截图_选择区域_20240704121611.png)
如果你输入的是词汇,则会按照第一个字来辅助反查,因此在开关中有:[词组优先、单字优先],例如:"```nihk`r```" 候选会有:你好 你,如果单字优先就是 你 你好,此时上屏“你” 整个编码的视觉就是 "```你hk` ```"此时可以继续输入n来筛选出”好“这样你好就完成了上屏当然一般用于输入一些生僻词组
实际上我们同时支持,```两分:你(ni`rferni`re)、多分mu`ckrida、笔画你ni`pspzhpd```
**功能4** 通过 拼音状态下``` `〔反查:部件|笔画〕``` 来引导拆字模式 举例 ```震``` 假设你不认识,你可以通过`雨和辰` 来合并输入拼音状态输入后继续输入其它字符字母az会消失如下图输入 ```yu if``` 即雨 辰,结果出现了我们要的震字,且给出了辅助码 ```y``` 和 ```i``` ```y```是雨的声母```y``````i```是辰的声母```ch```同时兼容通过hspnz代表横竖撇捺折五笔画。功能3是功能4的另一种表现形式,或者叫用法。这个功能依赖wanxiang_reverse.schema.yaml方案,可以通过custom配置成任意全拼双拼以匹配主方案一致的输入方式,因此是不是输入jn=jin需要看你具体的双拼类型。
![截图_选择区域_20240928112256.png](https://storage.deepin.org/thread/202409280324599355_截图_选择区域_20240928112256.png)
**功能5** 句子中间或者单字输入时需要可以使用更精确的聚拢方式"声调辅助"7890数字按键代表1234声轻声归并到4声在功能4中我们可以在双拼两码后面3个编码的位置任意插入声调与两位辅助码混合使用就是除了不用斜杠了我们还顺序自由了下面由两个图片说明问题,其实在键盘上想要安排四个按键是很难得,不是占用这个按键就是占用另外的,还有得朋友觉得离得远,还有得更是不需要声调,要把候选做成9个。这些都是存在的情况,现在的处理也是妥协后的结果,要想完全不占用按键类似的办法可以改成大写字母来代表,像地球拼音则是使用大于小于号这一片的符号来表示,我们的词库有声调这个基础,一定程度上还是要利用起来:
<img src="https://storage.deepin.org/thread/202505120222182012_截图_选择区域_20250512101814.png" height="130" width="520">
<img src="https://storage.deepin.org/thread/20250512022217432_截图_选择区域_20250512101752.png" height="130" width="520">
<img src="https://storage.deepin.org/thread/202505120222163619_截图_选择区域_20250512101713.png" height="130" width="520">
**功能6** 混合输入:字母、汉字、数字、用于连接的特殊符号等组合以及英文混输我们统一放在了wanxiang_mixedcode.schema.yaml混合编码方案里此功能无需引导直接输入不参与组句类似1000wclips、AD钙奶、PN结、Type-C以及纯英文同样可以通过custom来定义你所使用的双拼。
![东风5C](https://storage.deepin.org/thread/202509260105536966_混合编码.jpg)
**整合说明** 万象方案整合度很高我们不希望使用户文件夹变得复杂功能5中我们将两类习惯的五笔画和多分拆字和两分拆字整合到了一起可以认为是4个挂接方案在功能6中我们将 英文输入、中英混合编码、以及一些其他混合编码整合到了一起,共享方案转写,两个功能都保证了可配置性,都能与你所使用的双拼契合,
对于词库也都整合到了dicts里面为了能更好的统一更新和分发仓库中我们支持基础版本词库、携带pro的辅助码版本词库、英文词库、混合词库4个类别在release中各自归类最终做到了根目录15个文件、4个文件夹示人其中的custom目录还携带了用户自定义的法宝秘籍能称得上简约而不简单。
#### 其他亮点功能
**日期、时间、节日、节气、问候模板:**
可以在按键配置的地方定制引导前缀
```key_binder/shijian_keys: ["/", "o"]``` 这样的配置以为你你可以/sj也可以osj某些方案o有别的作用时候可以去掉o,灵活处理。
输入后N0101四位数模式下可以采用qwerty...依次代表123456上屏也可以按下方向键上下进行候选的选择。如果输入完整的八个数字则还是使用数字就能选择上屏
还有他强大的自定义能力,类型、格式、顺序、候选数,每一样都可以自定义,安全的占位逻辑和转译方式
```yaml
#shijian:仅仅作为提示使用编码已经写死引导键可以在key_binder下修改前缀
#时间osj 或者 /sj
#日期orq 或者 /rq
#农历onl 或者 /nl
#星期oxq 或者 /xq
#今年第几周oww 或者 /ww
#节气ojq 或者 /jq
#日期+时间odt 或者 /dt
#时间戳ott 或者 /tt
#大写N日期N20250315 或者N0312不带年
#节日ojr 或者 /jr
#问候模板:/day 或者 oday
# 通用日期时间格式化函数(供 /rq、/sj、/dt、N0101、N20150101 场景复用)
# 支持转义:
# \X —— 转义单个字符 X按字面量输出如 \Y \m \H 等)
# [[...]] —— 区块整体按字面量输出
#
# 约定占位符:
# 【日期】
# Y 四位年份 0000-9999 例2025
# y 两位年份 00-99 例25
# m 月(前导零) 01-12 例02
# n 月(不带前导零) 1-12 例2
# d 日(前导零) 01-31 例09
# j 日(不带前导零) 1-31 例9
#
# 【时间】
# H 24小时前导零 00-23 例08
# G 24小时不带零 0-23 例8
# I 12小时前导零 01-12 例08
# l 12小时不带零 1-12 例8 (注意是小写 L
# M 分钟(前导零) 00-59 例05
# S 秒(前导零) 00-59 例09
# p am/pm小写 am / pm
# P AM/PM大写 AM / PM
# 【时区】
# O 带冒号格式 +08:00、-04:30、+05:45
# o 不带冒号格式 +0800、-0430、+0545
date_formats:
- "Y年m月d日"
- "Y-m-d"
- "Y/m/d"
- "Y.m.d"
- "Ymd"
- "Y年n月j日"
- "y年n月j日"
- "n月j日"
time_formats:
- "H:M"
- "H点M分"
- "H:M:S"
- "H时M分S秒"
- "下午I:M"
- "I:M P"
datetime_formats:
- "Y-m-d H:M:S"
- "Y-m-dTH:M:S O"
- "YmdHMS"
- "Y年m月d日 H点M分"
- "y/m/d I:M p"
```
<img src="https://storage.deepin.org/thread/202509260107542641_N20250102.jpg" height="80">
<img src="https://storage.deepin.org/thread/202509260108069991_N0102.jpg" height="80">
**Unicode** 大写 U 开头,如 U62fc 得到「拼」。
<img src="https://storage.deepin.org/thread/202509260111366093_U码.jpg" height="80">
**数字、金额大写:** 大写 R 开头,如 R1234 得到「一千二百三十四、壹仟贰佰叁拾肆元整」。输入后该模式下可以采用qwerty...依次代表123456上屏也可以按下方向键上下进行候选的选择。
<img src="https://storage.deepin.org/thread/202509260124573417_金额大写.jpg" height="80">
**/引导模式:** 通过输入 /sx 快捷输入关于“数学”的特殊符号,具体能输入什么可以打开 symbols.yaml学习。以及前述提到的日期时间等的引导都共用斜杠开头可以理解为一种命令模式。
<img src="https://storage.deepin.org/thread/202509260126183029_符号数学.jpg" height="80">
<img src="https://storage.deepin.org/thread/202509260126173818_符号大于.jpg" height="80">
<img src="https://storage.deepin.org/thread/202509260126167252_符号圆点.jpg" height="80">
**计算器:** 通过输入大写V引导继续输入如V3+5 候选框就会有8和3+5=8基础功能 `+ - * / % ^` 还支持 `sin(x) cos(x)` 等众多运算方式打开super_calculator.lua阅读相关用法。
<img src="https://storage.deepin.org/thread/202509260127113759_计算器1.png" height="80">
<img src="https://storage.deepin.org/thread/202509260127126065_计算器2.jpg" height="80">
**自动上屏:** 例如:三位、四位简码唯一时,自动上屏如`jjkw岌岌可危` `zmhu怎么回事` 。默认未开启,方案文件中`speller:`字段下取消注释这两句开启 `# auto_select: true # auto_select_pattern: ^[a-z]+/|^[a-df-zA-DF-Z]\w{3}|^e\w{4}`
**错音错字提示:** 例如:输入`gei yu给予`,获得`jǐ yǔ`提示,此功能与全拼、双拼类型无关全部支持;
<img src="https://storage.deepin.org/thread/202509260127525844_错音给予.jpg" height="80"> <img src="https://storage.deepin.org/thread/202509260127524705_错音崩溃.jpg" height="80">
**快符Lua** 例如通过 ```a/``` 快速自动上屏“”符号或者定义为任意字符享受26字母的扩展。其中值设置为`repeat`则意味着按下对应按键能否重复上一次上屏的内容。位于方案中quick_symbol_text段落是可以自定义映射关系的对于特殊需求用户还可以修改正则表达式让引导策略发生变化如首字符引导
**超级tips** 支持将表情、化学式、翻译、简码 提示等等你能想到得数据获得提示显示并将通过一个自定义按键直接上屏,默认为“,” 也表现为逗号避免了这类内容占用候选框轻量化提示与上屏的能力。如果你设置逗号句号为翻页逗号翻页如果正好是首选匹配句号作为下一页则不干扰当想要回到第一页此时已经不匹配tips此时逗号就不被tips占用了就可以用于翻页。也可以将触发键变更为其他位于key_binder/tips_key: "comma"。对于加载的类型可以屏蔽某一种位于tips/disabled_types: [],括号内填入# 可选项为偏旁符号化学式时间符号组字翻译表情货币车牌等禁用类型。通过Control+t 进行开关。
仓输入法、超越输入法设置按键交由rime去处理没有特殊需求应该一律交给rime如需关闭将tips开关reset 0即可
某些前端开启嵌入与窗口交互有bug在开启tips的时候可能会造成异常的编码上屏此时可以关闭tips在这些窗口使用输入法。
化学式:<img src="https://storage.deepin.org/thread/202509260128462735_tips化学式.jpg" height="80">符号:<img src="https://storage.deepin.org/thread/202509260128454675_tips符号.jpg" height="80">表情:<img src="https://storage.deepin.org/thread/202509260128457494_tips表情.jpg" height="80">
**首选格式化:** 将自定义短语中,诸如\n \s \t 等行中标识符转换为实际的换行、空格、制表符等等使得类似输入jys可以打出一首带格式的《静夜思》这将成为类似书名号输入场景的利器。
例:```静夜思\n\s\s李白\n床前明月光\n疑似地上霜\n举头望明月\n低头思故乡 jys```
<img src="https://storage.deepin.org/thread/202509260129305342_格式化.jpg" height="260">
**首选加成对符号:** 将输入中的短语通过输入追加\a 这样的末尾编码触发相对于a这个字母映射的成对符号例如``` sj mk lq lh ji\l=《三毛流浪记》```可以通过custom自定义符号和触发方式。
工作逻辑:输入词汇编码 > 按下锁定按钮\ > 按下映射字符\a > 《候选包裹成对符号》
<img src="https://storage.deepin.org/thread/202509260130219621_首选成对符号1.jpg" height="80"> <img src="https://storage.deepin.org/thread/202509260130208277_首选成对符号2.jpg" height="80"> <img src="https://storage.deepin.org/thread/202509260130199763_首选成对符号3.jpg" height="80">
**英文候选格式化:** 输入hello则得到hello输入首字母大写Hello则得到Hello和一众首字母大写的联想词输入前两码大写HEllo则得到全为大写的HELLO和一众大写英文。
<img src="https://storage.deepin.org/thread/202509260133175234_首字母大写.jpg" height="80">
<img src="https://storage.deepin.org/thread/202509260133175362_双字母大写.jpg" height="80">
**辅助码提示仅PRO** 任意长度候选词的辅助码提示能力默认开启1个字的辅助码可以在方案文件中定义更长的长度。Ctrl+a可以实时在开启辅助码提示、开启声调全拼提示、关闭注释 三个状态循环Ctrl+c开启拆分辅助提示优先级高于普通辅助提示
<img src="https://storage.deepin.org/thread/202509260134283927_辅助码提示.jpg" height="80">
<img src="https://storage.deepin.org/thread/202509260134278003_声调提示.jpg" height="80">
<img src="https://storage.deepin.org/thread/202509260134284782_拆分提示.jpg" height="80">
**输入码音调显示:** 通过Ctrl+s可以使得输入码实时动态显示全拼并加音调这是万象特色功能
**用户按需造词仅PRO** 默认通过``` `` ```引导的方式进入用户词自造词模式,继续输入则``` `` ```前缀消失,后面打出来的字上屏后完成造词。 pro版本讲究自主可控由于辅助码的使用在很多时候不熟悉的时候可能会上屏更加异常的词汇或者生僻字有的用户还不会使用Esc退出输入而是选择直接敲下空格。按需造词可以有效把控造出的词是有意义的而且默认靠后原因简单基本上有意义的高频词万象已经提供你应该使用辅助码将其前置。**重点**:在此基础上我们还支持“后触发”当你输入编码后发现没有你要的行业词汇,此时在后面双击``` `` ``` 就可以在不删除编码的情况下完成造词。还有一个是次选造词,如果次选是你想要的,并且是词库组合成的,上屏就会记录下来。
总结一下,造词功能由:①``` `` ```起始的主动造词,②``` `` ```在编码后面的主动造词,③次选造词。三个特性构成
**中文无感造词仅PRO** 在关闭调频的情况下通过逐步选字选词的方式上屏将为你记录整段且不会产生小碎片所造词汇与db用户词是一回事遵循用户词管理的相关逻辑其中直接上屏不造词。相比按需造词更加不打断输入。
**英文造词:** 例如当输入scx的时候没有任何候选此时可以追加\```scx\```可以触发创建候选,但是有的时候我们想要任意编码进行英文造词,但是又有汉字在前面怎么办,本着一次不行就来两次的原则```nihao\\```末尾输入两个就可以了。然后空格上屏他就记录到了en.userdb导出和同步与用户词逻辑一致。
**用户词删除:** 使用Ctrl+del是rime系统删除用户词,就可以将用户词标记为c<=0这在rime系统中就表现为不使用假性删除。
**输入模式切换:** 使用Ctrl+q来进行中文候选词、英文候选词、混合候选词之间切换默认为混合编码输入模式。
**手动排序Lua** ①词典候选类型对选中的候选词操作使用Ctrl+j向左一步Ctrl+k向右一步Ctrl+l(零)移除选中排序信息Ctrl+p 置顶选中候选。其作用于当时编码与候选词②动态生成的Lua候选很多时候我们对日期、时间等输出格式首选有着自己的追求复杂的配置又往往提升了使用难度于是我们基于排序Lua实现了动态内容的按序号索引的排序也就是说该序号下原本生成的格式整个发生了位置变化使用方法一致。信息储存于Lua文件夹下排序数据库中sequence.userdb支持导出导入数据便于多设备共用。
排序信息同步:
A 先点击同步,多见于右键菜单,保证创建了相应的同步目录,如没有自定义则位于用户目录下/sync
1. 打开用户目录会有installation.yaml文件打开后会有如下信息我们将installation_id认为是设备id初次会创建自动串号你也可以将其修改为当前设备名称
```
distribution_code_name: "fcitx-rime"
distribution_name: Rime
distribution_version: 5.1.9
install_time: "Mon Jun 23 18:47:55 2025"
installation_id: "ff9b2823-8733-44bb-a497-daf382b74ca5" #这里可以随意编辑比如修改为windows
rime_version: 1.13.1
update_time: "Sat Sep 6 16:08:56 2025"
```
得到这个id后我们就可以下一步构建出同步文件的名称sequence_设备id.txt
2. 首先确定一个主要管理设备,在/sync中创建一个描述设备清单的文件 `sequence_device_list.txt`,这个清单告诉程序要读取同目录下哪些文件进行合并
```内部内容为:
sequence_deepin.txt
sequence_windows.txt
sequence_iPhone.txt
```
3. 按「部署」,会进行以下几步:
①、自动导出数据到 `sequence_deepin.txt` 文件(假设为当前设备),因此这个当前设备文件会被覆盖,请不要手动修改避免丢失;
②、读取列表中列出的文件,按时序以保留最新动作为依据进行去重合并,合并后数据将会回写到 `sequence_deepin.txt` 文件;
③、将合并后的文件导入db数据库完成数据合并注意p=0的重置后的编码不会导入数据库如数据库原本有对应的词汇将删除对应的键。
4. 通过云同步将/sync完成同步到windows设备同步后编辑 `sequence_device_list.txt`将sequence_windows.txt写入文件让同步程序再次完成多端同步
此时目录中已经存在如下文件,此时重新部署,稍作等待将会完成`sequence_windows.txt`的输出
`sequence_device_list.txt`
`sequence_deepin.txt`
`sequence_windows.txt` #同步后新增
再次手动完成手动云同步,及时让文件对齐。
B 重复以上操作完成更多设备的添加和同步
由于此流程为模拟rime同步的方式rime的同步本质上就是多端的数据合并的过程可靠性可能相较于原生较弱一些尤其是iPhone可能遇到更多问题。
**声调辅助回退Lua** 万象是将7890用来代表1234声轻声归并到了4我们支持在例如输入ni9后发现我可能要4声ni0此时我们无需删除数字9而是直接输入对的0类似手动在7890之间轮巡能有效快速提升声调辅助的效率减少使用负担也是万象独创功能。
**小键盘有妙用Lua** auto模式可配置输入中数字跟在字母后面不上屏。compose模式可配置数字持续不上屏不用区分先后。
**删除键限制Lua** 可以在输入中当持续按下删除编码为0时会卡住抬起重新按下才能继续删除已经上屏内容避免误删除上屏内容。目前仅PC可用也是万象独创功能。
**输入长度限制Lua** 对两类场景进行限制避免数据并发卡顿1、重复输入8个连续相同的字母aaaaaaaa会提示:已超最大重复声母。因为连续多个的重复字母会造成严重的卡顿2、分词片段限制在30个也就是30个字过长的语句价值不大还会造成卡顿。
**Tab循环切换音节** 当输入多个字词时想要给前面补充辅助码可以多次按下tab循环切换这种可能比那些复杂的快捷键好用一些同样逻辑的按键还包含ctrl+tab相当于逐字确认错了可以补充编码对了继续按下直到全部上屏
**“候选切割机”Lua** 这个功能是有候选的时候通过按下ctrl+1~0中的10组组合键直接上屏首选前N个字编码按现有音节分割后续编码保留一般来说在输入句子的时候由于读音和构词的相似性以及模型数据的偏差可能会出现错误的连续这个时候恰当的切割让前面正确的直接上屏残留的编码一般自动变为首选正确的选项了此时上屏或继续切割或者使用tab补充编码。这个功能在base双拼中具备更高的确定性而在pro版本中如果遇到直接辅助码的聚拢那么此时候选估计与你初心不一致此时可以考虑借助多次按下单引号来循环分词或许能得到你要的候选如未得到直接esc重新输入更为高效。更为激进的用法直接上屏正确的部分后面的编码直接遗弃现在没有写进去或许可以作为一个选项如果你也像这样可以issue告诉我我们可以改造成布尔选项
**翻译模式:** 输入状态按下Ctrl+E快捷键进入翻译模式原理是opencc查表进行中英文互译能否翻译取决于词表的丰富度
**字符集过滤Lua** 默认开启过滤写在charset.dict.yaml的就是可以通过的字表默认为8105+𰻞𰻞如果你想什么字在小字集模式可以通过可以写在这里配套开关【小字集、大字集】快捷键Ctrl+g
**万能键斜杠/**
* 符号扩展输入: rime(大部分前端)是一种最小化ui的输入法除了输入界面几乎看不到ui设置界面及符号表情面板的组件因此我们在想要输入一些符号表情等特殊内容的时候会根据类型设计一个触发条件这个条件类似以什么编码开始作为标识、或者是某种tag状态。万象又是一个兼容多种输入类型的方案我们无法找到一个绝对的空码字母作为触发条件或多或少会冲突因此我们选择了斜杠作为引导条件例如/sx可以打出加减乘除等等/yd可以打出圆点集合等等
* 辅助码聚拢: 我们在转写中将四个字母+/作为高权重的编码意思就是侧重输入单字而四个字母则采用abbrev这种情况有词的情况有限出词没词才会变成单字毕竟我们是一个语句流方案核心还是想输入多长输入多长的类大厂习惯的输入法因此单字就不能像字词音形方案那样四码定位一个字
* 间接辅助码引导: 直接辅助码我们是在四个编码末尾追加斜杠/而间接辅助是在两个编码即双拼后面加斜杠意思就是后面继续输入编码就能用辅助码对这个单字进行筛选如果不加斜杠就与正常的双拼无异这时vs g=中国就能被打出来,不习惯直接辅助的可以选用这种方式;
* 短码英文前置: 对于英文词典中我们常常遇到us以及United States这种缩写那么在你水平一般的情况下输入两个字母前面可能是一大堆重要的中文词汇和单字那么这个例子就显得不恰当了不重要这个时候输入us/就可以让us编码相关的英文词条前置此时次选就是United States有的时候是能输出对应大写支持1-3个字母因为但凡输入四个字母以上基本上会获得直接的前置了
* 快符: 输入一个单字母+/完成对应映射上屏a/这样还能定义某个按键是用来重复上屏之前的内容例如q/最终形成自己的习惯,原本分号引导包括数字都能用,但是分号太过珍贵,方案层面就不占用了;
* 上屏斜杠自己: 通过双击斜杠直接上屏他自己;
**按键设置思考:**
* 我们说有舍有得如何合理安排这些按键是一个重要课题很多新手上来就要遵循自己以前的习惯但那些习惯又何尝不是其他软件灌输给你的我们何曾思考过合理性对于rime不思考就定义不好定义不好不如继续用大厂。对于万象斜杠/是不可能被挪作他用的因此莫要针对这件事提问修改的地方过多没有精力教学。反斜杠是顿号、分号有次选需求、引号要分词中括号要以词定字逗号句号在没有tips的时候更倾向于随语句一起上屏节约按键在有tips的时候句号在手机电脑上任何键盘大概率都能直接按因此默认-=作为翻页这与老祖宗ABC时期用法一样某种程度7890代表的1234声调与-=凑在一起构成了一个筛选区在重新选择rime作为输入法的时候我还是建议重新思考一下自己所谓的习惯
**自定义短语:** 将根目录中的custom_phrase.txt文本以表导入到rime实现实际的编码对应你想要的输出床前明月光\tcqm其中\t代表制表符不能输入的复制前面的行修改可见字符尽量不要使用记事本编辑换一个更高级的文本编辑器。这个功能主要用来短编码输入长短语、符号数字串等等各种需要置顶的内容一定要根据万象的初始化在wanxiang.custom中修改名称避免更新被覆盖丢失数据。
**自定义词库:** 自定义词库首先要利用工具将你自己的词库刷成与万象同类型的声调、或者声调+辅助码的形态因为主词库要参与转写。对于custom_phrase则需要手动编辑编码为实际输入的编码。
要保证每个字编码与chars完全一致这是基础不再赘述。
##### 固定词库:
#packs法要保证外部名称`userxx.dict.yaml`与里面`name: userxx`一致,
```
patch:
translator/packs/+:
- userxx
```
#重命名法,重命名用户根目录`wanxiang.dict.yaml`为`wanxianguser.dict.yaml`,避免更新被覆盖
#所有主方案文件中使用了这个固定词库的位置都要变更
```
patch:
translator/dictionary: wanxianguser
radical_reverse_lookup/dictionary: wanxianguser
user_dict_set/dictionary: wanxianguser
add_user_dict/dictionary: wanxianguser
```
##### 用户词库迁移:
一个前置知识:同步是将用户词按时序合并导入导出的本地操作。
请不要将这个rime文件夹部署到同步软件下面这将造成数据库被同步锁定无法正常工作同步的最高级目录为/sync
确认你的同步目录,默认用户目录下面的/sync如果自定义在installation.yaml文件中写入
linux\mac\android这样写
```
sync_dir: "/home/amz/sync"
```
windows这样写
```
sync_dir: "D:\\home\\amz\\sync" #双引号
sync_dir: 'D:\home\amz\sync' #单引号
```
你还可以将installation_id字段改成一个可辨识的名称如按系统命名
知道了这些以后你可以创建以下文件夹他们的名称来自installation_id字段
```
xxx/sync/windows
xxx/sync/linux
xxx/sync/ios
```
你完全可以在用户目录看到wanxiang.userdb他就是你实时工作的数据库PRO版本是zc.userdb当你点击右键菜单同步用户数据时
系统将会将用户词库以txt方式释放到`xxx/sync/windows/wanxiang.userdb.txt`
每一个wanxiang.userdb.txt表头都有一个表头
```
# Rime user dictionary
#@/db_name zc
#@/db_type userdb
#@/rime_version 1.13.1
#@/tick 793
#@/user_id ff9b2823-8733-44bb-a497-daf382b74ca5
```
关注db_name必须与用户词典文件名一致且不管多个设备不同设备文件夹下面的文件名称都应该一致看起来都是wanxiang.userdb.txt
关注user_id=windows(设备文件夹名称)=installation_id字段必须保持一致
如果只有一个设备,你完全可以在同步后删除用户目录的`userdb`,手动编辑`xxx/sync/windows/wanxiang.userdb.txt`
注意这里的编辑必须是经过预处理格式与万象编码完全一致的情形下,万象提供的工具就可以完成声调标注和辅助码标注
编辑好文件,确保放入设备目录,点击同步即可导入数据库
你还可以将你迁移的数据txt内部设备名称都修改成linux并将文件放入xxx/sync/linux
此时点击同步也能将用户词与windows文件夹下面的合并一起导入数据库模拟多设备同步这也是未来真正的多设备同步逻辑
- [用于Linux Mac的词库刷拼音辅助码工具](https://github.com/amzxyz/RIME-LMDG/releases/download/tools/wanxiang-dicts-tools-linux-mac)
- [用于Windows的词库刷拼音辅助码工具](https://github.com/amzxyz/RIME-LMDG/releases/download/tools/wanxiang-dicts-tools.exe)
<img alt="pay" src="./custom/万象输入方案.png">
## 鸣谢
- 感谢网友的热情提报问题,使得模型和词库体验进一步提升。
## 赞赏
如果觉得项目好用可以请AMZ喝咖啡
<img alt="pay" src="./custom/赞赏.jpg" height="312" width="446">

46238
custom/aux_code.txt Normal file

File diff suppressed because it is too large Load Diff

17756
custom/jm_flypy.txt Normal file

File diff suppressed because it is too large Load Diff

1766
custom/jm_zrm.txt Normal file

File diff suppressed because it is too large Load Diff

151
custom/patch方法论.md Normal file
View File

@@ -0,0 +1,151 @@
# Rime YAML Custom Patch 语法指南
## 语法表格
| 操作类型 | 语法 | 说明 |
| -------------- | ------------------------- | ---------------------------- |
| **新增** | `key/+:` | 在某个列表中追加值,自动加在末尾 |
| **删除** | `key/-:`(不可用) | 从列表中移除值(不可用) |
| **全局替换** | `key: new_value` | 替换整个键的值 |
| **部分替换** | `key/index/subkey: value` | 修改列表中的特定项,不影响其他项 |
| **特定行替换** | engine/filters/@12 | 替换列表中第13行的值 |
| **末尾行替换** | engine/processors/@last | 替换列表中最后一行的值 |
| **特定行追加** | engine/filters/@before 5 | 在第6行插入新值原值后移一行 |
注意在进行有关特定行的操作时请注意列表的计数是从0开始的。例如如果想在第5行插入一个值应该使用`@before 4`。如果要替换第5行的值应该使用`@4`
---
## 1. **新增值 (`/+`)**
```yaml
patch:
schema_list/+:
- luna_pinyin # 这是正确的例子:追加这个方案列表为启用状态,多个值列表即可
schema_list/-: wubi # 这是一个错误的例子:/-不可被使用
engine/filters/-:
- lua_filter@*en_spacer #这是一个错误的例子:/-不可被使用
menu/page_size: 10 # 这是正确的例子:单独替换最下层具体的值 page_size 值,不影响其他值
更多方式参考rime文档
```
# Rime YAML Patch 机制解析
## 为什么 `menu/page_size: 10` 和 `menu: { page_size: 10 }` 结果不同?
**Rime YAML Patch 机制** 下,`menu/page_size: 10``menu: { page_size: 10 }` **看似等价**,但 **行为是不同的**,主要原因在于 **Patch 机制的覆盖策略**
- **`menu/page_size: 10`** 仅修改 `menu` 下的 `page_size`,不会影响 `menu` 里的其他键值。
- **`menu: { page_size: 10 }`** **会直接覆盖** `menu`,即 **清空 `menu` 下原有的所有内容**,只留下 `page_size`
---
**假设一个段落:**
```yaml
menu:
page_size: 10
settings:
font_size: 14
color: blue
```
**正确写法(不会删除 `settings`)就是局部修改值:**
```yaml
patch:
menu/page_size: 10
```
**错误写法(会删除 `settings`)就是全局替换:**
```yaml
patch:
menu:
- page_size: 10
```
**以下是常用的三种情况:**
```yaml
#整体替换
patch:
engine:
translators:
- table_translator@custom_phrase #此例会替换整个engine模块的值只保留translators下的table_translator@custom_phrase其他值全部删除
```
```yaml
#部分替换
patch:
engine/translators:
- table_translator@custom_phrase #此例只会替换engine下的translators模块的值为table_translator@custom_phrasetranslators模块的其他值全部删除而engine其他模块的值不受影响
```
```yaml
#追加新的内容
patch:
engine/translators/+:
- table_translator@custom_phrase #此例只在engine下的translators模块下新增table_translator@custom_phrasetranslators模块的其他值不变engine其他模块的值也不受影响
```
也就是说不能用/-,如果想要删除某一行
下面再用两个实际的例子来巩固一下:
```yaml
#由于下面列表值,所以你想删除某一行只能在这里注释掉,还要观察主方案是否提供了新的值,删除某一个单独的值确实是个难点
patch:
engine/filters:
- lua_filter@*chars_filter
- lua_filter@*cold_word_drop.filter
- lua_filter@*assist_sort
- lua_filter@*autocap_filter
- reverse_lookup_filter@radical_reverse_lookup
- lua_filter@*pro_preedit_format
- simplifier@emoji
- simplifier@traditionalize
- simplifier@mars
- simplifier@chinese_english
- simplifier@zrm_chaifen
- lua_filter@*search@radical_pinyin
#- lua_filter@*en_spacer
- lua_filter@*pro_comment_format
- uniquifier
```
```yaml
#但是如果你想删除某一行携带值的整行,有办法了,用如下的表示即可,将现有的值清空,部署的时候整行也就不会生效了,这一行就不存在了
patch:
custom_phrase/user_dict:
custom_phrase/initial_quality:
```
最后还要注意一点,非常重要:
在engine模块下面的选项是有顺序的所以想要新增一个行需要判断添加到末尾是否可用如果是一个引导器就不能下面这样添加这会导致这一行排列在最后导致功能不能使用
```yaml
#追加新的内容
patch:
engine/translators/+: #这种方式将把新增值自动加在列表末尾,导致功能失效
- table_translator@custom_phrase
```
应该使用**特定行追加** engine/translator/@before 5 意思就是放到translator下面的第6行而原来第6行的值会移到第7行其他的依次后移
```yaml
patch:
engine/translator/@before 5: #这种方式将在第5行后面新增一行后面的行后移
table_translator@custom_phrase #注意前面不能加短线了,这样才是一个值,而不是一个表
engine/translator/@5: #这种方式将替换第6行的值
table_translator@custom_phrase #注意前面不能加短线了,这样才是一个值,而不是一个表
```

41742
custom/tips_user.txt Normal file

File diff suppressed because it is too large Load Diff

272
custom/wanxiang.custom.yaml Normal file
View File

@@ -0,0 +1,272 @@
#使用之前请详细遍历每一行,都注释了功能点,看清楚是不是你要的,需不需要修改参数,哪些该留,哪些该删除,够语重心长了吧😄
patch:
speller/algebra:
__patch:
#- 模糊音 # 这里启用后,本文件末尾可配置具体条目
- wanxiang_algebra:/base/全拼 # 可选输入方案名称:全拼,自然码, 自然龙, 汉心龙,小鹤双拼, 搜狗双拼, 微软双拼, 智能ABC, 紫光双拼, 国标双拼拼音加加乱序17
##########################以上格式受指令初始化控制,最好保持格式不变,如果发生变更请不要使用指令修改相关数据#####################################
#custom_phrase/user_dict: custom_phrasexx # 这里改成什么就需要手动创建同名的 custom_phrasexx.txt 文件在用户目录,这个文件主要用于置顶,编码为自定义编码的词汇
#translator/packs/+:
#- userxx #导入根目录下名称为userxx.dict.yaml的自定义固定词典编码要与固定词库一致编码权重都不要少形如姓名、专有名词公司名称等等
#下面是候选数量
menu/page_size: 6 #不要超过67890用于代表声调12346个管够你用了如果你非要10个不要问我😜。
#下面是超级注释相关
super_comment: # 超级注释模块,子项配置 true 开启false 关闭
candidate_length: 1 # 候选词辅助码提醒的生效长度0为关闭 但同时清空其它,应当使用上面开关来处理
corrector_type: "comment" # 错音措字,随意更换左右括号,比如"comment" 不加括号为无括号comment占位不能动
chaifen: "chaifen" # 拆分显示,随意更换左右括号,比如"chaifen" 不加括号为无括号chaifen占位不能动
#在8105基础上你可以通过黑白名单微调你自己的字符集过滤清单主数据库位于lua/charset.bin不可编辑
charsetlist: [你]
charsetblacklist: [鹵, 彔]
#小键盘数字处理逻辑
# "compose" : 小键盘数字始终参与编码
# "auto" : 输入中 push空闲时 commit默认
kp_number_mode: auto
#下面用于对/rq和N20250101这样的日期候选自定义顺序、类型、候选个数由你完全掌控前面是对于公历后面默认携带农历
# 通用日期时间格式化函数(供 /rq、/sj、/dt、N0101、N20150101 场景复用)
# 支持转义:
# \X —— 转义单个字符 X按字面量输出如 \Y \m \H 等)
# [[...]] —— 区块整体按字面量输出
#
# 约定占位符:
# 【日期】
# Y 四位年份 0000-9999 例2025
# y 两位年份 00-99 例25
# m 月(前导零) 01-12 例02
# n 月(不带前导零) 1-12 例2
# d 日(前导零) 01-31 例09
# j 日(不带前导零) 1-31 例9
#
# 【时间】
# H 24小时前导零 00-23 例08
# G 24小时不带零 0-23 例8
# I 12小时前导零 01-12 例08
# l 12小时不带零 1-12 例8 (注意是小写 L
# M 分钟(前导零) 00-59 例05
# S 秒(前导零) 00-59 例09
# p am/pm小写 am / pm
# P AM/PM大写 AM / PM
# 【时区】
# O 带冒号格式 +08:00、-04:30、+05:45
# o 不带冒号格式 +0800、-0430、+0545
date_formats:
- "Y年m月d日"
- "Y-m-d"
- "Y/m/d"
- "Y.m.d"
- "Ymd"
- "Y年n月j日"
- "y年n月j日"
- "n月j日"
time_formats:
- "H:M"
- "H点M分"
- "H:M:S"
- "H时M分S秒"
- "下午I:M"
- "I:M P"
datetime_formats:
- "Y-m-d H:M:S"
- "Y-m-dTH:M:S O"
- "YmdHMS"
- "Y年m月d日 H点M分"
- "y/m/d I:M p"
#下面用来改变你的windows小狼毫右下角软件图标
#schema/+:
# icon: "icons/zhong.ico"
# ascii_icon: "icons/ying.ico"
#下面这个可以改变tips上屏的按键
key_binder/tips_key: "comma" #修改时候去default找默认是逗号
key_binder/sequence: # Lua 配置:手动排序的快捷键 super_sequence.lua不要用方向键各种冲突一定要避免冲突
up: "Control+j" # 上移
down: "Control+k" # 下移
reset: "Control+l" # 重置
pin: "Control+p" # 置顶
# 快符功能:
# a/、单字母组合,触发预设编码自动上屏快符,支持将值设为"repeat" 以支持对应按键重复上屏功能custom>schema>lua最终合并键值
# 现在就支持26字母快符结合成对符号输入这边的压力小一些
quick_symbol_text:
trigger: "^([a-z])/$"
symkey:
q: "repeat"
w: ""
e: ""
r: ""
t: "~"
y: "·"
u: "『"
i: "』"
o: "〖"
p: "〗"
a: ""
s: "……"
d: "、"
f: "“"
g: "”"
h: ""
j: ""
k: "【"
l: "】"
z: "。”"
x: "?”"
c: "!”"
v: "——"
b: "%"
n: "《"
m: "》"
#通过在有候选的情况下,通过末尾检测到形如\a来触发为第一候选进行成对符号包裹例如nihao\c 候选[你好]
#trigger只能设置为单符号因为按下一次锁定第一候选按下映射开始包裹符号pro用户不能设置为/
#两个字符可以不用|默认前后分割,需要明确区分前后的使用|分割,可以有一侧为空,不可以使用多个||
paired_symbols:
#sort_window: 10
trigger: "\\" #(注意反斜杠这是转义写法\\使用时\单反斜杠即可)
mirror: true #包裹后完全替换第一候选true,原候选后移到第二false
symkey:
# ===== 基本括号与引号 =====
a: "[]" # 方括号
b: "【】" # 黑方头括号
c: "" # 双大括号 / 装饰括号
d: "" # 方头括号
e: "⟮⟯" # 小圆括号 / 装饰括号
f: "⟦⟧" # 双方括号 / 数学集群括号
g: "「」" # 直角引号
# h: 预留用于 Markdown 一级标题
i: "『』" # 双直角引号
j: "<>" # 尖括号
k: "《》" # 书名号(双)
l: "〈〉" # 书名号(单)
m: "" # 法文单书名号
n: "«»" # 法文双书名号
o: "⦅⦆" # 白圆括号
p: "⦇⦈" # 白方括号
q: "()" # 圆括号
r: "|儿" #儿化候选
s: "" # 全角方括号
t: "⟨⟩" # 数学角括号
u: "〈〉" # 数学尖括号
v: "〖〗" # 装饰花括号
w: "" # 全角圆括号
x: "" # 全角花括号
y: "⟪⟫" # 双角括号
z: "{}" # 花括号
# ===== 扩展括号族 / 引号 =====
dy: "''" # 英文单引号
sy: "\"\"" # 英文双引号
zs: "“”" # 中文弯双引号
zd: "" # 中文弯单引号
fy: "``" # 反引号
# ===== 双字母括号族 =====
aa: "〚〛" # 双中括号
bb: "〘〙" # 双中括号(小)
cc: "〚〛" # 双中括号(重复,可用于 Lua 匹配)
dd: "" # 小圆括号装饰
ee: "❪❫" # 小圆括号装饰
ff: "❬❭" # 小尖括号装饰
gg: "⦉⦊" # 双弯方括号
ii: "⦍⦎" # 双弯方括号
jj: "⦏⦐" # 双弯方括号
kk: "⦑⦒" # 双弯方括号
ll: "" # 小尖括号装饰
mm: "⌈⌉" # 上取整 / 数学符号
nn: "⌊⌋" # 下取整 / 数学符号
oo: "⦗⦘" # 双方括号装饰(补齐)
pp: "⦙⦚" # 双方括号装饰(补齐)
qq: "⟬⟭" # 小双角括号
rr: "" # 花括号装饰
ss: "⌜⌝" # 数学上角符号
tt: "⌞⌟" # 数学下角符号
uu: "⸢⸣" # 装饰方括号
vv: "⸤⸥" # 装饰方括号
ww: "﹁﹂" # 中文书名号 / 注释引号
xx: "﹃﹄" # 中文书名号 / 注释引号
yy: "⌠⌡" # 数学 / 程序符号
zz: "⟅⟆" # 数学 / 装饰括号
# ===== Markdown / 标记 =====
md: "**|**" # Markdown 粗体
jc: "**|**" # 加粗
it: "__|__" # 斜体
st: "~~|~~" # 删除线
eq: "==|==" # 高亮
ln: "`|`" # 行内代码
cb: "```|```" # 代码块
qt: "> |" # 引用
ul: "- |" # 无序列表项
ol: "1. |" # 有序列表项
lk: "[|](url)" # 链接
im: "![|](img)" # 图片
h: "# |" # 一级标题
hh: "## |" # 二级标题
hhh: "### |" # 三级标题
hhhh: "#### |" # 四级标题
sp: "\\|" # 反斜杠转义
br: "| " # 换行
cm: "<!--|-->" # 注释
# ===== 运算与标记符 =====
pl: "++"
mi: "--"
sl: "//"
bs: "\\\\"
at: "@@"
dl: "$$"
pc: "%%"
an: "&&"
cr: "^^"
cl: "::"
sc: ";;"
ex: "!!"
qu: "??"
sb: "sb"
#translator/enable_user_dict: true # 是否开启自动调频用户词,如果你希望使用下面``造词功能请保持false因为两个跨翻译器会造成词汇不能正常记录
#以下恢复``造词功能,也就是平时不记录,引导才记录,按需造词,如果你想恢复这个功能,请取消注释----
#recognizer/patterns/add_user_dict: "^``[A-Za-z/`']*$" #自造词引导方式
#user_dict_set/enable_user_dict: true
#add_user_dict/enable_user_dict: true
# 取消注释以开启自动无词频造词
#add_user_dict/enable_auto_phrase: true
#按需造词全功能段落结束---------------------------------------------------------------
模糊音:
__append:
# n - l
- derive/^l/n
- derive/^n/l
# r - y 开头
- derive/^y/r
- derive/^r/y
# h - f 开头
- derive/^h/f
- derive/^f/h
# r - l 开头
- derive/^r/l
- derive/^l/r
# k - g 开头
- derive/^k/g
- derive/^g/k
# an - ang
- derive/([ui]?)([āáǎàa])ng(.*)$/$1$2n$3
- derive/([ui]?)([āáǎàa])n(.*)$/$1$2ng$3
# en - eng
- derive/([ēéěèe])ng(.*)$/$1n$2
- derive/([ēéěèe])n(.*)$/$1ng$2
# in - ing
- derive/([īíǐìi])ng(.*)$/$1n$2
- derive/([īíǐìi])n(.*)$/$1ng$2
# c - ch
- derive/^c([^h]*)/ch$1
- derive/^ch/c
# z - zh
- derive/^z([^h]*)/zh$1
- derive/^zh/z
# s - sh
- derive/^s([^h]*)/sh$1
- derive/^sh/s

View File

@@ -0,0 +1,12 @@
# Rime schema settings
# encoding: utf-8
schema:
schema_id: wanxiang_chaifen
name: 万象:拆分注释滤镜
version: "1.0"
engine:
translator:
dictionary: wanxiang_chaifen

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
patch:
speller/algebra:
__include: wanxiang_algebra:/mixed/通用派生规则
__patch: wanxiang_algebra:/mixed/全拼 #可选的选项有(全拼, 自然码, 小鹤双拼, 微软双拼, 搜狗双拼, 智能ABC, 紫光双拼, 拼音加加, 自然龙, 汉心龙)

View File

@@ -0,0 +1,280 @@
patch:
speller/algebra:
__patch:
#- 模糊音 # 这里启用后,本文件末尾可配置具体条目
- wanxiang_algebra:/pro/自然码 # 可选输入方案名称:自然码, 自然龙, 小鹤双拼, 搜狗双拼, 微软双拼, 智能ABC, 紫光双拼, 国标双拼,龙三
- wanxiang_algebra:/pro/直接辅助 #辅助码升级为直接辅助和间接辅助两种类型都是句中任意不同点在于直接辅助是nire=你 而间接则需要/引导 ni/re=你 ,在这个基础上直接辅助支持拼音后任意位置数字声调参与,间接辅助声调在/引导前参与
#- 自然码提权 #本文件末尾,有自然码和小鹤的可以用
##########################以上格式受指令初始化控制,最好保持格式不变,如果发生变更请不要使用指令修改相关数据#####################################
#通过下面的设置可以让你自己的文件引入而与仓库custom_phrase.txt不同防止更新时被仓库文件覆盖
#custom_phrase/user_dict: custom_phrasexx # 这里改成什么就需要手动创建同名的 custom_phrasexx.txt 文件在用户目录,这个文件主要用于置顶,编码为自定义编码的词汇
#translator/packs/+:
#- userxx #导入根目录下名称为userxx.dict.yaml的自定义固定词典编码要与固定词库一致编码权重都不要少形如姓名、专有名词公司名称等等
#下面是候选数量未来7890分别代表1234声请候选长度不要大于6避免冲突
menu/page_size: 6
#下面是超级注释相关
super_comment: # 超级注释模块,子项配置 true 开启false 关闭
candidate_length: 1 # 候选词辅助码提醒的生效长度0为关闭 但同时清空其它,应当使用上面开关来处理
corrector_type: "comment" # 错音措字,随意更换左右括号,比如"comment" 不加括号为无括号comment占位不能动
chaifen: "chaifen" # 拆分显示,随意更换左右括号,比如"chaifen" 不加括号为无括号chaifen占位不能动
#在8105基础上你可以通过黑白名单微调你自己的字符集过滤清单主数据库位于lua/charset.bin不可编辑
charsetlist: [你]
charsetblacklist: [鹵, 彔]
#小键盘数字处理逻辑
# "compose" : 小键盘数字始终参与编码
# "auto" : 输入中 push空闲时 commit默认
kp_number_mode: auto
#下面用于对/rq和N20250101这样的日期候选自定义顺序、类型、候选个数由你完全掌控前面是对于公历后面默认携带农历
# 通用日期时间格式化函数(供 /rq、/sj、/dt、N0101、N20150101 场景复用)
# 支持转义:
# \X —— 转义单个字符 X按字面量输出如 \Y \m \H 等)
# [[...]] —— 区块整体按字面量输出
#
# 约定占位符:
# 【日期】
# Y 四位年份 0000-9999 例2025
# y 两位年份 00-99 例25
# m 月(前导零) 01-12 例02
# n 月(不带前导零) 1-12 例2
# d 日(前导零) 01-31 例09
# j 日(不带前导零) 1-31 例9
#
# 【时间】
# H 24小时前导零 00-23 例08
# G 24小时不带零 0-23 例8
# I 12小时前导零 01-12 例08
# l 12小时不带零 1-12 例8 (注意是小写 L
# M 分钟(前导零) 00-59 例05
# S 秒(前导零) 00-59 例09
# p am/pm小写 am / pm
# P AM/PM大写 AM / PM
# 【时区】
# O 带冒号格式 +08:00、-04:30、+05:45
# o 不带冒号格式 +0800、-0430、+0545
date_formats:
- "Y年m月d日"
- "Y-m-d"
- "Y/m/d"
- "Y.m.d"
- "Ymd"
- "Y年n月j日"
- "y年n月j日"
- "n月j日"
time_formats:
- "H:M"
- "H点M分"
- "H:M:S"
- "H时M分S秒"
- "下午I:M"
- "I:M P"
datetime_formats:
- "Y-m-d H:M:S"
- "Y-m-dTH:M:S O"
- "YmdHMS"
- "Y年m月d日 H点M分"
- "y/m/d I:M p"
#下面用来改变你的windows小狼毫右下角软件图标
#schema/+:
# icon: "icons/zhong.ico"
# ascii_icon: "icons/ying.ico"
#下面这个可以改变tips上屏的按键
key_binder/tips_key: "comma" #修改时候去default找默认是逗号
key_binder/sequence: # Lua 配置:手动排序的快捷键 super_sequence.lua不要用方向键各种冲突一定要避免冲突
up: "Control+j" # 上移
down: "Control+k" # 下移
reset: "Control+l" # 重置
pin: "Control+p" # 置顶
# 快符功能:
# a/、单字母组合,触发预设编码自动上屏快符,支持将值设为"repeat" 以支持对应按键重复上屏功能custom>schema>lua最终合并键值
# 现在就支持26字母快符结合成对符号输入这边的压力小一些
quick_symbol_text:
trigger: "^([a-z])/$"
symkey:
q: "repeat"
w: ""
e: ""
r: ""
t: "~"
y: "·"
u: "『"
i: "』"
o: "〖"
p: "〗"
a: ""
s: "……"
d: "、"
f: "“"
g: "”"
h: ""
j: ""
k: "【"
l: "】"
z: "。”"
x: "?”"
c: "!”"
v: "——"
b: "%"
n: "《"
m: "》"
#通过在有候选的情况下,通过末尾检测到形如\a来触发为第一候选进行成对符号包裹例如nihao\c 候选[你好]
#trigger只能设置为单符号因为按下一次锁定第一候选按下映射开始包裹符号pro用户不能设置为/
#两个字符可以不用|默认前后分割,需要明确区分前后的使用|分割,可以有一侧为空,不可以使用多个||
paired_symbols:
#sort_window: 10
trigger: "\\" #(注意反斜杠这是转义写法\\使用时\单反斜杠即可)
mirror: true #包裹后完全替换第一候选true,原候选后移到第二false
symkey:
# ===== 基本括号与引号 =====
a: "[]" # 方括号
b: "【】" # 黑方头括号
c: "" # 双大括号 / 装饰括号
d: "" # 方头括号
e: "⟮⟯" # 小圆括号 / 装饰括号
f: "⟦⟧" # 双方括号 / 数学集群括号
g: "「」" # 直角引号
# h: 预留用于 Markdown 一级标题
i: "『』" # 双直角引号
j: "<>" # 尖括号
k: "《》" # 书名号(双)
l: "〈〉" # 书名号(单)
m: "" # 法文单书名号
n: "«»" # 法文双书名号
o: "⦅⦆" # 白圆括号
p: "⦇⦈" # 白方括号
q: "()" # 圆括号
r: "|儿" #儿化候选
s: "" # 全角方括号
t: "⟨⟩" # 数学角括号
u: "〈〉" # 数学尖括号
v: "〖〗" # 装饰花括号
w: "" # 全角圆括号
x: "" # 全角花括号
y: "⟪⟫" # 双角括号
z: "{}" # 花括号
# ===== 扩展括号族 / 引号 =====
dy: "''" # 英文单引号
sy: "\"\"" # 英文双引号
zs: "“”" # 中文弯双引号
zd: "" # 中文弯单引号
fy: "``" # 反引号
# ===== 双字母括号族 =====
aa: "〚〛" # 双中括号
bb: "〘〙" # 双中括号(小)
cc: "〚〛" # 双中括号(重复,可用于 Lua 匹配)
dd: "" # 小圆括号装饰
ee: "❪❫" # 小圆括号装饰
ff: "❬❭" # 小尖括号装饰
gg: "⦉⦊" # 双弯方括号
ii: "⦍⦎" # 双弯方括号
jj: "⦏⦐" # 双弯方括号
kk: "⦑⦒" # 双弯方括号
ll: "" # 小尖括号装饰
mm: "⌈⌉" # 上取整 / 数学符号
nn: "⌊⌋" # 下取整 / 数学符号
oo: "⦗⦘" # 双方括号装饰(补齐)
pp: "⦙⦚" # 双方括号装饰(补齐)
qq: "⟬⟭" # 小双角括号
rr: "" # 花括号装饰
ss: "⌜⌝" # 数学上角符号
tt: "⌞⌟" # 数学下角符号
uu: "⸢⸣" # 装饰方括号
vv: "⸤⸥" # 装饰方括号
ww: "﹁﹂" # 中文书名号 / 注释引号
xx: "﹃﹄" # 中文书名号 / 注释引号
yy: "⌠⌡" # 数学 / 程序符号
zz: "⟅⟆" # 数学 / 装饰括号
# ===== Markdown / 标记 =====
md: "**|**" # Markdown 粗体
jc: "**|**" # 加粗
it: "__|__" # 斜体
st: "~~|~~" # 删除线
eq: "==|==" # 高亮
ln: "`|`" # 行内代码
cb: "```|```" # 代码块
qt: "> |" # 引用
ul: "- |" # 无序列表项
ol: "1. |" # 有序列表项
lk: "[|](url)" # 链接
im: "![|](img)" # 图片
h: "# |" # 一级标题
hh: "## |" # 二级标题
hhh: "### |" # 三级标题
hhhh: "#### |" # 四级标题
sp: "\\|" # 反斜杠转义
br: "| " # 换行
cm: "<!--|-->" # 注释
# ===== 运算与标记符 =====
pl: "++"
mi: "--"
sl: "//"
bs: "\\\\"
at: "@@"
dl: "$$"
pc: "%%"
an: "&&"
cr: "^^"
cl: "::"
sc: ";;"
ex: "!!"
qu: "??"
sb: "sb"
#开启自动无词频造词(默认已经开了)
#add_user_dict/enable_auto_phrase: true
#下面的数据有需要的可以patch引用
#特殊优化:部分音节字极少,几乎不参与构词,则提升对应四码字的优先级,仅对小鹤双拼有效,其他双拼方案需作对应修改)
小鹤双拼提权:
__append:
- derive/^(.*?)(\d?);(bl|dx|df|eg|fn|kw|ny|tw|vw|yd|rx|fs|ix)$/$1$3/
- derive/^(.*?)(\d?);.*?,(bl|dx|df|eg|fn|kw|ny|tw|vw|yd|rx|fs|ix)$/$1$3/
#特殊优化:部分音节字极少,几乎不参与构词,则提升对应四码字的优先级,仅对自然码有效,其他双拼方案需作对应修改)
自然码提权:
__append:
- derive/^(.*?)(\d?);(jb|wq|aq|av|dn|xh|bv|jz|hm|sn|cd|iw|xl|ak|zy|fy|uz|yx|wb|wr|yw|dz|qz|ms|at|xf|gi|gn|or|ux|ww|nw|fs|qk|rl|cq|sw|jv|cy|sq|dd|fp|ae|ix|td|ep|ar|wm|pd|et|yz|eh|ct|os|hx|zq|ew|fm|ab|kc|tf|fx|we|sz|wx|bq|ic|ez|bs|ej|oh|ps|pw|fr|pq|au|wc|wp|dt|qf|zc|vx|im|br|mw|un|qb|fi|zm|vn|oz|kt|rq|ay|fn|yc|um|eq|eu|cz|yq|tq|oi|ek|az|fv|zx|ut|vz|ry|ac|ws|af|qv|ea|qj|al|ol|on|sx|ap|df|eg|rz|ey|em|ag|hi|iz|ki|xz|xj|ad|ft|pt|op|vt|oj|kn|pr|hq|eb|ev|cx|zd|am|ov|oq|ym|ef|ot|mr|rd|sy|oc|rc|oe|fq|cn|ok|rn|bp|yv|uc|wk|oy|bt|je|ow|xg|jj|rw|pp|ja|wt|lf|xe|wy|kx|sm|qe|fw|gc|xa|cw|zn|tn|cc|jo|md|sd|ql|kq|it|bd|sc|wv|fc|dw|ob|vm|ed|jl|xo|fl|gq|gt|of|pv|wd|qa|xk|yd|fe|og|iq|oa|uq|om|xv|mv|as|ox|km|zt|od|ht|el|hn|st|wn|mt|wi|tz|aj|yg|bw|jf|jg|kz|es|xb|ax|rt|gx|bb|qo|yf|ex|rx|tt|us|qg|pe|zw|mp|qh|rm|hc|np|jh|cm|yl|eo|ra|vc|aw|tw|fk|gm|ec|be|vq|fd|jk|in)$/$1$3/
- derive/^(.*?)(\d?);.*?,(jb|wq|aq|av|dn|xh|bv|jz|hm|sn|cd|iw|xl|ak|zy|fy|uz|yx|wb|wr|yw|dz|qz|ms|at|xf|gi|gn|or|ux|ww|nw|fs|qk|rl|cq|sw|jv|cy|sq|dd|fp|ae|ix|td|ep|ar|wm|pd|et|yz|eh|ct|os|hx|zq|ew|fm|ab|kc|tf|fx|we|sz|wx|bq|ic|ez|bs|ej|oh|ps|pw|fr|pq|au|wc|wp|dt|qf|zc|vx|im|br|mw|un|qb|fi|zm|vn|oz|kt|rq|ay|fn|yc|um|eq|eu|cz|yq|tq|oi|ek|az|fv|zx|ut|vz|ry|ac|ws|af|qv|ea|qj|al|ol|on|sx|ap|df|eg|rz|ey|em|ag|hi|iz|ki|xz|xj|ad|ft|pt|op|vt|oj|kn|pr|hq|eb|ev|cx|zd|am|ov|oq|ym|ef|ot|mr|rd|sy|oc|rc|oe|fq|cn|ok|rn|bp|yv|uc|wk|oy|bt|je|ow|xg|jj|rw|pp|ja|wt|lf|xe|wy|kx|sm|qe|fw|gc|xa|cw|zn|tn|cc|jo|md|sd|ql|kq|it|bd|sc|wv|fc|dw|ob|vm|ed|jl|xo|fl|gq|gt|of|pv|wd|qa|xk|yd|fe|og|iq|oa|uq|om|xv|mv|as|ox|km|zt|od|ht|el|hn|st|wn|mt|wi|tz|aj|yg|bw|jf|jg|kz|es|xb|ax|rt|gx|bb|qo|yf|ex|rx|tt|us|qg|pe|zw|mp|qh|rm|hc|np|jh|cm|yl|eo|ra|vc|aw|tw|fk|gm|ec|be|vq|fd|jk|in)$/$1$3/
模糊音:
__append:
# n - l
- derive/^l/n
- derive/^n/l
# r - y 开头
- derive/^y/r
- derive/^r/y
# h - f 开头
- derive/^h/f
- derive/^f/h
# r - l 开头
- derive/^r/l
- derive/^l/r
# k - g 开头
- derive/^k/g
- derive/^g/k
# an - ang
- derive/([ui]?)([āáǎàa])ng(.*)$/$1$2n$3
- derive/([ui]?)([āáǎàa])n(.*)$/$1$2ng$3
# en - eng
- derive/([ēéěèe])ng(.*)$/$1n$2
- derive/([ēéěèe])n(.*)$/$1ng$2
# in - ing
- derive/([īíǐìi])ng(.*)$/$1n$2
- derive/([īíǐìi])n(.*)$/$1ng$2
# c - ch
- derive/^c([^h]*)/ch$1
- derive/^ch/c
# z - zh
- derive/^z([^h]*)/zh$1
- derive/^zh/z
# s - sh
- derive/^s([^h]*)/sh$1
- derive/^sh/s

View File

@@ -0,0 +1,24 @@
# Rime dictionary
# encoding: utf-8
#
# rime配置的部署位置
# ~/.local/share/fcitx5/rime 或者 ~/.config/ibus/rime (Linux)
# ~/Library/Rime (Mac OS)
# %APPDATA%\Rime (Windows)
#
#
---
name: wanxiang_pro
version: "LTS"
sort: by_weight #字典初始排序可選original或by_weight
use_preset_vocabulary: false
import_tables:
- dicts/zi.pro #字表,包含了所有带拼音的汉字
- dicts/jichu.pro #基础词库2-3字词汇
- dicts/lianxiang.pro #联想词库5字以上词汇多用于输入前半段第二候选可以出来整段
- dicts/cuoyin.pro #错音错字支持错音和错字输入的兼容同时供超级注释lua使用会在输入错误音节打出的时候给予提示
- dicts/duoyin.pro #兼容词库,是基础词库的扩充,收录了多场景多种读音的词组
- dicts/shici.pro #诗词
- dicts/diming.pro #地名
...

View File

@@ -0,0 +1,645 @@
# Rime schema
# encoding: utf-8
# 方案说明
schema:
schema_id: wanxiang_pro
name: 万象拼音PRO
version: "LTS"
author:
- amzxyz
description: |
请勾选【万象拼音PRO】以启用万象拼音 支持常见双拼方案和全拼输入,辅助码同时支持 全拼拼音、墨奇码、鹤形、自然码、虎码首末、五笔前2、汉心码、首右拥有超越大厂的输入体验带声调的词库支持语法模型全拼、简拼、整句、声调辅助筛选
【文本框输入:/pinyin全拼/zrm自然码,/flypy小鹤/mspy,/sogou,/pyjj等详见README.md】
dependencies:
- wanxiang_mixedcode #中英文混合词汇
- wanxiang_reverse # 部件拆字,反查及辅码
- wanxiang_chaifen #辅助码拆分注释、翻译注释、行政区划匹配、车牌、等等注释类显示滤镜Lua专用super_comment
# 开关
# reset: 默认状态。注释掉后,切换窗口时不会重置到默认状态。
# states: 方案选单显示的名称。可以注释掉,仍可以通过快捷键切换。
# abbrev: 默认的缩写取 states 的第一个字符abbrev 可自定义一个字符
switches:
- name: ascii_mode # 中英输入状态
states: [ 中文, 英文 ]
- name: ascii_punct # 中英标点
states: [ 中标, 英标 ]
- name: full_shape #全角、半角字符输出
states: [ 半角, 全角 ]
- name: emoji #候选出现emoji滤镜会显示在相应的候选后面万象侧重于tips提示避免候选被占用因此默认为reset: 0归属opencc emoji滤镜
states: [ 表情关, 表情开 ]
- name: chinese_english #候选进入翻译模式滤镜会显示在相应的候选后面万象侧重于tips提示避免候选被占用快捷键配套ctrl+e,归属opencc 翻译滤镜
states: [ 翻译关, 翻译开 ]
- name: chaifen_switch #开启后在候选的注释里面实时显示辅助码的拆分提醒优先级高于普通辅助提醒不开启则采用系统配置快捷键配套ctrl+c,影响的是comment_format归属super_comment.lua
states: [ 拆分关, 拆分开 ]
- name: charset_filter #字符集过滤默认开启8105通规显示即小字集可通过开关实时开启全字集快捷键配套ctrl+g,归属super_filter.lua
states: [ 小字集, 大字集 ]
- name: super_tips #开启后在输入编码后面的提示区显示实时的提示数据受tips数据库影响表情、翻译、车牌、符号等对应关系数据并可实现句号上屏不开启则默认影响的是segment.prompt参数归属super_tips.lua
states: [ 提示关, 提示开 ]
reset: 1
- options: [ raw_input, tone_display, full_pinyin ] #开启后在输入编码的位置实时转换为带声调全拼或者不带声调全拼不开启则采用系统配置原始编码影响的是preedit_format,归属super_preedit.lua
states: [ 原编码, 有声调, 无声调 ]
# reset: 2 #对于开关组从0开始数第几个就reset几可设为默认
- options: [ comment_off, fuzhu_hint, tone_hint ] #开启后在候选的注释里面实时显示辅助码或者全拼声调不开启则采用系统配置影响的是comment_format快捷键配套ctrl+a,归属super_comment.lua
states: [ 注释关, 辅助开, 读音开 ]
- options: [ s2s, s2t, s2hk, s2tw ] # 简繁转换开关组,可以在一个空选项和多个实际“- simplifier@s2hk”引入的项目之前切换这是一个开关组你可以将其中任意一个s2s等设置为toggle快捷键多次按下将轮询
states: [ 简体, 通繁, 港繁, 臺繁 ]
- name: char_priority #多体现在编码重合但候选有单字或者多字的情况`引导的辅码查词时是否单字优先全拼常见类似于特定编码情况下、反查状态下的调序能力。归属super_lookup.lua
states: [词组先, 单字先]
- options: [ mixed, zh_only, en_only ]
states: [ 混合输入, 仅中文, 仅英文 ]
# 输入引擎
engine:
processors:
- lua_processor@*select_character #以词定字,默认左中括号上屏一个词的前一个字,右中括号上屏一个词的后一个字
- lua_processor@*partial_commit #通过ctrl+1~0局部提交10个字以内的句子的前几个字一般为正确的前几个使用时要遵循合理的分词结构能促进后续编码打出正确的词汇
- lua_processor@*letter_selector #在N模式R模式下输入数字被视为编码那么如何上屏呢现在除了方向键还提供qwertyuio对照1-9来选词
- lua_processor@*tone_fallback #声调辅助回退,当你输入声调数字错误时,继续输入正确的而不用回退删除
- lua_processor@*super_sequence*P #手动排序,高亮候选 ctrl+j左移动 ctrl+k 右移动 ctrl+l 移除位移 ctrl+p 置顶
- lua_processor@*quick_symbol_text #快符引导以及重复上屏配合quick_symbol_text顶层配置清单定义扩展按键
- lua_processor@*super_tips #超级提示模块:表情、简码、翻译、化学式、等等靠你想象
- lua_processor@*limit_repeated #用于限制最大候选长度以及最大重复输入声母编码长度,避免性能异常
- lua_processor@*backspace_limit #防止连续 Backspace 在编码为空时删除已上屏内容
- lua_processor@*kp_number_processor #管理小键盘的处理逻辑,有输入中数字不上屏和数字一直不上屏设置可选
- lua_processor@*super_segmentation #通过双击分词符号触发重新分词,并在持续输入分词符号时,能在预设方式之间循环,用于应对类似自然码:必输 必须是 为相同编码导致的必输前置的问题
- ascii_composer #处理英文模式及中英文切换
- recognizer #与 matcher 搭配,处理符合特定规则的输入码,如网址、反查等 tags
- key_binder #在特定条件下将按键绑定到其他按键,如重定义逗号、句号为候选翻页、开关快捷键等
- lua_processor@*key_binder #绑定按键扩展能力,支持正则扩展将按键生效情景更加细化
- speller #拼写处理器,接受字符按键,编辑输入
- punctuator #符号处理器,将单个字符按键直接映射为标点符号或文字
- selector #选字处理器,处理数字选字键〔可以换成别的哦〕、上、下候选定位、换页
- navigator #处理输入栏内的光标移动
- express_editor #编辑器,处理空格、回车上屏、回退键
segmentors:
- ascii_segmentor #标识英文段落〔譬如在英文模式下〕字母直接上屛
- matcher #配合 recognizer 标识符合特定规则的段落,如网址、反查等,加上特定 tag
- abc_segmentor #标识常规的文字段落,加上 abc 这个 tag
- affix_segmentor@wanxiang_reverse #反查 tag
- affix_segmentor@add_user_dict #自造词加词 tag
- punct_segmentor #标识符号段落〔键入标点符号用〕加上 punct 这个 tag
- fallback_segmentor #标识其他未标识段落必须放在最后帮助tag模式切换后回退重新处理
translators:
- punct_translator #配合 punct_segmentor 转换标点符号
- script_translator #脚本翻译器,用于拼音、粤拼等基于音节表的输入方案
- lua_translator@*version_display #输入'/wx',显示万象项目网址和当前版本号
- lua_translator@*set_schema #输入'/zrm',快速切换为自然码双拼, /flypy→小鹤双拼 /mspy→微软双拼 /zrm→自然码 /sogou→搜狗双拼 /abc→智能ABC /ziguang→紫光双拼 /pyjj→拼音加加 /gbpy→国标双拼 /lxsq→乱序17 /pinyin→全拼
- lua_translator@*shijian #农历、日期、节气、节日、时间、周、问候模板等等,触发清单看下文
- lua_translator@*unicode #通过输入大写U引导并输入Unicode编码获得汉字输出
- lua_translator@*number_translator #数字、金额大写通过输入大写R1234获得候选输出
- lua_translator@*super_calculator #超级计算器Lua内查看高级用法
- lua_translator@*input_statistics #一个输入统计的脚本,以日、周、月、年等维度的统计
- table_translator@custom_phrase #自定义短语 custom_phrase.txt用于置顶自定义编码候选词
- table_translator@chengyu #简码成语词汇表导入
- table_translator@wanxiang_mixedcode #中英等混合词汇表导入
- table_translator@wanxiang_reverse #挂接部件组字和笔画反查
- script_translator@user_dict_set #自造词之使用词汇入口
- script_translator@add_user_dict #自造词之制造词汇入口
filters:
- reverse_lookup_filter@radical_reverse_lookup #部件拆字滤镜放在super_comment前面进一步被超级注释处理以获得拼音编码的提示
- lua_filter@*auto_phrase #无感造词,关闭调频的时候将汉字写入次翻译器,当没有英文候选的时候追加\上屏可完成英文造词
- lua_filter@*super_comment_preedit #超级注释模块、超级preedit支持错词提示、辅助码显示部件组字读音注释有声调、无声调全拼编码的转换支持个性化配置和关闭相应的功能详情搜索super_comment_preedit进行详细配置
- simplifier@emoji #Emoji滤镜
- simplifier@s2t #简繁切换通繁
- simplifier@s2tw #简繁切换台繁
- simplifier@s2hk #简繁切换港繁
- simplifier@chinese_english #中英翻译滤镜
- lua_filter@*super_sequence*F #手动排序,对高亮候选 ctrl+j左移动 ctrl+k 右移动 ctrl+0 移除位移
- lua_filter@*super_filter #功能太多详见Lua文件
- lua_filter@*super_lookup #字词输入中反查辅助筛选
- uniquifier #去重
grammar:
language: wanxiang-lts-zh-hans
collocation_max_length: 8 #命中的最长词组
collocation_min_length: 2 #命中的最短词组搭配词频健全的词库时候应当最小值设为3避开2字高频词
collocation_penalty: -10 #默认-12 对常见搭配词组施加的惩罚值。较高的负值会降低这些搭配被选中的概率,防止过于频繁地出现某些固定搭配。
non_collocation_penalty: -17 #默认-12 对非搭配词组施加的惩罚值。较高的负值会降低非搭配词组被选中的概率,避免不合逻辑或不常见的词组组合。
weak_collocation_penalty: -24 #默认-24 对弱搭配词组施加的惩罚值。保持默认值通常是为了有效过滤掉不太常见但仍然合理的词组组合。
rear_penalty: -18 #默认-18 对词组中后续词语的位置施加的惩罚值。较高的负值会降低某些词语在句子后部出现的概率,防止句子结构不自然。
super_comment: # 超级注释模块,子项配置 true 开启false 关闭
candidate_length: 1 # 候选词辅助码提醒的生效长度0为关闭 但同时清空其它,应当使用上面开关来处理
corrector_type: "comment" # 随意更换左右括号,比如"comment" 不加括号为无括号comment占位不能动
chaifen: "chaifen" # 随意更换左右括号,比如"chaifen" 不加括号为无括号chaifen占位不能动
# Tips 配置项
tips:
# 禁用的 tips 类型,初始化 tips 数据库的时候会直接忽略相关规则,修改部署后生效
# 可选项为:偏旁,符号,化学式,时间,符号,组字,翻译,表情,货币,车牌
disabled_types: []
#在8105基础上你可以通过黑白名单微调你自己的字符集过滤清单主数据库位于lua/charset.bin不可编辑
charsetlist: []
charsetblacklist: []
#shijian:仅仅作为提示使用编码已经写死引导键可以在key_binder下修改前缀
#时间osj 或者 /sj
#日期orq 或者 /rq
#农历onl 或者 /nl
#星期oxq 或者 /xq
#今年第几周oww 或者 /ww
#节气ojq 或者 /jq
#日期+时间odt 或者 /dt
#时间戳ott 或者 /tt
#大写N日期N20250315 或者N0312不带年
#节日ojr 或者 /jr
#问候模板:/day 或者 oday
# 通用日期时间格式化函数(供 /rq、/sj、/dt、N0101、N20150101 场景复用)
# 支持转义:
# \X —— 转义单个字符 X按字面量输出如 \Y \m \H 等)
# [[...]] —— 区块整体按字面量输出
#
# 约定占位符:
# 【日期】
# Y 四位年份 0000-9999 例2025
# y 两位年份 00-99 例25
# m 月(前导零) 01-12 例02
# n 月(不带前导零) 1-12 例2
# d 日(前导零) 01-31 例09
# j 日(不带前导零) 1-31 例9
#
# 【时间】
# H 24小时前导零 00-23 例08
# G 24小时不带零 0-23 例8
# I 12小时前导零 01-12 例08
# l 12小时不带零 1-12 例8 (注意是小写 L
# M 分钟(前导零) 00-59 例05
# S 秒(前导零) 00-59 例09
# p am/pm小写 am / pm
# P AM/PM大写 AM / PM
# 【时区】
# O 带冒号格式 +08:00、-04:30、+05:45
# o 不带冒号格式 +0800、-0430、+0545
date_formats:
- "Y年m月d日"
- "Y-m-d"
- "Y/m/d"
- "Y.m.d"
- "Ymd"
- "Y年n月j日"
- "y年n月j日"
- "n月j日"
time_formats:
- "H:M"
- "H点M分"
- "H:M:S"
- "H时M分S秒"
- "下午I:M"
- "I:M P"
datetime_formats:
- "Y-m-d H:M:S"
- "Y-m-dTH:M:S O"
- "YmdHMS"
- "Y年m月d日 H点M分"
- "y/m/d I:M p"
#常规状态下数字转换成相应的字符由超级preedit接管
tone_preedit:
"7": "¹"
"8": "²"
"9": "³"
"0": "⁴"
# a/、单字母组合,触发预设编码自动上屏快符,支持将值设为"repeat" 以支持对应按键重复上屏功能custom>schema>lua最终合并键值
# 现在就支持26字母快符结合成对符号输入这边的压力小一些
quick_symbol_text:
trigger: "^([a-z])/$"
symkey:
q: "repeat"
w: ""
e: ""
r: ""
t: "~"
y: "·"
u: "『"
i: "』"
o: "〖"
p: "〗"
a: ""
s: "……"
d: "、"
f: "“"
g: "”"
h: ""
j: ""
k: "【"
l: "】"
z: "。”"
x: "?”"
c: "!”"
v: "——"
b: "%"
n: "《"
m: "》"
#通过在有候选的情况下,通过末尾检测到形如\a来触发为第一候选进行成对符号包裹例如nihao\c 候选[你好]
#trigger只能设置为单符号因为按下一次锁定第一候选按下映射开始包裹符号pro用户不能设置为/
#两个字符可以不用|默认前后分割,需要明确区分前后的使用|分割,可以有一侧为空,不可以使用多个||
paired_symbols:
#sort_window: 10
trigger: "\\" #(注意反斜杠这是转义写法\\使用时\单反斜杠即可)
mirror: true #包裹后完全替换第一候选true,原候选后移到第二false
symkey:
# ===== 基本括号与引号 =====
a: "[]" # 方括号
b: "【】" # 黑方头括号
c: "" # 双大括号 / 装饰括号
d: "" # 方头括号
e: "⟮⟯" # 小圆括号 / 装饰括号
f: "⟦⟧" # 双方括号 / 数学集群括号
g: "「」" # 直角引号
# h: 预留用于 Markdown 一级标题
i: "『』" # 双直角引号
j: "<>" # 尖括号
k: "《》" # 书名号(双)
l: "〈〉" # 书名号(单)
m: "" # 法文单书名号
n: "«»" # 法文双书名号
o: "⦅⦆" # 白圆括号
p: "⦇⦈" # 白方括号
q: "()" # 圆括号
r: "|儿" #儿化候选
s: "" # 全角方括号
t: "⟨⟩" # 数学角括号
u: "〈〉" # 数学尖括号
v: "〖〗" # 装饰花括号
w: "" # 全角圆括号
x: "" # 全角花括号
y: "⟪⟫" # 双角括号
z: "{}" # 花括号
# ===== 扩展括号族 / 引号 =====
dy: "''" # 英文单引号
sy: "\"\"" # 英文双引号
zs: "“”" # 中文弯双引号
zd: "" # 中文弯单引号
fy: "``" # 反引号
# ===== 双字母括号族 =====
aa: "〚〛" # 双中括号
bb: "〘〙" # 双中括号(小)
cc: "〚〛" # 双中括号(重复,可用于 Lua 匹配)
dd: "" # 小圆括号装饰
ee: "❪❫" # 小圆括号装饰
ff: "❬❭" # 小尖括号装饰
gg: "⦉⦊" # 双弯方括号
fa: "⦋⦌" # 双弯方括号
ii: "⦍⦎" # 双弯方括号
jj: "⦏⦐" # 双弯方括号
kk: "⦑⦒" # 双弯方括号
ll: "" # 小尖括号装饰
mm: "⌈⌉" # 上取整 / 数学符号
nn: "⌊⌋" # 下取整 / 数学符号
oo: "⦗⦘" # 双方括号装饰(补齐)
pp: "⦙⦚" # 双方括号装饰(补齐)
qq: "⟬⟭" # 小双角括号
rr: "" # 花括号装饰
ss: "⌜⌝" # 数学上角符号
tt: "⌞⌟" # 数学下角符号
uu: "⸢⸣" # 装饰方括号
vv: "⸤⸥" # 装饰方括号
ww: "﹁﹂" # 中文书名号 / 注释引号
xx: "﹃﹄" # 中文书名号 / 注释引号
yy: "⌠⌡" # 数学 / 程序符号
zz: "⟅⟆" # 数学 / 装饰括号
# ===== Markdown / 标记 =====
md: "**|**" # Markdown 粗体
jc: "**|**" # 加粗
it: "__|__" # 斜体
st: "~~|~~" # 删除线
eq: "==|==" # 高亮
ln: "`|`" # 行内代码
cb: "```|```" # 代码块
qt: "> |" # 引用
ul: "- |" # 无序列表项
ol: "1. |" # 有序列表项
lk: "[|](url)" # 链接
im: "![|](img)" # 图片
h: "# |" # 一级标题
hh: "## |" # 二级标题
hhh: "### |" # 三级标题
hhhh: "#### |" # 四级标题
sp: "\\|" # 反斜杠转义
br: "| " # 换行
cm: "<!--|-->" # 注释
# ===== 运算与标记符 =====
pl: "++"
mi: "--"
sl: "//"
bs: "\\\\"
at: "@@"
dl: "$$"
pc: "%%"
an: "&&"
cr: "^^"
cl: "::"
sc: ";;"
ex: "!!"
qu: "??"
sb: "sb"
# Lua 配置:计算器触发关键字
calculator:
trigger: "V"
# 主翻译器,拼音
translator:
dictionary: wanxiang_pro # 挂载词库 wanxiang.dict.yaml
# packs: user #导入根目录下名称为user.dict.yaml的自定义固定词典
# prism: double_pinyin # 多方案共用一个词库时,为避免冲突,需要用 prism 指定一个名字。
enable_completion: true # 启用候选词补全
# user_dict: zrm.userdb # 用户词典的文件名称
# db_class: tabledb #开启后就不会产生zrm.userdb这样的文件夹会直接输出文本zrm.txt同时无法使用同步能力
enable_user_dict: false # 是否开启自动调频
contextual_suggestions: false #模型用来开启词组权重预测,效果一般关闭
max_homophones: 5
max_homographs: 5
# disable_user_dict_for_patterns:
# - "^[a-z]{1,6}" #基本的6码3字不调频
enable_correction: false #是否开启自动纠错
initial_quality: 4 # 初始质量拼音的权重应该比英文大
spelling_hints: 50 # 将注释以词典字符串形式完全暴露通过super_comment.lua完全接管灵活配置。
always_show_comments: true # Rime 默认在 preedit 等于 comment 时取消显示 comment这里强制一直显示供super_comment_preedit.lua做判断用。
comment_format: {comment} #将注释以词典字符串形式完全暴露通过super_comment.lua完全接管灵活配置。
# 自定义短语
custom_phrase:
dictionary: ""
user_dict: custom_phrase # 需要手动创建 custom_phrase.txt 文件
db_class: stabledb
enable_completion: false # 补全提示
enable_sentence: false # 禁止造句
initial_quality: 99 # custom_phrase 的权重应该比 pinyin 和 wanxiang_en 大
# 简码词库导入位于dicts得txt文件词库
chengyu:
dictionary: ""
user_dict: dicts/chengyu
db_class: stabledb
enable_sentence: false
enable_completion: false
initial_quality: 1.2 #本表词和系统词重码居后
# 中文、英文、数字、符号等混合词汇
wanxiang_mixedcode:
dictionary: wanxiang_mixedcode
user_dict: en
enable_completion: true
enable_sentence: false
initial_quality: 2
comment_format:
- xform/^.+$//
# Emoji
emoji:
option_name: emoji
opencc_config: emoji.json
tags: [abc]
inherit_comment: false
#中文转英文
chinese_english:
option_name: chinese_english
opencc_config: chinese_english.json
tips: char
inherit_comment: false
# 简繁切换
s2t:
option_name: s2t
opencc_config: s2t.json # s2t.json | s2hk.json | s2tw.json | s2twp.json
tips: none # 转换提示: all 都显示 | char 仅单字显示 | none 不显示。
tags: [ abc ] # 限制在对应 tag不对其他如反查的内容做简繁转换
s2hk:
opencc_config: s2hk.json
option_name: s2hk
tags: [abc]
s2tw:
opencc_config: s2tw.json
option_name: s2tw
tags: [abc]
# 部件拆字反查
wanxiang_reverse:
tag: wanxiang_reverse
dictionary: wanxiang_reverse
db_class: stabledb
enable_user_dict: false
enable_sentence: false
prefix: "`" # 反查前缀(反查时前缀会消失),与 recognizer/patterns/wanxiang_reverse 匹配
tips: "〔反查:拆分|笔画〕"
# 部件拆字滤镜
radical_reverse_lookup:
tags: [ wanxiang_reverse ] #起作用tag范围
overwrite_comment: true #是否覆盖其他提示
dictionary: wanxiang_pro #带音调的词典
wanxiang_lookup: #设置归属于super_lookup.lua
tags: [ abc ] # 检索当前tag的候选
key: "`" # 输入中反查引导符,要添加到 speller/alphabet
lookup: [ wanxiang_reverse ] #反查滤镜数据库,万象都合并为一个了
# 处理符合特定规则的输入码,如网址、反查
recognizer:
import_preset: default # 从 default.yaml 继承通用的
patterns: # 再增加方案专有的:
punct: "^/([0-9]|10|[A-Za-z]+)$" # 响应 symbols.yaml 的 symbols
wanxiang_reverse: "^`[A-Za-z]*$" # 响应部件拆字与笔画的反查,与 radical_lookup/prefix 匹配
add_user_dict: "^``[A-Za-z/`']*$" #自造词
unicode: "^U[a-f0-9]+" # 脚本将自动获取第 2 个字符 U 作为触发前缀,响应 lua_translator@unicode输出 Unicode 字符
number: "^R[0-9]+[.]?[0-9]*" # 脚本将自动获取第 2 个字符 R 作为触发前缀,响应 lua_translator@number_translator数字金额大写
yr1: "^N0[1-9]?0?[1-9]?"
yr2: "^N1[02]?0?[1-9]?"
yr3: "^N0[1-9]?[1-2]?[1-9]?"
yr4: "^N1[02]?[1-2]?[1-9]?"
yr5: "^N0[1-9]?3?[01]?"
yr6: "^N1[02]?3?[01]?"
nyr1: "^N19?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?"
nyr2: "^N20?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?"
calculator: "^V.*$" #计算器功能引导
email: "^[A-Za-z][-_.0-9A-Za-z]*@.*$" # email @ 之后不上屏
url: "^(www[.]|https?:|ftp[.:]|mailto:|file:).*$|^[a-z]+[.].+$" # URL
# 给 kp_number_processor 用的“命令模式 Lua 正则集合”
# 能够细化哪些情况数字是用来当作输入编码的,不在正则范围的将用于上屏
# 直接加载上面的正则会遇到不符合预期的情况毕竟Lua正则逻辑与之不同
kp_number:
#小键盘数字处理逻辑
# "compose" : 小键盘数字始终参与编码
# "auto" : 输入中 push空闲时 commit默认
kp_number_mode: auto
patterns:
# /符号引导模式
- "^/[0-9]$"
- "^/10$"
- "^/[A-Za-z]+$"
# U模式
- "^U[%da-f]+$"
# R模式
- "^R[0-9]+%.?[0-9]*$"
# N模式
# Lua 不支持 {1,8}改成等价写法N 后 1~8 个数字
- "^N0[1-9]?0?[1-9]?$"
- "^N1[02]?0?[1-9]?$"
- "^N0[1-9]?[1-2]?[1-9]?$"
- "^N1[02]?[1-2]?[1-9]?$"
- "^N0[1-9]?3?[01]?$"
- "^N1[02]?3?[01]?$"
- "^N19?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$"
- "^N20?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$"
# 计算器模式
- "^V.*$"
# email
- "^[A-Za-z][-_.0-9A-Za-z]*@.*$"
# URL 前缀几种:
- "^www[.].*$"
- "^https?:.*$"
- "^ftp[.:].*$"
- "^mailto:.*$"
- "^file:.*$"
- "^webdav:.*$"
# 标点符号
# punctuator 下面有三个子项:
# 设置为一个映射,就自动上屏;设置为多个映射,如 '/' : [ '/', ÷ ] 则进行复选。
# full_shape: 全角没改,使用预设值
# half_shape: 标点符号全部直接上屏,和 macOS 自带输入法的区别是
# '|' 是半角的,
# '~' 是半角的,
# '`'(反引号)没有改成 '·'(间隔号)。
# symbols Rime 的预设配置是以 '/' 前缀开头输出一系列字符,自定义的修改 symbols.yaml
punctuator:
digit_separators: ":,." #数字分隔符
__include: wanxiang_symbols:/symbol_table # 从 symbols.yaml 导入配置
# 从 default 继承快捷键
key_binder:
import_preset: default # 从 default.yaml 继承通用的
# Lua 配置: 以词定字(上屏当前词句的第一个或最后一个字),和中括号翻页有冲突
select_first_character: "bracketleft" # 左中括号 [
select_last_character: "bracketright" # 右中括号 ]
sequence: # Lua 配置:手动排序的快捷键 super_sequence.lua不要用方向键各种冲突一定要避免冲突
up: "Control+j" # 上移
down: "Control+k" # 下移
reset: "Control+l" # 重置
pin: "Control+p" # 置顶
# Lua 配置: shijian.lua 的引导符,涉及:日期、时间、节日、节气、生日、问候模板等功能
shijian_keys: ["/", "o"]
# Lua 配置: 超级tips上屏按键
tips_key: "comma" #修改时候去default找
bindings: # 也可以再增加方案专有的
# 通过按下/发送/+1节约一个按键不冲突的时候可以开启
#- { match: "[a-z]{1,4}", accept: "/", send_sequence: "/1" }
# 翻页 , .
# - { when: paging, accept: comma, send: Page_Up }
# - { when: has_menu, accept: period, send: Page_Down }
# 翻页 [ ]
# - { when: paging, accept: bracketleft, send: Page_Up }
# - { when: has_menu, accept: bracketright, send: Page_Down }
# 翻页 - =
- { when: has_menu, accept: minus, send: Page_Up }
- { when: has_menu, accept: equal, send: Page_Down }
# Option/Alt + ←/→ 切换光标至下/上一个拼音
- { when: always, toggle: ascii_punct, accept: Control+Shift+3 } # 切换中英标点
- { when: always, toggle: ascii_punct, accept: Control+Shift+numbersign } # 切换中英标点
- { when: always, toggle: s2t, accept: Control+Shift+4 } # 切换简繁
- { when: always, toggle: s2t, accept: Control+Shift+dollar } # 切换简繁
- { when: composing, accept: Alt+Left, send: Shift+Left }
- { when: composing, accept: Alt+Right, send: Shift+Right }
- { when: composing, accept: Control+w, send: Control+BackSpace }
# 分号用于次选,微软、搜狗双拼不可启用
#- { when: has_menu, accept: semicolon, send: 2 }
# 使用Control+e进入翻译模式
- { when: has_menu, accept: "Control+e", toggle: chinese_english }
# 使用快捷键Control+c拆分显示
- { when: has_menu, accept: "Control+c", toggle: chaifen_switch }
# 使用快捷键Control+a开启和关闭辅助码显示
- { when: has_menu, accept: "Control+a", toggle: fuzhu_hint }
# 通过快捷键Control+s使得输入码显示音调
- { when: has_menu, accept: "Control+s", toggle: tone_display }
# 通过快捷键Control+t开启超级tips
- { when: has_menu, accept: "Control+t", toggle: super_tips }
# 通过快捷键Control+g开启字符集过滤
- { when: has_menu, accept: "Control+g", toggle: charset_filter }
#通过快捷键Control+q切换中文、英文、混合模式
- { when: has_menu, accept: "Control+q", toggle: zh_only }
# 使用 tab 在不同音节之间跳转
- { when: has_menu, accept: "Tab", send: "Control+Right" }
- { when: composing, accept: "Tab", send: "Control+Right" }
# 当tab第一个字补码正确后可以使用Ctrl+tab进行上屏并依次补码
- { when: composing, accept: "Control+Tab", send_sequence: '{Home}{Shift+Right}{1}{Shift+Right}' }
# 当输入编码后发现没有词,则通过双击``进入造词模式而且不需要删除编码,这个功能与``直接引导相呼应相配合
- { match: "^.*`$", accept: "`", send_sequence: '{BackSpace}{Home}{`}{`}{End}' }
# 斜杠被占用引导符号,因此输入本身设置为双击
- { match: "^/$", accept: "/", send_sequence: '{space}' }
editor:
bindings:
space: confirm # 空格键:上屏候选项
Return: commit_raw_input # 回车键:上屏原始输入
Control+Return: commit_script_text # Ctrl+回车键:上屏变换后输入(经过 preedit转换的
Control+Shift+Return: commit_comment # Ctrl+Shift+回车键:上屏 comment
BackSpace: revert # 退格键:向前删除(撤消上次输入)
Delete: delete # Delete 键:向后删除
Control+BackSpace: back_syllable # Ctrl+退格键:删除一个音节
Control+Delete: delete_candidate # Ctrl+Delete键删除或降权候选项
Escape: cancel # Esc 键:取消输入
# 拼写设定
speller:
# table_translator翻译器支持自动上屏。例如 “zmhu”可以自动上屏“怎么回事”
# auto_select: true
# auto_select_pattern: ^[a-z]+/|^[a-df-zA-DF-Z]\w{3}|^e\w{4}
# 如果不想让什么标点直接上屏,可以加在 alphabet或者编辑标点符号为两个及以上的映射
alphabet: zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA1234567890`;/\
# initials 定义仅作为始码的按键,排除 ` 让单个的 ` 可以直接上屏
initials: zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA/
delimiter: " '" # 第一位<空格>是拼音之间的分隔符;第二位<'>表示可以手动输入单引号来分割拼音。
visual_delimiter: " " # super_preedit.lua配置是否让分隔符号跟着一起转换例如nǐ'hǎo 在实际使用中表现出视觉拥挤我们可以让delimiter平时是'转换为拼音的时候使用空格nǐ hǎo更符合实际。
algebra:
__patch:
#- 模糊音 #模糊音选择性开启
- wanxiang_algebra:/pro/自然码 #拼音转双拼码
- wanxiang_algebra:/pro/直接辅助 #辅助码部分
###############################以下是拼写运算规则中全拼转双拼码以及形码的过程,按照不同的方案规则划分段落###########################
user_dict_set:
dictionary: wanxiang_pro
initial_quality: 2.5
enable_completion: false
enable_sentence: false
core_word_length: 4 # >0 启用,按段学词 + 相邻段拼接
max_word_length: 7 # >0 启用,过长短语不记整词,只加元素权重
contextual_suggestions: false
max_homophones: 5
max_homographs: 5
spelling_hints: 50
comment_format:
enable_user_dict: true
user_dict: zc
# 自定义词典加词(ac引导)
add_user_dict:
tag: add_user_dict
dictionary: wanxiang_pro
initial_quality: -1
user_dict: zc
enable_completion: true # 提前显示尚未输入完整码的字〔仅 table_translator 有效〕
enable_user_dict: true
spelling_hints: 50
enable_auto_phrase: true # lua造词功能在custom开启相关功能位于auto_phrase.lua开启后模型能造的句子不造词现有的词不造词只造词库没有的选词可造词
comment_format:
prefix: "``"
tips: "〔开始造词〕"

View File

@@ -0,0 +1,5 @@
patch:
# 只修改下面配置中的输入方案名称名称与wanxiang.custom.yaml保持一致这个用于反查
speller/algebra:
__include: wanxiang_algebra:/reverse/全拼 #可选的选项有(全拼, 自然码, 小鹤双拼, 微软双拼, 搜狗双拼, 智能ABC, 紫光双拼, 拼音加加)
__patch: wanxiang_algebra:/reverse/hspzn #笔画类型有hspznhupvd及hslzy适配乱序17可选

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
custom/赞赏.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

3
custom_phrase.txt Normal file
View File

@@ -0,0 +1,3 @@
#给自定义用户词扩展一个换行:\n, 制表符:\t, 回车符:\r, 空格:\s
吧 b 50
静夜思\n\s\s李白\n床前明月光\n疑似地上霜\n举头望明月\n低头思故乡 jys 50

256
default.yaml Normal file
View File

@@ -0,0 +1,256 @@
# Rime default settings
# encoding: utf-8
# 要比共享目录的同名文件的 config_version 大才可以生效
config_version: 'LTS'
# 方案列表
schema_list:
- schema: wanxiang
# - schema: wanxiang_t9
# 菜单
menu:
page_size: 6 # 候选词个数不得超过6个7890代表声调
alternative_select_labels: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] # 修改候选项标签Windows用这行会自动加点
#alternative_select_labels: [ ⒈, ⒉, ⒊, ⒋, ⒌, ⒍, ⒎, ⒏, ⒐, ⒑ ] # 修改候选项标签Linux用这行用了加点字符
#alternative_select_keys: ASDFGHJKL # 这里战略性占用选字按键,如编码字符占用数字键,则需另设选字键
# 方案选单相关
switcher:
caption: 「方案选单」
hotkeys:
- Control+grave
# - Alt+grave
save_options: # 开关记忆(方案中的 switches从方案选单而非快捷键切换时会记住的选项需要记忆的开关不能设定 reset
- ascii_punct
- s2t
- s2hk
- s2tw
- emoji
- full_shape
- prediction
- super_tips
- charset_filter
- chaifen_switch
- tone_display
- fuzhu_hint
- tone_hint
- full_pinyin
- chinese_english
- search_single_char
fold_options: true # 呼出时是否折叠,多方案时建议折叠 true ,一个方案建议展开 false
abbreviate_options: true # 折叠时是否缩写选项
option_list_separator: ' / ' # 折叠时的选项分隔符
# 中西文切换
#
# good_old_caps_lock:
# true 切换大写
# false 切换中英
# macOS 偏好设置的优先级更高如果勾选【使用大写锁定键切换“ABC”输入法】则始终会切换输入法。
#
# 切换中英:
# 不同的选项表示:打字打到一半时按下了 CapsLock、Shift、Control 后:
# commit_code 上屏原始的编码,然后切换到英文
# commit_text 上屏拼出的词句,然后切换到英文
# clear 清除未上屏内容,然后切换到英文
# inline_ascii 切换到临时英文模式,按回车上屏后回到中文状态
# noop 屏蔽快捷键,不切换中英,但不要屏蔽 CapsLock
ascii_composer:
good_old_caps_lock: true # true | false
switch_key:
Caps_Lock: clear # commit_code | commit_text | clear
Shift_L: commit_code # commit_code | commit_text | inline_ascii | clear | noop
Shift_R: commit_code # commit_code | commit_text | inline_ascii | clear | noop
Control_L: noop # commit_code | commit_text | inline_ascii | clear | noop
Control_R: noop # commit_code | commit_text | inline_ascii | clear | noop
# 处理符合特定规则的输入码,如网址、反查
# 此处配置较为通用的选项,各方案中另增加了和方案功能绑定的 patterns。
recognizer:
patterns:
email: "^[A-Za-z][-_.0-9A-Za-z]*@.*$" # email @ 之后不上屏
url: "^(www[.]|https?:|ftp[.:]|mailto:|file:).*$|^[a-z]+[.].+$" # URL
underscore: "^[A-Za-z]+_.*" # 下划线不上屏
# url_2: "^[A-Za-z]+[.].*" # 句号不上屏,支持 google.com abc.txt 等网址或文件名,使用句号翻页时需要注释掉
# colon: "^[A-Za-z]+:.*" # 冒号不上屏
# 快捷键
key_binder:
bindings:
# Tab / Shift+Tab 切换光标至下/上一个拼音
#- { when: composing, accept: Shift+Tab, send: Shift+Left }
#- { when: composing, accept: Tab, send: Shift+Right }
# Tab / Shift+Tab 翻页
# - { when: has_menu, accept: Shift+Tab, send: Page_Up }
# - { when: has_menu, accept: Tab, send: Page_Down }
# numbered_mode_switch:
# - { when: always, select: .next, accept: Control+Shift+1 } # 在最近的两个方案之间切换
# - { when: always, select: .next, accept: Control+Shift+exclam } # 在最近的两个方案之间切换
# - { when: always, toggle: ascii_mode, accept: Control+Shift+2 } # 切换中英
# - { when: always, toggle: ascii_mode, accept: Control+Shift+at } # 切换中英
# - { when: always, toggle: full_shape, accept: Control+Shift+5 } # 切换全半角
# - { when: always, toggle: full_shape, accept: Control+Shift+percent } # 切换全半角
# emacs_editing:
# - { when: composing, accept: Control+p, send: Up }
# - { when: composing, accept: Control+n, send: Down }
# - { when: composing, accept: Control+b, send: Left }
# - { when: composing, accept: Control+f, send: Right }
# - { when: composing, accept: Control+a, send: Home }
# - { when: composing, accept: Control+e, send: End }
# - { when: composing, accept: Control+d, send: Delete }
- { when: composing, accept: Control+k, toggle: xxxxx } #释放Ctrl+k=ctrl+del 万象用来调序,且删除属于低频场景,建议双手操作
# - { when: composing, accept: Control+h, send: BackSpace }
# - { when: composing, accept: Control+g, send: Escape }
# - { when: composing, accept: Control+bracketleft, send: Escape }
# - { when: composing, accept: Control+y, send: Page_Up }
# - { when: composing, accept: Alt+v, send: Page_Up }
# - { when: composing, accept: Control+v, send: Page_Down }
# optimized_mode_switch:
# - { when: always, accept: Control+Shift+space, select: .next }
# - { when: always, accept: Shift+space, toggle: ascii_mode }
# - { when: always, accept: Control+comma, toggle: full_shape }
# - { when: always, accept: Control+period, toggle: ascii_punct }
# - { when: always, accept: Control+slash, toggle: traditionalization }
# 将小键盘 0~9 . 映射到主键盘,数字金额大写的 Lua 如 R1234.5678 可使用小键盘输入
- {accept: KP_0, send: 0, when: composing}
- {accept: KP_1, send: 1, when: composing}
- {accept: KP_2, send: 2, when: composing}
- {accept: KP_3, send: 3, when: composing}
- {accept: KP_4, send: 4, when: composing}
- {accept: KP_5, send: 5, when: composing}
- {accept: KP_6, send: 6, when: composing}
- {accept: KP_7, send: 7, when: composing}
- {accept: KP_8, send: 8, when: composing}
- {accept: KP_9, send: 9, when: composing}
- {accept: KP_Decimal, send: period , when: composing}
- {accept: KP_Multiply, send: asterisk, when: composing}
- {accept: KP_Add, send: plus, when: composing}
- {accept: KP_Subtract, send: minus, when: composing}
- {accept: KP_Divide, send: slash, when: composing}
- {accept: KP_Enter, send: Return, when: composing}
# 按键速查
# https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/Rime_description.md
# (没有 Command 键,不支持)
# accept 和 send 可用字段除 A-Za-z0-9 外,还包含以下键盘上实际有的键:
# (区分大小写)
# BackSpace 退格
# Tab 水平定位符
# Linefeed 换行
# Clear 清除
# Return 回车
# Pause 暂停
# Sys_Req 印屏
# Escape 退出
# Delete 删除
# Home 原位
# Left 左箭头
# Up 上箭头
# Right 右箭头
# Down 下箭头
# Prior、Page_Up 上翻
# Next、Page_Down 下翻
# End 末位
# Begin 始位
# Shift_L 左Shift
# Shift_R 右Shift
# Control_L 左Ctrl
# Control_R 右Ctrl
# Meta_L 左Meta
# Meta_R 右Meta
# Alt_L 左Alt
# Alt_R 右Alt
# Super_L 左Super
# Super_R 右Super
# Hyper_L 左Hyper
# Hyper_R 右Hyper
# Caps_Lock 大写锁
# Shift_Lock 上档锁
# Scroll_Lock 滚动锁
# Num_Lock 小键板锁
# Select 选定
# Print 打印
# Execute 运行
# Insert 插入
# Undo 还原
# Redo 重做
# Menu 菜单
# Find 搜寻
# Cancel 取消
# Help 帮助
# Break 中断
# space 空格
# exclam !
# quotedbl "
# numbersign #
# dollar $
# percent %
# ampersand &
# apostrophe '
# parenleft (
# parenright )
# asterisk *
# plus +
# comma ,
# minus -
# period .
# slash /
# colon :
# semicolon ;
# less <
# equal =
# greater >
# question ?
# at @
# bracketleft [
# backslash \
# bracketright ]
# asciicircum ^
# underscore _
# grave `
# braceleft {
# bar |
# braceright }
# asciitilde ~
# KP_Space 小键板空格
# KP_Tab 小键板水平定位符
# KP_Enter 小键板回车
# KP_Delete 小键板删除
# KP_Home 小键板原位
# KP_Left 小键板左箭头
# KP_Up 小键板上箭头
# KP_Right 小键板右箭头
# KP_Down 小键板下箭头
# KP_Prior、KP_Page_Up 小键板上翻
# KP_Next、KP_Page_Down 小键板下翻
# KP_End 小键板末位
# KP_Begin 小键板始位
# KP_Insert 小键板插入
# KP_Equal 小键板等于
# KP_Multiply 小键板乘号
# KP_Add 小键板加号
# KP_Subtract 小键板减号
# KP_Divide 小键板除号
# KP_Decimal 小键板小数点
# KP_0 小键板0
# KP_1 小键板1
# KP_2 小键板2
# KP_3 小键板3
# KP_4 小键板4
# KP_5 小键板5
# KP_6 小键板6
# KP_7 小键板7
# KP_8 小键板8
# KP_9 小键板9

19411
dicts/chengyu.txt Normal file

File diff suppressed because it is too large Load Diff

1904
dicts/cn&en.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

155
dicts/cuoyin.dict.yaml Normal file
View File

@@ -0,0 +1,155 @@
# Rime dictionary
# encoding: utf-8
#https://github.com/amzxyz/RIME-LMDG
#错音错字对照表
---
name: cuoyin
version: "LTS"
sort: by_weight
...
株木琅玛 zhū mù láng mǎ 1 有声
衾何以堪 qīn hé yǐ kān 36 小说
墨明棋妙 mò míng qí miào 38 乐队
压力山大 yā lì shān dà 19 网络语
鸭梨山大 yā lí shān dà 48 网络语
麻麻赖赖 má má lài lài 16 网络语
绝代双椒 jué dài shuāng jiāo 30 网络语
毁人不倦 huǐ rén bú juàn 43 歌曲名
佛教胜地 fó jiào shèng dì 1 佛教(圣)地
杉杉来吃 shān shān lái chī 42 书名
食话食说 shí huà shí shuō 25 节目
零零总总 ling ling zong zong 6 林林总总
文绉绉 wen zou zou 16 zhōu
大栅栏 da zha lan 23 dà shí làn
粘贴 nian tie 382 粘(zhān)贴
曝光 pu guang 410 曝(bào)光
东庠岛 dong yang dao 10 东庠(xiáng)岛
视频 shi ping 490 视频(pín)
剖腹产 pao fu chan 170 剖(pōu)腹产
阻塞 zu sai 20 阻塞(sè)
着想 zhao xiang 370 着(zhuó)想
崩溃 ben kui 480 崩(bēng)溃
句芒 ju mang 320 句(gōu)芒
烘焙 hong pei 400 hōng bèi
谄媚 xian mei 300 chǎn mèi
着落 zhao luo 470 zhuó luò
胁差 lei cha 430 xié chā
刚劲 gang jin 420 gāng jìng
井陉 jing jing 420 jǐng xíng
猇亭 hu ting 340 xiāo tíng
猇亭区 hu ting qu 130 猇(xiāo)亭区
屎溺 shi ni 320 shǐ niào
东庠 dong yang 230 dōng xiáng
莒县 lü xian 440 jǔ xiàn
浚县 jun xian 390 xùn xiàn
郯城 ye cheng 390 tán chéng
丽水 lì shuǐ 530 lí shuǐ
珲春 hui chun 460 hún chūn
甪直 yong zhi 440 lù zhí
五厍 wu ku 360 wú shè
台州 tái zhōu 400 tāi zhōu
膻中 shan zhong 360 膻(dàn)中
渑池 yin chi 400 miǎn chí
渑池 sheng chi 400 miǎn chí
铅山 qian shan 350 yán shān
铅山县 qian shan xian 180 铅(yán)山县
按耐 an nai 30 按捺(nà)
甭介 béng jie 60 甭价(jie)
别介 bié jie 30 别价(jie)
槟榔 bin lang 630 bīng láng
脖颈 bo jing 480 bó gěng
草薙 cao zhi 90 cǎo tì
掺和 chan he 440 chān huo
称职 cheng zhi 90 chèn zhí
龇牙 ci ya 60 zī yá
凑活 còu huo 250 凑合(he)
道行 dao hang 270 dào héng
给予 gei yu 350 jǐ yǔ
厚朴 hou pu 50 hòu pò
馄饨 hun dun 400 hún tun
角色 jiao se 200 jué sè
结扎 jie zha 130 jié zā
钜惠 jù huì 550 (巨)惠
六安 liu an 110 lù ān
女主角 nv zhu jiao 200 女主角(jué)
埋怨 mai yuan 140 mán yuàn
模板 mo ban 467 mú bǎn
模具 mo ju 194 mú jù
模样 mo yang 519 mú yàng
木讷 mu na 470 mù nè
弄堂 nong tang 130 lòng táng
暖和 nuan he 590 nuǎn huo
偌大 nuo da 680 偌(ruò)大
强劲 qiang jin 281 qiáng jìng
说服 shui fu 564 shuō fú
似的 si de 700 似(shì)的
藤蔓 teng man 320 téng wàn
调换 tiao huan 620 diào huàn
胴体 tong ti 80 dòng tǐ
荨麻 xun ma 70 qián má
亳州 hao zhou 500 bó zhōu
天秤座 tian ping zuo 100 秤(chèng)
戛然而止 ga ran er zhi 590 戛(jiá)然而止
自怨自艾 zi yuan zi ai 520 自怨自艾(yì)
洪洞 hong dong 420 hóng tóng
蔚县 wei xian 430 yù xiàn
嵊州 cheng zhou 440 shèng zhōu
吱声 zhi sheng 220 zī shēng
主角 zhu jiao 541 zhǔ jué
脖颈儿 bo jing er 10 bó gěng er
草薙剑 cao zhi jian 20 cǎo tì jiàn
草薙京 cao zhi jing 140 cǎo tì jīng
龇着牙 ci zhe ya 10 zī zhe yá
大宛马 da wan ma 10 dà yuān mǎ
独乐乐 du le le 10 dú yuè lè
海参崴 hai shen wei 300 hǎi shēn wǎi
贾平凹 jia ping ao 250 jià píng wā
卡脖子 ka bo zi 310 qiǎ bó zi
六安市 liu an shi 20 lù ān shì
六安县 liu an xian 10 lù ān xiàn
六合区 liu he qū 10 lù hé qū
螺蛳粉 luo shi fen 650 luó sī fěn
温庭筠 wen ting jun 210 温庭筠(yún)
关卡 guan ka 640 guān qiǎ
牛皮癣 niu pi xian 289 (癣)xuǎn
三昧真火 san wei zhen huo 440 三昧(mèi)真火
优惠券 you hui juan 420 优惠券(quàn)
没食子 mei shi zi 70 没(mò)食子
魔蝎座 mó xiē zuò 10 摩羯(jié)座
鄱阳湖 pan yang hu 134 pó yáng hú
契科夫 qī kē fū 10 契诃(hē)夫
荨麻疹 qian ma zhen 200 xún má zhěn
太行山 tai xing shan 390 tài háng shān
头皮屑 tou pi xue 530 tóu pi xiè
万柏林 wàn bó lín 10 万柏(bǎi)林
雪佛兰 xue fo lan 370 xuě fú lán
鸭绿江 ya lv jiang 150 yā lù jiāng
张柏芝 zhang bai zhi 75 zhāng bó zhī
众乐乐 zhong le le 20 zhòng yuè lè
阿弥陀佛 a mi tuo fo 37 ē mí tuó fó
安徽六安 an hui liu an 2 ān huī lù ān
按耐不住 àn nài bú zhù 1 按捺(nà)不住
龇牙咧嘴 ci ya lie zui 17 zī yá liě zuǐ
大腹便便 da fu bian bian 15 dà fù pián pián
歇斯底里 jie si di li 88 xiē sī dǐ lǐ
力能扛鼎 li neng kang ding 3 lì néng gāng dǐng
模棱两可 mo ling liang ke 85 mó léng liǎng kě
南京六合 nan jing liu he 1 nán jīng lù hé
人模狗样 ren mo gou yang 15 rén mú góu yàng
心宽体胖 xin kuan ti pang 4 xīn kūan tǐ pán
虚与委蛇 xu yu wei she 9 xū yǔ wēi yí
血脉偾张 xuè mài fèn zhāng 1 血脉贲(bēn)张 | 血脉偾(fèn)张
血脉喷张 xuè mài pēn zhāng 1 血脉贲(bēn)张 | 血脉偾(fèn)张
一模一样 yi mo yi yang 508 yì mú yí yàng
饮鸩解渴 yin jiu jie ke 1 饮鸩(zhèn)解渴
饮鸩止渴 yin jiu zhi ke 34 饮鸩(zhèn)止渴
饮鸩解渴 yin zhen jie ke 1 饮鸩(zhèn)解渴
有模有样 you mo you yang 28 yǒu mú yǒu yàng
装模作样 zhuang mo zuo yang 49 zhuāng mú zuò yàng
安徽六安市 an hui liu an shi 1 ān huī lù ān shì
南京六合区 nan jing liu he qu 1 nán jīng lù hé qū
安徽省六安市 an hui sheng liu an shi 1 ān huī shěng lù ān shì
南无阿弥陀佛 na mo a mi tuo fo 4 nā mó ē mí tuó fó
南京市六合区 nan jing shi liu he qu 1 nán jīng shì lù hé qū
南无阿弥陀佛 nan wu a mi tuo fo 4 nā mó ē mí tuó fó
南无阿弥陀佛 nan wu e mi tuo fo 4 nā mó ē mí tuó fó

40571
dicts/diming.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

5314
dicts/duoyin.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

51910
dicts/en.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

1530646
dicts/jichu.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

317009
dicts/lianxiang.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

327961
dicts/shici.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

70240
dicts/wuzhong.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

51047
dicts/zi.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

231
lua/auto_phrase.lua Normal file
View File

@@ -0,0 +1,231 @@
-- @amzxyz https://github.com/amzxyz/rime_wanxiang
-- 自动造词
local AP = {}
-- 注释缓存text -> comment只给中文造词用
local comment_cache = {}
-- 工具是否纯英文ASCII 且至少 1 个字母)
local function is_ascii_word(text)
if not text or text == "" then
return false
end
local has_alpha = false
for i = 1, #text do
local b = text:byte(i)
if b > 127 then
return false
end
if (b >= 65 and b <= 90) or (b >= 97 and b <= 122) then
has_alpha = true
end
end
return has_alpha
end
-- 判断字符是否为汉字(原逻辑)
function AP.is_chinese_only(text)
local non_chinese_pattern = "[%w%p]"
if not text or text == "" then
return false
end
if text:match(non_chinese_pattern) then
return false
end
for _, cp in utf8.codes(text) do
-- 常用汉字区 + 扩展 A/B/C/D/E/F/G
if not (
(cp >= 0x4E00 and cp <= 0x9FFF) or -- CJK Unified Ideographs
(cp >= 0x3400 and cp <= 0x4DBF) or -- CJK Ext-A
(cp >= 0x20000 and cp <= 0x2EBEF) -- CJK Ext-B~G
) then
return false
end
end
return true
end
function AP.init(env)
local config = env.engine.schema.config
local ctx = env.engine.context
-- 中文自动造词的开关(只控制 add_user_dict
local enable_auto_phrase =
config:get_bool("add_user_dict/enable_auto_phrase") or false
local enable_user_dict =
config:get_bool("add_user_dict/enable_user_dict") or false
-- 中文add_user_dict受 add_* 开关影响)
if enable_auto_phrase and enable_user_dict then
env.memory = Memory(env.engine, env.engine.schema, "add_user_dict")
else
env.memory = nil
end
-- 英文enuser不受 add_* 开关影响,始终尝试启用)
env.en_memory = Memory(env.engine, env.engine.schema, "wanxiang_mixedcode")
-- 只要有一边需要,就挂上 commit/delete 通知
if env.en_memory or env.memory then
env._commit_conn = ctx.commit_notifier:connect(function(c)
AP.commit_handler(c, env)
end)
env._delete_conn = ctx.delete_notifier:connect(function(_)
comment_cache = {}
end)
end
end
function AP.fini(env)
if env._commit_conn then
env._commit_conn:disconnect()
env._commit_conn = nil
end
if env._delete_conn then
env._delete_conn:disconnect()
env._delete_conn = nil
end
if env.memory then
env.memory:disconnect()
env.memory = nil
end
if env.en_memory then
env.en_memory:disconnect()
env.en_memory = nil
end
end
function AP.save_comment_cache(cand)
local comment = cand.comment
local comment_text = cand.text
if comment_text and comment_text ~= "" and comment and comment ~= "" then
comment_cache[comment_text] = comment
end
end
-- 入口lua_filter
function AP.func(input, env)
local config = env.engine.schema.config
local context = env.engine.context
local use_comment_cache = env.memory ~= nil -- 只有中文造词才需要缓存注释
for cand in input:iter() do
local genuine_cand = cand:get_genuine()
local preedit = genuine_cand.preedit or ""
local initial_comment = genuine_cand.comment
if use_comment_cache then
AP.save_comment_cache(cand)
end
yield(cand)
end
end
-- 造词(原逻辑 + 新增 '\' 英文造词)
function AP.commit_handler(ctx, env)
if not ctx or not ctx.composition then
comment_cache = {}
return
end
local segments = ctx.composition:toSegmentation():get_segments()
local segments_count = #segments
local commit_text = ctx:get_commit_text() or ""
local raw_input = ctx.input or ""
---------------------------------------------------
-- ① 英文 + '\' 造词 —— 始终启用,只依赖 env.en_memory
-- 条件:
-- - raw_input 末尾为 '\'
-- - commit_text 为“ASCII 且至少 1 字母”的英文
-- 行为:
-- - text = commit_text
-- - custom_code = 编码去掉末尾 '\' + 空格
---------------------------------------------------
if raw_input ~= "" and raw_input:sub(-1) == "\\" and is_ascii_word(commit_text) then
local code_body = raw_input:gsub("\\+$", "") -- 去掉末尾连续 '\'
code_body = code_body:gsub("%s+$", "") -- 去掉尾部空白
if code_body ~= "" and env.en_memory then
local entry = DictEntry()
entry.text = commit_text -- 上屏英文本身
entry.weight = 1
entry.custom_code = code_body .. " " -- 真实编码(无 '\') + 空格
env.en_memory:update_userdict(entry, 1, "")
-- log.info(string.format("[auto_phrase] EN 造词:[%s], code=[%s]", entry.text, entry.custom_code))
end
comment_cache = {}
return
end
---------------------------------------------------
-- ② 中文自动造词:只在 env.memory 存在时工作
---------------------------------------------------
if not env.memory then
-- 中文造词功能被关掉时,直接跳过这一段
comment_cache = {}
return
end
-- 检查是否符合最小造词单元要求
if segments_count <= 1 or utf8.len(commit_text) <= 1 then
comment_cache = {}
return
end
-- 检查是否符合造词内容要求
if not AP.is_chinese_only(commit_text) or comment_cache[commit_text] then
comment_cache = {}
return
end
local preedits_table = {}
local config = env.engine.schema.config
local delimiter = config:get_string("speller/delimiter") or " '"
local escaped_delimiter =
utf8.char(utf8.codepoint(delimiter)):gsub("(%W)", "%%%1")
for i = 1, segments_count do
local seg = segments[i]
local cand = seg:get_selected_candidate()
if cand then
local cand_text = cand.text
local preedit = comment_cache[cand_text]
if preedit and preedit ~= "" then
for part in preedit:gmatch("[^" .. escaped_delimiter .. "]+") do
table.insert(preedits_table, part)
end
end
end
end
if #preedits_table == 0 then
comment_cache = {}
return
end
local dictEntry = DictEntry()
dictEntry.text = commit_text
dictEntry.weight = 1
dictEntry.custom_code = table.concat(preedits_table, " ") .. " "
env.memory:update_userdict(dictEntry, 1, "")
comment_cache = {}
end
return AP

55
lua/backspace_limit.lua Normal file
View File

@@ -0,0 +1,55 @@
-- backspace_limiter.lua
-- 防止连续 Backspace 在编码为空时删除已上屏内容虽然我更推荐拍下esc。
-- 这个功能依赖按键事件的处理,运行逻辑的问题在手机上无法得到好的效果,其中macOS特非常特殊,它的按键事件等同于手机逻辑,因此手机和Mac都屏蔽了这一功能
-- @author amzxyz
local M = {}
local ACCEPT, PASS = 1, 2
-- 引入移动设备检测模块
local wanxiang = require("wanxiang")
-- 状态标志说明:
-- env.prev_input_len: 上一次按键前的输入长度
-- env.bs_sequence: 当前是否处于连续 Backspace 序列中
function M.init(env)
env.prev_input_len = -1 -- 初始化为无效值
env.bs_sequence = false
end
function M.func(key, env)
local ctx = env.engine.context
local kc = key.keycode
-- 非 Backspace 键或按键释放事件:重置状态
if kc ~= 0xFF08 or key:release() then
env.bs_sequence = false
env.prev_input_len = -1
return PASS
end
-- 获取当前输入长度
local current_len = #ctx.input
-- 处于连续 Backspace 序列中
if env.bs_sequence then
-- 移动设备由于运行逻辑的问题不能实现友好的逻辑
if wanxiang.is_mobile_device() then
return PASS -- 直接放行
-- PC设备保持原有逻辑长度1变0时拦截
else
if env.prev_input_len == 1 and current_len == 0 then
return ACCEPT -- 拦截PC设备上从1变为0的情况
end
end
-- 更新状态
env.prev_input_len = current_len
return PASS
end
-- 开始新的 Backspace 序列
env.bs_sequence = true
env.prev_input_len = current_len
-- 首次按键总是允许
return PASS
end
return M

BIN
lua/charset.bin Normal file

Binary file not shown.

262
lua/input_statistics.lua Normal file
View File

@@ -0,0 +1,262 @@
-- github.com/amzxyz
-- 一个用于统计输入字数和其他时间维度的统计。先搭起一个框架,有志之士看看如何优化,统计什么数据,什么维度,构建一个有效的统计信息
-- 硬编码输入方案信息
local schema_name = "万象拼音"
local software_name = rime_api.get_distribution_code_name()
local software_version = rime_api.get_distribution_version()
-- 初始化统计表(若未加载)
input_stats = input_stats or {
daily = {count = 0, length = 0, fastest = 0, ts = 0},
weekly = {count = 0, length = 0, fastest = 0, ts = 0},
monthly = {count = 0, length = 0, fastest = 0, ts = 0},
yearly = {count = 0, length = 0, fastest = 0, ts = 0},
lengths = {},
daily_max = 0,
recent = {}
}
-- 时间戳工具函数
local function start_of_day(t)
return os.time{year=t.year, month=t.month, day=t.day, hour=0}
end
local function start_of_week(t)
local d = t.wday == 1 and 6 or (t.wday - 2)
return os.time{year=t.year, month=t.month, day=t.day - d, hour=0}
end
local function start_of_month(t)
return os.time{year=t.year, month=t.month, day=1, hour=0}
end
local function start_of_year(t)
return os.time{year=t.year, month=1, day=1, hour=0}
end
-- 判断是否是统计命令
local function is_summary_command(text)
return text == "/rtj" or text == "/ztj" or text == "/ytj" or text == "/ntj" or text == "/tj"
end
-- 更新统计数据
local function update_stats(input_length)
local now = os.date("*t")
local now_ts = os.time(now)
local day_ts = start_of_day(now)
local week_ts = start_of_week(now)
local month_ts = start_of_month(now)
local year_ts = start_of_year(now)
if input_stats.daily.ts ~= day_ts then
input_stats.daily = {count = 0, length = 0, fastest = 0, ts = day_ts}
input_stats.daily_max = 0
input_stats.recent = {}
end
if input_stats.weekly.ts ~= week_ts then
input_stats.weekly = {count = 0, length = 0, fastest = 0, ts = week_ts}
end
if input_stats.monthly.ts ~= month_ts then
input_stats.monthly = {count = 0, length = 0, fastest = 0, ts = month_ts}
end
if input_stats.yearly.ts ~= year_ts then
input_stats.yearly = {count = 0, length = 0, fastest = 0, ts = year_ts}
end
-- 更新记录
local update = function(stat)
stat.count = stat.count + 1
stat.length = stat.length + input_length
end
update(input_stats.daily)
update(input_stats.weekly)
update(input_stats.monthly)
update(input_stats.yearly)
if input_length > input_stats.daily_max then
input_stats.daily_max = input_length
end
input_stats.lengths[input_length] = (input_stats.lengths[input_length] or 0) + 1
-- 最近一分钟统计
local ts = os.time()
table.insert(input_stats.recent, {ts = ts, len = input_length})
local threshold = ts - 60
local total = 0
local new_recent = {}
for _, item in ipairs(input_stats.recent) do
if item.ts >= threshold then
total = total + item.len
table.insert(new_recent, item)
end
end
input_stats.recent = new_recent
if total > input_stats.daily.fastest then input_stats.daily.fastest = total end
if total > input_stats.weekly.fastest then input_stats.weekly.fastest = total end
if total > input_stats.monthly.fastest then input_stats.monthly.fastest = total end
if total > input_stats.yearly.fastest then input_stats.yearly.fastest = total end
end
-- 表序列化工具(请自行根据实际添加到环境中)
table.serialize = function(tbl)
local lines = {"{"}
for k, v in pairs(tbl) do
local key = (type(k) == "string") and ("[\"" .. k .. "\"]") or ("[" .. k .. "]")
local val
if type(v) == "table" then
val = table.serialize(v)
elseif type(v) == "string" then
val = '"' .. v .. '"'
else
val = tostring(v)
end
table.insert(lines, string.format(" %s = %s,", key, val))
end
table.insert(lines, "}")
return table.concat(lines, "\n")
end
-- 保存至文件
local function save_stats()
local path = rime_api.get_user_data_dir() .. "/lua/input_stats.lua"
local file = io.open(path, "w")
if not file then return end
file:write("input_stats = " .. table.serialize(input_stats) .. "\n")
file:close()
end
-- 显示函数(以日统计为例)
local function format_daily_summary()
local s = input_stats.daily
if s.count == 0 then return "※ 今天没有任何记录。" end
return string.format(
"※ 今天的统计:\n%s\n◉ 今天\n共上屏[%d]次\n共输入[%d]字\n最快一分钟输入了[%d]字\n%s\n◉ 方案:%s\n◉ 平台:%s %s\n%s",
string.rep("", 14), s.count, s.length, s.fastest,
string.rep("", 14), schema_name, software_name, software_version,
string.rep("", 14))
end
-- 显示函数(周统计)
local function format_weekly_summary()
local s = input_stats.weekly
if s.count == 0 then return "※ 本周没有任何记录。" end
return string.format(
"※ 本周的统计:\n%s\n◉ 本周共上屏[%d]次\n共输入[%d]字\n最快一分钟输入了[%d]字\n周内单日最多一次输入[%d]字\n%s\n◉ 方案:%s\n◉ 平台:%s %s\n%s",
string.rep("", 14), s.count, s.length, s.fastest, input_stats.daily_max,
string.rep("", 14), schema_name, software_name, software_version,
string.rep("", 14))
end
-- 显示函数(月统计)
local function format_monthly_summary()
local s = input_stats.monthly
if s.count == 0 then return "※ 本月没有任何记录。" end
return string.format(
"※ 本月的统计:\n%s\n◉ 本月共上屏[%d]次\n共输入[%d]字\n最快一分钟输入了[%d]字\n%s\n◉ 方案:%s\n◉ 平台:%s %s\n%s",
string.rep("", 14), s.count, s.length, s.fastest,
string.rep("", 14), schema_name, software_name, software_version,
string.rep("", 14))
end
-- 显示函数(年统计)
local function format_yearly_summary()
local s = input_stats.yearly
if s.count == 0 then return "※ 本年没有任何记录。" end
local length_counts = {}
for length, count in pairs(input_stats.lengths) do
table.insert(length_counts, {length = length, count = count})
end
table.sort(length_counts, function(a, b) return a.count > b.count end)
local fav = length_counts[1] and length_counts[1].length or 0
return string.format(
"※ 本年的统计:\n%s\n◉ 本年共上屏[%d]次\n共输入[%d]字\n最快一分钟输入了[%d]字\n您最常输入长度为[%d]的词组\n%s\n◉ 方案:%s\n◉ 平台:%s %s\n%s",
string.rep("", 14), s.count, s.length, s.fastest, fav,
string.rep("", 14), schema_name, software_name, software_version,
string.rep("", 14))
end
-- 转换器函数:处理命令 /rtj /ztj /ytj /ntj
local function translator(input, seg, env)
if input:sub(1, 1) ~= "/" then return end
local summary = ""
if input == "/rtj" then
summary = format_daily_summary()
elseif input == "/ztj" then
summary = format_weekly_summary()
elseif input == "/ytj" then
summary = format_monthly_summary()
elseif input == "/ntj" then
summary = format_yearly_summary()
elseif input == "/tj" then
summary = format_daily_summary() .. "\n\n" .. format_weekly_summary() .. "\n\n" .. format_monthly_summary() .. "\n\n" .. format_yearly_summary()
elseif input == "/tjql" then
input_stats = {
daily = {count = 0, length = 0, fastest = 0, ts = 0},
weekly = {count = 0, length = 0, fastest = 0, ts = 0},
monthly = {count = 0, length = 0, fastest = 0, ts = 0},
yearly = {count = 0, length = 0, fastest = 0, ts = 0},
lengths = {},
daily_max = 0,
recent = {}
}
save_stats()
summary = "※ 所有统计数据已清空。"
end
if summary ~= "" then
yield(Candidate("stat", seg.start, seg._end, summary, ""))
end
end
-- 加载保存的统计数据input_stats.lua
local function load_stats_from_lua_file()
local path = rime_api.get_user_data_dir() .. "/lua/input_stats.lua"
local ok, result = pcall(function()
local env = {}
local f = loadfile(path, "t", env)
if f then f() end
return env.input_stats
end)
if ok and type(result) == "table" then
input_stats = result
else
-- 保底初始化,防止错误
input_stats = {
daily = {count = 0, length = 0, fastest = 0, ts = 0},
weekly = {count = 0, length = 0, fastest = 0, ts = 0},
monthly = {count = 0, length = 0, fastest = 0, ts = 0},
yearly = {count = 0, length = 0, fastest = 0, ts = 0},
lengths = {},
daily_max = 0,
recent = {}
}
end
end
local function init(env)
local ctx = env.engine.context
-- 加载历史统计数据
load_stats_from_lua_file()
-- 注册提交通知回调
ctx.commit_notifier:connect(function()
local commit_text = ctx:get_commit_text()
if not commit_text or commit_text == "" then return end
-- 排除统计命令(如 /rtj、/tj 等)
if is_summary_command(commit_text) then return end
-- 排除统计候选上屏内容(例如 "※ 今天..." 或 "◉ 本年..."
if commit_text:match("^[※◉]") then return end
-- 排除我们自己生成的统计候选comment 是 "input_stats_summary"
-- local cand = ctx:get_selected_candidate()
-- if cand and cand.comment == "input_stats_summary" then return end
-- 保存最近一次 commit 内容
env.last_commit_text = commit_text
-- 统计长度
local input_length = utf8.len(commit_text) or string.len(commit_text)
update_stats(input_length)
save_stats()
end)
end
return { init = init, func = translator }

92
lua/key_binder.lua Normal file
View File

@@ -0,0 +1,92 @@
-- 正则按键绑定处理器
-- 本处理器在 Rime 标准库的按键绑定处理器key_binder的基础上增加了用正则表达式判断当前输入的编码的功能
-- 也即,在输入编码不同时,可以将按键绑定到不同的功能
-- RIME_PROCESS_RESULTS 定义在 wanxiang.lua 中,这里需要引入才能使用
local wanxiang = require("wanxiang")
local this = {}
---@class KeyBinderEnv: Env
---@field redirecting boolean
---@field bindings Binding[]
---@class Binding
---element
---@field match string
---@field accept KeyEvent
---@field send_sequence KeySequence
---解析配置文件中的按键绑定配置
---@param value ConfigMap
---@return Binding | nil
local function parse(value)
local match = value:get_value("match")
local accept = value:get_value("accept")
local send_sequence = value:get_value("send_sequence")
if not match or not accept or not send_sequence then
return nil
end
local key_event = KeyEvent(accept:get_string())
local sequence = KeySequence(send_sequence:get_string())
local binding = { match = match:get_string(), accept = key_event, send_sequence = sequence }
return binding
end
---@param env KeyBinderEnv
function this.init(env)
env.redirecting = false
---@type Binding[]
env.bindings = {}
local bindings = env.engine.schema.config:get_list("key_binder/bindings")
if not bindings then
return
end
for i = 1, bindings.size do
local item = bindings:get_at(i - 1)
if not item then goto continue end
local value = item:get_map()
if not value then goto continue end
local binding = parse(value)
if not binding then goto continue end
table.insert(env.bindings, binding)
::continue::
end
end
---@param key_event KeyEvent
---@param env KeyBinderEnv
---@return ProcessResult
function this.func(key_event, env)
-- local input = rime.current(env.engine.context)
local input = env.engine.context.input
-- log.info("key_binder"..input)
if env.redirecting then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
if not input then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
if env.engine.context == nil or env.engine.context.composition == nil or env.engine.context.composition:back() == nil then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
if not env.engine.context.composition:back():has_tag("abc") then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
for _, binding in ipairs(env.bindings) do
-- 只有当按键和当前输入的模式都匹配的时候,才起作用
if key_event:eq(binding.accept) and rime_api.regex_match(input, binding.match) then
env.redirecting = true
for _, event in ipairs(binding.send_sequence:toKeyEvent()) do
env.engine:process_key(event)
end
env.redirecting = false
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
end
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return this

256
lua/kp_number_processor.lua Normal file
View File

@@ -0,0 +1,256 @@
-- https://github.com/amzxyz/rime_wanxiang
-- 万象家族 lua小键盘行为控制
-- - 小键盘数字:根据 kp_number_mode 决定 “参与编码 / 直接上屏”
-- - 主键盘数字:在有候选菜单时,用于选第 n 个候选
--
-- 用法示例schema.yaml
-- engine:
-- processors:
-- - lua_processor@*kp_number_processor
-- # 小键盘模式(可省略,默认 auto
-- # auto : 空闲时直接上屏,输入中参与编码
-- # compose : 无论是否在输入中,小键盘都参与编码(不直接上屏)
-- kp_number_mode: auto
local wanxiang = require("wanxiang")
-- 小键盘键码映射
local KP = {
[0xFFB1] = 1, -- KP_1
[0xFFB2] = 2,
[0xFFB3] = 3,
[0xFFB4] = 4,
[0xFFB5] = 5,
[0xFFB6] = 6,
[0xFFB7] = 7,
[0xFFB8] = 8,
[0xFFB9] = 9,
[0xFFB0] = 0, -- KP_0
}
local P = {}
-- 从 schema 读取 kp_number/patterns 列表
local function load_function_patterns(config)
local patterns = {}
local ok_list, list = pcall(function()
return config:get_list("kp_number/patterns")
end)
if ok_list and list and list.size and list.size > 0 then
for i = 0, list.size - 1 do
local item = list:get_value_at(i)
if item then
local pat = item:get_string()
if pat and pat ~= "" then
table.insert(patterns, pat)
end
end
end
end
-- 如果用户没配,给一份保底的默认集合(等价你现在用的那些)
if #patterns == 0 then
patterns = {
"^/[0-9]$", "^/10$", "^/[A-Za-z]+$",
"^`[A-Za-z]*$",
"^``[A-Za-z/`']*$",
"^U[%da-f]+$",
"^R[0-9]+%.?[0-9]*$",
"^N0[1-9]?0?[1-9]?$",
"^N1[02]?0?[1-9]?$",
"^N0[1-9]?[1-2]?[1-9]?$",
"^N1[02]?[1-2]?[1-9]?$",
"^N0[1-9]?3?[01]?$",
"^N1[02]?3?[01]?$",
"^N19?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$",
"^N20?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$",
"^V.*$",
}
end
return patterns
end
-- 根据“当前编码 + 这次按下的数字字符”判断是否属于命令模式
local function is_function_code_after_digit(env, context, digit_char)
if not context or not digit_char or digit_char == "" then
return false
end
local code = context.input or ""
local s = code .. digit_char
local pats = env.function_patterns
if not pats or #pats == 0 then
return false
end
for _, pat in ipairs(pats) do
-- 这里 pat 必须是 Lua pattern 语法
if s:match(pat) then
return true
end
end
return false
end
---@param env Env
function P.init(env)
local engine = env.engine
local config = engine.schema.config
local context = engine.context
-- 读数字选词个数
env.page_size = config:get_int("menu/page_size") or 6
-- 读小键盘模式auto / compose默认 auto
local m = config:get_string("kp_number/kp_number_mode") or "auto"
if m ~= "auto" and m ~= "compose" then
m = "auto"
end
env.kp_mode = m
-- 初始化状态快照
env.context = context
env.is_composing = context:is_composing()
env.has_menu = context:has_menu()
-- 读取命令模式 Lua pattern 集合
env.function_patterns = load_function_patterns(config)
-- 用 update_notifier 同步 context / is_composing / has_menu
env.kp_update_connection = context.update_notifier:connect(function(ctx)
env.context = ctx
env.is_composing = ctx:is_composing()
env.has_menu = ctx:has_menu()
end)
end
---@param env Env
function P.fini(env)
if env.kp_update_connection then
env.kp_update_connection:disconnect()
env.kp_update_connection = nil
end
env.context = nil
env.is_composing = nil
env.has_menu = nil
env.function_patterns = nil
end
---@param key KeyEvent
---@param env Env
---@return ProcessResult
function P.func(key, env)
-- 只处理按下
if key:release() then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local engine = env.engine
local context = env.context or engine.context
local mode = env.kp_mode or "auto"
local page_sz = env.page_size
local is_composing = env.is_composing
local has_menu = env.has_menu
------------------------------------------------------------------
-- 1) 小键盘数字auto / compose
-- 如果“加上本次数字后”还匹配某个命令模式 pattern
-- 只作为编码输入,不 commit、不选词。
------------------------------------------------------------------
local kp_num = KP[key.keycode]
if kp_num ~= nil then
local ch = tostring(kp_num) -- "0".."9"
if is_function_code_after_digit(env, context, ch) then
if context then
if context.push_input then
context:push_input(ch)
else
context.input = (context.input or "") .. ch
end
end
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
if mode == "auto" then
-- 输入中:参与编码;空闲:直接上屏
if is_composing then
if context.push_input then
context:push_input(ch)
else
context.input = (context.input or "") .. ch
end
else
engine:commit_text(ch)
end
else
-- compose始终参与编码
if context.push_input then
context:push_input(ch)
else
context.input = (context.input or "") .. ch
end
end
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
------------------------------------------------------------------
-- 2) 主键盘数字:
-- 2.1 若“加上本次数字后”匹配命令模式 → 只当编码输入
-- 2.2 否则:
-- 有菜单时:选第 n 个候选
-- 空闲时:直接上屏
------------------------------------------------------------------
local r = key:repr() or ""
if r:match("^[0-9]$") then
-- 命令模式:只作为编码输入
if is_function_code_after_digit(env, context, r) then
if context then
if context.push_input then
context:push_input(r)
else
context.input = (context.input or "") .. r
end
end
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
-- 有候选菜单时,用数字选「当前页」的第 n 个候选
if has_menu then
local d = tonumber(r)
if d and d >= 1 and d <= page_sz then
local composition = context and context.composition
if composition and not composition:empty() then
local seg = composition:back() -- 当前正在编辑的 segment
local menu = seg and seg.menu
if menu and not menu:empty() then
-- 当前高亮候选的全局下标0 开始)
local sel_index = seg.selected_index or 0
local page_size = page_sz
-- 当前页号 = 高亮索引 / 每页大小
local page_no = math.floor(sel_index / page_size)
local page_start = page_no * page_size
-- 当前页第 n 个候选的全局下标
local index = page_start + (d - 1)
-- 防止越界(最后一页候选不足一整页)
if index < menu:candidate_count() then
if context:select(index) then
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
end
end
end
end
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
end
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return P

89
lua/letter_selector.lua Normal file
View File

@@ -0,0 +1,89 @@
-- @amzxyz https://github.com/amzxyz/rime_wanxiang
-- 功能仅在特定前缀或者tag模式下按 qwertyuio 选择第 1~9 个候选
local wanxiang = require("wanxiang")
local M = {}
-- 键码映射q w e r t y u i o → 1..9
local KEY2IDX = {
[0x71] = 1, -- q
[0x77] = 2, -- w
[0x65] = 3, -- e
[0x72] = 4, -- r
[0x74] = 5, -- t
[0x79] = 6, -- y
[0x75] = 7, -- u
[0x69] = 8, -- i
[0x6F] = 9, -- o
}
-- 判断是否在命令模式
local function is_function_mode_active(context)
if not context or not context.composition or context.composition:empty() then
return false
end
local seg = context.composition:back()
if not seg then return false end
return seg:has_tag("number") or seg:has_tag("Ndate")
end
-- 缓存命令模式的状态,避免每次按键都计算
local function on_update(env, ctx)
env._fn_active = is_function_mode_active(ctx)
end
function M.init(env)
env._fn_active = false
env._upd_conn = env.engine.context.update_notifier:connect(function(ctx)
on_update(env, ctx)
end)
end
function M.fini(env)
if env._upd_conn then
env._upd_conn:disconnect()
env._upd_conn = nil
end
end
local function handle_key(key_event, env)
-- 只处理按下;有修饰键则忽略
if key_event:release() or key_event:ctrl() or key_event:alt() or key_event:super() then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local idx = KEY2IDX[key_event.keycode]
if not idx then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local context = env.engine.context
if not env._fn_active then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
if not context or not context.composition or context.composition:empty() then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local seg = context.composition:back()
if not seg or not seg.menu then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 准备最多 9 个候选
local count = seg.menu:prepare(9)
if idx < 1 or idx > count then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 选择:候选索引从 0 开始
context:select(idx - 1)
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
function M.func(key_event, env)
return handle_key(key_event, env)
end
return M

68
lua/lib/bit.lua Normal file
View File

@@ -0,0 +1,68 @@
local bit_ok, bit_ = pcall(require, "bit") -- LuaJIT 内置 bit 库
local bit32_ok, bit32_ = pcall(require, "bit32") -- Lua 5.2 内置 bit32 库
---@alias fn_band fun(a: integer, b: integer): integer
---@alias fn_bxor fun(a: integer, b: integer): integer
---@type nil | { band: fn_band, bxor: fn_bxor }
local bit53_ = nil -- Lua 5.3 引入的原生位运算操作符
---@diagnostic disable-next-line: deprecated
local load_func = load or loadstring
if load_func then
---将新语法放入字符串中,避免在旧版 Lua 中导致语法错误
local bit53_func, bit53_err = load_func("return {" ..
"band = function(a, b) return a & b end," ..
"bxor = function(a, b) return a ~ b end," ..
"}")
if bit53_func and not bit53_err then
bit53_ = bit53_func()
end
end
local bit = {}
---@return integer
function bit.bxor(a, b)
if bit_ok then
return bit_.bxor(a, b)
elseif bit32_ok then
return bit32_.bxor(a, b)
elseif bit53_ then
return bit53_.bxor(a, b)
end
local p, c = 1, 0
while a > 0 and b > 0 do
local ra, rb = a % 2, b % 2
if ra ~= rb then c = c + p end
a, b, p = (a - ra) / 2, (b - rb) / 2, p * 2
end
if a < b then a = b end
while a > 0 do
local ra = a % 2
if ra > 0 then c = c + p end
a, p = (a - ra) / 2, p * 2
end
return c
end
---@return integer
function bit.band(a, b)
if bit_ok then
return bit_.band(a, b)
elseif bit32_ok then
return bit32_.band(a, b)
elseif bit53_ then
return bit53_.band(a, b)
end
local p, c = 1, 0
while a > 0 and b > 0 do
local ra, rb = a % 2, b % 2
if ra + rb > 1 then c = c + p end
a, b, p = (a - ra) / 2, (b - rb) / 2, p * 2
end
return c
end
return bit

116
lua/lib/userdb.lua Normal file
View File

@@ -0,0 +1,116 @@
local META_KEY_PREFIX = "\001" .. "/"
-- UserDb 缓存,使用弱引用表,不阻止垃圾回收并能自动清理
local db_pool = setmetatable({}, { __mode = "v" })
---@class WrappedUserDb: UserDb
---@field meta_query fun(self: self, prefix: string): DbAccessor
---@field meta_fetch fun(self: self, key: string): string|nil
---@field meta_update fun(self: self, key: string, value: string): boolean
---@field meta_erase fun(self: self, key: string): boolean
---@field query_with fun(self: self, prefix: string, handler: fun(key: string, value: string))
---@field empty fun(self: self, include_metafield?: boolean) -- 清空数据库
-- 用于存放包装器对象的自定义方法
local extends = {}
--- @param key string
--- @return string|nil
function extends:meta_fetch(key)
return self._db:fetch(META_KEY_PREFIX .. key)
end
--- @param key string
--- @param value string
--- @return boolean
function extends:meta_update(key, value)
return self._db:update(META_KEY_PREFIX .. key, value)
end
--- @param key string
--- @return boolean
function extends:meta_erase(key)
return self._db:erase(META_KEY_PREFIX .. key)
end
--- @param prefix string
--- @return DbAccessor
function extends:meta_query(prefix)
return self._db:query(META_KEY_PREFIX .. prefix)
end
function extends:query_with(prefix, handler)
local da = self._db:query(prefix)
if da then
for key, value in da:iter() do
handler(key, value)
end
end
da = nil
collectgarbage()
end
--- @param include_metafield boolean 是否也清理元数据。
function extends:empty(include_metafield)
self:query_with("", function(key, _)
local is_metafield = key:find(META_KEY_PREFIX, 1, true) == 1
if include_metafield or not is_metafield then
self._db:erase(key)
end
end)
end
local mt = {
__index = function(wrapper, key)
-- 优先使用自定义方法
if extends[key] then
return extends[key]
end
-- 不是自定义方法,委托给真实的 UserDb 对象
local real_db = wrapper._db
local value = real_db[key]
if type(value) == "function" then
return function(_, ...)
return value(real_db, ...)
end
end
return value
end,
}
local userdb = {}
--- @param db_name string
--- @param db_class "userdb" | "plain_userdb" | nil
--- @return WrappedUserDb
function userdb.UserDb(db_name, db_class)
db_class = db_class or "userdb"
local key = db_name .. "." .. db_class
---@type UserDb
local db = db_pool[key]
if not db then
db = UserDb(db_name, db_class)
db_pool[key] = db
end
local wrapper = {
_db = db,
_pool_key = key,
}
return setmetatable(wrapper, mt)
end
function userdb.LevelDb(db_name)
return userdb.UserDb(db_name, "userdb")
end
function userdb.TableDb(db_name)
return userdb.UserDb(db_name, "plain_userdb")
end
return userdb

722
lua/librime.lua Normal file
View File

@@ -0,0 +1,722 @@
-- librime-lua 官方类型提示
-- ⚠️ 仅用于类型提升,请勿直接 require 使用
-- from https://github.com/hchunhui/librime-lua/blob/master/contrib/librime.lua
-- Last Change: LTS
---@meta rime
--- 全局对象
---@class RimeAPI
---@field get_rime_version fun(): string
---@field get_shared_data_dir fun(): string
---@field get_user_data_dir fun(): string
---@field get_sync_dir fun(): string
---@field get_distribution_name fun(): string
---@field get_distribution_code_name fun(): string
---@field get_distribution_version fun(): string
---@field get_user_id fun(): string
---@field get_time_ms fun(): number
---@field regex_match fun(input: string, pattern: string): boolean
---@field regex_search fun(input: string, pattern: string): string[] | nil
---@field regex_replace fun(input: string, pattern: string, fmt: string): string
rime_api = {}
---@class Log
---@field info fun(string)
---@field warning fun(string)
---@field error fun(string)
log = {}
---@param cand Candidate
function yield(cand) end
--- 常量
---@enum ConfigType
local config_types = {
kNull = "kNull",
kScalar = "kScalar",
kList = "kList",
kMap = "kMap",
}
---@enum SegmentType
local segment_types = {
kVoid = "kVoid",
kGuess = "kGuess",
kSelected = "kSelected",
kConfirmed = "kConfirmed",
}
---@enum CandidateDynamicType
local candidate_dynamic_types = {
kSentence = "Sentence",
kPhrase = "Phrase",
kSimple = "Simple",
kShadow = "Shadow",
kUniquified = "Uniquified",
kOther = "Other",
}
---@enum ProcessResult
local process_results = {
kRejected = 0,
kAccepted = 1,
kNoop = 2,
}
---@enum ModifierMask
local modifier_masks = {
kShift = 0x1,
kLock = 0x2,
kControl = 0x4,
kAlt = 0x8,
}
--- 工具
---@class Set
---@field empty fun(self: self): boolean
---@field __index function
---@field __add function
---@field __sub function
---@field __mul function
---@field __set function
---@param values any[]
---@return Set
function Set(values) end
--- 对象接口及构造函数
---@class Env
---@field engine Engine
---@field name_space string
---@class Engine
---@field schema Schema
---@field context Context
---@field active_engine Engine
---@field process_key fun(self: self, key_event: KeyEvent): boolean
---@field compose fun(self: self, ctx: Context)
---@field commit_text fun(self: self, text: string)
---@field apply_schema fun(self: self, schema: Schema)
---@class Context
---@field composition Composition
---@field input string
---@field caret_pos integer
---@field commit_notifier Notifier
---@field select_notifier Notifier
---@field update_notifier Notifier
---@field delete_notifier Notifier
---@field option_update_notifier OptionUpdateNotifier
---@field property_update_notifier PropertyUpdateNotifier
---@field unhandled_key_notifier KeyEventNotifier
---@field commit_history CommitHistory
---@field commit fun(self: self)
---@field get_commit_text fun(self: self): string
---@field get_script_text fun(self: self): string
---@field get_preedit fun(self: self): Preedit
---@field is_composing fun(self: self): boolean
---@field has_menu fun(self: self): boolean
---@field get_selected_candidate fun(self: self): Candidate
---@field push_input fun(self: self, text: string)
---@field pop_input fun(self: self, len: integer): boolean
---@field delete_input fun(self: self, len: integer): boolean
---@field clear fun(self: self)
---@field select fun(self: self, index: integer): boolean
---@field highlight fun(self: self, index: integer): boolean
---@field confirm_current_selection fun(self: self): boolean
---@field delete_current_selection fun(self: self): boolean
---@field confirm_previous_selection fun(self: self): boolean
---@field reopen_previous_selection fun(self: self): boolean
---@field clear_previous_segment fun(self: self): boolean
---@field reopen_previous_segment fun(self: self): boolean
---@field clear_non_confirmed_composition fun(self: self): boolean
---@field refresh_non_confirmed_composition fun(self: self): boolean
---@field set_option fun(self: self, name: string, value: boolean)
---@field get_option fun(self: self, name: string): boolean
---@field set_property fun(self: self, key: string, value: string)
---@field get_property fun(self: self, key: string): string
---@field clear_transient_options fun(self: self)
---@class Preedit
---@field text string
---@field caret_pos integer
---@field sel_start integer
---@field sel_end integer
---@class Composition
---@field empty fun(self: self): boolean
---@field back fun(self: self): Segment
---@field pop_back fun(self: self)
---@field push_back fun(self: self)
---@field has_finished_composition fun(self: self): boolean
---@field get_prompt fun(self: self): string
---@field toSegmentation fun(self: self): Segmentation
---@field spans fun(self: self): Spans
---@class Segmentation
---@field input string
---@field size integer
---@field empty fun(self: self): boolean
---@field back fun(self: self): Segment | nil
---@field pop_back fun(self: self)
---@field reset_length fun(self: self, length: integer)
---@field add_segment fun(self: self, seg: Segment): boolean
---@field forward fun(self: self): boolean
---@field trim fun(self: self): boolean
---@field has_finished_segmentation fun(self: self): boolean
---@field get_current_start_position fun(self: self): integer
---@field get_current_end_position fun(self: self): integer
---@field get_current_segment_length fun(self: self): integer
---@field get_confirmed_position fun(self: self): integer
---@field get_segments fun(self: self): Segment[]
---@field get_at fun(self: self, index: integer): Segment
---@class Segment
---@field status SegmentType
---@field start integer
---@field _start integer
---@field _end integer
---@field length integer
---@field tags Set
---@field menu Menu
---@field selected_index integer
---@field prompt string
---@field clear fun(self: self)
---@field close fun(self: self)
---@field reopen fun(self: self, caret_pos: integer)
---@field has_tag fun(self: self, tag: string): boolean
---@field get_candidate_at fun(self: self, index: integer): Candidate
---@field get_selected_candidate fun(self: self): Candidate
---@field active_text fun(self: self, text: string): string
---@field spans fun(self: self): Spans
---@param start_pos integer
---@param end_pos integer
---@return Segment
function Segment(start_pos, end_pos) end
---@class Spans
---@field _start integer
---@field _end integer
---@field count integer
---@field vertices integer[]
---@field add_span fun(self: self, start: integer, end: integer)
---@field add_spans fun(self: self, spans: Spans)
---@field add_vertex fun(self: self, vertex: integer)
---@field previous_stop fun(self: self, caret_pos: integer): integer
---@field next_stop fun(self: self, caret_pos: integer): integer
---@field has_vertex fun(self: self, vertex: integer): boolean
---@field count_between fun(self: self, start: integer, end: integer): integer
---@field clear fun(self: self)
---@return Spans
function Spans() end
---@class Schema
---@field schema_id string
---@field schema_name string
---@field config Config
---@field page_size integer
---@field select_keys string
---@param schema_id string
---@return Schema
function Schema(schema_id) end
---@class Config
---@field load_from_file fun(self: self, filename: string): boolean
---@field save_to_file fun(self: self, filename: string): boolean
---@field is_null fun(self: self, conf_path: string): boolean
---@field is_value fun(self: self, conf_path: string): boolean
---@field is_list fun(self: self, conf_path: string): boolean
---@field is_map fun(self: self, conf_path: string): boolean
---@field get_bool fun(self: self, conf_path: string): boolean|nil
---@field set_bool fun(self: self, conf_path: string, b: boolean): boolean
---@field get_int fun(self: self, conf_path: string): integer|nil
---@field set_int fun(self: self, conf_path: string, i: integer): boolean
---@field get_double fun(self: self, conf_path: string): number|nil
---@field set_double fun(self: self, conf_path: string, f: number): boolean
---@field get_string fun(self: self, conf_path: string): string|nil
---@field set_string fun(self: self, conf_path: string, s: string): boolean
---@field get_item fun(self: self, conf_path: string): ConfigItem|nil
---@field set_item fun(self: self, conf_path: string, item: ConfigItem): boolean
---@field get_value fun(self: self, conf_path: string): ConfigValue|nil
---@field set_value fun(self: self, conf_path: string, value: ConfigValue): boolean
---@field get_list fun(self: self, conf_path: string): ConfigList|nil
---@field set_list fun(self: self, conf_path: string, list: ConfigList): boolean
---@field get_map fun(self: self, conf_path: string): ConfigMap|nil
---@field set_map fun(self: self, conf_path: string, map: ConfigMap): boolean
---@field get_list_size fun(self: self, conf_path: string): integer|nil
---@class ConfigMap
---@field type ConfigType
---@field size integer
---@field element ConfigItem
---@field empty fun(self: self): boolean
---@field has_key fun(self: self, key: string): boolean
---@field keys fun(self: self): string[]
---@field get fun(self: self, key: string): ConfigItem|nil
---@field get_value fun(self: self, key: string): ConfigValue|nil
---@field set fun(self: self, key: string, item: ConfigItem)
---@field clear fun(self: self)
---@return ConfigMap
function ConfigMap() end
---@class ConfigList
---@field type ConfigType
---@field size integer
---@field element ConfigItem
---@field get_at fun(self: self, index: integer): ConfigItem|nil
---@field get_value_at fun(self: self, index: integer): ConfigValue|nil
---@field set_at fun(self: self, index: integer, item: ConfigItem): boolean
---@field append fun(self: self, item: ConfigItem): boolean
---@field insert fun(self: self, i: integer, item: ConfigItem): boolean
---@field clear fun(self: self): boolean
---@field empty fun(self: self): boolean
---@field resize fun(self: self, size: integer): boolean
---@return ConfigList
function ConfigList() end
---@class ConfigValue
---@field type ConfigType
---@field value string
---@field element ConfigItem
---@field get_bool fun(self: self): boolean|nil
---@field get_int fun(self: self): integer|nil
---@field get_double fun(self: self): number|nil
---@field get_string fun(self: self): string|nil
---@field set_bool fun(self: self, b: boolean)
---@field set_int fun(self: self, i: integer)
---@field set_double fun(self: self, f: number)
---@field set_string fun(self: self, s: string)
---@param value string | boolean
---@return ConfigValue
function ConfigValue(value) end
---@class ConfigItem
---@field type ConfigType
---@field empty boolean
---@field get_value fun(self: self): ConfigValue|nil
---@field get_map fun(self: self): ConfigMap|nil
---@field get_list fun(self: self): ConfigList|nil
---@field get_obj fun(self: self): ConfigMap|ConfigList|ConfigValue|nil
---@class KeyEvent
---@field keycode integer
---@field modifier integer
---@field shift fun(self: self): boolean
---@field ctrl fun(self: self): boolean
---@field alt fun(self: self): boolean
---@field caps fun(self: self): boolean
---@field super fun(self: self): boolean
---@field release fun(self: self): boolean
---@field repr fun(self: self): string
---@field eq fun(self: self, key: KeyEvent): boolean
---@field lt fun(self: self, key: KeyEvent): boolean
---@param repr string
---@return KeyEvent
function KeyEvent(repr) end
---@param keycode integer
---@param modifier integer
---@return KeyEvent
function KeyEvent(keycode, modifier) end
---@class KeySequence
---@field parse fun(self: self, repr: string): boolean
---@field repr fun(self: self): string
---@field toKeyEvent fun(self: self): KeyEvent[]
---@param repr string?
---@return KeySequence
function KeySequence(repr) end
---@class Candidate
---@field type string
---@field start integer
---@field _start integer
---@field _end integer
---@field quality number
---@field text string
---@field comment string
---@field preedit string
---@field get_dynamic_type fun(self: self): CandidateDynamicType
---@field get_genuine fun(self: self): Candidate
---@field get_genuines fun(self: self): Candidate[]
---@field to_shadow_candidate fun(self: self, type: string?, text: string?, comment: string?, inherit_comment: boolean?): ShadowCandidate
---@field to_uniquified_candidate fun(self: self, type: string?, text: string?, comment: string?): UniquifiedCandidate
---@field to_phrase fun(self: self): Phrase
---@field to_sentence fun(self: self): Sentence
---@field append fun(self: self, cand: Candidate)
---@field spans fun(self: self): Spans
---@param type string
---@param start integer
---@param _end integer
---@param text string
---@param comment string
---@return Candidate
function Candidate(type, start, _end, text, comment) end
---@class UniquifiedCandidate: Candidate
---@param candidate Candidate
---@param type string?
---@param text string?
---@param comment string?
function UniquifiedCandidate(candidate, type, text, comment) end
---@class ShadowCandidate: Candidate
---@param candidate Candidate
---@param type string?
---@param text string?
---@param comment string?
---@param inherit_comment boolean?
---@return ShadowCandidate
function ShadowCandidate(candidate, type, text, comment, inherit_comment) end
---@class Phrase
-----@field language Language 暂时不支持
---@field lang_name string
---@field type string
---@field start integer
---@field _start integer
---@field _end integer
---@field quality number
---@field text string
---@field comment string
---@field preedit string
---@field weight number
---@field code Code
---@field entry DictEntry
---@field toCandidate fun(self: self): Candidate
---@field spans fun(self: self): Spans
---@param memory Memory
---@param type string
---@param start integer
---@param _end integer
---@param entry DictEntry
---@return Phrase
function Phrase(memory, type, start, _end, entry) end
---@class Sentence
-----@field language Language 暂时不支持
---@field lang_name string
---@field type string
---@field start integer
---@field _start integer
---@field _end integer
---@field quality number
---@field text string
---@field comment string
---@field preedit string
---@field weight number
---@field code Code
---@field entry DictEntry
---@field word_lengths integer[]
---@field entrys DictEntry[]
---@field entrys_size integer
---@field entrys_empty boolean
---@field toCandidate fun(self: self): Candidate
---@class Menu
---@field add_translation fun(self: self, translation: Translation)
---@field prepare fun(self: self, candidate_count: integer): integer
---@field get_candidate_at fun(self: self, i: integer): Candidate|nil
---@field candidate_count fun(self: self): integer
---@field empty fun(self: self): boolean
---@return Menu
function Menu() end
---@class Opencc
---@field convert fun(self: self, text: string): string
---@field convert_text fun(self: self, text: string): string
---@field random_convert_text fun(self: self, text: string): string
---@field convert_word fun(self: self, text: string): string[]
---@param filename string
---@return Opencc
function Opencc(filename) end
---@class Dictionary
---@field name string
---@field loaded boolean
---@field lookup_words fun(self: self, code: string, predictive: boolean, limit: integer): boolean
---@field decode fun(self: self, code: Code): string[]
---@class DictEntryIterator
---@field exhausted boolean
---@field size integer
---@field iter fun(self: self): fun(): DictEntry|nil
---@class UserDictionary
---@field name string
---@field loaded boolean
---@field tick integer
---@field lookup_words fun(self: self, code: string, predictive: boolean, limit: integer): boolean
---@field update_entry fun(self: self, entry: DictEntry, commits: integer, prefix: string, lang_name: string): boolean
---@class UserDictEntryIterator
---@field exhausted boolean
---@field size integer
---@field iter fun(self: self): fun(): DictEntry|nil
---@class ReverseDb
---@field lookup fun(self: self, key: string): string
---@param file_name string
---@return ReverseDb
function ReverseDb(file_name) end
---@class ReverseLookup
---@field lookup fun(self: self, key: string): string
---@field lookup_stems fun(self: self, key: string): string
---@param dict_name string
---@return ReverseLookup
function ReverseLookup(dict_name) end
---@class DictEntry
---@field text string
---@field comment string
---@field preedit string
---@field weight number
---@field commit_count integer `2`
---@field custom_code string "hao", "ni hao"
---@field remaining_code_length integer "~ao"
---@field code Code
---@return DictEntry
function DictEntry() end
---@class CommitEntry: DictEntry
---@field get fun(self: self): DictEntry[]
---@field update_entry fun(self: self, entry: DictEntry, commit: integer, prefix: string): boolean
---@field update fun(self: self, commit: integer): boolean
---@class Code
---@field push fun(self: self, syllable_id: integer)
---@field print fun(self: self): string
---@return Code
function Code() end
---@class Translation
---@field exhausted boolean
---@field iter fun(self: self): fun(): Candidate|nil
function Translation() end
---@class Memory
---@field lang_name string
---@field dict Dictionary
---@field user_dict UserDictionary
---@field start_session fun(self: self): boolean
---@field finish_session fun(self: self): boolean
---@field discard_session fun(self: self): boolean
---@field dict_lookup fun(self: self, input: string, predictive: boolean, limit: integer): boolean
---@field user_lookup fun(self: self, input: string, predictive: boolean): boolean
---@field dictiter_lookup fun(self: self, input: string, predictive: boolean, limit: integer): DictEntryIterator
---@field useriter_lookup fun(self: self, input: string, predictive: boolean): UserDictEntryIterator
---@field memorize fun(self: self, callback: fun(ce: CommitEntry))
---@field decode fun(self: self, code: Code): string[]
---@field iter_dict fun(self: self): fun(): DictEntry|nil
---@field iter_user fun(self: self): fun(): DictEntry|nil
---@field update_userdict fun(self: self, entry: DictEntry, commits: integer, prefix: string): boolean
---@field update_entry fun(self: self, entry: DictEntry, commits: integer, prefix: string, lang_name?: string): boolean
---@field update_candidate fun(self: self, candidate: Candidate, commits: integer): boolean
---@field disconnect fun(self: self)
---@param engine Engine
---@param schema Schema
---@param namespace string?
---@return Memory
function Memory(engine, schema, namespace) end
---@class Projection
---@field load fun(self: self, rules: ConfigList): boolean
---@field apply fun(self: self, str: string, ret_org_str?: boolean): string
---@return Projection
function Projection() end
---@class Component
---@field Processor fun(engine: Engine, namespace: string, klass: string): Processor
---@field Translator fun(engine: Engine, namespace: string, klass: string): Translator
---@field Segmentor fun(engine: Engine, namespace: string, klass: string): Segmentor
---@field Filter fun(engine: Engine, namespace: string, klass: string): Filter
---@field ScriptTranslator fun(engine: Engine, namespace: string, klass: string): ScriptTranslator
---@field TableTranslator fun(engine: Engine, namespace: string, klass: string): TableTranslator
Component = {}
---@class Processor
---@field name_space string
---@field process_key_event fun(self: self, key_event: KeyEvent): ProcessResult
---@class Segmentor
---@field name_space string
---@field proceed fun(self: self, segmentation: Segmentation): boolean
---@class Translator
---@field name_space string
---@field query fun(self: self, input: string, segment: Segment): Translation
---@class ScriptTranslator
---@field name_space string
---@field lang_name string
---@field memorize_callback fun(ce: CommitEntry)
---@field max_homophones integer
---@field spelling_hints integer
---@field always_show_comments boolean
---@field enable_correction boolean
---@field delimiters string
---@field tag string
---@field enable_completion boolean
---@field contextual_suggestions boolean
---@field strict_spelling boolean
---@field initial_quality number
---@field preedit_formatter Projection
---@field comment_formatter Projection
---@field dict Dictionary
---@field user_dict UserDictionary
---@field translator Translator
---@field query fun(self: self, input: string, segment: Segment): Translation
---@field start_session fun(self: self): boolean
---@field finish_session fun(self: self): boolean
---@field discard_session fun(self: self): boolean
---@field memorize fun(self: self, callback: fun(ce: CommitEntry))
---@field update_entry fun(self: self, entry: DictEntry, commits: integer, prefix: string): boolean
---@field reload_user_dict_disabling_patterns fun(self: self, config_list: ConfigList): boolean
---@field set_memorize_callback fun(self: self, callback: fun(ce: CommitEntry))
---@field disconnect fun(self: self)
---@class TableTranslator
---@field name_space string
---@field lang_name string
---@field memorize_callback fun(ce: CommitEntry)
---@field enable_charset_filter boolean
---@field enable_encoder boolean
---@field enable_sentence boolean
---@field sentence_over_completion boolean
---@field encode_commit_history boolean
---@field max_phrase_length integer
---@field max_homographs integer
---@field delimiters string
---@field tag string
---@field enable_completion boolean
---@field contextual_suggestions boolean
---@field strict_spelling boolean
---@field initial_quality number
---@field preedit_formatter Projection
---@field comment_formatter Projection
---@field dict Dictionary
---@field user_dict UserDictionary
---@field translator Translator
---@field query fun(self: self, input: string, segment: Segment): Translation
---@field start_session fun(self: self): boolean
---@field finish_session fun(self: self): boolean
---@field discard_session fun(self: self): boolean
---@field memorize fun(self: self, callback: fun(ce: CommitEntry))
---@field update_entry fun(self: self, entry: DictEntry, commits: integer, prefix: string): boolean
---@field reload_user_dict_disabling_patterns fun(self: self, config_list: ConfigList): boolean
---@field set_memorize_callback fun(self: self, callback: fun(ce: CommitEntry))
---@field disconnect fun(self: self)
---@class Filter
---@field name_space string
---@field apply fun(self: self, translation: Translation): Translation
---@class Notifier
---@field connect fun(self: self, f: fun(ctx: Context), group: integer|nil): Connection
---@class OptionUpdateNotifier: Notifier
---@field connect fun(self: self, f: fun(ctx: Context, name: string), group:integer|nil): function[]
---@class PropertyUpdateNotifier: Notifier
---@field connect fun(self: self, f: fun(ctx: Context, name: string), group:integer|nil): function[]
---@class KeyEventNotifier: Notifier
---@field connect fun(self: self, f: fun(ctx: Context, key: string), group:integer|nil): function[]
---@class Connection
---@field disconnect fun(self: self)
---@class Switcher
---@field attached_engine Engine
---@field user_config Config
---@field active boolean
---@field process_key fun(self: self, key_event: KeyEvent): boolean
---@field select_next_schema fun(self: self)
---@field is_auto_save fun(self: self, option: string): boolean
---@field refresh_menu fun(self: self)
---@field activate fun(self: self)
---@field deactivate fun(self: self)
---@param engine Engine
---@return Switcher
function Switcher(engine) end
---@class CommitRecord
---@field text string
---@field type string
---@class CommitHistory
---@field size integer
---@field push fun(self: self, key_event: KeyEvent)
---@field back fun(self: self): CommitRecord|nil
---@field to_table fun(self: self): CommitRecord[]
---@field iter fun(self: self): fun(): (number, CommitRecord)|nil
---@field latest_text fun(self: self): string
---@field empty fun(self: self): boolean
---@field clear fun(self: self)
---@field pop_back fun(self: self)
---@class DbAccessor
---@field reset fun(self: self): boolean
---@field jump fun(self: self, prefix: string): boolean
---@field iter fun(self: self): fun(): (string, string) | nil
---@class UserDb
---@field _loaded boolean
---@field read_only boolean
---@field disabled boolean
---@field name string
---@field file_name string
---@field open fun(self: self): boolean
---@field open_read_only fun(self: self): boolean
---@field close fun(self: self): boolean
---@field query fun(self: self, prefix: string): DbAccessor
---@field fetch fun(self: self, key: string): string|nil
---@field update fun(self: self, key: string, value: string): boolean
---@field erase fun(self: self, key: string): boolean
---@field loaded fun(self: self): boolean
---@field disable fun(self: self): boolean
---@field enable fun(self: self): boolean
---@param db_name string
---@param db_class string
---@return UserDb
function UserDb(db_name, db_class) end
---@class LevelDb: UserDb
---@param db_name string
---@return LevelDb
function LevelDb(db_name) end
---@class TableDb: UserDb
---@param db_name string
---@return TableDb
function TableDb(db_name) end

61
lua/limit_repeated.lua Normal file
View File

@@ -0,0 +1,61 @@
-- 用于限制最大候选数量以及重复最大输入编码,防止卡顿性能异常
--@amzxyz
--https://github.com/amzxyz
local M = {}
local ACCEPT, PASS = 1, 2
local MAX_REPEAT = 8 -- 连续重复输入声母上限
local MAX_SEGMENTS = 40 -- 允许的最大“分段”数
local INITIALS = "[bpmfdtnlgkhjqxrzcsywiu]"
-- 计算末尾重复
local function tail_rep(s)
local last, n = s:sub(-1), 1
for i = #s - 1, 1, -1 do
if s:sub(i, i) == last then n = n + 1 else break end
end
return last, n
end
-- 在候选栏最后一个 segment 加提示
local function prompt(ctx, msg)
local comp = ctx.composition
if comp and not comp:empty() then comp:back().prompt = msg end
end
function M.func(key, env)
local ctx, kc = env.engine.context, key.keycode
-- 先拿到“上一轮”高亮候选的 preedit 及段数
local cand = ctx:get_selected_candidate()
local preedit = cand and (cand.preedit or cand:get_genuine().preedit) or ""
local segs = 1
for _ in preedit:gmatch("[%'%s]") do segs = segs + 1 end
-- 本次按键字符(只关心字母 / 分隔符)
local ch
if kc >= 0x61 and kc <= 0x7A then -- a~z
ch = string.char(kc)
elseif kc == 0x27 then -- '
ch = "'"
elseif kc == 0x20 then -- space
ch = " "
end
-- ① 连续声母限制:第 MAX_REPEAT 个同声母直接拦截
if ch and kc >= 0x61 and kc <= 0x7A then
local nxt = ctx.input .. ch
local last, rep_n = tail_rep(nxt)
if last:match(INITIALS) and rep_n > MAX_REPEAT then
prompt(ctx, " 〔已超最大重复声母〕")
return ACCEPT
end
end
-- ② 分段限制:第 MAX_SEGMENTS 段拦截
local segs_after = segs
if ch == "'" or ch == " " then segs_after = segs + 1 end
if segs_after >= MAX_SEGMENTS and kc >= 0x61 and kc <= 0x7A then
prompt(ctx, " 〔已超最大输入长度〕")
return ACCEPT
end
return PASS
end
return M

175
lua/number_translator.lua Normal file
View File

@@ -0,0 +1,175 @@
-- 来源 https://github.com/yanhuacuo/98wubi-tables > http://98wb.ysepan.com/
-- 数字、金额大写
-- 触发前缀默认为 recognizer/patterns/number 的第 2 个字符,即 R
local function splitNumPart(str)
local part = {}
part.int, part.dot, part.dec = string.match(str, "^(%d*)(%.?)(%d*)")
return part
end
local function GetPreciseDecimal(nNum, n)
if type(nNum) ~= "number" then nNum = tonumber(nNum) end
n = n or 0;
n = math.floor(n)
if n < 0 then n = 0 end
local nDecimal = 10 ^ n
local nTemp = math.floor(nNum * nDecimal);
local nRet = nTemp / nDecimal;
return nRet;
end
local function decimal_func(str, posMap, valMap)
local dec
posMap = posMap or { [1] = "", [2] = "", [3] = "", [4] = "" }
valMap = valMap or { [0] = "", "", "", "", "", "", "", "", "", "" }
if #str > 4 then dec = string.sub(tostring(str), 1, 4) else dec = tostring(str) end
dec = string.gsub(dec, "0+$", "")
if dec == "" then return "" end
local result = ""
for pos = 1, #dec do
local val = tonumber(string.sub(dec, pos, pos))
if val ~= 0 then result = result .. valMap[val] .. posMap[pos] else result = result .. valMap[val] end
end
result = result:gsub(valMap[0] .. valMap[0], valMap[0])
return result:gsub(valMap[0] .. valMap[0], valMap[0])
end
-- 把数字串按千分位四位数分割,进行转换为中文
local function formatNum(num, t)
local digitUnit, wordFigure
local result = ""
num = tostring(num)
if tonumber(t) < 1 then digitUnit = { "", "", "", "" } else digitUnit = { "", "", "", "" } end
if tonumber(t) < 1 then
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
else
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
end
if string.len(num) > 4 or tonumber(num) == 0 then return wordFigure[1] end
local lens = string.len(num)
for i = 1, lens do
local n = wordFigure[tonumber(string.sub(num, -i, -i)) + 1]
if n ~= wordFigure[1] then result = n .. digitUnit[i] .. result else result = n .. result end
end
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
result = result:gsub(wordFigure[1] .. "$", "")
result = result:gsub(wordFigure[1] .. "$", "")
return result
end
-- 数值转换为中文
local function number2cnChar(num, flag, digitUnit, wordFigure) --flag=0中文小写反之为大写
local result = ""
if tonumber(flag) < 1 then
digitUnit = digitUnit or { [1] = "", [2] = "亿" }
wordFigure = wordFigure or { [1] = "", [2] = "", [3] = "", [4] = "" }
else
digitUnit = digitUnit or { [1] = "", [2] = "亿" }
wordFigure = wordFigure or { [1] = "", [2] = "", [3] = "", [4] = "" }
end
local lens = string.len(num)
if lens < 5 then
result = formatNum(num, flag)
elseif lens < 9 then
result = formatNum(string.sub(num, 1, -5), flag) .. digitUnit[1] .. formatNum(string.sub(num, -4, -1), flag)
elseif lens < 13 then
result = formatNum(string.sub(num, 1, -9), flag) ..
digitUnit[2] ..
formatNum(string.sub(num, -8, -5), flag) .. digitUnit[1] .. formatNum(string.sub(num, -4, -1), flag)
else
result = ""
end
result = result:gsub("^" .. wordFigure[1], "")
result = result:gsub(wordFigure[1] .. digitUnit[1], "")
result = result:gsub(wordFigure[1] .. digitUnit[2], "")
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
result = result:gsub(wordFigure[1] .. "$", "")
if lens > 4 then result = result:gsub("^" .. wordFigure[2] .. wordFigure[3], wordFigure[3]) end
if result ~= "" then result = result .. wordFigure[4] else result = "数值超限!" end
return result
end
local function number2zh(num, t)
local result, wordFigure
result = ""
if tonumber(t) < 1 then
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
else
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
end
if tostring(num) == nil then return "" end
for pos = 1, string.len(num) do
result = result .. wordFigure[tonumber(string.sub(num, pos, pos) + 1)]
end
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
return result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
end
local function number_translatorFunc(num)
local numberPart = splitNumPart(num)
local result = {}
if numberPart.dot ~= "" then
table.insert(result,
{ number2cnChar(numberPart.int, 0, { "", "亿" }, { "", "", "", "" }) .. number2zh(numberPart.dec, 0),
"" })
-- table.insert(result,
-- { number2cnChar(numberPart.int, 1, { "萬", "億" }, { "", "一", "十", "点" }) .. number2zh(numberPart.dec, 1),
-- "〔数字大写〕" })
local upperRaw = number2cnChar(numberPart.int, 1, { "", "" }, { "", "", "", "" })
local upper = upperRaw:gsub("^拾", "壹拾") .. number2zh(numberPart.dec, 1)
table.insert(result, { upper, "" })
else
table.insert(result, { number2cnChar(numberPart.int, 0, { "", "亿" }, { "", "", "", "" }), "" })
table.insert(result,
{ number2cnChar(numberPart.int, 1, { "", "" }, { "", "", "", "" }):gsub("^拾", "壹拾"), "" })
end
table.insert(result,
{ number2cnChar(numberPart.int, 0) ..
decimal_func(numberPart.dec, { [1] = "", [2] = "", [3] = "", [4] = "" },
{ [0] = "", "", "", "", "", "", "", "", "", "" }), "" })
local number2cnCharInt = number2cnChar(numberPart.int, 1)
local number2cnCharDec = decimal_func(numberPart.dec, { [1] = "", [2] = "", [3] = "", [4] = "" },
{ [0] = "", "", "", "", "", "", "", "", "", "" })
if string.len(numberPart.int) > 4 and number2cnCharInt:find('^拾[壹贰叁肆伍陆柒捌玖]?') and number2cnCharInt:find('[万亿]') then -- 简易地规避 utf8 匹配问题
local number2cnCharInt_var = number2cnCharInt:gsub('^拾', '壹拾')
table.insert(result, { number2cnCharInt_var .. number2cnCharDec, "" })
-- 会计书写要求 https://github.com/iDvel/rime-ice/issues/989
else
table.insert(result, { number2cnCharInt .. number2cnCharDec, "" })
end
local result = { result[1], result[4], result[2], result[3] }
return result
end
local function number_translator(input, seg, env)
-- 获取 recognizer/patterns/number 的第 2 个字符作为触发前缀
env.number_keyword = env.number_keyword or
env.engine.schema.config:get_string('recognizer/patterns/number'):sub(2, 2)
local str, num, numberPart
if env.number_keyword ~= '' and input:sub(1, 1) == env.number_keyword then
local context = env.engine.context
local segment = context.composition:back()
-- 设置手动排序的排序编码以支持 N 指令的手动排序
context:set_property("sequence_adjustment_code", env.number_keyword)
str = string.gsub(input, "^(%a+)", "")
numberPart = number_translatorFunc(str)
if str and #str > 0 and #numberPart > 0 then
-- 设置标签
segment.tags = segment.tags + Set({ "number" })
for i = 1, #numberPart do
yield(Candidate(input, seg.start, seg._end, numberPart[i][1], numberPart[i][2]))
end
end
end
end
-- print(#number_translatorFunc(3355.433))
return number_translator

191
lua/partial_commit.lua Normal file
View File

@@ -0,0 +1,191 @@
-- @amzxyz https://github.com/amzxyz/rime_wanxiang
-- Ctrl+1..9,0上屏首选前 N 字;按 preedit/script_text 的前 N 音节对齐 raw input
local wanxiang = require("wanxiang")
local M = {}
-- 数字键映射(主键盘 + 小键盘)
local DIGIT = { [0x31]=1,[0x32]=2,[0x33]=3,[0x34]=4,[0x35]=5,[0x36]=6,[0x37]=7,[0x38]=8,[0x39]=9,[0x30]=10 }
local KP = { [0xFFB1]=1,[0xFFB2]=2,[0xFFB3]=3,[0xFFB4]=4,[0xFFB5]=5,[0xFFB6]=6,[0xFFB7]=7,[0xFFB8]=8,[0xFFB9]=9,[0xFFB0]=10 }
-- 工具:字符串缩略 / 获取分隔符 / 安全转义 / 清洗 raw
local function short(s)
if not s then return "" end
if #s > 120 then
return s:sub(1, 117) .. "..."
end
return s
end
local function get_delimiters(ctx)
local cfg = ctx.engine and ctx.engine.schema and ctx.engine.schema.config
local delimiter = (cfg and cfg:get_string("speller/delimiter")) or " '"
return delimiter:sub(1, 1), delimiter:sub(2, 2) -- auto, manual
end
-- 放进字符类 [...] 使用的转义(只转义 % ^ ] -
local function esc_class(c)
if not c or c == "" then return "" end
return (c:gsub("([%%%^%]%-])", "%%%1"))
end
-- 普通模式串位置的单字符转义(最小化:仅非字母数字下划线时转义)
local function esc_pat(c)
if not c or c == "" then return "" end
if c:match("[%w_]") then return c end
return (c:gsub("(%W)", "%%%1"))
end
-- 清洗整串 raw去掉手动分隔符如 "'"
local function clean_raw(ctx, raw)
if not raw or raw == "" then return "" end
local _, manual = get_delimiters(ctx)
if manual and #manual == 1 then
raw = raw:gsub(esc_pat(manual), "")
end
return raw
end
-- 取候选前 n 个字符
local function utf8_head(s, n)
local i, c = 1, 0
while i <= #s and c < n do
local b = s:byte(i)
i = i + ((b < 0x80) and 1 or ((b < 0xE0) and 2 or ((b < 0xF0) and 3 or 4)))
c = c + 1
end
return s:sub(1, i - 1)
end
-- 生成 target按分隔符切 preedit/script_text取前 n 个并去分隔符拼接
local function script_prefix(ctx, n)
local raw_in = ctx.input or ""
local prop_key = ctx:get_property("sequence_preedit_key") or ""
local prop_val = ctx:get_property("sequence_preedit_val") or ""
local script_txt = ctx:get_script_text() or ""
local s
if prop_key == raw_in and prop_val ~= "" then
s = prop_val
else
s = script_txt
end
if s == "" then return "" end
local auto, manual = get_delimiters(ctx)
local pat = "[^" .. esc_class(auto) .. esc_class(manual) .. "%s]+"
local parts = {}
for w in s:gmatch(pat) do parts[#parts + 1] = w end
if #parts == 0 then return "" end
local upto = math.min(n, #parts)
local target = table.concat({ table.unpack(parts, 1, upto) }, "")
return target
end
-- 对齐“去分隔符后的 raw_clean”与 target返回消耗长度基于 raw_clean
local function eat_len_by_target(ctx, target)
if target == "" then return 0 end
local raw = ctx.input or ""
if raw == "" then return 0 end
local clean = clean_raw(ctx, raw)
local i, j, Lc, Lt = 1, 1, #clean, #target
while i <= Lc and j <= Lt do
if clean:sub(i, i) ~= target:sub(j, j) then
return 0
end
i, j = i + 1, j + 1
end
if j <= Lt then return 0 end
return i - 1
end
local function set_pending(env, rest)
env._cpc_pending_rest = rest or ""
end
local function has_pending(env)
return type(env._cpc_pending_rest) == "string" and env._cpc_pending_rest ~= nil
end
local function take_pending(env)
local r = env._cpc_pending_rest
env._cpc_pending_rest = nil
return r
end
function M.init(env)
local ctx = env.engine.context
env._cpc_update_conn = ctx.update_notifier:connect(function(c)
if not has_pending(env) then return end
local rest = take_pending(env) or ""
c.input = rest
if c.clear_non_confirmed_composition then
c:clear_non_confirmed_composition()
end
if c.caret_pos ~= nil then
c.caret_pos = #rest
end
end)
env._cpc_key_handler = function(key)
if not key:ctrl() or key:release() then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local n = DIGIT[key.keycode] or KP[key.keycode]
if not n then return wanxiang.RIME_PROCESS_RESULTS.kNoop end
local c = env.engine.context
if not c:is_composing() then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local cand = c:get_selected_candidate() or c:get_candidate(0)
if not cand or not cand.text or #cand.text == 0 then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local head = utf8_head(cand.text, n)
if head == "" then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local target = script_prefix(c, n)
if target == "" then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local consumed = eat_len_by_target(c, target)
if consumed == 0 then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local raw_clean = clean_raw(c, c.input or "")
local rest = raw_clean:sub(consumed + 1)
env.engine:commit_text(head)
set_pending(env, rest)
c:refresh_non_confirmed_composition()
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
end
function M.fini(env)
if env._cpc_update_conn then
env._cpc_update_conn:disconnect()
env._cpc_update_conn = nil
end
env._cpc_key_handler = nil
end
function M.func(key, env)
if not env._cpc_key_handler then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return env._cpc_key_handler(key)
end
return M

137
lua/quick_symbol_text.lua Normal file
View File

@@ -0,0 +1,137 @@
-- 欢迎使用万象拼音方案quick_symbol_text
-- @amzxyz
-- https://github.com/amzxyz/rime_wanxiang
-- 触发:由 schema.yaml -> quick_symbol_text/trigger 加载(默认 ^([a-z])/$
-- a/、b/ ... 单字母触发预设编码自动上屏;值可设为 "repeat" 实现重复上屏上一条提交内容
-- custom>schema>lua 合并键值(仅合并单字母 a-z 键)
local wanxiang = require("wanxiang")
-- 读取 symkey
local function load_mapping_from_config(config)
local symbol_map = {}
local ok_map, map = pcall(function() return config:get_map("quick_symbol_text/symkey") end)
if not ok_map or not map then return symbol_map end
local ok_keys, keys = pcall(function() return map:keys() end)
if not ok_keys or not keys then return symbol_map end
for _, key in ipairs(keys) do
local v = config:get_string("quick_symbol_text/symkey/" .. key)
if v ~= nil then
symbol_map[string.lower(tostring(key))] = v
end
end
return symbol_map
end
-- 读取 trigger
local function load_trigger_from_config(config)
local default_pat = "^([a-z])/$"
if not config then return default_pat end
local ok, s = pcall(function() return config:get_string("quick_symbol_text/trigger") end)
if ok and type(s) == "string" and #s > 0 then return s end
return default_pat
end
-- 默认单字母映射
local default_mapping = {
q = "",
w = "",
e = "",
r = "",
t = "~",
y = "·",
u = "",
i = "",
o = "",
p = "",
a = "",
s = "……",
d = "",
f = "",
g = "",
h = "",
j = "",
k = "",
l = "",
z = "",
x = "",
c = "",
v = "——",
b = "%",
n = "",
m = "",
}
local function init(env)
local config = env.engine.schema.config
env.single_symbol_pattern = load_trigger_from_config(config)
-- 默认表
env.mapping = {}
for k, v in pairs(default_mapping) do
if #k == 1 and k:match("^[a-z]$") then env.mapping[k] = v end
end
-- 覆盖(仅单字母)
local custom = load_mapping_from_config(config)
for k, v in pairs(custom) do
local key = tostring(k):lower()
if #key == 1 and key:match("^[a-z]$") then
env.mapping[key] = v -- ""=禁用;"repeat"=特殊语义
end
end
env.last_commit_text = "欢迎使用万象拼音!"
-- 记录上屏文本(供 repeat
env.quick_symbol_text_commit_notifier =
env.engine.context.commit_notifier:connect(function(ctx)
local t = ctx:get_commit_text()
if t ~= "" then env.last_commit_text = t end
end)
-- 命中触发则上屏并清空
env.quick_symbol_text_update_notifier =
env.engine.context.update_notifier:connect(function(context)
local input = context.input or ""
local key = string.match(input, env.single_symbol_pattern)
if not key then return end
key = string.lower(key)
local symbol = env.mapping[key]
if symbol == nil or symbol == "" then return end -- 未配置/禁用
if type(symbol) == "string" and symbol:lower() == "repeat" then
if env.last_commit_text ~= "" then
env.engine:commit_text(env.last_commit_text)
context:clear()
end
else
env.engine:commit_text(symbol)
context:clear()
end
end)
end
local function fini(env)
if env.quick_symbol_text_commit_notifier then
env.quick_symbol_text_commit_notifier:disconnect()
env.quick_symbol_text_commit_notifier = nil
end
if env.quick_symbol_text_update_notifier then
env.quick_symbol_text_update_notifier:disconnect()
env.quick_symbol_text_update_notifier = nil
end
end
-- 命中时吃键,避免后续流程处理
local function processor(key_event, env)
local input = env.engine.context.input or ""
local key = string.match(input, env.single_symbol_pattern)
if key then
key = string.lower(key)
local symbol = env.mapping[key]
if symbol ~= nil and symbol ~= "" then
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
end
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return { init = init, fini = fini, func = processor }

41
lua/select_character.lua Normal file
View File

@@ -0,0 +1,41 @@
-- 以词定字
local wanxiang = require("wanxiang")
local select = {}
function select.init(env)
local config = env.engine.schema.config
select.first_key = config:get_string('key_binder/select_first_character')
select.last_key = config:get_string('key_binder/select_last_character')
end
function select.func(key, env)
local engine = env.engine
local context = env.engine.context
if
not key:release()
and (context:is_composing() or context:has_menu())
and (select.first_key or select.last_key)
then
local text = context.input
if context:get_selected_candidate() then
text = context:get_selected_candidate().text
end
if utf8.len(text) > 1 then
if (key:repr() == select.first_key) then
engine:commit_text(text:sub(1, utf8.offset(text, 2) - 1))
context:clear()
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
elseif (key:repr() == select.last_key) then
engine:commit_text(text:sub(utf8.offset(text, -1)))
context:clear()
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
end
end
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return select

185
lua/set_schema.lua Normal file
View File

@@ -0,0 +1,185 @@
--https://github.com/amzxyz/rime_wanxiang
--@amzxyz
--一个快速初始化方案类型的工具,使用方法,方案文件放进用户目录后先部署,再执行相关指令后重新部署完成切换
local wanxiang = require("wanxiang")
-- 文件复制函数
local function copy_file(src, dest)
local fi = io.open(src, "r")
if not fi then
return false
end
local content = fi:read("*a")
fi:close()
local fo = io.open(dest, "w")
if not fo then
return false
end
fo:write(content)
fo:close()
return true
end
-- 替换方案函数(根据文件名应用特定替换模式)
local function replace_schema(file_path, target_schema)
local f = io.open(file_path, "r")
if not f then
return false
end
local content = f:read("*a")
f:close()
-- 根据文件名决定替换模式
if file_path:find("wanxiang_reverse") then
-- 把 "__include: wanxiang_reverse.schema:/"(含可选后缀)改成 "__include: wanxiang_algebra:/mixed/"
content = content:gsub("(%-?%s*__include:%s*)wanxiang_reverse%.schema:/[^%s\r\n]*", "%1wanxiang_algebra:/reverse/" .. target_schema)
-- "__patch: wanxiang_reverse.schema:/hspzn" -> "__patch: wanxiang_algebra:/reverse/hspzn"
content = content:gsub("(%-?%s*__patch:%s*)wanxiang_reverse%.schema:/([^%s\r\n]+)", "%1wanxiang_algebra:/reverse/%2")
content = content:gsub("([%s]*__include:%s*wanxiang_algebra:/reverse/)%S+", "%1" .. target_schema)
elseif file_path:find("wanxiang_mixedcode") then
-- "__include: wanxiang_mixedcode.schema:/全拼"
-- -> "__include: wanxiang_algebra:/mixed/通用派生规则"
-- "__patch: wanxiang_algebra:/mixed/全拼"
content = content:gsub(
"(%-?%s*)__include:%s*wanxiang_mixedcode%.schema:/全拼",
function(lead)
return lead .. "__include: wanxiang_algebra:/mixed/通用派生规则\n"
.. lead .. "__patch: wanxiang_algebra:/mixed/全拼"
end
)
content = content:gsub("([%s]*__patch:%s*wanxiang_algebra:/mixed/)%S+", "%1" .. target_schema)
elseif file_path:find("wanxiang%.custom") or file_path:find("wanxiang_pro%.custom") then
-- 先把旧前缀整体替换为新前缀
-- "- wanxiang.schema:/" -> "- wanxiang_algebra:/base/"
-- "- wanxiang_pro.schema:/" -> "- wanxiang_algebra:/pro/"
content = content:gsub("(%-+%s*)wanxiang%.schema:/", "%1wanxiang_algebra:/base/")
content = content:gsub("(%-+%s*)wanxiang_pro%.schema:/", "%1wanxiang_algebra:/pro/")
-- 再将 base/pro 后面的 schema 名替换为 target_schema
content = content:gsub("([%s%-]*wanxiang_algebra:/pro/)%S+", "%1" .. target_schema, 1)
content = content:gsub("([%s%-]*wanxiang_algebra:/base/)%S+", "%1" .. target_schema, 1)
end
f = io.open(file_path, "w")
if not f then
return false
end
f:write(content)
f:close()
return true
end
-- translator 主函数
local function translator(input, seg, env)
if input == "/zjf" or input == "/jjf" then
local target_aux = (input == "/zjf") and "直接辅助" or "间接辅助"
local user_dir = rime_api.get_user_data_dir()
local paths = {
user_dir .. "/wanxiang_pro.custom.yaml",
user_dir .. "/wanxiang.custom.yaml",
}
local total_hits, touched = 0, 0
for _, p in ipairs(paths) do
local f = io.open(p, "r")
if f then
local content = f:read("*a"); f:close()
-- 两次 gsub 都要接收“新文本 + 命中次数”
local n1, n2 = 0, 0
content, n1 = content:gsub("(%-+%s*wanxiang_algebra:/pro/)直接辅助(%s*#?.*)", "%1" .. target_aux .. "%2")
content, n2 = content:gsub("(%-+%s*wanxiang_algebra:/pro/)间接辅助(%s*#?.*)", "%1" .. target_aux .. "%2")
local n = n1 + n2
if n > 0 then
local w = io.open(p, "w")
if w then w:write(content); w:close() end
total_hits = total_hits + n
touched = touched + 1
end
end
end
local msg = (total_hits > 0)
and ("已切换到〔" .. target_aux .. "〕,请重新部署")
or "未找到可切换的条目"
yield(Candidate("switch", seg.start, seg._end, msg, ""))
return
end
local schema_map = {
["/flypy"] = "小鹤双拼",
["/mspy"] = "微软双拼",
["/zrm"] = "自然码",
["/sogou"] = "搜狗双拼",
["/znabc"] = "智能ABC",
["/ziguang"] = "紫光双拼",
["/pyjj"] = "拼音加加",
["/gbpy"] = "国标双拼",
["/lxsq"] = "乱序17",
["/zrlong"] = "自然龙",
["/hxlong"] = "汉心龙",
["/pinyin"] = "全拼",
}
local target_schema = schema_map[input]
if target_schema then
local user_dir = rime_api.get_user_data_dir()
-- 检查根目录是否存在自定义文件
local pro_file = user_dir .. "/wanxiang_pro.custom.yaml"
local normal_file = user_dir .. "/wanxiang.custom.yaml"
local pro_exists = io.open(pro_file, "r")
local normal_exists = io.open(normal_file, "r")
local custom_file_exists = false
if pro_exists or normal_exists then
custom_file_exists = true
if pro_exists then pro_exists:close() end
if normal_exists then normal_exists:close() end
end
local files = {
"wanxiang_mixedcode.custom.yaml",
"wanxiang_reverse.custom.yaml"
}
-- 判断是否为专业版
local is_pro = wanxiang.is_pro_scheme(env)
local fourth_file = is_pro and "wanxiang_pro.custom.yaml" or "wanxiang.custom.yaml"
table.insert(files, fourth_file)
for _, name in ipairs(files) do
local src = user_dir .. "/custom/" .. name
local dest = user_dir .. "/" .. name
if name == fourth_file and custom_file_exists then
-- 根目录自定义文件已存在,不复制,但依然修改
replace_schema(dest, target_schema)
else
-- 其他文件: 若 custom 目录存在文件,则复制到根目录并修改
local src_file = io.open(src, "r")
if src_file then
src_file:close()
if copy_file(src, dest) then
replace_schema(dest, target_schema)
end
end
end
end
-- 返回提示候选
if custom_file_exists then
yield(Candidate("switch", seg.start, seg._end, "检测到已有自定义文件,已为您切换到〔" .. target_schema .. "〕,请手动重新部署", ""))
else
yield(Candidate("switch", seg.start, seg._end, "已帮您复制并切换到〔" .. target_schema .. "〕,请手动重新部署", ""))
end
end
end
return translator

3017
lua/shijian.lua Normal file

File diff suppressed because it is too large Load Diff

3491
lua/super_calculator.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,535 @@
--@amzxyz https://github.com/amzxyz/rime_wanxiang
local wanxiang = require('wanxiang')
local tone_map = {
['ā']='a', ['á']='a', ['ǎ']='a', ['à']='a',
['ē']='e', ['é']='e', ['ě']='e', ['è']='e',
['ī']='i', ['í']='i', ['ǐ']='i', ['ì']='i',
['ō']='o', ['ó']='o', ['ǒ']='o', ['ò']='o', ['ň']='n',
['ū']='u', ['ú']='u', ['ǔ']='u', ['ù']='u', ['ǹ']='n',
['ǖ']='ü', ['ǘ']='ü', ['ǚ']='ü', ['ǜ']='ü', ['ń']='n',
}
local function remove_pinyin_tone(s)
local result = {}
for uchar in s:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
table.insert(result, tone_map[uchar] or uchar)
end
return table.concat(result)
end
-- ----------------------
-- # 辅助码拆分提示模块
-- PRO 专用
-- ----------------------
local CF = {}
function CF.init(env)
if wanxiang.is_pro_scheme(env) then -- pro 版直接初始化
CF.get_dict(env)
end
end
function CF.fini(env)
env.chaifen_dict = nil
collectgarbage()
end
function CF.get_dict(env)
if env.chaifen_dict == nil then
env.chaifen_dict = ReverseLookup("wanxiang_chaifen")
end
return env.chaifen_dict
end
function CF.get_comment(cand, env)
local dict = CF.get_dict(env)
if not dict then return "" end
local raw = dict:lookup(cand.text)
if not raw or raw == "" then return "" end
local tpl = (env and env.settings and env.settings.chaifen) or ""
if tpl ~= "" then
-- 取 chaifen 左右两边
local left, right = tpl:match("^(.-)chaifen(.-)$")
if left then
return left .. raw .. right
end
end
return raw
end
-- ----------------------
-- # 错音错字提示模块
-- ----------------------
local CR = {}
local corrections_cache = nil -- 用于缓存已加载的词典
function CR.init(env)
CR.style = env.settings.corrector_type or '{comment}'
--if corrections_cache then return end
local auto_delimiter = env.settings.auto_delimiter
local is_pro = wanxiang.is_pro_scheme(env)
-- 根据方案选择加载路径
local path = (is_pro and "dicts/cuoyin.pro.dict.yaml") or "dicts/cuoyin.dict.yaml"
local file, close_file, err = wanxiang.load_file_with_fallback(path)
if not file then
log.error(string.format("[super_comment]: 加载失败 %s错误: %s", path, err))
return
end
corrections_cache = {}
for line in file:lines() do
if not line:match("^#") then
local text, code, weight, comment = line:match("^(.-)\t(.-)\t(.-)\t(.-)$")
if text and code then
text = text:match("^%s*(.-)%s*$")
code = code:match("^%s*(.-)%s*$")
comment = comment and comment:match("^%s*(.-)%s*$") or ""
comment = comment:gsub("%s+", auto_delimiter)
code = code:gsub("%s+", auto_delimiter)
corrections_cache[code] = { text = text, comment = comment }
end
end
end
close_file()
end
function CR.get_comment(cand)
local correction = corrections_cache and corrections_cache[cand.comment] or nil
if not (correction and cand.text == correction.text) then
return nil
end
-- 只认占位符 `comment`,按“刀法”切分
local tpl = CR.style or "comment"
local left, right = tpl:match("^(.-)comment(.-)$")
if left then
return left .. correction.comment .. right
else
return correction.comment
end
end
-- ----------------------
-- 部件组字返回的注释
-- ----------------------
---@return string
local function get_az_comment(_, env, initial_comment)
if not initial_comment or initial_comment == "" then return "〔无〕" end
local final_comment = nil
local auto_delimiter = env.settings.auto_delimiter or " "
-- 拆分初始评论为多个段落
local segments = {}
for segment in initial_comment:gmatch("[^%s]+") do
table.insert(segments, segment)
end
local semicolon_count = select(2, segments[1]:gsub(";", "")) -- 使用第一个段来判断分号的数量
local pinyins = {}
local fuzhu = nil
for _, segment in ipairs(segments) do
local pinyin = segment:match("^[^;~]+")
local fz = nil
if semicolon_count == 1 then
-- 一个分号:取后段
fz = segment:match(";(.+)$")
else
-- 无分号不取辅助码
fz = nil
end
if pinyin then table.insert(pinyins, pinyin) end
if not fuzhu and fz and fz ~= "" then fuzhu = fz end
end
-- 拼接结果
if #pinyins > 0 then
local pinyin_str = table.concat(pinyins, ",")
if fuzhu then
final_comment = string.format("〔音%s 辅%s", pinyin_str, fuzhu)
else
final_comment = string.format("〔音%s", pinyin_str)
end
end
return final_comment or "〔无〕"
end
-- ----------------------
-- # 辅助码提示或带调全拼注释模块 (Fuzhu)
-- ----------------------
local function get_fz_comment(cand, env, initial_comment)
local length = utf8.len(cand.text)
if length > env.settings.candidate_length then
return ""
end
local auto_delimiter = env.settings.auto_delimiter or " "
local segments = {}
for segment in string.gmatch(initial_comment, "[^" .. auto_delimiter .. "]+") do
table.insert(segments, segment)
end
-- 根据 option 动态决定是否强制使用 tone
local use_tone = env.engine.context:get_option("tone_hint")
local fuzhu_type = use_tone and "tone" or "fuzhu"
local first_segment = segments[1] or ""
local semicolon_count = select(2, first_segment:gsub(";", ""))
local fuzhu_comments = {}
-- 没有分号的情况
if semicolon_count == 0 then
return initial_comment:gsub(auto_delimiter, " ")
else
-- 有分号:按类型提取
for _, segment in ipairs(segments) do
if fuzhu_type == "tone" then
-- 取第一个分号“前”的内容
local before = segment:match("^(.-);")
if before and before ~= "" then
table.insert(fuzhu_comments, before)
end
else -- "fuzhu"
-- 取第一个分号“后”的内容(到行尾)
local after = segment:match(";(.+)$")
if after and after ~= "" then
table.insert(fuzhu_comments, after)
end
end
end
end
-- 最终拼接输出fuzhu用 `,`tone用 /连接
if #fuzhu_comments > 0 then
if fuzhu_type == "tone" then
return table.concat(fuzhu_comments, " ")
else
return table.concat(fuzhu_comments, "/")
end
else
return ""
end
end
local SV = {}
-- 工具:取光标前的编码(安全处理 caret 越界)
local function front_input(ctx)
if not ctx then return "" end
local raw_full = ctx.input or ""
local caret = ctx.caret_pos or #raw_full
if caret < 0 then
caret = 0
elseif caret > #raw_full then
caret = #raw_full
end
return raw_full:sub(1, caret)
end
-- 这个模块主要用于将滤镜阶段未修改前的注释或者 preedit
-- 存到上下文变量里按键处理阶段使用update_notifier 保证一致性
function SV.init(env)
env._sv_seq_sig = ""
env._sv_last_pre = "" -- 最近一次要写入的 preedit
env._saved_input_for_seq = "" -- 上次对应的 raw_in光标前编码
local ctx = env.engine.context
env._sv_ctx_conn = ctx.update_notifier:connect(function(c)
local raw_in = front_input(c)
local pre = env._sv_last_pre or ""
if pre == "" or raw_in == "" then
return
end
-- 不重写:光标前编码 + preedit
local sig = raw_in .. "\t" .. pre
if env._sv_seq_sig == sig then
return
end
c:set_property("sequence_preedit_key", raw_in)
c:set_property("sequence_preedit_val", pre)
env._sv_seq_sig = sig
end)
end
-- 断开 notifier清理状态
function SV.fini(env)
if env._sv_ctx_conn then
env._sv_ctx_conn:disconnect()
env._sv_ctx_conn = nil
end
env._sv_seq_sig = nil
env._sv_last_pre = nil
env._saved_input_for_seq = nil
end
-- 限制更新范围:同一个 raw_in 只记第一次的 preedit
function SV.update_preedit(env, preedit)
local ctx = env.engine.context
if not ctx then return end
local raw_in = front_input(ctx)
preedit = preedit or ""
if raw_in == "" or preedit == "" then
return
end
if env._saved_input_for_seq ~= raw_in then
env._saved_input_for_seq = raw_in
env._sv_last_pre = preedit
end
end
-- 对 cand.preedit 应用 tone_preedit/0..9 的映射(数字 -> 上标等)
local function apply_tone_preedit(env, cand)
if not cand or not cand.preedit or cand.preedit == "" then
return
end
-- 用 context.input 判断是否有相邻数字
local input
local engine = env.engine
if engine and engine.context then
-- Rime 里一般是 string保险起见兜个 nil
input = engine.context.input or ""
end
-- 如果整条输入串中存在相邻两个数字(例如 "li39"、"abc10" 等),
-- 则整体不做任何转换,直接返回,为了配合小键盘输入逻辑中包吃书字面大小一致性
if input and input ~= "" and input:match("%d%d") then
return
end
-- 懒加载 tone_map
if not env.tone_map then
env.tone_map = {}
local cfg = engine and engine.schema and engine.schema.config
if cfg then
for d = 0, 9 do
local k = tostring(d)
local v = cfg:get_string("tone_preedit/" .. k)
if v and v ~= "" then
env.tone_map[k] = v
end
end
end
end
local preedit = cand.preedit
local converted = preedit:gsub("([^%d%s]+)(%d+)", function(body, digits)
local mapped = digits:gsub("%d", function(d)
return env.tone_map and env.tone_map[d] or d
end)
return body .. mapped
end)
if converted ~= preedit then
cand.preedit = converted
end
end
-- ----------------------
-- 主函数根据优先级处理候选词的注释和preedit
-- ----------------------
local ZH = {}
function ZH.init(env)
local config = env.engine.schema.config
local delimiter = config:get_string('speller/delimiter') or " '"
local auto_delimiter = delimiter:sub(1, 1)
local manual_delimiter = delimiter:sub(2, 2)
env.settings = {
delimiter = delimiter,
auto_delimiter = auto_delimiter,
manual_delimiter = manual_delimiter,
corrector_enabled = config:get_bool("super_comment/corrector") or true,
corrector_type = config:get_string("super_comment/corrector_type") or "{comment}",
chaifen = config:get_string("super_comment/chaifen") or "chaifen",
candidate_length = tonumber(config:get_string("super_comment/candidate_length")) or 1,
}
CR.init(env)
SV.init(env)
end
function ZH.fini(env)
-- 清理
CF.fini(env)
SV.fini(env)
end
function ZH.func(input, env)
local config = env.engine.schema.config
local context = env.engine.context
local input_str = context.input
local is_radical_mode = wanxiang.is_in_radical_mode(env)
local schema_id = env.engine.schema.schema_id or ""
local is_wanxiang_pro = (schema_id == "wanxiang_pro")
local should_skip_candidate_comment = wanxiang.is_function_mode_active(context) or input_str == ""
local is_tone_comment = env.engine.context:get_option("tone_hint")
local is_comment_hint = env.engine.context:get_option("fuzhu_hint")
local is_chaifen_enabled = env.engine.context:get_option("chaifen_switch")
--preedit相关声明
local delimiter = env.settings.delimiter
local auto_delimiter = env.settings.auto_delimiter
local manual_delimiter = env.settings.manual_delimiter
local visual_delim = config:get_string("speller/visual_delimiter") or " "
local tone_isolate = config:get_bool("speller/tone_isolate")
local is_tone_display = context:get_option("tone_display")
local is_full_pinyin = context:get_option("full_pinyin")
local index = 0
-- auto_phrase 相关声明
local enable_auto_phrase = config:get_bool("add_user_dict/enable_auto_phrase") or false
local enable_user_dict = config:get_bool("add_user_dict/enable_user_dict") or false
for cand in input:iter() do
local genuine_cand = cand:get_genuine()
local preedit = genuine_cand.preedit or ""
local initial_comment = genuine_cand.comment
local final_comment = initial_comment
index = index + 1
SV.update_preedit(env, preedit) --储存到环境变量
-- preedit相关处理只跳过 preedit不影响注释
if is_radical_mode then
goto after_preedit
end
if not is_tone_display and not is_full_pinyin then
goto after_preedit
end
if (not initial_comment or initial_comment == "") then
goto after_preedit
end
do
-- 拆分 preedit
local input_parts = {}
local current_segment = ""
for i = 1, #preedit do
local char = preedit:sub(i, i)
if char == auto_delimiter or char == manual_delimiter then
if #current_segment > 0 then
table.insert(input_parts, current_segment)
current_segment = ""
end
table.insert(input_parts, char)
else
current_segment = current_segment .. char
end
end
if #current_segment > 0 then
table.insert(input_parts, current_segment)
end
-- 拆分拼音段comment
local pinyin_segments = {}
for segment in string.gmatch(initial_comment, "[^" .. auto_delimiter .. manual_delimiter .. "]+") do
local pinyin = segment:match("^[^;]+")
if pinyin then
pinyin = pinyin:gsub("[%[%]]", "") --去掉英文词库编码中的[]
table.insert(pinyin_segments, pinyin)
end
end
-- 替换逻辑
local pinyin_index = 1
for i, part in ipairs(input_parts) do
if part == auto_delimiter or part == manual_delimiter then
input_parts[i] = visual_delim
else
local body, tone = part:match("([%a]+)([^%a]+)") --后面加号很必要
local py = pinyin_segments[pinyin_index]
if py then
if is_wanxiang_pro then
input_parts[i] = py
pinyin_index = pinyin_index + 1
elseif i == #input_parts and #part == 1 then
local prefix = py:sub(1, 2)
local first_char = part:sub(1,1):lower()
if first_char == "s" or first_char == "c" or first_char == "z" then
input_parts[i] = part
else
if prefix == "zh" or prefix == "ch" or prefix == "sh" then
input_parts[i] = prefix
else
input_parts[i] = part
end
end
else
if tone_isolate then
input_parts[i] = py .. (tone or "")
else
input_parts[i] = py
end
pinyin_index = pinyin_index + 1
end
end
end
end
if is_full_pinyin then
for idx, part in ipairs(input_parts) do
input_parts[idx] = remove_pinyin_tone(part)
end
end
genuine_cand.preedit = table.concat(input_parts)
end
::after_preedit::
apply_tone_preedit(env, genuine_cand)
if should_skip_candidate_comment then
yield(genuine_cand)
goto continue
end
-- 进入注释处理阶段
-- ① 辅助码注释或者声调注释
if is_comment_hint then
local fz_comment = get_fz_comment(cand, env, initial_comment)
if fz_comment then
final_comment = fz_comment
end
elseif is_tone_comment then
local fz_comment = get_fz_comment(cand, env, initial_comment)
if fz_comment then
final_comment = fz_comment
end
else
final_comment = ""
end
-- ② 拆分注释
if is_chaifen_enabled then
local cf_comment = CF.get_comment(cand, env)
if cf_comment and cf_comment ~= "" then --不为空很重要
final_comment = cf_comment
end
end
-- ③ 错音错字提示
if env.settings.corrector_enabled then
local cr_comment = CR.get_comment(cand)
if cr_comment and cr_comment ~= "" then
final_comment = cr_comment
end
end
-- ④ 反查模式提示
if is_radical_mode then
local az_comment = get_az_comment(cand, env, initial_comment)
if az_comment and az_comment ~= "" then
final_comment = az_comment
end
end
-- 应用注释
if final_comment ~= initial_comment then
genuine_cand.comment = final_comment
end
yield(genuine_cand)
::continue::
end
end
return ZH

1030
lua/super_filter.lua Normal file

File diff suppressed because it is too large Load Diff

589
lua/super_lookup.lua Normal file
View File

@@ -0,0 +1,589 @@
--@amzxyz https://github.com/amzxyz/rime_wanxiang
--wanxiang_lookup: #设置归属于super_lookup.lua
--tags: [ abc ] # 检索当前tag的候选
--key: "`" # 输入中反查引导符,要添加到 speller/alphabet
--lookup: [ wanxiang_reverse ] #反查滤镜数据库,万象都合并为一个了
-- 获取 wanxiang 模块
local function get_wanxiang()
local ok, mod = pcall(function() return require('wanxiang') end)
if ok and type(mod) == 'table' then return mod end
if type(_G.wanxiang) == 'table' then return _G.wanxiang end
return nil
end
-- 各输入法类型对应的转换规则
-- flypy/mspy/sogou/abc/ziguang/pyjj/gbpy/lxsq/zrlong/hxlong
local LOCAL_PROJECTION_RULES = {
-- 全拼pinyin
pinyin = {
"xform/'//",
"derive/^([nl])ue$/$1ve/",
"derive/'([nl])ue$/'$1ve/",
"derive/^([jqxy])u/$1v/",
"derive/'([jqxy])u/'$1v/",
},
-- 自然码zrm
zrm = {
"derive/^([jqxy])u(?=^|$|')/$1v/",
"derive/'([jqxy])u(?=^|$|')/'$1v/",
"derive/^([aoe])([ioun])(?=^|$|')/$1$1$2/",
"derive/'([aoe])([ioun])(?=^|$|')/'$1$1$2/",
"xform/^([aoe])(ng)?(?=^|$|')/$1$1$2/",
"xform/'([aoe])(ng)?(?=^|$|')/'$1$1$2/",
"xform/iu(?=^|$|')/<q>/",
"xform/[iu]a(?=^|$|')/<w>/",
"xform/[uv]an(?=^|$|')/<r>/",
"xform/[uv]e(?=^|$|')/<t>/",
"xform/ing(?=^|$|')|uai(?=^|$|')/<y>/",
"xform/^sh/<u>/",
"xform/^ch/<i>/",
"xform/^zh/<v>/",
"xform/'sh/'<u>/",
"xform/'ch/'<i>/",
"xform/'zh/'<v>/",
"xform/uo(?=^|$|')/<o>/",
"xform/[uv]n(?=^|$|')/<p>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<s>/",
"xform/[iu]ang(?=^|$|')/<d>/",
"xform/([a-z>])en(?=^|$|')/$1<f>/",
"xform/([a-z>])eng(?=^|$|')/$1<g>/",
"xform/([a-z>])ang(?=^|$|')/$1<h>/",
"xform/ian(?=^|$|')/<m>/",
"xform/([a-z>])an(?=^|$|')/$1<j>/",
"xform/iao(?=^|$|')/<c>/",
"xform/([a-z>])ao(?=^|$|')/$1<k>/",
"xform/([a-z>])ai(?=^|$|')/$1<l>/",
"xform/([a-z>])ei(?=^|$|')/$1<z>/",
"xform/ie(?=^|$|')/<x>/",
"xform/ui(?=^|$|')/<v>/",
"xform/([a-z>])ou(?=^|$|')/$1<b>/",
"xform/in(?=^|$|')/<n>/",
"xform/'|<|>//",
},
-- 小鹤flypy
flypy = {
"derive/^([jqxy])u(?=^|$|')/$1v/",
"derive/'([jqxy])u(?=^|$|')/'$1v/",
"derive/^([aoe])([ioun])(?=^|$|')/$1$1$2/",
"derive/'([aoe])([ioun])(?=^|$|')/'$1$1$2/",
"xform/^([aoe])(ng)?(?=^|$|')/$1$1$2/",
"xform/'([aoe])(ng)?(?=^|$|')/'$1$1$2/",
"xform/iu(?=^|$|')/<q>/",
"xform/(.)ei(?=^|$|')/$1<w>/",
"xform/uan(?=^|$|')/<r>/",
"xform/[uv]e(?=^|$|')/<t>/",
"xform/un(?=^|$|')/<y>/",
"xform/^sh/<u>/",
"xform/^ch/<i>/",
"xform/^zh/<v>/",
"xform/'sh/'<u>/",
"xform/'ch/'<i>/",
"xform/'zh/'<v>/",
"xform/uo(?=^|$|')/<o>/",
"xform/ie(?=^|$|')/<p>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<s>/",
"xform/ing(?=^|$|')|uai(?=^|$|')/<k>/",
"xform/([a-z>])ai(?=^|$|')/$1<d>/",
"xform/([a-z>])en(?=^|$|')/$1<f>/",
"xform/([a-z>])eng(?=^|$|')/$1<g>/",
"xform/[iu]ang(?=^|$|')/<l>/",
"xform/([a-z>])ang(?=^|$|')/$1<h>/",
"xform/ian(?=^|$|')/<m>/",
"xform/([a-z>])an(?=^|$|')/$1<j>/",
"xform/([a-z>])ou(?=^|$|')/$1<z>/",
"xform/[iu]a(?=^|$|')/<x>/",
"xform/iao(?=^|$|')/<n>/",
"xform/([a-z>])ao(?=^|$|')/$1<c>/",
"xform/ui(?=^|$|')/<v>/",
"xform/in(?=^|$|')/<b>/",
"xform/'|<|>//",
},
-- 微软mspy
mspy = {
"derive/^([jqxy])u(?=^|$|')/$1v/",
"derive/'([jqxy])u(?=^|$|')/'$1v/",
"derive/^([aoe].*)(?=^|$|')/o$1/",
"derive/'([aoe].*)(?=^|$|')/'o$1/",
"xform/^([ae])(.*)(?=^|$|')/$1$1$2/",
"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/'sh/'<u>/",
"xform/'ch/'<i>/",
"xform/'zh/'<v>/",
"xform/uo(?=^|$|')/<o>/",
"xform/[uv]n(?=^|$|')/<p>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<s>/",
"xform/[iu]ang(?=^|$|')/<d>/",
"xform/([a-z>])en(?=^|$|')/$1<f>/",
"xform/([a-z>])eng(?=^|$|')/$1<g>/",
"xform/([a-z>])ang(?=^|$|')/$1<h>/",
"xform/ian(?=^|$|')/<m>/",
"xform/([a-z>])an(?=^|$|')/$1<j>/",
"xform/iao(?=^|$|')/<c>/",
"xform/([a-z>])ao(?=^|$|')/$1<k>/",
"xform/([a-z>])ai(?=^|$|')/$1<l>/",
"xform/([a-z>])ei(?=^|$|')/$1<z>/",
"xform/ie(?=^|$|')/<x>/",
"xform/ui(?=^|$|')/<v>/",
"derive/<t>(?=^|$|')/<v>/",
"xform/([a-z>])ou(?=^|$|')/$1<b>/",
"xform/in(?=^|$|')/<n>/",
"xform/ing(?=^|$|')/;/",
"xform/'|<|>//",
},
-- 搜狗双拼sogou
sogou = {
"derive/^([jqxy])u(?=^|$|')/$1v/",
"derive/'([jqxy])u(?=^|$|')/'$1v/",
"derive/^([aoe].*)(?=^|$|')/o$1/",
"derive/'([aoe].*)(?=^|$|')/'o$1/",
"xform/^([ae])(.*)(?=^|$|')/$1$1$2/",
"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/'sh/'<u>/",
"xform/'ch/'<i>/",
"xform/'zh/'<v>/",
"xform/uo(?=^|$|')/<o>/",
"xform/[uv]n(?=^|$|')/<p>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<s>/",
"xform/[iu]ang(?=^|$|')/<d>/",
"xform/([a-z>])en(?=^|$|')/$1<f>/",
"xform/([a-z>])eng(?=^|$|')/$1<g>/",
"xform/([a-z>])ang(?=^|$|')/$1<h>/",
"xform/ian(?=^|$|')/<m>/",
"xform/([a-z>])an(?=^|$|')/$1<j>/",
"xform/iao(?=^|$|')/<c>/",
"xform/([a-z>])ao(?=^|$|')/$1<k>/",
"xform/([a-z>])ai(?=^|$|')/$1<l>/",
"xform/([a-z>])ei(?=^|$|')/$1<z>/",
"xform/ie(?=^|$|')/<x>/",
"xform/ui(?=^|$|')/<v>/",
"xform/([a-z>])ou(?=^|$|')/$1<b>/",
"xform/in(?=^|$|')/<n>/",
"xform/ing(?=^|$|')/;/",
"xform/'|<|>//",
},
-- 智能abc
abc = {
"xform/^zh/<a>/",
"xform/^ch/<e>/",
"xform/^sh/<v>/",
"xform/'zh/'<a>/",
"xform/'ch/'<e>/",
"xform/'sh/'<v>/",
"xform/^([aoe].*)(?=^|$|')/<o>$1/",
"xform/'([aoe].*)(?=^|$|')/'<o>$1/",
"xform/ei(?=^|$|')/<q>/",
"xform/ian(?=^|$|')/<w>/",
"xform/er(?=^|$|')|iu(?=^|$|')/<r>/",
"xform/[iu]ang(?=^|$|')/<t>/",
"xform/ing(?=^|$|')/<y>/",
"xform/uo(?=^|$|')/<o>/",
"xform/uan(?=^|$|')/<p>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<s>/",
"xform/[iu]a(?=^|$|')/<d>/",
"xform/en(?=^|$|')/<f>/",
"xform/eng(?=^|$|')/<g>/",
"xform/ang(?=^|$|')/<h>/",
"xform/an(?=^|$|')/<j>/",
"xform/iao(?=^|$|')/<z>/",
"xform/ao(?=^|$|')/<k>/",
"xform/in(?=^|$|')|uai(?=^|$|')/<c>/",
"xform/ai(?=^|$|')/<l>/",
"xform/ie(?=^|$|')/<x>/",
"xform/ou(?=^|$|')/<b>/",
"xform/un(?=^|$|')/<n>/",
"xform/[uv]e(?=^|$|')|ui(?=^|$|')/<m>/",
"xform/'|<|>//",
},
-- 紫光ziguang
ziguang = {
"derive/^([jqxy])u(?=^|$|')/$1v/",
"derive/'([jqxy])u(?=^|$|')/'$1v/",
"xform/'([aoe].*)(?=^|$|')/'<o>$1/",
"xform/^([aoe].*)(?=^|$|')/<o>$1/",
"xform/en(?=^|$|')/<w>/",
"xform/eng(?=^|$|')/<t>/",
"xform/in(?=^|$|')|uai(?=^|$|')/<y>/",
"xform/^zh/<u>/",
"xform/^sh/<i>/",
"xform/'zh/'<u>/",
"xform/'sh/'<i>/",
"xform/uo(?=^|$|')/<o>/",
"xform/ai(?=^|$|')/<p>/",
"xform/^ch/<a>/",
"xform/'ch/'<a>/",
"xform/[iu]ang(?=^|$|')/<g>/",
"xform/ang(?=^|$|')/<s>/",
"xform/ie(?=^|$|')/<d>/",
"xform/ian(?=^|$|')/<f>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<h>/",
"xform/er(?=^|$|')|iu(?=^|$|')/<j>/",
"xform/ei(?=^|$|')/<k>/",
"xform/uan(?=^|$|')/<l>/",
"xform/ing(?=^|$|')/;/",
"xform/ou(?=^|$|')/<z>/",
"xform/[iu]a(?=^|$|')/<x>/",
"xform/iao(?=^|$|')/<b>/",
"xform/ue(?=^|$|')|ui(?=^|$|')|ve(?=^|$|')/<n>/",
"xform/un(?=^|$|')/<m>/",
"xform/ao(?=^|$|')/<q>/",
"xform/an(?=^|$|')/<r>/",
"xform/'|<|>//",
},
-- 拼音加加pyjj
pyjj = {
"derive/^([jqxy])u(?=^|$|')/$1v/",
"derive/'([jqxy])u(?=^|$|')/'$1v/",
"derive/^([aoe])([ioun])(?=^|$|')/$1$1$2/",
"derive/'([aoe])([ioun])(?=^|$|')/'$1$1$2/",
"xform/^([aoe])(ng)?(?=^|$|')/$1$1$2/",
"xform/'([aoe])(ng)?(?=^|$|')/'$1$1$2/",
"xform/iu(?=^|$|')/<n>/",
"xform/[iu]a(?=^|$|')/<b>/",
"xform/[uv]an(?=^|$|')/<c>/",
"xform/[uv]e(?=^|$|')|uai(?=^|$|')/<x>/",
"xform/ing(?=^|$|')|er(?=^|$|')/<q>/",
"xform/^sh/<i>/",
"xform/^ch/<u>/",
"xform/^zh/<v>/",
"xform/'sh/'<i>/",
"xform/'ch/'<u>/",
"xform/'zh/'<v>/",
"xform/uo(?=^|$|')/<o>/",
"xform/[uv]n(?=^|$|')/<z>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<y>/",
"xform/[iu]ang(?=^|$|')/<h>/",
"xform/([a-z>])en(?=^|$|')/$1<r>/",
"xform/([a-z>])eng(?=^|$|')/$1<t>/",
"xform/([a-z>])ang(?=^|$|')/$1<g>/",
"xform/ian(?=^|$|')/<j>/",
"xform/([a-z>])an(?=^|$|')/$1<f>/",
"xform/iao(?=^|$|')/<k>/",
"xform/([a-z>])ao(?=^|$|')/$1<d>/",
"xform/([a-z>])ai(?=^|$|')/$1<s>/",
"xform/([a-z>])ei(?=^|$|')/$1<w>/",
"xform/ie(?=^|$|')/<m>/",
"xform/ui(?=^|$|')/<v>/",
"xform/([a-z>])ou(?=^|$|')/$1<p>/",
"xform/in(?=^|$|')/<l>/",
"xform/'|<|>//",
},
-- 国标双拼gbpy
gbpy = {
"derive/^([aoe])([ioun])(?=^|$|')/$1$1$2/",
"derive/'([aoe])([ioun])(?=^|$|')/'$1$1$2/",
"xform/^([aoe])(ng)?(?=^|$|')/$1$1$2/",
"xform/'([aoe])(ng)?(?=^|$|')/'$1$1$2/",
"xform/iu(?=^|$|')/<y>/",
"xform/(.)ei(?=^|$|')/$1<b>/",
"xform/uan(?=^|$|')/<w>/",
"xform/[uv]e(?=^|$|')/<x>/",
"xform/un(?=^|$|')/<z>/",
"xform/^sh/<u>/",
"xform/^ch/<i>/",
"xform/^zh/<v>/",
"xform/'sh/'<u>/",
"xform/'ch/'<i>/",
"xform/'zh/'<v>/",
"xform/uo(?=^|$|')/<o>/",
"xform/ie(?=^|$|')/<t>/",
"xform/([a-z>])i?ong(?=^|$|')/$1<s>/",
"xform/ing(?=^|$|')|uai(?=^|$|')/<j>/",
"xform/([a-z>])ai(?=^|$|')/$1<k>/",
"xform/([a-z>])en(?=^|$|')/$1<r>/",
"xform/([a-z>])eng(?=^|$|')/$1<h>/",
"xform/[iu]ang(?=^|$|')/<n>/",
"xform/([a-z>])ang(?=^|$|')/$1<g>/",
"xform/ian(?=^|$|')/<d>/",
"xform/([a-z>])an(?=^|$|')/$1<f>/",
"xform/([a-z>])ou(?=^|$|')/$1<p>/",
"xform/[iu]a(?=^|$|')/<q>/",
"xform/iao(?=^|$|')/<m>/",
"xform/([a-z>])ao(?=^|$|')/$1<c>/",
"xform/ui(?=^|$|')/<v>/",
"xform/in(?=^|$|')/<l>/",
"xform/'|<|>//",
},
}
-- 根据输入法类型选择一套规则(只看 id
local function pick_rules(env)
local wanx = get_wanxiang()
local id = 'pinyin'
if wanx and type(wanx.get_input_method_type) == 'function' then
local ok, ret_id = pcall(wanx.get_input_method_type, env)
if ok and type(ret_id) == 'string' and #ret_id > 0 then
id = ret_id
end
end
return LOCAL_PROJECTION_RULES[id] or LOCAL_PROJECTION_RULES['pinyin'] or {}
end
------------------------------------------------------------
-- 工具函数
------------------------------------------------------------
local function alt_lua_punc(s)
if s then
return s:gsub('([%.%+%-%*%?%[%]%^%$%(%)%%])', '%%%1')
else
return ''
end
end
-- 仅保留纯小写字母
local function is_pure_lower_alpha(s)
return type(s) == "string" and s:match("^[a-z]+$") ~= nil
end
local function is_all_upper(s) return s:match('^%u+$') ~= nil end
local function is_all_lower(s) return s:match('^%l+$') ~= nil end
local function add_to_set_list(set_map, list, elem)
if not elem or #elem == 0 then return end
if not set_map[elem] then
set_map[elem] = true
table.insert(list, elem)
end
end
------------------------------------------------------------
-- 规则应用 / 反查逻辑
------------------------------------------------------------
local function expand_code_variant(code_projection, part)
local out, seen = {}, {}
local function add(s) add_to_set_list(seen, out, s) end
add(part)
if code_projection then
local p = code_projection:apply(part, true)
if p and #p > 0 then add(p) end
end
local base = {}
for i = 1, #out do base[i] = out[i] end
for _, s in ipairs(base) do
if is_all_upper(s) then add(string.lower(s)) end -- 笔画:仅转小写参与
if #s == 4 and is_all_lower(s) then -- 4 小写 → 取 1/3
local s13 = s:sub(1,1) .. s:sub(3,3)
add(s13)
end
end
return out
end
local function build_reverse_group(code_projection, db_table, text)
local group, seen = {}, {}
for _, db in ipairs(db_table) do
local code = db:lookup(text)
if code and #code > 0 then
for part in code:gmatch('%S+') do
local variants = expand_code_variant(code_projection, part)
for _, v in ipairs(variants) do add_to_set_list(seen, group, v) end
end
end
end
-- 最终清理:只保留纯小写字母
local cleaned, seen2 = {}, {}
for _, v in ipairs(group) do
v = tostring(v)
if is_pure_lower_alpha(v) then add_to_set_list(seen2, cleaned, v) end
end
return cleaned
end
-- 不支持通配global_match=true 为“包含”,否则“前缀”
local function group_match(group, fuma, global_match)
if not fuma or #fuma == 0 then return false end
local patt = alt_lua_punc(string.lower(fuma))
for _, elem in ipairs(group) do
local e = string.lower(elem)
if global_match then
if e:find(patt) then return true end
else
if e:find('^' .. patt) then return true end
end
end
return false
end
-- 单字优先
local function handle_long_cand(if_single_char_first, cand, long_word_cands)
if if_single_char_first and utf8.len(cand.text) > 1 then
table.insert(long_word_cands, cand)
else
yield(cand)
end
end
------------------------------------------------------------
-- 过滤器主体
------------------------------------------------------------
local f = {}
function f.init(env)
local config = env.engine.schema.config
-- 反查 db
env.if_reverse_lookup = false
env.db_table = nil
local db = config:get_list("wanxiang_lookup/lookup")
if db and db.size > 0 then
env.db_table = {}
for i = 0, db.size - 1 do
table.insert(env.db_table, ReverseLookup(db:get_value_at(i).value))
end
env.if_reverse_lookup = true
end
if not env.if_reverse_lookup then return end
-- 内置规则 + 自动选择(不读 schema 的 format
do
local rules = pick_rules(env)
if type(rules) == 'table' and #rules > 0 then
env.code_projection = Projection()
env.code_projection:load(rules)
else
env.code_projection = nil
end
end
-- 引导键:优先从 wanxiang_lookup/key 读;否则默认 `
env.search_key_str = config:get_string('wanxiang_lookup/key') or '`'
env.search_key_alt = alt_lua_punc(env.search_key_str)
-- tags
local tag = config:get_list('wanxiang_lookup/tags')
if tag and tag.size > 0 then
env.tag = {}
for i = 0, tag.size - 1 do
table.insert(env.tag, tag:get_value_at(i).value)
end
else
env.tag = { 'abc' }
end
-- 选词接管:词组保留引导码,否则上屏
env.notifier = env.engine.context.select_notifier:connect(function(ctx)
local input = ctx.input
local code = input:match('^(.-)' .. env.search_key_alt)
if (not code or #code == 0) then return end
local preedit = ctx:get_preedit()
local no_search_string = ctx.input:match('^(.-)' .. env.search_key_alt)
local edit = preedit.text:match('^(.-)' .. env.search_key_alt)
if edit and edit:match('[%w;]') then
ctx.input = no_search_string .. env.search_key_str
else
ctx.input = no_search_string
env.commit_code = no_search_string
ctx:commit()
end
end)
env._group_cache = setmetatable({}, { __mode = 'kv' })
end
function f.func(input, env)
if not env.if_reverse_lookup then
for cand in input:iter() do yield(cand) end
return
end
local code, fuma = env.engine.context.input:match('^(.-)' .. env.search_key_alt .. '(.+)$')
if (not code or #code == 0) or (not fuma or #fuma == 0) then
for cand in input:iter() do yield(cand) end
return
end
-- 双段辅码a`X`Y第二段匹配第二字或第一字“包含”
local fuma_2
if fuma:find(env.search_key_alt) then
fuma, fuma_2 = fuma:match('^(.-)' .. env.search_key_alt .. '(.*)$')
end
local if_single_char_first = env.engine.context:get_option('char_priority')
local long_word_cands = {}
for cand in input:iter() do
if cand.type == 'sentence' then goto skip end
local cand_text = cand.text
local text = cand_text
local text_2 = nil
if utf8.len(cand_text) and utf8.len(cand_text) > 1 then
text = cand_text:sub(1, utf8.offset(cand_text, 2) - 1)
local cand_text_2 = cand_text:gsub('^' .. text, '')
text_2 = cand_text_2:sub(1, utf8.offset(cand_text_2, 2) - 1)
end
local group1 = env._group_cache[text]
if not group1 then
group1 = build_reverse_group(env.code_projection, env.db_table, text)
env._group_cache[text] = group1
end
local ok = false
if fuma_2 and #fuma_2 > 0 then
local group2 = nil
if text_2 then
group2 = env._group_cache[text_2]
if not group2 then
group2 = build_reverse_group(env.code_projection, env.db_table, text_2)
env._group_cache[text_2] = group2
end
end
ok =
group_match(group1, fuma, false) and
(
(group2 and group_match(group2, fuma_2, false)) or
group_match(group1, fuma_2, true) -- 第一字“包含”
)
else
ok = group_match(group1, fuma, false) -- 单段:前缀匹配第一字
end
if ok then
handle_long_cand(if_single_char_first, cand, long_word_cands)
end
::skip::
end
for _, c in ipairs(long_word_cands) do yield(c) end
end
function f.tags_match(seg, env)
for _, v in ipairs(env.tag) do if seg.tags[v] then return true end end
return false
end
function f.fini(env)
if env.if_reverse_lookup and env.notifier then env.notifier:disconnect() end
env.db_table = nil
env._group_cache = nil
collectgarbage('collect')
end
return f

250
lua/super_segmentation.lua Normal file
View File

@@ -0,0 +1,250 @@
-- super_segmentation.lua
--@amzxyz https://github.com/amzxyz/rime_wanxiang
-- 规则:
-- 1) 第 1 个 '仅记录“现场”baseline_head=当前整段输入,含你之前的手动分隔),记录起点索引,不重建
-- 2) 第 2 个 ' 起:开始循环
-- - 命中起点 s只循环 s 后面的 m-1 个形态(跳过 s 本身)
-- - 未命中:从 all[1] 开始循环 m 个形态
-- 3) 走完一圈:恢复到 baseline_head并尾部只保留 1 个 '
-- 4) 支持 N=3..8(可扩展 PATTERNS
-- 5) 使用 update_notifier 预缓存可见分段,避免移动端“晚一拍”
local K_REJECT, K_ACCEPT, K_NOOP = 0, 1, 2
local M = {}
-- ---------- utils ----------
local function escp(ch) return ch:gsub("(%W)","%%%1") end
local function sum(a) local s=0; for _,v in ipairs(a) do s=s+v end; return s end
local function key_of(a) return table.concat(a, ",") end
local function find_idx(list, key) for i,t in ipairs(list) do if key_of(t)==key then return i end end end
local function count_trailing(s, ch) local n=0; for i=#s,1,-1 do if s:sub(i,i)==ch then n=n+1 else break end end; return n end
local function strip_trailing(s, ch) return (s:gsub(escp(ch).."+$","")) end
-- 去掉手动与自动分隔符,得到“纯编码”
local function strip_delims(s, md, ad)
if md and md~="" then s = s:gsub(escp(md),"") end
if ad and ad~="" then s = s:gsub(escp(ad),"") end
return s
end
-- 依据分组把 core 插入手动分隔符重建
local function build_by_groups(core, ch_manual, groups)
if not groups or #groups==0 or sum(groups)~=#core then return core end
local out, i = {}, 1
for gi,g in ipairs(groups) do
out[#out+1] = core:sub(i, i+g-1); i = i + g
if gi < #groups then out[#out+1] = ch_manual end
end
return table.concat(out)
end
-- 从字符串解析分段长度(空格或 ' 都视为可见分隔)
local function lens_from_string(s, md, ad)
if not s or s=="" then return nil end
local segs, buf = {}, {}
local function flush() if #buf>0 then segs[#segs+1]=table.concat(buf); buf={} end end
for i=1,#s do
local c=s:sub(i,i)
if c==md or c==ad or c==" " then
flush()
else
local b=string.byte(c)
if b and ((b>=65 and b<=90) or (b>=97 and b<=122)) then
buf[#buf+1]=string.char(b):lower()
end
end
end
flush()
if #segs==0 then return nil end
local L={}; for _,seg in ipairs(segs) do L[#L+1]=#seg end
return L
end
-- —— 缓存读取:优先用通知器缓存的 lens其次现场计算 ——
local function get_cached_lens(env, ctx, md, ad)
local L = env._last_preedit_lens
if L and type(L)=="table" and #L>0 then return L end
local seg = ctx.composition:back()
local cand = seg and seg:get_selected_candidate() or nil
return lens_from_string(cand and cand.preedit or nil, md, ad)
end
-- ---------- patterns ----------
local PATTERNS = {
[3] = { all = { {2,1}, {1,2} } },
[4] = { all = { {2,2}, {1,3}, {3,1} } },
[5] = { all = { {2,3}, {3,2} } },
[6] = { all = { {2,2,2}, {3,3} } },
[7] = { all = { {2,2,3}, {2,3,2}, {3,2,2} } },
[8] = { all = { {2,2,2,2}, {2,3,3}, {3,2,3}, {3,3,2} } },
[10] = { all = { {2,2,2,2,2} } },
[12] = { all = { {2,2,2,2,2,2} } },
}
-- ---------- session state ----------
local function reset_session(env)
env._ss_core_letters = nil -- 纯编码(去分隔)
env._ss_start_idx = nil -- 起点索引1..m未命中则 0
env._ss_N = nil
env._ss_baseline_head = nil -- 基线:包含你之前的手动分隔/空格
end
local function ulen(s)
if not s or s == "" then return 0 end
if utf8 and utf8.len then
local ok, n = pcall(utf8.len, s)
if ok and n then return n end
end
-- 兜底:简单按 UTF-8 码点数
local n = 0
if utf8 and utf8.codes then
for _ in utf8.codes(s) do n = n + 1 end
return n
end
-- 再兜底:直接 #s有误差但总比没有好
return #s
end
function M.init(env)
local cfg = env.engine.schema.config
local delimiter = cfg:get_string("speller/delimiter") or " '"
if #delimiter < 2 then delimiter = " '" end
env.auto_delim = delimiter:sub(1,1) -- 通常空格
env.manual_delim = delimiter:sub(2,2) -- 通常单引号
-- 缓存最新一帧的可见分段与输入
env._upd_conn = env.engine.context.update_notifier:connect(function(ctx)
local seg = ctx.composition:back()
local cand = seg and seg:get_selected_candidate() or nil
local pre = cand and cand.preedit or nil
env._last_preedit_lens = lens_from_string(pre, env.manual_delim, env.auto_delim)
env._last_input_head = ctx.input
env._last_input_for_caret = ctx.input
env._last_caret_pos = ctx.caret_pos
end)
reset_session(env)
end
function M.fini(env)
if env._upd_conn then env._upd_conn:disconnect(); env._upd_conn=nil end
end
-- ---------- main ----------
function M.func(key_event, env)
if key_event:release() then return K_NOOP end
local ctx = env.engine.context
if ctx.composition:empty() then return K_NOOP end
local md = env.manual_delim or "'"
local ad = env.auto_delim or " "
-- 只处理手动分隔符键
if key_event.keycode ~= string.byte(md) then
reset_session(env); return K_NOOP
end
--用「上一帧」的光标位置判断是不是在中间编辑
do
local last_input = env._last_input_for_caret or ctx.input or ""
local last_caret = env._last_caret_pos
local total_len = ulen(last_input)
-- 只有「上一帧光标在末尾」我们才认定在玩超分段
if not last_caret or last_caret ~= total_len then
-- 上一帧光标不在末尾:说明用户在中间编辑,这次 ' 交给默认逻辑
reset_session(env)
return K_NOOP
end
end
-- 把这次 ' 并入输入,统计尾部 ' 数
local before = ctx.input or ""
local after = before .. md
local tlen = count_trailing(after, md)
-- 去掉末尾 ' 串,得到 head本次按键前的完整输入与 core纯编码
local head = strip_trailing(after, md)
local core = strip_delims(head, md, ad)
local N = #core
local conf = PATTERNS[N]
-- 若核心/长度变化,重置会话
if env._ss_core_letters ~= core or env._ss_N ~= N then
env._ss_core_letters = core
env._ss_N = N
env._ss_start_idx = nil
env._ss_baseline_head = nil
end
-- 只要本轮还没记过,就立刻记录“基线 + 起点”(无论 tlen==1 还是 tlen>=2
if env._ss_baseline_head == nil then
env._ss_baseline_head = head -- 保留你原有的空格或手动 '
end
if conf and env._ss_start_idx == nil then
local start_idx = 0
-- 先用缓存的可见分段;不行就直接用 head 切分可避免“23 又走到 23'”的伪步骤)
local L = get_cached_lens(env, ctx, md, ad)
if not (L and sum(L)==N) then
L = lens_from_string(head, md, ad)
end
if L and sum(L)==N then
local idx = find_idx(conf.all, key_of(L))
if idx then start_idx = idx end
end
env._ss_start_idx = start_idx
end
-- 第 1 个 ' :仅记录,不重建
if tlen == 1 then
ctx.input = after
return K_ACCEPT
end
-- 第 2 个 ' 起:循环(若无该长度配置,直接接纳输入)
if not conf then
ctx.input = after
return K_ACCEPT
end
local m = #conf.all
local k = tlen - 1 -- 从第二个 ' 开始计数
-- 恢复:回到第一拍记录的 baseline保留空格/已有 '),尾部只留 1 个 '
local function restore()
local baseline = env._ss_baseline_head or head
ctx.input = baseline .. md
reset_session(env)
env._ss_core_letters = core
env._ss_N = N
end
if env._ss_start_idx and env._ss_start_idx ~= 0 then
-- 命中起点:只循环后续 m-1 个形态,跳过当前形态
local variants_count = m - 1
local cycle_len = variants_count + 1
local r = k % cycle_len
if r == 0 then
restore(); return K_ACCEPT
else
local idx = ((env._ss_start_idx - 1 + r) % m) + 1 -- 跳过起点本身
local groups = conf.all[idx]
local rebuilt = build_by_groups(core, md, groups)
ctx.input = rebuilt .. md:rep(tlen)
return K_ACCEPT
end
else
-- 未命中起点:从 all[1] 开始循环 m 个形态
local variants_count = m
local cycle_len = variants_count + 1
local r = k % cycle_len
if r == 0 then
restore(); return K_ACCEPT
else
local idx = ((r - 1) % m) + 1
local groups = conf.all[idx]
local rebuilt = build_by_groups(core, md, groups)
ctx.input = rebuilt .. md:rep(tlen)
return K_ACCEPT
end
end
end
return { init = M.init, fini = M.fini, func = M.func }

734
lua/super_sequence.lua Normal file
View File

@@ -0,0 +1,734 @@
-- 万象拼音 · 手动自由排序
-- 核心规则: 向前移动 = "Control+j", 向后移动 = "Control+k", 重置 = "Control+l", 置顶 = "Control+p
-- 1) p>0有效排序DB upsert + 导出)
-- 2) p=0墓碑DB 删除 + 导出墓碑)
-- 3) 初始化:先 flush 本机增量到导出 → 外部合并(所有设备文件+本机DBLWW) → 重写本机导出(含墓碑) → 导入覆盖DBp=0删除键不导入
-- 4) 关于同步的使用方法先点击同步确保同步目录已经创建建立sequence_device_list.txt设备清单内部填写不同设备导出文件名称
-- sequence_ff9b2823-8733-44bb-a497-daf382b74ca5.txt
-- sequence_deepin.txt
-- 可能是自定义名称,可能是随机串号
-- sequence_开头后面跟着installation_id这个参数来自用户目录installation.yaml
-- 清单有什么文件就会读取什么文件
-- 仅使用 installation.yaml 的 sync_dir读不到就回退到 user_dir/sync
-- 核心规则: 向前移动 = "Control+j", 向后移动 = "Control+k", 重置 = "Control+l", 置顶 = "Control+p"
-- 1) p>0有效排序DB upsert + 导出)
-- 2) p=0墓碑DB 删除 + 导出墓碑)
-- 3) 初始化:先 flush 本机增量到导出 → 外部合并(所有设备文件+本机DBLWW) → 重写本机导出(含墓碑) → 导入覆盖DBp=0删除键不导入
-- 4) 同步路径策略:能从 installation.yaml 读取到 sync_dir 就用它;读不到才用默认 user_dir/sync
local wanxiang = require("wanxiang")
local userdb = require("lib/userdb")
------------------------------------------------------------
-- 一、常量与键位
------------------------------------------------------------
local DEFAULT_SEQ_KEY = { up = "Control+j", down = "Control+k", reset = "Control+l", pin = "Control+p" }
local SYNC_FILE_PREFIX, SYNC_FILE_SUFFIX = "sequence", ".txt"
-- 运行期是否立刻写出到导出文件(只在重新部署时写出→设为 false
local RUNTIME_EXPORT = false
-- ☆☆ 前向声明,避免被当作全局导致 nil ☆☆
local _normalize_path, _is_abs_path, _path_join, _manifest_path
------------------------------------------------------------
-- 二、通用工具(仅处理 "\" 与 "\\", 统一成 "/"
------------------------------------------------------------
_normalize_path = function(p)
if not p or p == "" then return "" end
if p:sub(1, 2) == "\\\\" then
-- UNC\\server\share\foo -> //server/share/foo
return "//" .. p:sub(3):gsub("\\", "/"):gsub("/+", "/")
else
-- 普通D:\dir\\file -> D:/dir/file
return p:gsub("\\", "/"):gsub("/+", "/")
end
end
_is_abs_path = function(p)
p = _normalize_path(p)
return p:sub(1, 2) == "//" or p:match("^[A-Za-z]:/")
end
_path_join = function(a, b)
a = _normalize_path(a)
b = _normalize_path(b)
if not a or a == "" then return b end
if not b or b == "" then return a end
if _is_abs_path(b) then return b end
if a:sub(-1) ~= "/" then a = a .. "/" end
return a .. b
end
_manifest_path = function(dir)
return _path_join(dir, "sequence_device_list.txt")
end
local function _read_lines(path)
local t, f = {}, io.open(path, "r")
if not f then return t end
for line in f:lines() do t[#t + 1] = line end
f:close()
return t
end
local function _write_lines(path, lines)
local f = io.open(path, "w"); if not f then return false end
for _, line in ipairs(lines) do f:write(line, "\n") end
f:close()
return true
end
local function _trim(s) return (s:gsub("^%s+", ""):gsub("%s+$", "")) end
local function _file_exists(path)
if not path or path == "" then return false end
local f = io.open(path, "r"); if f then f:close(); return true end
return false
end
------------------------------------------------------------
-- 三、安装信息 & 同步目录(仅看 YAML读不到就默认
------------------------------------------------------------
local function _read_installation_yaml()
local user_dir = rime_api.get_user_data_dir()
if not user_dir or user_dir == "" then return nil, nil end
local path = _path_join(user_dir, "installation.yaml")
local f = io.open(path, "r"); if not f then return nil, nil end
local installation_id, sync_dir
for line in f:lines() do
line = line:gsub("%s+#.*$", "")
local key, val = line:match("^%s*([%w_]+)%s*:%s*(.+)$")
if key and val then
-- 去引号
val = val:gsub('^%s*"(.*)"%s*$', "%1"):gsub("^%s*'(.*)'%s*$", "%1")
val = val:gsub("^%s+", ""):gsub("%s+$", "")
if key == "installation_id" then
installation_id = val
elseif key == "sync_dir" then
sync_dir = _normalize_path(val)
end
end
end
f:close()
return installation_id, sync_dir
end
-- 只看 installation.yaml读到就用读不到就 user_dir/sync
local function _sync_dir()
local user_dir = rime_api.get_user_data_dir() or ""
local _, ysync = _read_installation_yaml()
local function fix(x)
if not x or x == "" then return "" end
if x == "sync" then
return (user_dir ~= "" and _path_join(user_dir, "sync")) or "sync"
end
return _normalize_path(x)
end
if ysync and ysync ~= "" then
return fix(ysync)
end
return _path_join(user_dir, "sync")
end
local function _sync_ready()
local install_id, ysync = _read_installation_yaml()
local user_dir = rime_api.get_user_data_dir() or ""
local dir
if ysync and ysync ~= "" then
dir = _normalize_path(ysync)
if dir == "sync" then dir = _path_join(user_dir, "sync") end
else
dir = _path_join(user_dir, "sync")
end
local ok = (install_id and install_id ~= "") and (dir and dir ~= "")
return ok, dir, install_id
end
local function _detect_device_name()
local installation_id = select(1, _read_installation_yaml())
local function _san(s) return tostring(s):gsub("[%s/\\:%*%?\"<>|]", "_") end
if installation_id and installation_id ~= "" then return _san(installation_id) end
local dir = _sync_dir()
for _, raw in ipairs(_read_lines(_manifest_path(dir))) do
local name = _trim(raw or "")
local m = name:match("^sequence_(.+)%.txt$")
if m and not _is_abs_path(name) then return _san(m) end
end
return "device"
end
------------------------------------------------------------
-- 四、时间
------------------------------------------------------------
local function get_timestamp()
local ms = type(rime_api.get_time_ms) == "function" and tonumber(rime_api.get_time_ms()) or nil
return ms and (os.time() + ms / 1000.0) or os.time()
end
------------------------------------------------------------
-- 五、DB 与状态
------------------------------------------------------------
local seq_db = userdb.LevelDb("lua/sequence")
local seq_property = {
ADJUST_KEY = "sequence_adjustment_code",
}
---@param context Context
function seq_property.get(context)
return context:get_property(seq_property.ADJUST_KEY)
end
---@param context Context
function seq_property.reset(context)
local code = seq_property.get(context)
if code ~= nil and code ~= "" then
context:set_property(seq_property.ADJUST_KEY, "")
end
end
local curr_state = {}
curr_state.ADJUST_MODE = { None = -1, Reset = 0, Pin = 1, Adjust = 2 }
curr_state.default = {
selected_phrase = nil, offset = 0, mode = curr_state.ADJUST_MODE.None,
highlight_index = nil, adjust_code = nil, adjust_key = nil,
dirty = false, last_dirty_ts = 0,
}
function curr_state.reset()
if curr_state.mode == curr_state.ADJUST_MODE.None then return end
for k, v in pairs(curr_state.default) do curr_state[k] = v end
end
function curr_state.is_pin_mode() return curr_state.mode == curr_state.ADJUST_MODE.Pin end
function curr_state.is_reset_mode() return curr_state.mode == curr_state.ADJUST_MODE.Reset end
function curr_state.is_adjust_mode() return curr_state.mode == curr_state.ADJUST_MODE.Adjust end
function curr_state.has_adjustment() return curr_state.mode ~= curr_state.ADJUST_MODE.None end
------------------------------------------------------------
-- 六、关键日志(精简)
------------------------------------------------------------
--[[
local function _print_sync_probe(phase)
local user_dir = tostring(rime_api.get_user_data_dir() or "")
local iid, ysync = _read_installation_yaml()
local chosen = _sync_dir()
local inst_yaml = _path_join(user_dir, "installation.yaml")
log.warning(string.format(
"[sequence][%s] installation_id=%s yaml_sync_dir=%s chosen_sync_dir=%s inst_yaml=%s exists=%s",
phase, tostring(iid), tostring(ysync), tostring(chosen),
inst_yaml, tostring(_file_exists(inst_yaml))
))
end
local function _debug_paths_once()
local dir = _sync_dir()
local device_name = _detect_device_name()
local export_name = string.format("%s_%s%s", SYNC_FILE_PREFIX, device_name, SYNC_FILE_SUFFIX)
local export_path = _path_join(dir, export_name)
log.info(string.format("[sequence] chosen_sync_dir=%s manifest_exists=%s",
tostring(dir), tostring(_file_exists(_manifest_path(dir)))))
log.info(string.format("[sequence] export_path=%s exists=%s",
tostring(export_path), tostring(_file_exists(export_path))))
end ]]--
------------------------------------------------------------
-- 七、记录解析(新格式)
------------------------------------------------------------
local function parse_adjustment_value_item(value_item)
local item, p, o, t = value_item:match("i=(.+) p=(%S+) o=(%S*) t=(%S+)")
if not item then return nil, nil end
return item, { fixed_position = tonumber(p) or 0, offset = tonumber(o) or 0, updated_at = tonumber(t) }
end
local function parse_adjustment_values(values_str)
local mp = {}
for seg in values_str:gmatch("[^\t]+") do
local item, adj = parse_adjustment_value_item(seg)
if item then mp[item] = adj end
end
return next(mp) and mp or nil
end
local function get_input_adjustments(input)
if not input or input == "" then return nil end
local value_str = seq_db:fetch(input)
return value_str and parse_adjustment_values(value_str) or nil
end
------------------------------------------------------------
-- 八、导出缓冲(去重 + 节流)
------------------------------------------------------------
local seq_data = {
status = "pending",
device_name = "device",
last_export_ts = 0,
export_interval = 1.2, -- 秒
pending_map = {}, -- key: input.."\t"..item => line
}
local function _pending_count() local n = 0; for _ in pairs(seq_data.pending_map) do n = n + 1 end; return n end
function seq_data._current_paths()
local dir = _sync_dir()
local device_name = seq_data.device_name or "device"
local export_name = string.format("%s_%s%s", SYNC_FILE_PREFIX, device_name, SYNC_FILE_SUFFIX)
local export_path = _path_join(dir, export_name)
local manifest = _manifest_path(dir)
return dir, device_name, export_name, export_path, manifest
end
function seq_data._ensure_export_file()
local ok = _sync_ready()
if not ok then
--log.info("[sequence] installation_id 或 sync_dir 缺失,跳过导出")
return false
end
local _, _, export_name, export_path, manifest = seq_data._current_paths()
if not _file_exists(manifest) then
local mf = io.open(manifest, "w"); if not mf then return false end; mf:close()
end
if not _file_exists(export_path) then
local f = io.open(export_path, "w"); if not f then return false end
local user_id = wanxiang.get_user_id()
if user_id then f:write("\001/user_id\t", user_id, "\n") end
f:write("\001/device_name\t", seq_data.device_name or "device", "\n")
f:close()
end
local names = _read_lines(manifest)
local seen = {}; for _, n in ipairs(names) do seen[_trim(n)] = true end
if not seen[export_name] then names[#names + 1] = export_name; _write_lines(manifest, names) end
return true
end
local function _enqueue_export(input, item, adj)
local k = input .. "\t" .. item
seq_data.pending_map[k] = string.format("%s\ti=%s p=%s o=%s t=%s\n",
input, item, adj.fixed_position or 0, adj.offset or 0, adj.updated_at or "")
end
function seq_data.flush_pending(max_lines)
if _pending_count() == 0 then return end
if not seq_data._ensure_export_file() then return end
local _, _, _, export_path = seq_data._current_paths()
local f = io.open(export_path, "a"); if not f then return end
local wrote = 0
for _, line in pairs(seq_data.pending_map) do
if max_lines and wrote >= max_lines then break end
f:write(line); wrote = wrote + 1
end
f:close()
seq_data.pending_map = {}
end
function seq_data.maybe_export(force)
if force then
seq_data.flush_pending(nil)
seq_data.last_export_ts = get_timestamp()
return
end
if _pending_count() == 0 then return end
local now = get_timestamp()
if now - (seq_data.last_export_ts or 0) < (seq_data.export_interval or 1.2) then return end
seq_data.flush_pending(200)
seq_data.last_export_ts = now
end
------------------------------------------------------------
-- 九、保存本机操作p=0 也导出墓碑运行期不写盘DB 暂存墓碑以便重部署覆盖)
------------------------------------------------------------
local function save_adjustment(input, item, adjustment, no_export)
if not input or input == "" or not item or item == "" then return end
local p = tonumber(adjustment.fixed_position) or 0
local o = tonumber(adjustment.offset) or 0
local t = adjustment.updated_at
local mp = get_input_adjustments(input) or {}
if p <= 0 then
-- 关键DB 内也保留 p=0 墓碑(含时间戳),用于重部署时 LWW 覆盖外部文件
mp[item] = { fixed_position = 0, offset = o, updated_at = t }
else
mp[item] = { fixed_position = p, offset = o, updated_at = t }
end
local arr = {}
for it, a in pairs(mp) do
arr[#arr + 1] = string.format("i=%s p=%s o=%s t=%s",
it, a.fixed_position, a.offset or 0, a.updated_at or "")
end
seq_db:update(input, table.concat(arr, "\t"))
-- 仅在允许运行期写出时才入队(默认 RUNTIME_EXPORT=false不入队
if (not no_export) and RUNTIME_EXPORT then
_enqueue_export(input, item, { fixed_position = p, offset = o, updated_at = t }) -- 包含 p=0 墓碑
end
end
------------------------------------------------------------
-- 十、合并器:收集“所有文件 + 本机DB”按 t 取最新(包含 p=0
------------------------------------------------------------
local function _keep_latest(latest, input, item, adj)
latest[input] = latest[input] or {}
local prev = latest[input][item]
if (not prev) or ((adj.updated_at or 0) > (prev.updated_at or 0)) then
latest[input][item] = {
fixed_position = tonumber(adj.fixed_position) or 0,
offset = tonumber(adj.offset) or 0,
updated_at = tonumber(adj.updated_at) or 0
}
end
end
local function collect_latest_from_all_sources()
local latest = {}
-- A) 本机 DB包含 p=0 墓碑:让 DB 能覆盖外部)
seq_db:query_with("", function(key, value)
local mp = parse_adjustment_values(value)
if mp then
for item, a in pairs(mp) do
_keep_latest(latest, key, item, a)
end
end
end)
-- B) 清单里的所有导出文件(包含 p=0
local dir = _sync_dir()
local names = _read_lines(_manifest_path(dir))
for _, raw in ipairs(names) do
local name = _trim(raw or "")
if name ~= "" and name:sub(1, 1) ~= "#" then
if name:sub(1, #SYNC_FILE_PREFIX) == SYNC_FILE_PREFIX
and name:sub(-#SYNC_FILE_SUFFIX) == SYNC_FILE_SUFFIX then
local path = _is_abs_path(name) and name or _path_join(dir, name)
local f = io.open(path, "r")
if f then
for line in f:lines() do
if line ~= "" and line:sub(1, 2) ~= "\001" .. "/" then
local key, value = line:match("^(%S+)\t(.+)$")
if key and value then
local item, adj1 = parse_adjustment_value_item(value)
if item then
_keep_latest(latest, key, item, adj1)
else
local mp = parse_adjustment_values(value)
if mp then for it, a in pairs(mp) do _keep_latest(latest, key, it, a) end end
end
end
end
end
f:close()
end
end
end
end
return latest
end
------------------------------------------------------------
-- 十一、把“合并结果”重写到我机导出(含 p=0
------------------------------------------------------------
local function rewrite_export_from_latest(latest)
local ok = _sync_ready()
if not ok then return end
local dir = _sync_dir()
local installation_id = select(1, _read_installation_yaml())
local device_name = (installation_id and installation_id ~= "") and tostring(installation_id):gsub("[%s/\\:%*%?\"<>|]", "_") or "device"
local export_name = string.format("%s_%s%s", SYNC_FILE_PREFIX, device_name, SYNC_FILE_SUFFIX)
local export_path = _path_join(dir, export_name)
local manifest = _manifest_path(dir)
if not _file_exists(manifest) then local mf = io.open(manifest, "w"); if mf then mf:close() end end
do
local names = _read_lines(manifest); local seen = {}; for _, n in ipairs(names) do seen[_trim(n)] = true end
if not seen[export_name] then names[#names + 1] = export_name; _write_lines(manifest, names) end
end
local f = io.open(export_path, "w"); if not f then return end
local user_id = wanxiang.get_user_id()
if user_id then f:write("\001/user_id\t", user_id, "\n") end
f:write("\001/device_name\t", device_name, "\n")
local inputs = {}
for input, _ in pairs(latest) do inputs[#inputs + 1] = input end
table.sort(inputs)
for _, input in ipairs(inputs) do
local items, keys = latest[input], {}
for item, _ in pairs(items) do keys[#keys + 1] = item end
table.sort(keys)
for _, item in ipairs(keys) do
local a = items[item]
f:write(string.format("%s\ti=%s p=%s o=%s t=%s\n",
input, item, a.fixed_position or 0, a.offset or 0, a.updated_at or ""))
end
end
f:close()
--log.info(string.format("[sequence] export rewritten (merged LWW, incl tombstones): %s", export_path))
end
------------------------------------------------------------
-- 十二、把“合并结果”导入覆盖 DBp<=0 删)
------------------------------------------------------------
local function apply_latest_to_db(latest)
local updated_keys = 0
for input, kv in pairs(latest) do
local keep = {}
for item, a in pairs(kv) do
if (tonumber(a.fixed_position) or 0) > 0 then
keep[item] = { fixed_position = a.fixed_position, offset = a.offset or 0, updated_at = a.updated_at }
end
end
if next(keep) == nil then
seq_db:erase(input)
else
local arr = {}
for item, a in pairs(keep) do
arr[#arr + 1] = string.format("i=%s p=%s o=%s t=%s", item, a.fixed_position, a.offset or 0, a.updated_at or "")
end
seq_db:update(input, table.concat(arr, "\t"))
end
updated_keys = updated_keys + 1
end
--log.info(string.format("[sequence] DB applied from merged LWW: %d keys", updated_keys))
end
------------------------------------------------------------
-- 十三、初始化先导出→合并→重写导出→导入DB
------------------------------------------------------------
local function init_once()
-- 1) 先导出:把本机 pending 增量写出去如果是旧版本留下的队列这里可一次性落盘RUNTIME_EXPORT 与此无关)
seq_data._ensure_export_file()
seq_data.maybe_export(true)
-- 2) 外部合并(所有设备文件 + 本机 DBLWW含 p=0
local latest = collect_latest_from_all_sources()
-- 3) 用合并结果重写我机导出(包含 p=0——始终写盘
rewrite_export_from_latest(latest)
-- 4) 导入合并结果覆盖 DBp<=0 删)
apply_latest_to_db(latest)
end
------------------------------------------------------------
-- 十四、PipelineP / F
------------------------------------------------------------
local P = {}
function P.init(env)
seq_db:open()
seq_data.device_name = _detect_device_name()
--_print_sync_probe("init") -- 关键:一次性输出最终使用的 sync_dir
--_debug_paths_once() -- 关键:简要输出导出与清单路径是否存在
init_once()
end
local function process_adjustment(context)
local c = context:get_selected_candidate()
curr_state.selected_phrase = c and c.text or nil
context:refresh_non_confirmed_composition()
if context.highlight and curr_state.highlight_index and curr_state.highlight_index > 0 then
context:highlight(curr_state.highlight_index)
end
end
-- 辅助:判断是否单个 ASCII 小写字母
local function _is_single_lowercase_letter(s)
return type(s) == "string" and #s == 1 and s:match("^[a-z]$") ~= nil
end
function P.func(key_event, env)
local context = env.engine.context
-- 不要在早期就重置 offset保持原代码行为
curr_state.reset()
local selected_cand = context:get_selected_candidate()
if not context:has_menu() or not selected_cand or not selected_cand.text then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 先判断当前的 adjust_code与 extract_adjustment_code 的逻辑一致)
local function get_adjust_code()
if wanxiang.is_function_mode_active(context) then
local code = seq_property.get(context)
if code and code ~= "" then return code end
return nil
end
return context.input:sub(1, context.caret_pos)
end
local adjust_code = get_adjust_code()
-- 如果不是 function-mode 且 adjust_code 是单个小写字母,则按键不应改变 curr_state.offset因为单字母存在时间复杂度
if (not wanxiang.is_function_mode_active(context)) and _is_single_lowercase_letter(adjust_code) then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
local key_repr = key_event:repr()
local function get_seq_key(type)
return env.engine.schema.config:get_string("key_binder/sequence/" .. type) or DEFAULT_SEQ_KEY[type]
end
if key_repr == get_seq_key("up") then
curr_state.offset = -1; curr_state.mode = curr_state.ADJUST_MODE.Adjust
elseif key_repr == get_seq_key("down") then
curr_state.offset = 1; curr_state.mode = curr_state.ADJUST_MODE.Adjust
elseif key_repr == get_seq_key("reset") then
curr_state.offset = nil; curr_state.mode = curr_state.ADJUST_MODE.Reset
elseif key_repr == get_seq_key("pin") then
curr_state.offset = nil; curr_state.mode = curr_state.ADJUST_MODE.Pin
else
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
process_adjustment(context)
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
local F = {}
function F.fini()
-- 退出时不落盘(仅在重新部署 init_once 重写导出)
if RUNTIME_EXPORT then
seq_data.maybe_export(true)
end
end
local function apply_prev_adjustment(cands, prev)
local list = {}
for _, info in pairs(prev or {}) do
if info.raw_position then info.from_position = info.raw_position; table.insert(list, info) end
end
table.sort(list, function(a, b) return (a.updated_at or 0) < (b.updated_at or 0) end)
local n = #cands
for i, record in ipairs(list) do
local fromp = record.from_position
if fromp and (record.fixed_position or 0) > 0 then
local top = (record.offset == 0) and record.fixed_position or (record.raw_position + record.offset)
if top < 1 then top = 1 elseif top > n then top = n end
if fromp ~= top then
local cand = table.remove(cands, fromp)
table.insert(cands, top, cand)
local lo, hi = math.min(fromp, top), math.max(fromp, top)
for j = i, #list do
local r = list[j]
if lo <= r.from_position and r.from_position <= hi then
r.from_position = r.from_position + ((top < fromp) and 1 or -1)
end
end
end
end
end
end
local function apply_curr_adjustment(candidates, curr_adjustment)
if curr_adjustment == nil then return end
---@type integer | nil
local from_position = nil
for position, cand in ipairs(candidates) do
if cand.text == curr_state.selected_phrase then
from_position = position
break
end
end
if from_position == nil then return end
local to_position = from_position
if curr_state.is_adjust_mode() then
to_position = from_position + curr_state.offset
curr_adjustment.offset = to_position - curr_adjustment.raw_position
curr_adjustment.fixed_position = to_position
local min_position, max_position = 1, #candidates
if from_position ~= to_position then
if to_position < min_position then
to_position = min_position
elseif to_position > max_position then
to_position = max_position
end
local candidate = table.remove(candidates, from_position)
table.insert(candidates, to_position, candidate)
-- 运行期仅写 DB不入导出队列
save_adjustment(curr_state.adjust_code, curr_state.adjust_key, curr_adjustment, true)
end
end
curr_state.highlight_index = to_position - 1
end
local function extract_adjustment_code(context)
if wanxiang.is_function_mode_active(context) then
local code = seq_property.get(context)
if code and code ~= "" then return code end
return nil
end
return context.input:sub(1, context.caret_pos)
end
function F.func(input, env)
local function original_list() for cand in input:iter() do yield(cand) end end
local context = env.engine.context
local adjustment_allowed = not (wanxiang.is_function_mode_active(context) and seq_property.get(context) == nil)
if not adjustment_allowed then
--log.warning("[sequence] 当前指令不支持手动排序")
return original_list()
end
local adjust_code = extract_adjustment_code(context)
if not adjust_code then return original_list() end
local prev_adjustments = get_input_adjustments(adjust_code)
local curr_adjustment = curr_state.has_adjustment() and { fixed_position = 0, offset = 0, updated_at = get_timestamp() } or nil
if (not curr_adjustment) and (not prev_adjustments) then return original_list() end
local cands, seen = {}, {}
local is_fun_mode = wanxiang.is_function_mode_active(context)
local pos = 0
for candidate in input:iter() do
local phrase = candidate.text
if not seen[phrase] then
seen[phrase] = true; pos = pos + 1; table.insert(cands, candidate)
local curr_key = is_fun_mode and tostring(pos - 1) or phrase
if curr_adjustment and curr_state.selected_phrase == phrase then
curr_state.adjust_code = adjust_code
curr_state.adjust_key = curr_key
curr_adjustment.raw_position = pos
end
if prev_adjustments and prev_adjustments[curr_key] then
prev_adjustments[curr_key].raw_position = pos
end
end
end
prev_adjustments = prev_adjustments or {}
-- 非位移:置顶/重置立即仅保存到 DB不入队
if curr_adjustment and not curr_state.is_adjust_mode() then
curr_adjustment.offset = 0
local key = tostring(curr_state.adjust_key)
if curr_state.is_reset_mode() then
curr_adjustment.fixed_position = 0
prev_adjustments[key] = nil
save_adjustment(curr_state.adjust_code, curr_state.adjust_key, curr_adjustment, true)
elseif curr_state.is_pin_mode() then
curr_adjustment.fixed_position = 1
prev_adjustments[key] = curr_adjustment
save_adjustment(curr_state.adjust_code, curr_state.adjust_key, curr_adjustment, true)
end
end
apply_prev_adjustment(cands, prev_adjustments)
apply_curr_adjustment(cands, curr_adjustment)
for _, cand in ipairs(cands) do yield(cand) end
-- 运行期不写盘;如需调试可改为 if RUNTIME_EXPORT then ... end
if RUNTIME_EXPORT and (not curr_state.is_reset_mode()) then
seq_data.maybe_export(false)
end
end
return { P = P, F = F }

279
lua/super_tips.lua Normal file
View File

@@ -0,0 +1,279 @@
-- 万象家族lua,超级提示,表情\化学式\方程式\简码等等直接上屏,不占用候选位置
-- 采用leveldb数据库,支持大数据遍历,支持多种类型混合,多种拼音编码混合,维护简单
-- 支持候选匹配和编码匹配两种,候选支持方向键高亮遍历
-- https://github.com/amzxyz/rime_wanxiang
-- - lua_processor@*super_tips
-- key_binder/tips_key: "slash" # 上屏按键配置
-- tips/disabled_types: [] # 禁用的 tips 类型
local wanxiang = require("wanxiang")
local bit = require("lib/bit")
local userdb = require("lib/userdb")
local tips_db = userdb.LevelDb("lua/tips")
-- 获取文件内容哈希值,使用 FNV-1a 哈希算法
local function calculate_file_hash(filepath)
local file = io.open(filepath, "rb")
if not file then return nil end
-- FNV-1a 哈希参数32位
local FNV_OFFSET_BASIS = 0x811C9DC5
local FNV_PRIME = 0x01000193
local hash = FNV_OFFSET_BASIS
while true do
local chunk = file:read(4096)
if not chunk then break end
for i = 1, #chunk do
local byte = string.byte(chunk, i)
hash = bit.bxor(hash, byte)
hash = (hash * FNV_PRIME) % 0x100000000
hash = bit.band(hash, 0xFFFFFFFF)
end
end
file:close()
return string.format("%08x", hash)
end
local tips = {}
---@type "pending" | "initialing" | "done"
tips.status = "pending"
---@type table<string, boolean>
tips.disabled_types = {}
tips.preset_file_path = wanxiang.get_filename_with_fallback("lua/tips/tips_show.txt")
tips.user_override_path = rime_api.get_user_data_dir() .. "/lua/tips/tips_user.txt"
local META_KEY = {
version = "wanxiang_version",
user_file_hash = "user_tips_file_hash",
disabled_types = "disabled_types",
}
---@param tip string
function tips.is_disabled(tip)
local type = tip:match("^(..-):")
or tip:match("^(..-)")
if not type then return false end
return tips.disabled_types[type] == true
end
function tips.init_db_from_file(path)
local file = io.open(path, "r")
if not file then return end
for line in file:lines() do
local value, key = line:match("([^\t]+)\t([^\t]+)")
if key and value
and not tips.is_disabled(value)
then
tips_db:update(key, value)
end
end
file:close()
end
function tips.ensure_dir_exist(dir)
-- 获取系统路径分隔符
local sep = package.config:sub(1, 1)
dir = dir:gsub([["]], [[\"]]) -- 处理双引号
if sep == "/" then
local cmd = 'mkdir -p "' .. dir .. '" 2>/dev/null'
os.execute(cmd)
end
end
---@param config Config
function tips.init(config)
if tips.status ~= "pending" then return end
local dist = rime_api.get_distribution_code_name() or ""
local user_lua_dir = rime_api.get_user_data_dir() .. "/lua"
if dist ~= "hamster" and dist ~= "hamster3" and dist ~= "Weasel" then
tips.ensure_dir_exist(user_lua_dir)
tips.ensure_dir_exist(user_lua_dir .. "/tips")
end
-- 读取配置
local disabled_types_list = config:get_list("tips/disabled_types")
if disabled_types_list then
for i = 1, disabled_types_list.size do
local item = disabled_types_list:get_value_at(i - 1)
if item and #item.value > 0 then
tips.disabled_types[item.value] = true
end
end
end
-- 检查是否需要重建数据库
tips_db:open()
local needs_rebuild = false
-- 检查 1: 万象版本号
if tips_db:meta_fetch(META_KEY.version) ~= wanxiang.version then
needs_rebuild = true
end
-- 检查 2: 用户文件哈希 (仅在版本号相同时检查)
local user_file_hash = calculate_file_hash(tips.user_override_path) or ""
if not needs_rebuild
and (tips_db:meta_fetch(META_KEY.user_file_hash) or "") ~= user_file_hash
then
needs_rebuild = true
end
-- 检查 3: 禁用类型 (仅在前两者都相同时检查)
local disabled_keys = {}
for k, _ in pairs(tips.disabled_types) do
table.insert(disabled_keys, k)
end
table.sort(disabled_keys) -- 排序以确保顺序一致
local disabled_types_str = table.concat(disabled_keys, ",")
if not needs_rebuild
and (tips_db:meta_fetch(META_KEY.disabled_types) or "") ~= disabled_types_str
then
needs_rebuild = true
end
-- 如果需要,则执行重建
if needs_rebuild then
tips_db:empty()
tips.init_db_from_file(tips.preset_file_path)
tips.init_db_from_file(tips.user_override_path)
-- 重建成功后,再更新所有元数据,确保操作的原子性
tips_db:meta_update(META_KEY.version, wanxiang.version)
tips_db:meta_update(META_KEY.user_file_hash, user_file_hash)
tips_db:meta_update(META_KEY.disabled_types, disabled_types_str)
end
-- 关闭并以只读模式重新打开
tips_db:close()
tips_db:open_read_only()
end
---从数据库中查询 tips
---@param keys string | string[] 接受一个字符串或一个字符串数组作为键,使用数组时会挨个查询,直到获得有效值
---@return string | nil
function tips.get_tip(keys)
-- 输入归一化:如果输入是 string将其包装成单元素的 table
if type(keys) == 'string' then
keys = { keys }
end
for _, key in ipairs(keys) do
if key and key ~= "" then
local tip = tips_db:fetch(key)
if tip and #tip > 0 then
return tip
end
end
end
return nil
end
---@class Env
---@field current_tip string | nil 当前 tips 值
---@field last_prompt string 最后一次设置的 prompt 值
---@field tips_update_connection Connection
---tips prompt 处理
---@param context Context
---@param env Env
local function update_tips_prompt(context, env)
env.current_tip = nil
local is_tips_enabled = context:get_option("super_tips")
if not is_tips_enabled then return end
local segment = context.composition:back()
if not segment then return end
local cand = context:get_selected_candidate() or {}
if segment.selected_index == 0 then
env.current_tip = tips.get_tip({ context.input, cand.text })
else
env.current_tip = tips.get_tip(cand.text)
end
if env.current_tip ~= nil and env.current_tip ~= "" then
-- 有 tips 则直接设置 prompt
segment.prompt = "" .. env.current_tip .. ""
env.last_prompt = segment.prompt
elseif segment.prompt ~= "" and env.last_prompt == segment.prompt then
-- 没有 tips且当前 prompt 不为空,且是由 super_tips 设置的,则重置
segment.prompt = ""
env.last_prompt = segment.prompt
end
end
local P = {}
-- Processor按键触发上屏 (S)
---@param env Env
function P.init(env)
local config = env.engine.schema.config
tips.init(config)
P.tips_key = config:get_string("key_binder/tips_key")
-- 注册 tips 查找监听器
local context = env.engine.context
env.tips_update_connection = context.update_notifier:connect(
function(context)
update_tips_prompt(context, env)
end
)
end
function P.fini(env)
-- 清理连接
if env.tips_update_connection then
env.tips_update_connection:disconnect()
env.tips_update_connection = nil
end
end
---@param key KeyEvent
---@param env Env
---@return ProcessResult
function P.func(key, env)
local context = env.engine.context
local is_tips_enabled = context:get_option("super_tips")
if not is_tips_enabled then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 以下处理 tips 上屏逻辑
if not P.tips_key -- 未设置上屏键
or P.tips_key ~= key:repr() -- 或者当前按下的不是上屏键
or wanxiang.is_function_mode_active(context) -- 或者是功能模式不用上屏
or not env.current_tip or env.current_tip == "" -- 或匹配的 tips 为空/空字符串
then
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
---@type string 从 tips 内容中获取上屏文本
local commit_txt = env.current_tip:match("%s*(.*)%s*") -- 优先匹配常规的全角冒号
or env.current_tip:match(":%s*(.*)%s*") -- 没有匹配则回落到半角冒号
if commit_txt and #commit_txt > 0 then
env.engine:commit_text(commit_txt)
context:clear()
return wanxiang.RIME_PROCESS_RESULTS.kAccepted
end
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return P

6853
lua/tips/tips_show.txt Normal file

File diff suppressed because it is too large Load Diff

128
lua/tone_fallback.lua Normal file
View File

@@ -0,0 +1,128 @@
-- 欢迎使用万象拼音方案
-- @amzxyz
-- https://github.com/amzxyz/rime_wanxiang
-- 用来在声调辅助的时候当你输入 2 个数字的时候自动将声调替换为第二个数字,
-- 也就是说你发现输入错误声调你可以手动轮巡输入而不用回退删除直接输入下一个即可
-- 兼容小键盘输入中不回退
local wanxiang = require("wanxiang")
-- 将目标字符的连续段压缩为“最后一个字符”
local function compress_runs_keep_last(text)
local changed = false
local out = text:gsub('([:"<>7890])([:"<>7890]+)', function(_, tail)
changed = true
return tail:sub(-1)
end)
return out, changed
end
local function should_ignore(ctx)
return wanxiang.is_function_mode_active(ctx) or ctx.input == ""
end
-- 小键盘 keycode 判定0xFFB0 ~ 0xFFB9
local function is_kp_digit_keycode(kc)
return kc >= 0xFFB0 and kc <= 0xFFB9
end
---@class Env
---@field tone_state "idle"|"skip"|"compress"
---@field tone_fallback_update_connection Connection|nil
local P = {}
function P.init(env)
env.tone_state = "idle"
local ctx = env.engine and env.engine.context
if not ctx or not ctx.update_notifier then return end
env.tone_fallback_update_connection = ctx.update_notifier:connect(function(c)
if should_ignore(c) then
env.tone_state = "idle"
return
end
-- 只在当前按键对应的一次更新里消费 state
local state = env.tone_state or "idle"
env.tone_state = "idle" -- 立刻消费,避免“下一次才生效”
-- 小键盘数字:标记为 skip本次直接不压缩
if state == "skip" then
return
end
-- 非压缩状态:直接不动
if state ~= "compress" then
return
end
-- 压缩逻辑
local input = c.input
local caret = (c.caret_pos ~= nil) and c.caret_pos or #input
if caret < 0 then caret = 0 end
if caret > #input then caret = #input end
-- 仅处理光标左侧;右侧保持不变
local left = (caret > 0) and input:sub(1, caret) or ""
local right = (caret < #input) and input:sub(caret + 1) or ""
local left_new, changed = compress_runs_keep_last(left)
if not changed then return end
-- 只改左侧,避免干扰右侧;并精确设置 caret_pos
if caret > 0 then c:pop_input(caret) end
if #left_new > 0 then c:push_input(left_new) end
if c.caret_pos ~= nil then c.caret_pos = #left_new end
-- 右侧 right 不需处理Rime 会保持不变
end)
end
function P.fini(env)
if env.tone_fallback_update_connection then
env.tone_fallback_update_connection:disconnect()
env.tone_fallback_update_connection = nil
end
env.tone_state = "idle"
end
---@return ProcessResult
function P.func(key, env)
local ctx = env.engine.context
if should_ignore(ctx) then
env.tone_state = "idle"
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 小键盘数字:标记这次按键为 skip本轮 update_notifier 不压缩
local kc = key.keycode
if is_kp_digit_keycode(kc) then
env.tone_state = "skip"
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 主键盘数字 09标记为 compress
local r = key:repr() or ""
if r:match("^[0-9]$") then
env.tone_state = "compress"
-- 这里用“预测压缩是否会发生”来决定要不要告诉 Rime “我处理了这个按键”
local input = ctx.input or ""
local caret = (ctx.caret_pos ~= nil) and ctx.caret_pos or #input
if caret < 0 then caret = 0 end
if caret > #input then caret = #input end
local left = (caret > 0) and input:sub(1, caret) or ""
local _, changed = compress_runs_keep_last(left)
return changed and wanxiang.RIME_PROCESS_RESULTS.kAccepted
or wanxiang.RIME_PROCESS_RESULTS.kNoop
end
-- 其它按键:不触发压缩,也不跳过
env.tone_state = "idle"
return wanxiang.RIME_PROCESS_RESULTS.kNoop
end
return P

32
lua/unicode.lua Normal file
View File

@@ -0,0 +1,32 @@
-- Unicode
-- 示例:输入 U62fc 得到「拼」
-- 触发前缀默认为 recognizer/patterns/unicode 的第 2 个字符,即 U
-- 2024.02.26: 限定编码最大值
local function unicode(input, seg, env)
-- 获取 recognizer/patterns/unicode 的第 2 个字符作为触发前缀
env.unicode_keyword = env.unicode_keyword or
env.engine.schema.config:get_string('recognizer/patterns/unicode'):sub(2, 2)
if seg:has_tag("unicode") and env.unicode_keyword ~= '' and input:sub(1, 1) == env.unicode_keyword then
local ucodestr = input:match(env.unicode_keyword .. "(%x+)")
if ucodestr and #ucodestr > 1 then
local segment = env.engine.context.composition:back()
-- 设置标签
segment.tags = segment.tags + Set({ "unicode" })
local code = tonumber(ucodestr, 16)
if code > 0x10FFFF then
yield(Candidate("unicode", seg.start, seg._end, "数值超限!", ""))
return
end
local text = utf8.char(code)
yield(Candidate("unicode", seg.start, seg._end, text, string.format("U%x", code)))
if code < 0x10000 then
for i = 0, 15 do
local text = utf8.char(code * 16 + i)
yield(Candidate("unicode", seg.start, seg._end, text, string.format("U%x~%x", code, i)))
end
end
end
end
end
return unicode

16
lua/version_display.lua Normal file
View File

@@ -0,0 +1,16 @@
local wanxiang = require("wanxiang")
--输入'/wx',显示万象项目地址和当前版本号
local function translator(input, seg, env)
if input == "/wx" then
-- 候选1: GitHub 网址
yield(Candidate("url", seg.start, seg._end, "https://github.com/amzxyz/rime_wanxiang", ""))
-- 候选2: CNB 网址
yield(Candidate("url", seg.start, seg._end, "https://cnb.cool/amzxyz/rime-wanxiang", ""))
-- 判断是否为专业版
local version_prefix = wanxiang.is_pro_scheme(env) and "增强版" or "标准版"
-- 候选3: 当前版本号(加上“增强版”或“标准版”前缀)
yield(Candidate("version", seg.start, seg._end, version_prefix .. wanxiang.version, ""))
end
end
return translator

710
lua/wanxiang.lua Normal file
View File

@@ -0,0 +1,710 @@
---@diagnostic disable: undefined-global
-- 万象的一些共用工具函数
local wanxiang = {}
-- x-release-please-start-version
wanxiang.version = "v13.6.3"
-- x-release-please-end
-- 全局内容
---@alias PROCESS_RESULT ProcessResult
wanxiang.RIME_PROCESS_RESULTS = {
kRejected = 0, -- 表示处理器明确拒绝了这个按键,停止处理链但不返回 true
kAccepted = 1, -- 表示处理器成功处理了这个按键,停止处理链并返回 true
kNoop = 2, -- 表示处理器没有处理这个按键,继续传递给下一个处理器
}
-- 整个生命周期内不变,缓存判断结果
local is_mobile_device = nil
-- 判断是否为手机设备
---@author amzxyz
---@return boolean
function wanxiang.is_mobile_device()
local function _is_mobile_device()
local dist = rime_api.get_distribution_code_name() or ""
local user_data_dir = rime_api.get_user_data_dir() or ""
local sys_dir = rime_api.get_shared_data_dir() or ""
-- 转换为小写以便比较
local lower_dist = dist:lower()
local lower_path = user_data_dir:lower()
local sys_lower_path = sys_dir:lower()
-- 主判断:常见移动端输入法
if lower_dist == "trime" or
lower_dist == "hamster" or
lower_dist == "hamster3" or
lower_dist == "squirrel" then
return true
end
-- 补充判断路径中包含移动设备特征很可以mac的运行逻辑和手机一球样
if lower_path:find("/android/") or
lower_path:find("/mobile/") or
lower_path:find("/sdcard/") or
lower_path:find("/data/storage/") or
lower_path:find("/storage/emulated/") or
lower_path:find("applications") or
lower_path:find("library") then
return true
end
-- 补充判断路径中包含移动设备特征很可以mac的运行逻辑和手机一球样
if sys_lower_path:find("applications") or
sys_lower_path:find("library") then
return true
end
-- 特定平台判断Android/Linux
if jit and jit.os then
local os_name = jit.os:lower()
if os_name:find("android") then
return true
end
end
-- 所有检查未通过则默认为桌面设备
return false
end
if is_mobile_device == nil then
is_mobile_device = _is_mobile_device()
end
return is_mobile_device
end
--- 检测是否为万象专业版
---@param env Env
---@return boolean
function wanxiang.is_pro_scheme(env)
-- local schema_name = env.engine.schema.schema_name
-- return schema_name:gsub("PRO$", "") ~= schema_name
return env.engine.schema.schema_id == "wanxiang_pro"
end
-- 以 `tag` 方式检测是否处于反查模式
function wanxiang.is_in_radical_mode(env)
local seg = env.engine.context.composition:back()
return seg and (
seg:has_tag("wanxiang_reverse")
) or false
end
---判断是否在命令模式
---@param context Context | nil
---@return boolean
function wanxiang.is_function_mode_active(context)
if not context or not context.composition or context.composition:empty() then
return false
end
local seg = context.composition:back()
if not seg then return false end
return seg:has_tag("number") or -- number_translator.lua 数字金额转换 R+数字
seg:has_tag("unicode") or -- unicode.lua 输出 Unicode 字符 U+小写字母或数字
--seg:has_tag("punct") or -- 标点符号 全角半角提示
seg:has_tag("calculator") or -- super_calculator.lua V键计算器
seg:has_tag("shijian") or -- shijian.lua /rq /sr 等与时间日期相关功能
seg:has_tag("Ndate") -- shijian.lua N日期功能
end
---判断文件是否存在
function wanxiang.file_exists(filename)
local f = io.open(filename, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
-- 判断字符是否为汉字
function wanxiang.IsChineseCharacter(text)
local codepoint = utf8.codepoint(text)
return
(codepoint >= 0x4E00 and codepoint <= 0x9FFF) -- Basic
or (codepoint >= 0x3400 and codepoint <= 0x4DBF) -- Ext A
or (codepoint >= 0x20000 and codepoint <= 0x2A6DF) -- Ext B
or (codepoint >= 0x2A700 and codepoint <= 0x2B73F) -- Ext C
or (codepoint >= 0x2B740 and codepoint <= 0x2B81F) -- Ext D
or (codepoint >= 0x2B820 and codepoint <= 0x2CEAF) -- Ext E
or (codepoint >= 0x2CEB0 and codepoint <= 0x2EBEF) -- Ext F
or (codepoint >= 0x30000 and codepoint <= 0x3134F) -- Ext G
or (codepoint >= 0x31350 and codepoint <= 0x323AF) -- Ext H
or (codepoint >= 0x2EBF0 and codepoint <= 0x2EE5F) -- Ext I
or (codepoint >= 0xF900 and codepoint <= 0xFAFF) -- Compatibility
or (codepoint >= 0x2F800 and codepoint <= 0x2FA1F) -- Compatibility Supplement
or (codepoint >= 0x2E80 and codepoint <= 0x2EFF) -- Radicals Supplement
or (codepoint >= 0x2F00 and codepoint <= 0x2FDF) -- Kangxi Radicals
end
---按照优先顺序获取文件:用户目录 > 系统目录
---@param filename string 相对路径
---@retur string | nil
function wanxiang.get_filename_with_fallback(filename)
local _path = filename:gsub("^/+", "") -- 去掉开头的斜杠
local user_path = rime_api.get_user_data_dir() .. '/' .. _path
if wanxiang.file_exists(user_path) then
return user_path
end
local shared_path = rime_api.get_shared_data_dir() .. '/' .. _path
if wanxiang.file_exists(shared_path) then
return shared_path
end
return nil
end
-- 按照优先顺序加载文件:用户目录 > 系统目录
---@param filename string 相对路径
---@retur file* | nil, function
function wanxiang.load_file_with_fallback(filename, mode)
mode = mode or "r" -- 默认读取模式
local _filename = wanxiang.get_filename_with_fallback(filename)
local file, err
local function close()
if not file then return end
file:close()
file = nil
end
if _filename then
file, err = io.open(_filename, mode)
end
return file, close, err
end
local USER_ID_DEFAULT = "unknown"
---作为「小狼毫」和「仓」 `rime_api.get_user_id()` 的一个 workaround
---详见:
---1. https://github.com/rime/weasel/pull/1649
---2. https://github.com/rime/librime/issues/1038
---@return string
function wanxiang.get_user_id()
local user_id = rime_api.get_user_id()
if user_id ~= USER_ID_DEFAULT then return user_id end
local user_data_dir = rime_api.get_user_data_dir()
local installation_path = user_data_dir .. "/installation.yaml"
local installation_file, _ = io.open(installation_path, "r")
if not installation_file then return user_id end
for line in installation_file:lines() do
local key, value = line:match('^([^#:]+):%s+"?([^"]%S+[^"])"?')
if key == "installation_id" then
user_id = value
break
end
end
installation_file:close()
return user_id
end
wanxiang.INPUT_METHOD_MARKERS = {
[""] = "pinyin", --全拼
[""] = "zrm", --自然码双拼
[""] = "flypy", --小鹤双拼
[""] = "mspy", --微软双拼
[""] = "sogou", --搜狗双拼
[""] = "abc", --智能abc双拼
[""] = "ziguang", --紫光双拼
[""] = "pyjj", --拼音加加
[""] = "gbpy", --国标双拼
[""] = "wxsp", --万象双拼
[""] = "zrlong", --自然龙
[""] = "hxlong", --汉心龙
[""] = "lxsq", --乱序17
[""] = "", -- 间接辅助标记:命中则额外返回 md="ⅲ"
}
local __input_type_cache = {} -- 缓存首个命中的 id兼容旧用法
local __input_md_cache = {} -- 新增:是否命中“ⅲ”(若命中则为 "ⅲ",否则为 nil
--- 根据 speller/algebra 中的特殊符号返回输入类型:
--- - 若未命中“ⅲ”,只返回 id保持旧行为
--- - 若命中“ⅲ”返回两个值id, "ⅲ"
---@param env Env
---@return string -- id
---@return string|nil -- md仅在命中“ⅲ”时返回 "ⅲ"
function wanxiang.get_input_method_type(env)
local schema_id = env.engine.schema.schema_id or "unknown"
-- 命中缓存则按是否有 md 决定返回 1 个或 2 个值
local cached_id = __input_type_cache[schema_id]
if cached_id then
local cached_md = __input_md_cache[schema_id]
if cached_md then
return cached_id, cached_md -- 返回两个值id, "ⅲ"
else
return cached_id -- 只返回 id
end
end
local cfg = env.engine.schema.config
local result_id = "unknown"
local md = nil -- 只有命中“ⅲ”时设为 "ⅲ"
local n = cfg:get_list_size("speller/algebra")
for i = 0, n - 1 do
local s = cfg:get_string(("speller/algebra/@%d"):format(i))
if s then
-- 不提前返回:需要把整段都扫描完,才能知道是否命中“ⅲ”
for symbol, id in pairs(wanxiang.INPUT_METHOD_MARKERS) do
if s:find(symbol, 1, true) then
if symbol == "" or id == "" then
md = "" -- 记录辅助标记
else
if result_id == "unknown" then
result_id = id -- 只记录第一个“正常映射”的 id
end
end
end
end
end
end
-- 写缓存
__input_type_cache[schema_id] = result_id
__input_md_cache[schema_id] = md -- 命中则为 "ⅲ",否则为 nil
-- 返回:命中“ⅲ”→两个值;否则一个值
if md then
return result_id, md
else
return result_id
end
end
wanxiang.tone_matrix = {
["a"] = {1,2,3,4},
["ai"] = {1,2,3,4},
["an"] = {1,2,3,4},
["ang"] = {1,2,3,4},
["ao"] = {1,2,3,4},
["ba"] = {1,2,3,4},
["bai"] = {1,2,3,4},
["ban"] = {1,3,4},
["bang"] = {1,3,4},
["bao"] = {1,2,3,4},
["bei"] = {1,3,4},
["ben"] = {1,3,4},
["beng"] = {1,2,3,4},
["bi"] = {1,2,3,4},
["bian"] = {1,3,4},
["biang"] = {2},
["biao"] = {1,2,3,4},
["bie"] = {1,2,3,4},
["bin"] = {1,4},
["bing"] = {1,3,4},
["bo"] = {1,2,3,4},
["bu"] = {1,2,3,4},
["bun"] = {1},
["ca"] = {1,3,4},
["cai"] = {1,2,3,4},
["can"] = {1,2,3,4},
["cang"] = {1,2,4},
["cao"] = {1,2,3,4},
["ce"] = {4},
["cei"] = {4},
["cen"] = {1,2},
["ceng"] = {1,2,4},
["ceok"] = {},
["ceon"] = {},
["cha"] = {1,2,3,4},
["chai"] = {1,2,3,4},
["chan"] = {1,2,3,4},
["chang"] = {1,2,3,4},
["chao"] = {1,2,3,4},
["che"] = {1,2,3,4},
["chen"] = {1,2,3,4},
["cheng"] = {1,2,3,4},
["chi"] = {1,2,3,4},
["chong"] = {1,2,3,4},
["chou"] = {1,2,3,4},
["chu"] = {1,2,3,4},
["chua"] = {1,3,4},
["chuai"] = {1,2,3,4},
["chuan"] = {1,2,3,4},
["chuang"] = {1,2,3,4},
["chui"] = {1,2,4},
["chun"] = {1,2,3},
["chuo"] = {1,4},
["ci"] = {1,2,3,4},
["cong"] = {1,2,3,4},
["cou"] = {1,2,3,4},
["cu"] = {1,2,3,4},
["cuan"] = {1,2,4},
["cui"] = {1,3,4},
["cun"] = {1,2,3,4},
["cuo"] = {1,2,3,4},
["da"] = {1,2,3,4},
["dai"] = {1,3,4},
["dan"] = {1,3,4},
["dang"] = {1,3,4},
["dao"] = {1,2,3,4},
["de"] = {1,2},
["dei"] = {1,3},
["den"] = {4},
["deng"] = {1,3,4},
["di"] = {1,2,3,4},
["dia"] = {3},
["dian"] = {1,2,3,4},
["diao"] = {1,3,4},
["die"] = {1,2,3,4},
["dim"] = {2},
["din"] = {4},
["ding"] = {1,3,4},
["diu"] = {1},
["dong"] = {1,3,4},
["dou"] = {1,2,3,4},
["du"] = {1,2,3,4},
["duan"] = {1,3,4},
["dui"] = {1,3,4},
["dun"] = {1,3,4},
["duo"] = {1,2,3,4},
["e"] = {1,2,3,4},
["ei"] = {1,2,3,4},
["en"] = {1,3,4},
["eng"] = {1},
["er"] = {2,3,4},
["fa"] = {1,2,3,4},
["fan"] = {1,2,3,4},
["fang"] = {1,2,3,4},
["fei"] = {1,2,3,4},
["fen"] = {1,2,3,4},
["feng"] = {1,2,3,4},
["fiao"] = {4},
["fo"] = {2},
["fou"] = {1,2,3},
["fu"] = {1,2,3,4},
["ga"] = {1,2,3,4},
["gai"] = {1,3,4},
["gan"] = {1,3,4},
["gang"] = {1,3,4},
["gao"] = {1,3,4},
["ge"] = {1,2,3,4},
["gei"] = {3},
["gen"] = {1,2,3,4},
["geng"] = {1,3,4},
["gong"] = {1,3,4},
["gou"] = {1,3,4},
["gu"] = {1,2,3,4},
["gua"] = {1,2,3,4},
["guai"] = {1,3,4},
["guan"] = {1,3,4},
["guang"] = {1,3,4},
["gui"] = {1,3,4},
["gun"] = {3,4},
["guo"] = {1,2,3,4},
["ha"] = {1,2,3,4},
["hai"] = {1,2,3,4},
["han"] = {1,2,3,4},
["hang"] = {1,2,4},
["hao"] = {1,2,3,4},
["he"] = {1,2,3,4},
["hei"] = {1},
["hen"] = {2,3,4},
["heng"] = {1,2,4},
["hong"] = {1,2,3,4},
["hou"] = {1,2,3,4},
["hu"] = {1,2,3,4},
["hua"] = {1,2,4},
["huai"] = {2,4},
["huan"] = {1,2,3,4},
["huang"] = {1,2,3,4},
["hui"] = {1,2,3,4},
["hun"] = {1,2,3,4},
["huo"] = {1,2,3,4},
["ji"] = {1,2,3,4},
["jia"] = {1,2,3,4},
["jian"] = {1,3,4},
["jiang"] = {1,3,4},
["jiao"] = {1,2,3,4},
["jie"] = {1,2,3,4},
["jin"] = {1,3,4},
["jing"] = {1,3,4},
["jiong"] = {1,3,4},
["jiu"] = {1,2,3,4},
["ju"] = {1,2,3,4},
["juan"] = {1,3,4},
["jue"] = {1,2,3,4},
["jun"] = {1,3,4},
["ka"] = {1,3},
["kai"] = {1,3,4},
["kan"] = {1,3,4},
["kang"] = {1,2,3,4},
["kao"] = {1,3,4},
["ke"] = {1,2,3,4},
["kei"] = {1},
["ken"] = {1,3,4},
["keng"] = {1,3},
["kong"] = {1,3,4},
["kou"] = {1,3,4},
["ku"] = {1,2,3,4},
["kua"] = {1,3,4},
["kuai"] = {2,3,4},
["kuan"] = {1,3,4},
["kuang"] = {1,2,3,4},
["kui"] = {1,2,3,4},
["kun"] = {1,3,4},
["kuo"] = {4},
["la"] = {1,2,3,4},
["lai"] = {2,3,4},
["lan"] = {2,3,4},
["lang"] = {1,2,3,4},
["lao"] = {1,2,3,4},
["le"] = {1,4},
["lei"] = {1,2,3,4},
["leng"] = {1,2,3,4},
["li"] = {1,2,3,4},
["lia"] = {3},
["lian"] = {2,3,4},
["liang"] = {1,2,3,4},
["liao"] = {1,2,3,4},
["lie"] = {1,2,3,4},
["lin"] = {1,2,3,4},
["ling"] = {2,3,4},
["liu"] = {1,2,3,4},
["lo"] = {},
["long"] = {1,2,3,4},
["lou"] = {1,2,3,4},
["lu"] = {1,2,3,4},
["luan"] = {2,3,4},
["lun"] = {1,2,3,4},
["luo"] = {1,2,3,4},
["lv"] = {2,3,4},
["lve"] = {4},
["ma"] = {1,2,3,4},
["mai"] = {2,3,4},
["man"] = {1,2,3,4},
["mang"] = {1,2,3,4},
["mao"] = {1,2,3,4},
["me"] = {1,4},
["mei"] = {2,3,4},
["men"] = {1,2,4},
["meng"] = {1,2,3,4},
["mi"] = {1,2,3,4},
["mian"] = {2,3,4},
["miao"] = {1,2,3,4},
["mie"] = {1,2,4},
["min"] = {2,3},
["ming"] = {2,3,4},
["miu"] = {3,4},
["mo"] = {1,2,3,4},
["mou"] = {1,2,3,4},
["mu"] = {2,3,4},
[""] = {},
["n"] = {2,3,4},
["na"] = {1,2,3,4},
["nai"] = {2,3,4},
["nan"] = {1,2,3,4},
["nang"] = {1,2,3,4},
["nao"] = {1,2,3,4},
["ne"] = {2,4},
["nei"] = {2,3,4},
["nen"] = {4},
["neng"] = {2,3,4},
["ng"] = {2,3,4},
["ni"] = {1,2,3,4},
["nian"] = {1,2,3,4},
["niang"] = {2,3,4},
["niao"] = {3,4},
["nie"] = {1,2,3,4},
["nin"] = {2,3},
["ning"] = {2,3,4},
["niu"] = {1,2,3,4},
["nong"] = {2,3,4},
["nou"] = {2,3,4},
["nu"] = {2,3,4},
["nuan"] = {2,3,4},
["nun"] = {2},
["nuo"] = {2,3,4},
["nv"] = {2,3,4},
["nve"] = {4},
["o"] = {1,2,3,4},
["ou"] = {1,2,3,4},
["pa"] = {1,2,3,4},
["pai"] = {1,2,3,4},
["pan"] = {1,2,3,4},
["pang"] = {1,2,3,4},
["pao"] = {1,2,3,4},
["pei"] = {1,2,3,4},
["pen"] = {1,2,3,4},
["peng"] = {1,2,3,4},
["pi"] = {1,2,3,4},
["pian"] = {1,2,3,4},
["piao"] = {1,2,3,4},
["pie"] = {1,3,4},
["pin"] = {1,2,3,4},
["ping"] = {1,2,4},
["po"] = {1,2,3,4},
["pou"] = {1,2,3},
["pu"] = {1,2,3,4},
["qi"] = {1,2,3,4},
["qia"] = {1,2,3,4},
["qian"] = {1,2,3,4},
["qiang"] = {1,2,3,4},
["qiao"] = {1,2,3,4},
["qie"] = {1,2,3,4},
["qin"] = {1,2,3,4},
["qing"] = {1,2,3,4},
["qiong"] = {1,2,4},
["qiu"] = {1,2,3,4},
["qu"] = {1,2,3,4},
["quan"] = {1,2,3,4},
["que"] = {1,2,4},
["qun"] = {1,2,3},
["ran"] = {2,3,4},
["rang"] = {1,2,3,4},
["rao"] = {2,3,4},
["re"] = {2,3,4},
["ren"] = {2,3,4},
["reng"] = {1,2},
["ri"] = {4},
["rong"] = {2,3,4},
["rou"] = {2,3,4},
["ru"] = {1,2,3,4},
["rua"] = {2},
["ruan"] = {2,3,4},
["rui"] = {2,3,4},
["run"] = {2,3,4},
["ruo"] = {2,4},
["sa"] = {1,2,3,4},
["sai"] = {1,3,4},
["san"] = {1,3,4},
["sang"] = {1,3,4},
["sao"] = {1,3,4},
["se"] = {1,4},
["sen"] = {1,3},
["seng"] = {1,4},
["sha"] = {1,2,3,4},
["shai"] = {1,3,4},
["shan"] = {1,2,3,4},
["shang"] = {1,3,4},
["shao"] = {1,2,3,4},
["she"] = {1,2,3,4},
["shei"] = {2},
["shen"] = {1,2,3,4},
["sheng"] = {1,2,3,4},
["shi"] = {1,2,3,4},
["shou"] = {1,2,3,4},
["shu"] = {1,2,3,4},
["shua"] = {1,3,4},
["shuai"] = {1,3,4},
["shuan"] = {1,4},
["shuang"] = {1,3,4},
["shui"] = {2,3,4},
["shun"] = {3,4},
["shuo"] = {1,4},
["si"] = {1,2,3,4},
["song"] = {1,2,3,4},
["sou"] = {1,3,4},
["su"] = {1,2,3,4},
["suan"] = {1,3,4},
["sui"] = {1,2,3,4},
["sun"] = {1,3,4},
["suo"] = {1,2,3,4},
["ta"] = {1,2,3,4},
["tai"] = {1,2,3,4},
["tan"] = {1,2,3,4},
["tang"] = {1,2,3,4},
["tao"] = {1,2,3,4},
["te"] = {4},
["tei"] = {1},
["teng"] = {1,2,4},
["ti"] = {1,2,3,4},
["tian"] = {1,2,3,4},
["tiao"] = {1,2,3,4},
["tie"] = {1,2,3,4},
["tii"] = {2},
["ting"] = {1,2,3,4},
["tong"] = {1,2,3,4},
["tou"] = {1,2,3,4},
["tu"] = {1,2,3,4},
["tuan"] = {1,2,3,4},
["tui"] = {1,2,3,4},
["tun"] = {1,2,3,4},
["tuo"] = {1,2,3,4},
["wa"] = {1,2,3,4},
["wai"] = {1,3,4},
["wan"] = {1,2,3,4},
["wang"] = {1,2,3,4},
["wei"] = {1,2,3,4},
["wen"] = {1,2,3,4},
["weng"] = {1,3,4},
["wo"] = {1,3,4},
["wu"] = {1,2,3,4},
["xi"] = {1,2,3,4},
["xia"] = {1,2,3,4},
["xian"] = {1,2,3,4},
["xiang"] = {1,2,3,4},
["xiao"] = {1,2,3,4},
["xie"] = {1,2,3,4},
["xin"] = {1,2,3,4},
["xing"] = {1,2,3,4},
["xiong"] = {1,2,4},
["xiu"] = {1,2,3,4},
["xu"] = {1,2,3,4},
["xuan"] = {1,2,3,4},
["xue"] = {1,2,3,4},
["xun"] = {1,2,4},
["ya"] = {1,2,3,4},
["yan"] = {1,2,3,4},
["yang"] = {1,2,3,4},
["yao"] = {1,2,3,4},
["ye"] = {1,2,3,4},
["yi"] = {1,2,3,4},
["yin"] = {1,2,3,4},
["ying"] = {1,2,3,4},
["yo"] = {1},
["yong"] = {1,2,3,4},
["you"] = {1,2,3,4},
["yu"] = {1,2,3,4},
["yuan"] = {1,2,3,4},
["yue"] = {1,3,4},
["yun"] = {1,2,3,4},
["za"] = {1,2,3},
["zai"] = {1,3,4},
["zan"] = {1,2,3,4},
["zang"] = {1,3,4},
["zao"] = {1,2,3,4},
["ze"] = {2,4},
["zei"] = {2},
["zen"] = {1,3,4},
["zeng"] = {1,3,4},
["zha"] = {1,2,3,4},
["zhai"] = {1,2,3,4},
["zhan"] = {1,3,4},
["zhang"] = {1,3,4},
["zhao"] = {1,2,3,4},
["zhe"] = {1,2,3,4},
["zhei"] = {4},
["zhen"] = {1,2,3,4},
["zheng"] = {1,3,4},
["zhi"] = {1,2,3,4},
["zhong"] = {1,3,4},
["zhou"] = {1,2,3,4},
["zhu"] = {1,2,3,4},
["zhua"] = {1,3},
["zhuai"] = {1,3,4},
["zhuan"] = {1,3,4},
["zhuang"] = {1,3,4},
["zhui"] = {1,3,4},
["zhun"] = {1,3,4},
["zhuo"] = {1,2,4},
["zi"] = {1,2,3,4},
["zong"] = {1,3,4},
["zou"] = {1,3,4},
["zu"] = {1,2,3,4},
["zuan"] = {1,3,4},
["zui"] = {1,2,3,4},
["zun"] = {1,3,4},
["zuo"] = {1,2,3,4},
["ḿ"] = {2},
}
return wanxiang

View File

@@ -0,0 +1,27 @@
{
"name": "Chinese to English",
"segmentation": {
"type": "mmseg",
"dict": {
"type": "text",
"file": "chinese_english.txt"
}
},
"conversion_chain": [
{
"dict": {
"type": "group",
"dicts": [
{
"type": "text",
"file": "chinese_english.txt"
},
{
"type": "text",
"file": "english_chinese.txt"
}
]
}
}
]
}

54171
opencc/chinese_english.txt Normal file

File diff suppressed because it is too large Load Diff

27
opencc/emoji.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "Chinese to Emoji",
"segmentation": {
"type": "mmseg",
"dict": {
"type": "text",
"file": "emoji.txt"
}
},
"conversion_chain": [
{
"dict": {
"type": "group",
"dicts": [
{
"type": "text",
"file": "emoji.txt"
},
{
"type": "text",
"file": "others.txt"
}
]
}
}
]
}

4910
opencc/emoji.txt Normal file

File diff suppressed because it is too large Load Diff

43787
opencc/english_chinese.txt Normal file

File diff suppressed because it is too large Load Diff

1335
opencc/others.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/refs/heads/main/schemas/config.json",
"bootstrap-sha": "3bc6a28c37385645de3e7a27e3f75faace624294",
"release-type": "simple",
"packages": {
".": {
"release-type": "simple",
"extra-files": [
"lua/wanxiang.lua"
],
"changelog-sections": [
{
"type": "feat",
"section": "✨ 新特性"
},
{
"type": "dict",
"section": "📚 词库更新"
},
{
"type": "perf",
"section": "🔥 性能优化"
},
{
"type": "fix",
"section": "🐛 Bug 修复"
},
{
"type": "refactor",
"section": "💅 重构"
},
{
"type": "docs",
"section": "📖 文档"
},
{
"type": "chore",
"section": "🏡 杂项"
},
{
"type": "ci",
"section": "🤖 持续集成"
}
]
}
}
}

1
version.txt Normal file
View File

@@ -0,0 +1 @@
13.6.3

24
wanxiang.dict.yaml Normal file
View File

@@ -0,0 +1,24 @@
# Rime dictionary
# encoding: utf-8
#
# rime配置的部署位置
# ~/.local/share/fcitx5/rime 或者 ~/.config/ibus/rime (Linux)
# ~/Library/Rime (Mac OS)
# %APPDATA%\Rime (Windows)
#
#
---
name: wanxiang
version: "LTS"
sort: by_weight #字典初始排序可選original或by_weight
use_preset_vocabulary: false
import_tables:
- dicts/zi #字表,包含了所有带拼音的汉字
- dicts/jichu #基础词库2-3字词汇
- dicts/lianxiang #联想词库5字以上词汇多用于输入前半段第二候选可以出来整段
- dicts/cuoyin #错音错字支持错音和错字输入的兼容同时供超级注释lua使用会在输入错误音节打出的时候给予提示
- dicts/duoyin #兼容词库,是基础词库的扩充,收录了多场景多种读音的词组
- dicts/shici #诗词
- dicts/diming #地名
...

641
wanxiang.schema.yaml Normal file
View File

@@ -0,0 +1,641 @@
# Rime schema
# encoding: utf-8
# 方案说明
schema:
schema_id: wanxiang
name: 万象拼音
version: "LTS"
author:
- amzxyz
description: |
请勾选【万象拼音】以启用,万象拼音标准版本,带声调的词库,支持语法模型,全拼、简拼、整句、声调辅助筛选,拥有超越大厂的输入体验!
【文本框输入:/pinyin全拼/zrm自然码,/flypy小鹤/mspy,/sogou,/pyjj等详见README.md】
dependencies:
- wanxiang_mixedcode #中英文混合词汇
- wanxiang_reverse # 部件拆字,反查及辅码
# 开关
# reset: 默认状态。注释掉后,切换窗口时不会重置到默认状态。
# states: 方案选单显示的名称。可以注释掉,仍可以通过快捷键切换。
# abbrev: 默认的缩写取 states 的第一个字符abbrev 可自定义一个字符
switches:
- name: ascii_mode # 中英输入状态
states: [ 中文, 英文 ]
- name: ascii_punct # 中英标点,可以在中文输入状态输入英文符号
states: [ 中标, 英标 ]
- name: full_shape #全角、半角字符输出
states: [ 半角, 全角 ]
- name: emoji #候选出现emoji滤镜会显示在相应的候选后面万象侧重于tips提示避免候选被占用因此默认为reset: 0归属opencc emoji滤镜
states: [表情关, 表情开]
- name: chinese_english #候选进入翻译模式滤镜会显示在相应的候选后面万象侧重于tips提示避免候选被占用归属opencc 翻译滤镜
states: [ 翻译关, 翻译开 ]
- options: [ raw_input, tone_display, full_pinyin ] #开启后在输入编码的位置实时转换为带声调全拼或者不带声调全拼不开启则采用系统配置原始编码影响的是preedit_format,归属super_preedit.lua
states: [ 原编码, 有声调, 无声调 ]
# reset: 2 #对于开关组从0开始数第几个就reset几可设为默认
- options: [ s2s, s2t, s2hk, s2tw ] # 简繁转换开关组,可以在一个空选项和多个实际“- simplifier@s2hk”引入的项目之前切换这是一个开关组你可以将其中任意一个s2s等设置为toggle快捷键多次按下将轮询
states: [ 简体, 通繁, 港繁, 臺繁 ]
- name: tone_hint #开启后在候选的注释里面实时显示全拼声调不开启则采用系统配置影响的是comment_format归属super_comment.lua
states: [ 读音关, 读音开 ]
- name: super_tips #开启后在输入编码后面的提示区显示实时的提示数据受tips数据库影响表情、翻译、车牌、符号等对应关系数据并可实现句号上屏不开启则默认影响的是segment.prompt参数归属super_tips.lua
states: [ 提示关, 提示开 ]
reset: 1
- name: charset_filter #字符集过滤默认开启8105通规显示即小字集可通过开关实时开启全字集快捷键配套ctrl+g,归属super_filter.lua
states: [ 小字集, 大字集 ]
reset: 1
- name: char_priority #多体现在编码重合但候选有单字或者多字的情况`引导的辅码查词时是否单字优先全拼常见类似于特定编码情况下、反查状态下的调序能力。归属super_lookup.lua
states: [词组先, 单字先]
- options: [ mixed, zh_only, en_only ]
states: [ 混合输入, 仅中文, 仅英文 ]
# 输入引擎
engine:
processors:
- lua_processor@*select_character #以词定字,默认左中括号上屏一个词的前一个字,右中括号上屏一个词的后一个字
- lua_processor@*partial_commit #通过ctrl+1~0局部提交10个字以内的句子的前几个字一般为正确的前几个使用时要遵循合理的分词结构能促进后续编码打出正确的词汇
- lua_processor@*letter_selector #在N模式R模式下输入数字被视为编码那么如何上屏呢现在除了方向键还提供qwertyuio对照1-9来选词
- lua_processor@*quick_symbol_text #快符引导以及重复上屏配合quick_symbol_text顶层配置清单定义扩展按键
- lua_processor@*super_tips #超级提示模块:表情、简码、翻译、化学式、等等靠你想象
- lua_processor@*tone_fallback #声调辅助回退,当你输入声调数字错误时,继续输入正确的而不用回退删除
- lua_processor@*super_sequence*P #手动排序,高亮候选 ctrl+j左移动 ctrl+k 右移动 ctrl+l 移除位移 ctrl+p 置顶
- lua_processor@*limit_repeated #用于限制最大候选长度以及最大重复输入声母编码长度,避免性能异常
- lua_processor@*backspace_limit #防止连续 Backspace 在编码为空时删除已上屏内容
- lua_processor@*kp_number_processor #管理小键盘的处理逻辑,有输入中数字不上屏和数字一直不上屏设置可选
- ascii_composer #处理英文模式及中英文切换
- recognizer #与 matcher 搭配,处理符合特定规则的输入码,如网址、反查等 tags
- key_binder #在特定条件下将按键绑定到其他按键,如重定义逗号、句号为候选翻页、开关快捷键等
- lua_processor@*key_binder #绑定按键扩展能力,支持正则扩展将按键生效情景更加细化
- speller #拼写处理器,接受字符按键,编辑输入
- punctuator #符号处理器,将单个字符按键直接映射为标点符号或文字
- selector #选字处理器,处理数字选字键〔可以换成别的哦〕、上、下候选定位、换页
- navigator #处理输入栏内的光标移动
- express_editor #编辑器,处理空格、回车上屏、回退键
segmentors:
- ascii_segmentor #标识英文段落〔譬如在英文模式下〕字母直接上屛
- matcher #配合 recognizer 标识符合特定规则的段落,如网址、反查等,加上特定 tag
- abc_segmentor #标识常规的文字段落,加上 abc 这个 tag
- affix_segmentor@wanxiang_reverse #反查 tag
- affix_segmentor@add_user_dict #自造词tag
- punct_segmentor #标识符号段落〔键入标点符号用〕加上 punct 这个 tag
- fallback_segmentor #标识其他未标识段落必须放在最后帮助tag模式切换后回退重新处理
translators:
- punct_translator #配合 punct_segmentor 转换标点符号
- script_translator #脚本翻译器,用于拼音、粤拼等基于音节表的输入方案
- lua_translator@*version_display #输入'/wx',显示万象项目网址和当前版本号
- lua_translator@*set_schema #输入'/zrm',快速切换为自然码双拼, /flypy→小鹤双拼 /mspy→微软双拼 /zrm→自然码 /sogou→搜狗双拼 /abc→智能ABC /ziguang→紫光双拼 /pyjj→拼音加加 /gbpy→国标双拼 /lxsq→乱序17 /pinyin→全拼
- lua_translator@*shijian #农历、日期、节气、节日、时间、周、问候模板等等,触发清单看下文
- lua_translator@*unicode #通过输入大写U引导并输入Unicode编码获得汉字输出
- lua_translator@*number_translator #数字、金额大写通过输入大写R1234获得候选输出
- lua_translator@*super_calculator #超级计算器Lua内查看高级用法
- lua_translator@*input_statistics #一个输入统计的脚本,以日、周、月、年等维度的统计
- table_translator@custom_phrase #自定义短语 custom_phrase.txt用于置顶自定义编码候选词
- table_translator@chengyu #简码成语词汇表导入
- table_translator@wanxiang_mixedcode #中英等混合词汇表导入
- table_translator@wanxiang_reverse #挂接部件组字和笔画反查
- script_translator@add_user_dict #按需自造词
- script_translator@user_dict_set #使用自造词
filters:
- reverse_lookup_filter@radical_reverse_lookup #部件拆字滤镜放在super_comment前面进一步被超级注释处理以获得拼音编码的提示
- lua_filter@*auto_phrase #无感造词,关闭调频的时候将汉字写入次翻译器,当没有英文候选的时候追加\上屏可完成英文造词
- lua_filter@*super_comment_preedit #超级注释模块、超级preedit支持错词提示、辅助码显示部件组字读音注释有声调、无声调全拼编码的转换支持个性化配置和关闭相应的功能详情搜索super_comment_preedit进行详细配置
- simplifier@emoji #Emoji滤镜
- simplifier@s2t #简繁切换通繁
- simplifier@s2tw #简繁切换台繁
- simplifier@s2hk #简繁切换港繁
- simplifier@chinese_english #中英翻译滤镜
- lua_filter@*super_sequence*F #手动排序,对高亮候选 ctrl+j左移动 ctrl+k 右移动 ctrl+0 移除位移
- lua_filter@*super_filter #功能太多详见Lua文件
- lua_filter@*super_lookup #字词输入中反查辅助筛选
- uniquifier # 去重
grammar:
language: wanxiang-lts-zh-hans
collocation_max_length: 8 #命中的最长词组
collocation_min_length: 2 #命中的最短词组搭配词频健全的词库时候应当最小值设为3避开2字高频词
collocation_penalty: -10 #默认-12 对常见搭配词组施加的惩罚值。较高的负值会降低这些搭配被选中的概率,防止过于频繁地出现某些固定搭配。
non_collocation_penalty: -17 #默认-12 对非搭配词组施加的惩罚值。较高的负值会降低非搭配词组被选中的概率,避免不合逻辑或不常见的词组组合。
weak_collocation_penalty: -24 #默认-24 对弱搭配词组施加的惩罚值。保持默认值通常是为了有效过滤掉不太常见但仍然合理的词组组合。
rear_penalty: -18 #默认-18 对词组中后续词语的位置施加的惩罚值。较高的负值会降低某些词语在句子后部出现的概率,防止句子结构不自然。
super_comment: # 超级注释模块,子项配置 true 开启false 关闭
candidate_length: 2 # 候选词辅助码提醒的生效长度0为关闭 但同时清空其它,应当使用上面开关来处理
corrector_type: "comment" # 随意更换左右括号,比如"comment" 不加括号为无括号comment占位不能动
chaifen: "chaifen" # 随意更换左右括号,比如"chaifen" 不加括号为无括号chaifen占位不能动
# Tips 配置项
tips:
# 禁用的 tips 类型,初始化 tips 数据库的时候会直接忽略相关规则,修改部署后生效
# 可选项为:偏旁,符号,化学式,时间,符号,组字,翻译,表情,货币,车牌
disabled_types: []
#在8105基础上你可以通过黑白名单微调你自己的字符集过滤清单主数据库位于lua/charset.bin不可编辑
charsetlist: []
charsetblacklist: []
#shijian:仅仅作为提示使用编码已经写死引导键可以在key_binder下修改前缀
#时间osj 或者 /sj
#日期orq 或者 /rq
#农历onl 或者 /nl
#星期oxq 或者 /xq
#今年第几周oww 或者 /ww
#节气ojq 或者 /jq
#日期+时间odt 或者 /dt
#时间戳ott 或者 /tt
#大写N日期N20250315 或者N0312不带年
#节日ojr 或者 /jr
#问候模板:/day 或者 oday
# 通用日期时间格式化函数(供 /rq、/sj、/dt、N0101、N20150101 场景复用)
# 支持转义:
# \X —— 转义单个字符 X按字面量输出如 \Y \m \H 等)
# [[...]] —— 区块整体按字面量输出
#
# 约定占位符:
# 【日期】
# Y 四位年份 0000-9999 例2025
# y 两位年份 00-99 例25
# m 月(前导零) 01-12 例02
# n 月(不带前导零) 1-12 例2
# d 日(前导零) 01-31 例09
# j 日(不带前导零) 1-31 例9
#
# 【时间】
# H 24小时前导零 00-23 例08
# G 24小时不带零 0-23 例8
# I 12小时前导零 01-12 例08
# l 12小时不带零 1-12 例8 (注意是小写 L
# M 分钟(前导零) 00-59 例05
# S 秒(前导零) 00-59 例09
# p am/pm小写 am / pm
# P AM/PM大写 AM / PM
# 【时区】
# O 带冒号格式 +08:00、-04:30、+05:45
# o 不带冒号格式 +0800、-0430、+0545
date_formats:
- "Y年m月d日"
- "Y-m-d"
- "Y/m/d"
- "Y.m.d"
- "Ymd"
- "Y年n月j日"
- "y年n月j日"
- "n月j日"
time_formats:
- "H:M"
- "H点M分"
- "H:M:S"
- "H时M分S秒"
- "下午I:M"
- "I:M P"
datetime_formats:
- "Y-m-d H:M:S"
- "Y-m-dTH:M:S O"
- "YmdHMS"
- "Y年m月d日 H点M分"
- "y/m/d I:M p"
#常规状态下数字转换成相应的字符由超级preedit接管
tone_preedit:
"7": "¹"
"8": "²"
"9": "³"
"0": "⁴"
# a/、单字母组合,触发预设编码自动上屏快符,支持将值设为"repeat" 以支持对应按键重复上屏功能custom>schema>lua最终合并键值
# 现在就支持26字母快符结合成对符号输入这边的压力小一些
quick_symbol_text:
trigger: "^([a-z])/$"
symkey:
q: "repeat"
w: ""
e: ""
r: ""
t: "~"
y: "·"
u: "『"
i: "』"
o: "〖"
p: "〗"
a: ""
s: "……"
d: "、"
f: "“"
g: "”"
h: ""
j: ""
k: "【"
l: "】"
z: "。”"
x: "?”"
c: "!”"
v: "——"
b: "%"
n: "《"
m: "》"
#通过在有候选的情况下,通过末尾检测到形如\a来触发为第一候选进行成对符号包裹例如nihao\c 候选[你好]
#trigger只能设置为单符号因为按下一次锁定第一候选按下映射开始包裹符号pro用户不能设置为/
#两个字符可以不用|默认前后分割,需要明确区分前后的使用|分割,可以有一侧为空,不可以使用多个||
paired_symbols:
#sort_window: 10
trigger: "\\" #(注意反斜杠这是转义写法\\使用时\单反斜杠即可)
mirror: true #包裹后完全替换第一候选true,原候选后移到第二false
symkey:
# ===== 基本括号与引号 =====
a: "[]" # 方括号
b: "【】" # 黑方头括号
c: "" # 双大括号 / 装饰括号
d: "" # 方头括号
e: "⟮⟯" # 小圆括号 / 装饰括号
f: "⟦⟧" # 双方括号 / 数学集群括号
g: "「」" # 直角引号
# h: 预留用于 Markdown 一级标题
i: "『』" # 双直角引号
j: "<>" # 尖括号
k: "《》" # 书名号(双)
l: "〈〉" # 书名号(单)
m: "" # 法文单书名号
n: "«»" # 法文双书名号
o: "⦅⦆" # 白圆括号
p: "⦇⦈" # 白方括号
q: "()" # 圆括号
r: "〖〗" # 花括号扩展 / 装饰括号
s: "" # 全角方括号
t: "⟨⟩" # 数学角括号
u: "〈〉" # 数学尖括号
v: "❰❱" # 装饰角括号
w: "" # 全角圆括号
x: "" # 全角花括号
y: "⟪⟫" # 双角括号
z: "{}" # 花括号
# ===== 扩展括号族 / 引号 =====
dy: "''" # 英文单引号
sy: "\"\"" # 英文双引号
zs: "“”" # 中文弯双引号
zd: "" # 中文弯单引号
fy: "``" # 反引号
# ===== 双字母括号族 =====
aa: "〚〛" # 双中括号
bb: "〘〙" # 双中括号(小)
cc: "〚〛" # 双中括号(重复,可用于 Lua 匹配)
dd: "" # 小圆括号装饰
ee: "❪❫" # 小圆括号装饰
ff: "❬❭" # 小尖括号装饰
gg: "⦉⦊" # 双弯方括号
ii: "⦍⦎" # 双弯方括号
jj: "⦏⦐" # 双弯方括号
kk: "⦑⦒" # 双弯方括号
ll: "" # 小尖括号装饰
mm: "⌈⌉" # 上取整 / 数学符号
nn: "⌊⌋" # 下取整 / 数学符号
oo: "⦗⦘" # 双方括号装饰(补齐)
pp: "⦙⦚" # 双方括号装饰(补齐)
qq: "⟬⟭" # 小双角括号
rr: "" # 花括号装饰
ss: "⌜⌝" # 数学上角符号
tt: "⌞⌟" # 数学下角符号
uu: "⸢⸣" # 装饰方括号
vv: "⸤⸥" # 装饰方括号
ww: "﹁﹂" # 中文书名号 / 注释引号
xx: "﹃﹄" # 中文书名号 / 注释引号
yy: "⌠⌡" # 数学 / 程序符号
zz: "⟅⟆" # 数学 / 装饰括号
# ===== Markdown / 标记 =====
md: "**|**" # Markdown 粗体
jc: "**|**" # 加粗
it: "__|__" # 斜体
st: "~~|~~" # 删除线
eq: "==|==" # 高亮
ln: "`|`" # 行内代码
cb: "```|```" # 代码块
qt: "> |" # 引用
ul: "- |" # 无序列表项
ol: "1. |" # 有序列表项
lk: "[|](url)" # 链接
im: "![|](img)" # 图片
h: "# |" # 一级标题
hh: "## |" # 二级标题
hhh: "### |" # 三级标题
hhhh: "#### |" # 四级标题
sp: "\\|" # 反斜杠转义
br: "| " # 换行
cm: "<!--|-->" # 注释
# ===== 运算与标记符 =====
pl: "++"
mi: "--"
sl: "//"
bs: "\\\\"
at: "@@"
dl: "$$"
pc: "%%"
an: "&&"
cr: "^^"
cl: "::"
sc: ";;"
ex: "!!"
qu: "??"
sb: "sb"
# Lua 配置:计算器触发关键字
calculator:
trigger: "V"
# 主翻译器,拼音
translator:
dictionary: wanxiang # 挂载主词库
# packs: user #导入根目录下名称为user.dict.yaml的自定义固定词典
#prism: wanxiang # 多方案共用一个词库时,为避免冲突,需要用 prism 指定一个名字。
enable_completion: true # 启用候选词补全
# user_dict: zrm.userdb # 用户词典的文件名称
# db_class: tabledb #开启后就不会产生wanxiang.userdb这样的文件夹会直接输出文本wanxiang.txt同时无法使用同步能力可设 tabledb文本或 userdb二进制
enable_user_dict: true # 是否开启自动调频,即开启用户词典
# enable_encoder: true #是否开启自动造词
# enable_sentence: false #是否开启自动造句
# enable_correction: false #是否开启自动纠错
# encode_commit_history: true # 预留历史上屏自动编码成词
core_word_length: 4 # >0 启用,按段学词 + 相邻段拼接
max_word_length: 7 # >0 启用,过长短语不记整词,只加元素权重
contextual_suggestions: false #模型用来开启词组权重预测,效果一般关闭
max_homophones: 5
max_homographs: 5
initial_quality: 3 #初始质量拼音的权重应该比英文大
spelling_hints: 30 #将注释以词典code字符串形式完全暴露通过super_comment.lua完全接管灵活配置。
always_show_comments: true # Rime 默认在 preedit 等于 comment 时取消显示 comment这里强制一直显示供super_comment_preedit.lua做判断用。
comment_format: {comment} #将注释以词典字符串形式完全暴露通过super_preedit.lua完全接管灵活配置。
#disable_user_dict_for_patterns: #如果你开启调频需要一并考虑这个配置是否需要基本的6码3字不调频你可以自定义目前的逻辑是依然记录用户词但满足规则的不输出不被使用
# - "^[a-z]{1,6}"
# 自定义短语
custom_phrase:
dictionary: ""
user_dict: custom_phrase #需要手动创建 custom_phrase.txt 文件
db_class: stabledb #可设 tabledb文本或 userdb二进制
enable_completion: false #补全提示
enable_sentence: false #禁止造句
initial_quality: 99 #custom_phrase 的权重应该比 pinyin 和 wanxiang_en 大
# 简码词库导入位于dicts得chengyu.txt文件词库
chengyu:
dictionary: ""
user_dict: dicts/chengyu
db_class: stabledb
enable_sentence: false
enable_completion: false
initial_quality: 1.3
# 中文、英文、数字、符号等混合词汇
wanxiang_mixedcode:
dictionary: wanxiang_mixedcode
user_dict: en
enable_completion: true
enable_sentence: false
initial_quality: 2
comment_format:
- xform/^.+$//
# Emoji
emoji:
option_name: emoji
opencc_config: emoji.json
tags: [abc]
inherit_comment: false
#中文转英文
chinese_english:
option_name: chinese_english
opencc_config: chinese_english.json
tips: char
inherit_comment: false
# 简繁切换
s2t:
option_name: s2t
opencc_config: s2t.json # s2t.json | s2hk.json | s2tw.json | s2twp.json
tips: none # 转换提示: all 都显示 | char 仅单字显示 | none 不显示。
tags: [ abc ] # 限制在对应 tag不对其他如反查的内容做简繁转换
s2hk:
opencc_config: s2hk.json
option_name: s2hk
tags: [abc]
s2tw:
opencc_config: s2tw.json
option_name: s2tw
tags: [abc]
# 部件拆字反查
wanxiang_reverse:
tag: wanxiang_reverse
dictionary: wanxiang_reverse
db_class: stabledb
enable_user_dict: false
enable_sentence: false
prefix: "`" # 反查前缀(反查时前缀会消失),与 recognizer/patterns/wanxiang_reverse 匹配
tips: "〔反查:拆分|笔画〕"
# 部件拆字滤镜
radical_reverse_lookup:
tags: [ wanxiang_reverse ] #起作用tag范围
overwrite_comment: true #是否覆盖其他提示
dictionary: wanxiang #带音调的词典
wanxiang_lookup: #设置归属于super_lookup.lua
tags: [ abc ] # 检索当前tag的候选
key: "`" # 输入中反查引导符,要添加到 speller/alphabet
lookup: [ wanxiang_reverse ] #反查滤镜数据库,万象都合并为一个了
# 处理符合特定规则的输入码,如网址、反查
recognizer:
import_preset: default # 从 default.yaml 继承通用的
patterns: # 再增加方案专有的:
punct: "^/([0-9]|10|[A-Za-z]+)$" # 响应 symbols.yaml 的 symbols
wanxiang_reverse: "^`[A-Za-z]*$" # 响应部件拆字与笔画的反查,与 wanxiang_reverse/prefix 匹配
#add_user_dict: "^ac[A-Za-z/`']*$" #引导式造词
unicode: "^U[a-f0-9]+" # U 作为触发前缀,响应 lua_translator@unicode输出 Unicode 字符
number: "^R[0-9]+[.]?[0-9]*" # R 作为触发前缀, 响应 lua_translator@number_translator数字金额大写
yr1: "^N0[1-9]?0?[1-9]?"
yr2: "^N1[02]?0?[1-9]?"
yr3: "^N0[1-9]?[1-2]?[1-9]?"
yr4: "^N1[02]?[1-2]?[1-9]?"
yr5: "^N0[1-9]?3?[01]?"
yr6: "^N1[02]?3?[01]?"
nyr1: "^N19?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?"
nyr2: "^N20?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?"
calculator: "^V.*$" # V 作为触发前缀,计算器功能引导
#add_user_dict: "^ac[A-Za-z/`']*$" #自造词引导方式
email: "^[A-Za-z][-_.0-9A-Za-z]*@.*$" # email @ 之后不上屏
url: "^(www[.]|https?:|ftp[.:]|mailto:|file:).*$|^[a-z]+[.].+$" # URL
# 给 kp_number_processor 用的“命令模式 Lua 正则集合”
# 能够细化哪些情况数字是用来当作输入编码的,不在正则范围的将用于上屏
# 直接加载上面的正则会遇到不符合预期的情况毕竟Lua正则逻辑与之不同
kp_number:
#小键盘数字处理逻辑
# "compose" : 小键盘数字始终参与编码
# "auto" : 输入中 push空闲时 commit默认
kp_number_mode: auto
patterns:
# /符号引导模式
- "^/[0-9]$"
- "^/10$"
- "^/[A-Za-z]+$"
# U模式
- "^U[%da-f]+$"
# R模式
- "^R[0-9]+%.?[0-9]*$"
# N模式
# Lua 不支持 {1,8}改成等价写法N 后 1~8 个数字
- "^N0[1-9]?0?[1-9]?$"
- "^N1[02]?0?[1-9]?$"
- "^N0[1-9]?[1-2]?[1-9]?$"
- "^N1[02]?[1-2]?[1-9]?$"
- "^N0[1-9]?3?[01]?$"
- "^N1[02]?3?[01]?$"
- "^N19?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$"
- "^N20?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$"
# 计算器模式
- "^V.*$"
# email
- "^[A-Za-z][-_.0-9A-Za-z]*@.*$"
# URL 前缀几种:
- "^www[.].*$"
- "^https?:.*$"
- "^ftp[.:].*$"
- "^mailto:.*$"
- "^file:.*$"
- "^webdav:.*$"
# 标点符号
# punctuator 下面有三个子项:
# 设置为一个映射,就自动上屏;设置为多个映射,如 '/' : [ '/', ÷ ] 则进行复选。
# full_shape: 全角没改,使用预设值
# half_shape: 标点符号全部直接上屏,和 macOS 自带输入法的区别是
# '|' 是半角的,
# '~' 是半角的,
# '`'(反引号)没有改成 '·'(间隔号)。
# symbols Rime 的预设配置是以 '/' 前缀开头输出一系列字符,自定义的修改 symbols.yaml
punctuator:
digit_separators: ",." #数字分隔符,系统逻辑是在中文状态下输入数字后继续输入句号按下两次即输入半角状态
__include: wanxiang_symbols:/symbol_table # 从 wanxiang_symbols.yaml 导入所有符号配置
# 从 default 继承快捷键
key_binder:
import_preset: default # 从 default.yaml 继承通用的
sequence: # Lua 配置:手动排序的快捷键 super_sequence.lua不要用方向键各种冲突一定要避免冲突
up: "Control+j" # 上移
down: "Control+k" # 下移
reset: "Control+l" # 重置
pin: "Control+p" # 置顶
# Lua 配置: shijian.lua 的引导符,涉及:日期、时间、节日、节气、生日、问候模板等功能
shijian_keys: ["/", "o"]
# Lua 配置: 超级tips上屏按键
tips_key: "comma" #修改时候去default找
# Lua 配置: 以词定字(上屏当前词句的第一个或最后一个字),和中括号翻页有冲突
select_first_character: "bracketleft" # 左中括号 [
select_last_character: "bracketright" # 右中括号 ]
bindings: # 也可以再增加方案专有的
# 通过按下/发送/+1节约一个按键不冲突的时候可以开启
#- { match: "[a-z]{1,4}", accept: "/", send_sequence: "/1" }
# 翻页 , .
# - { when: paging, accept: comma, send: Page_Up }
# - { when: has_menu, accept: period, send: Page_Down }
# 翻页 [ ]
# - { when: paging, accept: bracketleft, send: Page_Up }
# - { when: has_menu, accept: bracketright, send: Page_Down }
# 翻页 - =
- { when: has_menu, accept: minus, send: Page_Up }
- { when: has_menu, accept: equal, send: Page_Down }
# Option/Alt + ←/→ 切换光标至下/上一个拼音
- { when: always, toggle: ascii_punct, accept: Control+Shift+3 } # 切换中英标点
- { when: always, toggle: ascii_punct, accept: Control+Shift+numbersign } # 切换中英标点
- { when: always, toggle: s2t, accept: Control+Shift+4 } # 切换简繁
- { when: always, toggle: s2t, accept: Control+Shift+dollar } # 切换简繁
- { when: composing, accept: Alt+Left, send: Shift+Left }
- { when: composing, accept: Alt+Right, send: Shift+Right }
- { when: composing, accept: Control+w, send: Control+BackSpace }
#分号用于次选,微软、搜狗双拼不可启用
#- { when: has_menu, accept: semicolon, send: 2 }
#使用Control+e进入翻译模式
- { when: has_menu, accept: "Control+e", toggle: chinese_english}
#使用快捷键Control+a开启和关闭辅助码显示
- { when: has_menu, accept: "Control+a", toggle: tone_hint }
#通过快捷键Control+s使得输入码显示音调
- { when: has_menu, accept: "Control+s", toggle: tone_display }
#通过快捷键Control+t开启超级tips
- { when: has_menu, accept: "Control+t", toggle: super_tips }
#通过快捷键Control+q开启超级tips
- { when: has_menu, accept: "Control+q", toggle: corrector }
#通过快捷键Control+g开启字符集过滤
- { when: has_menu, accept: "Control+g", toggle: charset_filter }
#通过快捷键Control+q切换中文、英文、混合模式
- { when: has_menu, accept: "Control+q", toggle: zh_only }
# 使用 tab 在不同音节之间跳转
- { when: has_menu, accept: "Tab", send: "Control+Right" }
- { when: composing, accept: "Tab", send: "Control+Right" }
#当tab第一个字补码正确后可以使用Ctrl+tab进行上屏并依次补码
- { when: composing, accept: "Control+Tab", send_sequence: '{Home}{Shift+Right}{1}{Shift+Right}' }
#当输入编码后发现没有词,则通过双击``进入造词模式而且不需要删除编码,这个功能与``直接引导相呼应相配合
- { match: "^.*`$", accept: "`", send_sequence: '{BackSpace}{Home}{`}{`}{End}' }
#斜杠被占用引导符号,因此输入本身设置为双击
- { match: "^/$", accept: "/", send_sequence: '{space}' }
editor:
bindings:
space: confirm # 空格键:上屏候选项
Return: commit_raw_input # 回车键:上屏原始输入
Control+Return: commit_script_text # Ctrl+回车键:上屏变换后输入(经过 preedit转换的
Control+Shift+Return: commit_comment # Ctrl+Shift+回车键:上屏 comment
BackSpace: revert # 退格键:向前删除(撤消上次输入)
Delete: delete # Delete 键:向后删除
Control+BackSpace: back_syllable # Ctrl+退格键:删除一个音节
Control+Delete: delete_candidate # Ctrl+Delete键删除或降权候选项
Escape: cancel # Esc 键:取消输入
# 拼写设定
speller:
# table_translator翻译器支持自动上屏。例如 “zmhu”可以自动上屏“怎么回事”
# auto_select: true
# auto_select_pattern: ^[a-z]+/|^[a-df-zA-DF-Z]\w{3}|^e\w{4}
# 如果不想让什么标点直接上屏,可以加在 alphabet或者编辑标点符号为两个及以上的映射alphabet就是将字符纳入输入编码的范畴
alphabet: zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA1234567890`;/\
# initials 定义仅作为始码的按键,排除 ` 让单个的 ` 可以直接上屏
initials: zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA/
delimiter: " '" # 系统配置,第一位<空格>是拼音之间的分隔符;第二位<'>表示可以手动输入单引号来分割拼音。
visual_delimiter: " " # super_preedit.lua配置是否让分隔符号跟着一起转换例如nǐ'hǎo 在实际使用中表现出视觉拥挤我们可以让delimiter平时是'转换为拼音的时候使用空格nǐ hǎo更符合实际。
tone_isolate: true # super_preedit.lua配置是否将数字声调从转换后拼音中隔离出来true=隔离, false 直接参与转换例如nǐ3
algebra:
__patch:
#- 模糊音 #模糊音选择性开启
- wanxiang_algebra:/base/全拼 #拼音转双拼码
# 自定义词典
user_dict_set:
dictionary: wanxiang
initial_quality: 0
enable_completion: false
enable_sentence: false
spelling_hints: 50
contextual_suggestions: false #模型预测,假设模型里面有的四个字的词汇 现在智能 而首选组合 现在只能 当你输入 现在 上屏后下一次输入zhi neng就会输出智能前提是没有权重更高的了很明显这与你的预期“现在只能”不符。很明显实际上又要预测又要连续句子放一起是很难优雅的。
max_homophones: 5
max_homographs: 5
comment_format:
enable_user_dict: false
user_dict: zc
# 自定义词典加词(``引导)
add_user_dict:
tag: add_user_dict
dictionary: wanxiang
initial_quality: -1
user_dict: zc
enable_completion: true # 提前显示尚未输入完整码的字〔仅 table_translator 有效〕
enable_user_dict: false
enable_auto_phrase: true # lua造词功能在custom开启相关功能位于auto_phrase.lua开启后模型能造的句子不造词现有的词不造词只造词库没有的选词可造词
spelling_hints: 50
comment_format:
prefix: "``"
tips: "〔开始造词〕"

2880
wanxiang_algebra.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
# Rime dictionary
# encoding: utf-8
#
# rime配置的部署位置
# ~/.local/share/fcitx5/rime 或者 ~/.config/ibus/rime (Linux)
# ~/Library/Rime (Mac OS)
# %APPDATA%\Rime (Windows)
---
name: wanxiang_mixedcode
version: "LTS"
sort: by_weight #字典初始排序可選original或by_weight
use_preset_vocabulary: false
import_tables:
- dicts/en #英文词库
- dicts/cn&en #中英文混合词库
...

View File

@@ -0,0 +1,37 @@
# Rime schema settings
# encoding: utf-8
schema:
schema_id: wanxiang_mixedcode
name: "万象:英文与混合编码"
version: "LTS"
author: amzxyz
description: |
混合编码负责将英文、中英文混合、携带符号的词组等全部统一到这个方案中完成
engine:
processors:
- key_binder
- speller
- selector
- navigator
- express_editor
segmentors:
- abc_segmentor
translators:
- echo_translator
- table_translator
filters:
- uniquifier
key_binder:
__include: default:/key_binder?
speller:
alphabet: "abcdefghijklmnopqrstuvwxyz;"
delimiter: " '"
algebra:
__include: wanxiang_algebra:/mixed/通用派生规则
__patch: wanxiang_algebra:/mixed/全拼 #可选的选项有(全拼, 自然码, 小鹤双拼, 微软双拼, 搜狗双拼, 智能ABC, 紫光双拼, 拼音加加, 自然龙, 汉心龙)
translator:
dictionary: wanxiang_mixedcode
enable_user_dict: false

260374
wanxiang_reverse.dict.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
# Rime schema settings
# encoding: utf-8
schema:
schema_id: wanxiang_reverse
name: "万象:拆分与笔画反查"
version: "LTS"
author: amzxyz
description: |
万象的反查功能模块,方案融合了组字与笔画的能力
engine:
processors:
- key_binder
- speller
- selector
- navigator
- express_editor
segmentors:
- abc_segmentor
translators:
- echo_translator
- table_translator
filters:
- uniquifier
key_binder:
__include: default:/key_binder?
speller:
alphabet: "abcdefghijklmnopqrstuvwxyz;"
delimiter: " '"
algebra:
__include: wanxiang_algebra:/reverse/全拼
__patch: wanxiang_algebra:/reverse/hspzn #笔画类型有hspznhupvd及hslzy适配乱序17可选
translator:
dictionary: wanxiang_reverse
enable_user_dict: false

459
wanxiang_symbols.yaml Normal file
View File

@@ -0,0 +1,459 @@
# Rime's symbols
# encoding: utf-8
#
# copy from /Library/Input Methods/Squirrel.app/Contents/SharedSupport/symbols.yaml
# version: LTS
symbol_table:
full_shape:
' ' : { commit: ' ' }
',' : { commit: }
'.' : { commit: 。 }
'<' : [ 《, 〈, «, ]
'>' : [ 》, 〉, », ]
'/' : [ /, ÷, ×, , ]
'?' : { commit: }
';' : { commit: }
':' : { commit: }
'''' : { pair: [ '', '' ] }
'"' : { pair: [ '“', '”' ] }
'\' : [ 、, ]
'|' : [ ·, , '§', '¦' ]
'`' :
'~' :
'!' : { commit: }
'@' : [ , ☯ ]
'#' : [ , ⌘ ]
'%' : [ , '°', '℃' ]
'$' : [ ¥, '$', '€', '£', '¥', '¢', '¤' ]
'^' : { commit: …… }
'&' :
'*' : [ , ·, ・, ×, ※, ❂ ]
'(' :
')' :
'-' :
'_' : ——
'+' :
'=' :
'[' : [ 「, 【, , ]
']' : [ 」, 】, , ]
'{' : [ 『, 〖, ]
'}' : [ 』, 〗, ]
half_shape:
',' : ''
'.' : '。'
'<' : '《'
'>' : '》'
'/' : '/'
'?' : ''
';' : ''
':' : ''
'''' : { pair: [ '', '' ] }
'"' : { pair: [ '“', '”' ] }
'\' : '、'
'|' : '|'
'`' : [ "`", "```" ]
'~' : '~'
'!' : ''
'@' : '@'
'#' : '#'
'%' : '%'
'$' : '¥'
'^' : '……'
'&' : '&'
'*' : '*'
'(' : ''
')' : ''
'-' : '-'
'_' : ——
'+' : '+'
'=' : '='
'[' : '【'
']' : '】'
'{' : '「'
'}' : '」'
symbols:
#符号、电脑
'/fh': [ ©, ®, ℗, ℠, ™, ℡, ℻, ☇, ☈, ☉, ☊, ☋, ☌, ☍, ☎, ☏, ☐, ☑, ☒, ☓, ☕, ☖, ☗, ⛉, ⛊, ☘, ☙, ☚, ☛, ☜, ☝, ☞, ☟, ☠, ☡, ☢, ☣, ☤, ☥, ☦, ☧, ☨, ☩, ☪, ☫, ☬, ☭, ☮, ☯, ☸, ♨, ♰, ♱, ♲, ♳, ♴, ♵, ♶, ♷, ♸, ♹, ♺, ♻, ♼, ♽, ♾, ♿, ⚆, ⚇, ⚈, ⚉, ⚐, ⚑, ⚒, ⚓, ⚔, ⚕, ⚖, ⚗, ⚘, ⚙, ⚚, ⚛, ⚜, ⚝, ⚞, ⚟, ⚠, ⚡, ⚰, ⚱, ⚲, ⚳, ⚴, ⚵, ⚶, ⚷, ⚸, ⚹, ⚺, ⚻, ⚼, ⚽, ⚾, ⚿, ⛀, ⛁, ⛂, ⛃, ⛋, ⛌, ⛍, ⛎, ⛏, ⛐, ⛑, ⛒, ⛓, ⛔, ⛕, ⛖, ⛗, ⛘, ⛙, ⛚, ⛛, ⛜, ⛝, ⛞, ⛟, ⛠, ⛡, ⛢, ⛣, ⛨, ⛩, ⛪, ⛫, ⛬, ⛭, ⛮, ⛯, ⛰, ⛱, ⛲, ⛳, ⛴, ⛵, ⛶, ⛷, ⛸, ⛹, ⛺, ⛻, ⛼, ⛽, ⛾, ⛿ ]
'/dn': [ ❖, ⌘, ⌃, ⌥, ⎇, ⇧, ⇪, ␣, ⇥, ⇤, ↩, ⌅, ⌤, ⌫, ⌦, ⌧, ⎋, ⌨, ◁, ⌀, ⌖, ⌗, ⏏, ↖, ↘, ⇞, ⇟, ⌚, ⏰, ⏱, ⏲, ⏳, ⌛, ⌜, ⌝⌞⌟, ⍑, ⏩, ⏪, ⏫, ⏬, ⏭, ⏮, ⏯ ]
#象棋、麻将、色子、扑克
'/xq': [ ♔, ♕, ♖, ♗, ♘, ♙, ♚, ♛, ♜, ♝, ♞, ♟ ]
'/mj': [ 🀀, 🀁, 🀂, 🀃, 🀄, 🀅, 🀆, 🀇, 🀈, 🀉, 🀊, 🀋, 🀌, 🀍, 🀎, 🀏, 🀐, 🀑, 🀒, 🀓, 🀔, 🀕, 🀖, 🀗, 🀘, 🀙, 🀚, 🀛, 🀜, 🀝, 🀞, 🀟, 🀠, 🀡, 🀢, 🀣, 🀤, 🀥, 🀦, 🀧, 🀨, 🀩, 🀪, 🀫 ]
'/sz': [ ⚀, ⚁, ⚂, ⚃, ⚄, ⚅ ]
'/pk': [ ♠, ♥, ♣, ♦, ♤, ♡, ♧, ♢ ]
#音乐
'/yy': [ 𝄞, ♩, ♪, ♫, ♬, ♭, ♮, ♯ ]
#两性
'/lx': [ ♂, ♀, ⚢, ⚣, ⚤, ⚥, ⚦, ⚧, ⚨, ⚩, ⚪, ⚫, ⚬, ⚭, ⚮, ⚯ ]
#八卦、八卦名、六十四卦、六十四卦名、太玄经
'/bg': [ ☰, ☱, ☲, ☳, ☴, ☵, ☶, ☷ ]
'/bgm': [ 乾, 兑, 离, 震, 巽, 坎, 艮, 坤 ]
'/lssg': [ ䷀, ䷁, ䷂, ䷃, ䷄, ䷅, ䷆, ䷇, ䷈, ䷉, ䷊, ䷋, ䷌, ䷍, ䷎, ䷏, ䷐, ䷑, ䷒, ䷓, ䷔, ䷕, ䷖, ䷗, ䷘, ䷙, ䷚, ䷛, ䷜, ䷝, ䷞, ䷟, ䷠, ䷡, ䷢, ䷣, ䷤, ䷥, ䷦, ䷧, ䷨, ䷩, ䷪, ䷫, ䷬, ䷭, ䷮, ䷯, ䷰, ䷱, ䷲, ䷳, ䷴, ䷵, ䷶, ䷷, ䷸, ䷹, ䷺, ䷻, ䷼, ䷽, ䷾, ䷿ ]
'/lssgm': [ 乾, 坤, 屯, 蒙, 需, 讼, 师, 比, 小畜, 履, 泰, 否, 同人, 大有, 谦, 豫, 随, 蛊, 临, 观, 噬嗑, 贲, 剥, 复, 无妄, 大畜, 颐, 大过, 坎, 离, 咸, 恒, 遯, 大壮, 晋, 明夷, 家人, 睽, 蹇, 解, 损, 益, 夬, 姤, 萃, 升, 困, 井, 革, 鼎, 震, 艮, 渐, 归妹, 丰, 旅, 巽, 兑, 涣, 节, 中孚, 小过, 既济, 未济 ]
'/txj': [ ⚊, ⚋, ⚌, ⚍, ⚎, ⚏, 𝌀, 𝌁, 𝌂, 𝌃, 𝌄, 𝌅, 𝌆, 𝌇, 𝌈, 𝌉, 𝌊, 𝌋, 𝌌, 𝌍, 𝌎, 𝌏, 𝌐, 𝌑, 𝌒, 𝌓, 𝌔, 𝌕, 𝌖, 𝌗, 𝌘, 𝌙, 𝌚, 𝌛, 𝌜, 𝌝, 𝌞, 𝌟, 𝌠, 𝌡, 𝌢, 𝌣, 𝌤, 𝌥, 𝌦, 𝌧, 𝌨, 𝌩, 𝌪, 𝌫, 𝌬, 𝌭, 𝌮, 𝌯, 𝌰, 𝌱, 𝌲, 𝌳, 𝌴, 𝌵, 𝌶, 𝌷, 𝌸, 𝌹, 𝌺, 𝌻, 𝌼, 𝌽, 𝌾, 𝌿, 𝍀, 𝍁, 𝍂, 𝍃, 𝍄, 𝍅, 𝍆, 𝍇, 𝍈, 𝍉, 𝍊, 𝍋, 𝍌, 𝍍, 𝍎, 𝍏, 𝍐, 𝍑, 𝍒, 𝍓, 𝍔, 𝍕, 𝍖 ]
#天体、星座、星座名、十二宫
'/tt': [ ☄, ☼, ☽, ☾, ☿, ♀, ♁, ♂, ♃, ♄, ♅, ♆, ♇ ]
'/xz': [ ♈, ♉, ♊, ♋, ♌, ♍, ♎, ♏, ♐, ♑, ♒, ♓ ]
'/xzm': [ 白羊座, 金牛座, 双子座, 巨蟹座, 狮子座, 室女座, 天秤座, 天蝎座, 人马座, 摩羯座, 宝瓶座, 双鱼座 ]
'/xzg': [ 白羊宫, 金牛宫, 双子宫, 巨蟹宫, 狮子宫, 室女宫, 天秤宫, 天蝎宫, 人马宫, 摩羯宫, 宝瓶宫, 双鱼宫 ]
#星号
'/wjx': [ ★, ☆, ⛤, ⛥, ⛦, ⛧ ]
'/xh': [ ✡, ❋, ❊, ❉, ❈, ❇, ❆, ❅, ❄, ❃, ❂, ❁, ❀, ✿, ✾, ✽, ✼, ✻, ✺, ✹, ✸, ✷, ✶, ✵, ✴, ✳, ✲, ✱, ✰, ✯, ✮, ✭, ✬, ✫, ✪, ✩, ✧, ✦, ✥, ✤, ✣, ✢ ]
#方块
'/fk': [ ▀, ▁, ▂, ▃, ▄, ▅, ▆, ▇, █, ▉, ▊, ▋, ▌, ▍, ▎, ▏, ▐, ░, ▒, ▓, ▔, ▕, ▖, ▗, ▘, ▙, ▚, ▛, ▜, ▝, ▞, ▟ ]
#几何
'/jh': [ ■, □, ▢, ▣, ▤, ▥, ▦, ▧, ▨, ▩, ▪, ▫, ▬, ▭, ▮, ▯, ▰, ▱, ▲, △, ▴, ▵, ▶, ▷, ▸, ▹, ►, ▻, ▼, ▽, ▾, ▿, ◀, ◁, ◂, ◃, ◄, ◅, ◆, ◇, ◈, ◉, ◊, ○, ◌, ◍, ◎, ●, ◐, ◑, ◒, ◓, ◔, ◕, ◖, ◗, ◘, ◙, ◚, ◛, ◜, ◝, ◞, ◟, ◠, ◡, ◢, ◣, ◤, ◥, ◦, ◧, ◨, ◩, ◪, ◫, ◬, ◭, ◮, ◯, ◰, ◱, ◲, ◳, ◴, ◵, ◶, ◷, ◸, ◹, ◺, ◻, ◼, ◽, ◾, ◿ ]
#箭头
'/jt': [ →, ↑, ↓, ←, ↕, ↔, ↖, ↗, ↙, ↘, ↚, ↛, ↮, ↜, ↝, ↞, ↟, ↠, ↡, ↢, ↣, ↤, ↥, ↦, ↧, ↨, ↩, ↪, ↫, ↬, ↭, ↯, ↰, ↱, ↲, ↳, ↴, ↵, ↶, ↷, ↸, ↹, ↺, ↻, ↼, ↽, ↾, ↿, ⇀, ⇁, ⇂, ⇃, ⇄, ⇅, ⇆, ⇇, ⇈, ⇉, ⇊, ⇋, ⇌, ⇐, ⇍, ⇑, ⇒, ⇏, ⇓, ⇔, ⇎, ⇕, ⇖, ⇗, ⇘, ⇙, ⇚, ⇛, ⇜, ⇝, ⇞, ⇟, ⇠, ⇡, ⇢, ⇣, ⇤, ⇥, ⇦, ⇧, ⇨, ⇩, ⇪, ⇫, ⇬, ⇭, ⇮, ⇯, ⇰, ⇱, ⇲, ⇳, ⇴, ⇵, ⇶, ⇷, ⇸, ⇹, ⇺, ⇻, ⇼, ⇽, ➔, ➘, ➙, ➚, ➛, ➜, ➝, ➞, ➟, ➠, ➡, ➢, ➣, ➤, ➥, ➦, ➧, ➨, ➩, ➪, ➫, ➬, ➭, ➮, ➱, ➲, ➳, ➴, ➵, ➶, ➷, ➸, ➹, ➺, ➻, ➼, ➽, ➾ ]
#数学
'/sx': [ ,, ×, ÷, ±, ∈, ∏, ∑, , ≮, , ≠, , ≯, , √, ∝, ∞, ∟, ∠, ∥, ∧, , ∩, , ∫, ∮, ∴, ∵, ∷, ∽, ≈, ≌, ≒, ≡, ≤, ≥, ≦, ≧, ⊕, ⊙, ⊥, ⊿, ㏑, ㏒ ]
'/dy': [ , ≥, ≧, ≯ ]
'/xy': [ , ≤, ≦, ≮ ]
'/yw': [ ∵ ]
'/sy': [ ∴ ]
#数字+圆v弧v点
'/szq': [ ⓪, ①, ②, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨, ⑩, ⑪, ⑫, ⑬, ⑭, ⑮, ⑯, ⑰, ⑱, ⑲, ⑳, ㉑, ㉒, ㉓, ㉔, ㉕, ㉖, ㉗, ㉘, ㉙, ㉚, ㉛, ㉜, ㉝, ㉞, ㉟, ㊱, ㊲, ㊳, ㊴, ㊵, ㊶, ㊷, ㊸, ㊹, ㊺, ㊻, ㊼, ㊽, ㊾, ㊿, ⓿, ❶, ❷, ❸, ❹, ❺, ❻, ❼, ❽, ❾, ❿, ⓫, ⓬, ⓭, ⓮, ⓯, ⓰, ⓱, ⓲, ⓳, ⓴ ]
'/szh': [ ⑴, ⑵, ⑶, ⑷, ⑸, ⑹, ⑺, ⑻, ⑼, ⑽, ⑾, ⑿, ⒀, ⒁, ⒂, ⒃, ⒄, ⒅, ⒆, ⒇ ]
'/szd': [ ⒈, ⒉, ⒊, ⒋, ⒌, ⒍, ⒎, ⒏, ⒐, ⒑, ⒒, ⒓, ⒔, ⒕, ⒖, ⒗, ⒘, ⒙, ⒚, ⒛ ]
#字母+圈v弧
'/zmq': [ ⓐ, Ⓐ, ⓑ, Ⓑ, ⓒ, Ⓒ, ⓓ, Ⓓ, ⓔ, Ⓔ, ⓕ, Ⓕ, ⓖ, Ⓖ, ⓗ, Ⓗ, ⓘ, Ⓘ, ⓙ, Ⓙ, ⓚ, Ⓚ, ⓛ, Ⓛ, ⓜ, Ⓜ, ⓝ, Ⓝ, ⓞ, Ⓞ, ⓟ, Ⓟ, ⓠ, Ⓠ, ⓡ, Ⓡ, ⓢ, Ⓢ, ⓣ, Ⓣ, ⓤ, Ⓤ, ⓥ, Ⓥ, ⓦ, Ⓦ, ⓧ, Ⓧ, ⓨ, Ⓨ, ⓩ, Ⓩ ]
'/zmh': [ ⒜, ⒝, ⒞, ⒟, ⒠, ⒡, ⒢, ⒣, ⒤, ⒥, ⒦, ⒧, ⒨, ⒩, ⒪, ⒫, ⒬, ⒭, ⒮, ⒯, ⒰, ⒱, ⒲, ⒳, ⒴, ⒵ ]
#数字、分数
'/0': [ 零, , ⁰, ₀, ⓪, ⓿ , ]
'/1': [ 一, 壹, ¹, ₁, , , ①, ➀, ❶, ➊, ⓵, ⑴, ⒈, , ㊀, ㈠, 弌, 壱, 幺, ㆒ ]
'/2': [ 二, 贰, ², ₂, Ⅱ, ⅱ, ②, ➁, ❷, ➋, ⓶, ⑵, ⒉, , ㊁, ㈡, 弍, 弐, 貮, 㒃, 㒳, 两, 俩, ㆓]
'/3': [ 三, 叁, ³, ₃, Ⅲ, ⅲ, ③, ➂, ❸, ➌, ⓷, ⑶, ⒊, , ㊂, ㈢, 参, 参, 叁, 弎, 仨, ㆔]
'/4': [ 四, 肆, ⁴, ₄, Ⅳ, ⅳ, ④, ➃, ❹, ➍, ⓸, ⑷, ⒋, , ㊃, ㈣, 亖]
'/5': [ 五, 伍, ⁵, ₅, , , ⑤, ➄, ❺, ➎, ⓹, ⑸, ⒌, , ㊄, ㈤, 㐅, 㠪, 𠄡 ]
'/6': [ 六, 陆, ⁶, ₆, Ⅵ, ⅵ, ⑥, ➅, ❻, ➏, ⓺, ⑹, ⒍, , ㊅, ㈥, ↅ]
'/7': [ 七, 柒, ⁷, ₇, Ⅶ, ⅶ, ⑦, ➆, ❼, ➐, ⓻, ⑺, ⒎, , ㊆, ㈦, 漆]
'/8': [ 八, 捌, ⁸, ₈, Ⅷ, ⅷ, ⑧, ➇, ❽, ➑, ⓼, ⑻, ⒏, , ㊇, ㈧ ]
'/9': [ 九, 玖, ⁹, ₉, Ⅸ, ⅸ, ⑨, ➈, ❾, ➒, ⓽, ⑼, ⒐, , ㊈, ㈨ ]
'/10': [ 十, 拾, ¹⁰, ₁₀, , , ⑩, ➉, ❿, ➓, ⓾, ⑽, ⒑, , ㊉, ㈩, 什 ]
'/fs': [ ⅟, ½, ↉, ⅓, ⅔, ¼, ⅕, ⅖, ⅗, ⅘, ⅙, ⅚, ⅐, ⅛, ⅜, ⅝, ⅞, ⅑, ⅒, ‰]
#苏州码
'/szm': [ 〡, 〢, 〣, 〤, 〥, 〦, 〧, 〨, 〩, 〸, 〹, 〺 ]
#罗马数字
'/lm': [ , ⅱ, ⅲ, ⅳ, , ⅵ, ⅶ, ⅷ, ⅸ, , ⅺ, ⅻ, , , , ⅿ ]
'/lmd': [ , Ⅱ, Ⅲ, Ⅳ, , Ⅵ, Ⅶ, Ⅷ, Ⅸ, , Ⅺ, Ⅻ, , , , ]
#拉丁
'/a': [ā, á, ǎ, à, ȁ, â, ă, ȃ, ȧ, ä, å, ã, ₐ, ᵃ, ª, ⱥ, ꬰ, ả, ą, ạ, ḁ, ẚ, ấ, ầ, ẫ, ẩ, ắ, ằ, ẵ, ẳ, ǡ, ǟ, ǻ, ậ, ặ, ᶏ, ɐ, ᵄ, ɑ, ᵅ, ᶐ, ɒ, ᶛ]
'/A': [Ā, Á, Ǎ, À, Ȁ, Â, Ă, Ȃ, Ȧ, Ä, Å, Ã, ᴀ, ᴬ, Ⱥ, Ả, Ą, Ạ, Ḁ, Ấ, Ầ, Ẫ, Ẩ, Ắ, Ằ, Ẵ, Ẳ, Ǡ, Ǟ, Ǻ, Ậ, Ặ, Ɐ, Ɑ, Ɒ ]
'/b': [ḃ, ḅ, ᵇ, ƀ, ƃ, ḇ, ɓ, ᵬ, ᶀ, ꞗ]
'/B': [Ḃ, Ḅ, ʙ, ᴃ, ᴮ, ᴯ, Ƀ, Ƃ, Ḇ, Ɓ, Ꞗ]
'/c': [ç, ć, č, ĉ, ċ, ᶜ, ȼ, ꞓ, ƈ, ḉ, ꞔ, ɕ, ᶝ, ꜿ]
'/C': [Ç, Ć, Č, Ĉ, Ċ, , Ȼ, Ꞓ, Ƈ, Ḉ, Ꜿ]
'/d': [ď, ḋ, ᵈ, đ, ƌ, ᵭ, ḑ, ḓ, ḏ, ḍ, ɖ, ɗ, ᶑ, ᶁ, ð, ᶞ, ꝱ, ʤ, ʣ, ʥ, ȡ, ƍ, dz, dž, ẟ]
'/D': [Ď, Ḋ, ᴅ, ᴆ, ᴰ, Đ, Ƌ, Ḑ, Ḓ, Ḏ, Ḍ, Ɖ, Ɗ, Ð, DZ, Dz, DŽ, Dž ]
'/e': [ē, é, ě, è, ȅ, ê, ĕ, ȇ, ė, ë, ẽ, ₑ, ᵉ, ɇ, ꬳ, ẻ, ȩ, ę, ḙ, ẹ, ḛ, ḗ, ḕ, ế, ề, ễ, ể, ḝ, ệ, ᶒ, ꬴ, ɘ, ə, ɚ, ᶕ, ɛ, ᵋ, ᶓ, ɜ, ᵌ, ᴈ, ᶟ, ɝ, ᶔ, ɞ, ʚ, ǝ, ₔ, ᵊ, ȝ, ⱸ]
'/E': [Ē, É, Ě, È, Ȅ, Ê, Ĕ, Ȇ, Ė, Ë, Ẽ, ᴇ, ᴱ, Ɇ, Ẻ, Ȩ, Ę, Ḙ, Ẹ, Ḛ, Ḗ, Ḕ, Ế, Ề, Ễ, Ể, Ḝ, Ệ, Ə, Ɛ, , Ǝ, ⱻ, ᴲ, Ȝ ]
'/f': [ḟ, ᶠ, ƒ, ᵮ, ᶂ, ]
'/F': [Ḟ, ꜰ, Ƒ, , ꟻ]
'/g': [ḡ, ǵ, ǧ, ĝ, ğ, ġ, ᵍ, ǥ, ꞡ, ģ, ɠ, ᵷ, , ɡ, ꬶ, ᶢ, ɣ, ˠ, ɤ, ᵹ]
'/G': [Ḡ, Ǵ, Ǧ, Ĝ, Ğ, Ġ, ʛ, ᴳ, Ǥ, Ꞡ, Ģ, Ɠ, Ɡ, Ɣ ]
'/h': [ĥ, ȟ, ḣ, ḧ, ͪ, ħ, ɦ, ʱ, ꜧ, ꭜ, ɧ, ḩ, ẖ, ḫ, ḥ, ⱨ, ꞕ, ɥ, ᶣ, ʮ, ʯ, ⱶ]
'/H': [Ĥ, Ȟ, Ḣ, Ḧ, ʜ, ᴴ, Ħ, Ɦ, Ꜧ, Ḩ, Ḫ, Ḥ, Ⱨ, Ɥ, Ⱶ]
'/i': [ī, í, ǐ, ì, ȉ, î, ĭ, ȋ, ï, ĩ, ᵢ, ı, ɨ, ᶤ, ỉ, į, ị, ḭ, ᴉ, ᵎ, ḯ, ᶖ, ɩ, ᶥ, ᵼ]
'/I': [Ī, Í, Ǐ, Ì, Ȉ, Î, Ĭ, Ȋ, Ï, Ĩ, ɪ, ᴵ, ᶦ, Ɨ, ᵻ, ᶧ, Ỉ, Į, Ị, Ḭ, Ḯ, ꟾ, Ɩ ]
'/j': [ĵ, ǰ, ⱼ, ʲ, ɉ, ȷ, ɟ, ᶡ, ʄ, ʝ, ᶨ]
'/J': [Ĵ, ᴊ, ᴶ, Ɉ, ]
'/k': [ḱ, ǩ, ₖ, ᵏ, ꝁ, ꝃ, ꞣ, ꝅ, ķ, ḵ, ḳ, ƙ, ᶄ, ⱪ, ʞ, ĸ]
'/K': [Ḱ, Ǩ, ᴋ, ᴷ, Ꝁ, Ꝃ, Ꞣ, Ꝅ, Ķ, Ḵ, Ḳ, Ƙ, Ⱪ, Ʞ ]
'/l': [ĺ, ˡ, ł, ꝉ, ƚ, ⱡ, ɫ, ꭞ, ꬸ, ɬ, ľ, ļ, ḻ, ḽ, ḷ, ŀ, ꝲ, ƛ, ᶅ, ᶪ, ɭ, ᶩ, ḹ, ꬷ, ꭝ, ꬹ, ȴ, ꝇ]
'/L': [Ĺ, ʟ, ᶫ, Ƚ, Ꝉ, Ł, ᴌ, Ⱡ, Ɫ, Ɬ, Ľ, Ļ, Ḻ, Ḽ, Ḷ, Ŀ, Ꝇ]
'/m': [ḿ, m̀, ṁ, ᵐ, ₘ, ṃ, ᵯ, ɱ, ᶬ, ꬺ, ᶆ, ꝳ, ɯ, ᵚ, ɰ, ᶭ, ᴟ]
'/M': [Ḿ, Ṁ, ᴍ, ᴹ, Ṃ, Ɱ, Ɯ, ꟽ, ꟿ ]
'/n': [ń, ň, ǹ, ṅ, ñ, ₙ, ⁿ, ɲ, ᶮ, ɳ, ᶯ, ȵ, ƞ, ŋ, ᵑ, ꬻ, ꬼ, ꝴ, ʼn, ꞥ, ņ, ṉ, ṋ, ṇ, ᵰ, ꞑ, ᶇ]
'/N': [Ń, Ň, Ǹ, Ṅ, Ñ, ɴ, ᴺ, ᴻ, ᶰ, Ɲ, Ƞ, Ŋ, Ņ, Ṉ, Ṋ, Ṇ, Ꞑ ]
'/o': [ō, ó, ǒ, ò, ő, ô, ŏ, ȯ, ö, õ, ₒ, ᵒ, º, ɔ, ᵓ, ᶗ, ꬿ, ø, ǫ, ọ, ơ, ɵ, ᶱ, , ᴒ, ᴓ, ꝋ, ꝍ, ṓ, ṑ, ố, ồ, ỗ, ổ, ȱ, ȫ, ȭ, ṍ, ṏ, ộ, ǭ, ǿ, ớ, ờ, ỡ, ở, ợ, ɷ, ⱺ, ᴖ, ᵔ, ᴗ, ᵕ]
'/O': [Ō, Ó, Ő, Ǒ, Ò, Ô, Ŏ, Ȯ, Ö, Õ, , ᴼ, Ɔ, ᴐ, Ø, Ǫ, Ọ, Ơ, Ɵ, Ꝋ, Ꝍ, Ṓ, Ṑ, Ố, Ồ, Ỗ, Ổ, Ȱ, Ȫ, Ȭ, Ṍ, Ṏ, Ộ, Ǭ, Ǿ, Ớ, Ờ, Ỡ, Ở, Ợ ]
'/p': [ṕ, ṗ, ᵖ, ᵽ, ꝑ, ᵱ, ƥ, ᶈ, ꝓ, ꝕ, ɸ, ᶲ, ⱷ ]
'/P': [Ṕ, Ṗ, ᴘ, ᴾ, Ᵽ, Ꝑ, Ƥ, Ꝓ, Ꝕ, ꟼ]
'/q': [ɋ, ꝗ, ꝙ, ʠ]
'/Q': [Ɋ, Ꝗ, Ꝙ ]
'/r': [ŕ, ř, ȑ, ȓ, ṙ, ᵣ, ɍ, ꞧ, ᵲ, ŗ, ṟ, ṛ, ṝ, ᵳ, ɽ, ᶉ, , , ꭊ, ꭉ, ꝵ, ꭋ, ꭌ, ɹ, ʴ, ɺ, ɻ, ʵ, ⱹ, ɼ, ʳ, ɾ, ɿ, ꝛ, ꝝ]
'/R': [Ŕ, Ř, Ȑ, Ȓ, Ṙ, ʀ, ᴙ, ᴿ, Ʀ, ꭆ, Ɍ, Ꞧ, Ŗ, Ṟ, Ṛ, Ṝ, Ɽ, ꝶ, ʶ, ʁ, , Ꝝ]
'/s': [ś, ŝ, š, ṡ, ˢ, ʂ, ᶳ, ᵴ, ꞩ, ᶊ, ş, ṣ, ș, ȿ, ṥ, ṧ, ṩ, ʃ, ᶴ, ʆ, ᶘ, ʅ, ƪ, ß, ſ, ẛ, ẜ, ]
'/S': [Ś, Ŝ, Š, Ṡ, , Ꞩ, Ş, Ṣ, Ș, Ṥ, Ṧ, Ṩ, Ʃ, ẞ, ]
'/t': [ť, ṫ, ẗ, ᵗ, ₜ, ʈ, þ, ꝥ, ꝧ, ŧ, ⱦ, ţ, ṯ, ṱ, ṭ, ț, ƭ, ᵵ, ƫ, ᶵ, ʇ, ȶ, ꝷ]
'/T': [Ť, Ṫ, ᴛ, ᵀ, Ʈ, Þ, Ꝥ, Ꝧ, Ŧ, Ⱦ, Ţ, Ṯ, Ṱ, Ṭ, Ț, Ƭ, Ʇ ]
'/u': [ū, ú, ǔ, ù, ű, ȕ, û, ŭ, ȗ, ü, ǖ, ǘ, ǚ, ǜ, ů, ũ, ᵤ, ᵘ, ʉ, ᶶ, ủ, ų, ṷ, ụ, ṳ, ṵ, ư, ʊ, ᶷ, ᵿ, ᶙ, ṻ, ṹ, ứ, ừ, ữ, ử, ự, , ꭟ, , , ꭏ, ᴝ, ᵙ, ᴞ]
'/U': [Ū, Ú, Ű, Ǔ, Ù, Ȕ, Û, Ŭ, Ȗ, Ü, Ǖ, Ǘ, Ǚ, Ǜ, Ů, Ũ, , ᵁ, ᶸ, Ʉ, Ủ, Ų, Ṷ, Ụ, Ṳ, Ṵ, Ư, Ʊ, Ṻ, Ṹ, Ứ, Ừ, Ữ, Ử, Ự ]
'/v': [ü, ǖ, ǘ, ǚ, ǜ, ṽ, ᵛ, ᵥ, ṿ, ꝟ, ʋ, ᶹ, , ⱴ, ⱱ, ỽ, ʌ, ᶺ]
'/V': [Ü, Ǖ, Ǘ, Ǚ, Ǜ, Ṽ, , ⱽ, Ṿ, Ꝟ, Ʋ, Ỽ, Ʌ ]
'/w': [ẃ, ẁ, ŵ, ẇ, ẅ, ẘ, ʷ, ẉ, ƿ, ʍ, ⱳ]
'/W': [Ẃ, Ẁ, Ŵ, Ẇ, Ẅ, W̊, , ᵂ, Ẉ, Ƿ, Ⱳ]
'/x': [ẋ, ẍ, ᶍ, ˣ, ₓ, ꭖ, ꭗ, ꭘ, ꭙ]
'/X': [Ẋ, Ẍ ]
'/y': [ȳ, ý, ỳ, ŷ, ẏ, ÿ, ẙ, ỹ, ʸ, ɏ, ỷ, ỵ, ƴ, ʎ, ỿ, ]
'/Y': [Ȳ, Ý, Ỳ, Ŷ, Ẏ, Ÿ, Ỹ, ʏ, Ɏ, Ỷ, Ỵ, Ƴ, Ỿ ]
'/z': [ź, ž, ẑ, ż, ᶻ, ʐ, ᶼ, ʑ, ᶽ, ƶ, ẕ, ẓ, ᵶ, ȥ, ⱬ, ᶎ, ʒ, ᶾ, ǯ, ʓ, ƹ, ƺ, ᶚ, θ, ᶿ, ɀ, ꝣ]
'/Z': [Ź, Ž, Ẑ, Ż, , Ƶ, Ẕ, Ẓ, Ȥ, Ⱬ, Ʒ, ᴣ, Ǯ, Ƹ, Ɀ, Ꝣ]
'/aa': [ꜳ]
'/AA': [Ꜳ]
'/ae': [æ, ǣ, ǽ, ᵆ, ᴂ]
'/AE': [Æ, Ǣ, Ǽ, ᴭ, ᴁ ]
'/ao': [ꜵ]
'/AO': [Ꜵ]
'/au': [ꜷ]
'/AU': [Ꜷ]
'/av': [ꜹ, ꜻ]
'/AV': [Ꜹ, Ꜻ]
'/ay': [ꜽ]
'/AY': [Ꜽ]
'/db': [ȸ]
'/ff': [ff]
'/ffi': [ffi]
'/ffl': [ffl]
'/fi': [fi]
'/fl': [fl]
'/fn': [ʩ]
'/hv': [ƕ]
'/HV': [Ƕ]
'/ij': [ij]
'/IJ': [IJ]
'/lj': [lj]
'/ll': [ỻ]
'/LL': [Ỻ]
'/ls': [ʪ]
'/lz': [ʫ, ɮ]
'/nj': [nj]
'/Nj': [Nj]
'/NJ': [NJ]
'/oe': [œ, ᴔ]
'/OE': [Œ, ɶ ]
'/oi': [ƣ]
'/OI': [Ƣ]
'/oo': [ꝏ]
'/OO': [Ꝏ]
'/ou': [ȣ ]
'/OU': [Ȣ, ᴽ]
'/qp': [ȹ]
'/Rx': [℞]
'/tc': [ʨ]
'/th': [ᵺ]
'/ts': [ʦ, ʧ]
'/tz': [ꜩ]
'/TZ': [Ꜩ]
'/ue': [ᵫ]
'/vy': [ꝡ]
'/VY': [Ꝡ]
'/ww': [ʬ]
'/num': [№]
#上标、下标
'/sb': [ ⁰, ¹, ², ³, ⁴, ⁵, ⁶, ⁷, ⁸, ⁹, ˜, ⁺, ⁻, ⁼, ⁽, ⁾, ᴬ, ᵃ, ᵄ, ᵅ, ᶛ, ᴭ, ᵆ, ᴮ, ᴯ, ᵇ, ᵝ, ᶜ, ᵓ, ᶝ, ᴰ, ᵈ, ᶞ, ᵟ, ᴱ, ᵉ, ᴲ, ᵊ, ᵋ, ᶟ, ᵌ, ᶠ, ᶡ, ᶲ, ᵠ, ᴳ, ᵍ, ᶢ, ˠ, ᵞ, ᴴ, ʰ, ᶣ, ʱ, ᴵ, ⁱ, ᶤ, ᵎ, ᶥ, ᴶ, ʲ, ᶨ, ᴷ, ᵏ, ᴸ, ᶫ, ˡ, ᶩ, ᶪ, ᴹ, ᵐ, ᶬ, ᵚ, ᶭ, ᴺ, ᴻ, ⁿ, ᵑ, ᶮ, ᶯ, ᴼ, ᵒ, ᶱ, ᴽ, ᴾ, ᵖ, ᴿ, ʳ, ʶ, ʴ, ʵ, ˢ, ᶴ, ᶳ, ᵀ, ᵗ, ᶵ, ᶿ, ᵁ, ᵘ, ᶶ, ᶷ, ᵙ, ⱽ, ᵛ, ᶺ, ᶹ, ᵂ, ʷ, ˣ, ᵡ, ʸ, ᶻ, ᶾ, ᶽ, ᶼ ]
'/xb': [ ₀, ₁, ₂, ₃, ₄, ₅, ₆, ₇, ₈, ₉, ₊, ₋, ₌, ₍, ₎, ‸, ᴀ, ₐ, ᴁ, ʙ, ᴃ, ᵦ, , ᴐ, ᴒ, ᴅ, ᴆ, ᴇ, ₑ, ₔ, ᵩ, ɢ, ʛ, , ᵧ, ʜ, ₕ, ɪ, ᵻ, ᵢ, ᴊ, ⱼ, ᴋ, ₖ, ʟ, ₗ, ᴌ, ᴧ, ᴍ, ₘ, ꟺ, ɴ, ᴎ, ₙ, , ₒ, ɶ, ʘ, ᴓ, , ᴘ, ₚ, ᴨ, ᴪ, ʀ, ᵣ, ᴙ, ʁ, ᴚ, ᵨ, ₛ, ᴛ, ₜ, , ᵤ, ᵾ, , ᵥ, , ₓ, ᵪ, ʏ, , ᴣ ]
#希腊
'/xl': [ α, β, γ, δ, ε, ζ, η, θ, ι, κ, λ, μ, ν, ξ, ο, π, ρ, σ, τ, υ, φ, χ, ψ, ω ]
'/xld': [ Α, Β, Γ, Δ, Ε, Ζ, Η, Θ, Ι, Κ, Λ, Μ, Ν, Ξ, Ο, Π, Ρ, Σ, Τ, Υ, Φ, Χ, Ψ, Ω ]
#俄语
'/ey': [ а, б, в, г, д, е, ё, ж, з, и, й, к, л, м, н, о, п, р, с, т, у, ф, х, ц, ч, ш, щ, ъ, ы, ь, э, ю, я ]
'/eyd': [ А, Б, В, Г, Д, Е, Ё, Ж, З, И, Й, К, Л, М, Н, О, П, Р, С, Т, У, Ф, Х, Ц, Ч, Ш, Щ, Ъ, Ы, Ь, Э, Ю, Я ]
#月份、日期、曜日等
'/yf': [ ㋀, ㋁, ㋂, ㋃, ㋄, ㋅, ㋆, ㋇, ㋈, ㋉, ㋊, ㋋ ]
'/rf': [ ㏠, ㏡, ㏢, ㏣, ㏤, ㏥, ㏦, ㏧, ㏨, ㏩, ㏪, ㏫, ㏬, ㏭, ㏮, ㏯, ㏰, ㏱, ㏲, ㏳, ㏴, ㏵, ㏶, ㏷, ㏸, ㏹, ㏺, ㏻, ㏼, ㏽, ㏾ ]
'/yr': [ 月, 火, 水, 木, 金, 土, 日, ㊊, ㊋, ㊌, ㊍, ㊎, ㊏, ㊐, ㊗, ㊡, ㈪, ㈫, ㈬, ㈭, ㈮, ㈯, ㈰, ㈷, ㉁, ㉀ ]
#时间
'/sj': [ ㍘, ㍙, ㍚, ㍛, ㍜, ㍝, ㍞, ㍟, ㍠, ㍡, ㍢, ㍣, ㍤, ㍥, ㍦, ㍧, ㍨, ㍩, ㍪, ㍫, ㍬, ㍭, ㍮, ㍯, ㍰ ]
#天干、地支、干支
'/tg': [ 甲, 乙, 丙, 丁, 戊, 己, 庚, 辛, 壬, 癸 ]
'/dz': [ 子, 丑, 寅, 卯, 辰, 巳, 午, 未, 申, 酉, 戌, 亥 ]
'/gz': [ 甲子, 乙丑, 丙寅, 丁卯, 戊辰, 己巳, 庚午, 辛未, 壬申, 癸酉, 甲戌, 乙亥, 丙子, 丁丑, 戊寅, 己卯, 庚辰, 辛巳, 壬午, 癸未, 甲申, 乙酉, 丙戌, 丁亥, 戊子, 己丑, 庚寅, 辛卯, 壬辰, 癸巳, 甲午, 乙未, 丙申, 丁酉, 戊戌, 己亥, 庚子, 辛丑, 壬寅, 癸卯, 甲辰, 乙巳, 丙午, 丁未, 戊申, 己酉, 庚戌, 辛亥, 壬子, 癸丑, 甲寅, 乙卯, 丙辰, 丁巳, 戊午, 己未, 庚申, 辛酉, 壬戌, 癸亥 ]
#节气
'/jq': [ 立春, 雨水, 惊蛰, 春分, 清明, 谷雨, 立夏, 小满, 芒种, 夏至, 小暑, 大暑, 立秋, 处暑, 白露, 秋分, 寒露, 霜降, 立冬, 小雪, 大雪, 冬至, 小寒, 大寒 ]
#单位
'/dw': [ Å, ℃, , ‰, ‱, °, ℉, ㏃, ㏆, ㎈, ㏄, ㏅, ㎝, ㎠, ㎤, ㏈, ㎗, ㎙, ㎓, ㎬, ㏉, ㏊, ㏋, ㎐, ㏌, ㎄, ㎅, ㎉, ㎏, ㎑, ㏍, ㎘, ㎞, ㏎, ㎢, ㎦, ㎪, ㏏, ㎸, ㎾, ㏀, ㏐, ㏓, ㎧, ㎨, ㎡, ㎥, ㎃, ㏔, ㎆, ㎎, ㎒, ㏕, ㎖, ㎜, ㎟, ㎣, ㏖, ㎫, ㎳, ㎷, ㎹, ㎽, ㎿, ㏁, ㎁, ㎋, ㎚, ㎱, ㎵, ㎻, ㏘, ㎩, ㎀, ㎊, ㏗, ㏙, ㏚, ㎰, ㎴, ㎺, ㎭, ㎮, ㎯, ㏛, ㏜, ㎔, ㏝, ㎂, ㎌, ㎍, ㎕, ㎛, ㎲, ㎶, ㎼ ]
#货币
'/hb': [ ¥, ¥, ¤, ¢, , $, £, £, ৳, ฿, ₠, ₡, ₢, ₣, ₤, ₥, ₦, ₧, ₩, ₪, ₫, €, ₭, ₮, ₯, ₰, ₱, ₲, ₳, ₴, ₵, ₶, ₷, ₸, ₹, ₺, ₨, ﷼ ]
#结构、偏旁、康熙(部首)、笔画、标点
'/jg': [ ⿰, ⿱, ⿲, ⿳, ⿴, ⿵, ⿶, ⿷, ⿸, ⿹, ⿺, ⿻, 〾 ]
'/pp': [ 乛, 冫, 丷, 龹, ⺌, 龸, 亻, 亼, 亽, 仒, 冖, 冂, 冃, 冄, 宀, 罒, 㓁, 罓, 冈, 凵, 厶, 刂, 勹, 匚, 匸, 卩, 阝, 厂, 丆, 广, 壬, 訁, 讠, 釒, 钅, 飠, 饣, 龺, 攵, 夂, 夊, 尢, 尣, 兂, 旡, 巜, 巛, 彐, 彑, 彡, 彳, 龰, 辶, 廴, 㞢, 忄, 㣺, 扌, 爫, 龵, 廾, 歺, 癶, 氵, 氺, 火, 灬, 爿, 丬, 疒, 牜, ⺶, 犭, 豕, 豸, 虍, 艹, 卝, 龷, 丗, 龶, 芈, 丵, 菐, 黹, 礻, 衤, 糸, 糹, 纟, 龻, 镸, 髟, 襾, 覀, 吅, 㗊, 㠭, 㸚, 叕]
'/kx': [ 一, 丨, , 丿, 乙, 亅, 二, 亠, 人, 儿, 入, 八, 冂, 冖, 冫, 几, 凵, 刀, 力, 勹, 匕, 匚, 匸, 十, 卜, 卩, 厂, 厶, 又, 口, 囗, 土, 士, 夂, 夊, 夕, 大, 女, 子, 宀, 寸, 小, 尢, 尸, 屮, 山, 巛, 工, 己, 巾, 干, 幺, 广, 廴, 廾, 弋, 弓, 彐, 彡, 彳, 心, 戈, 戶, 手, 支, 攴, 文, 斗, 斤, 方, 无, 日, 曰, 月, 木, 欠, 止, 歹, 殳, 毋, 比, 毛, 氏, 气, 水, 火, 爪, 父, 爻, 爿, 片, 牙, 牛, 犬, 玄, 玉, 瓜, 瓦, 甘, 生, 用, 田, 疋, 疒, 癶, 白, 皮, 皿, 目, 矛, 矢, 石, 示, 禸, 禾, 穴, 立, 竹, 米, 糸, 缶, 网, 羊, 羽, 老, 而, 耒, 耳, 聿, 肉, 臣, 自, 至, 臼, 舌, 舛, 舟, 艮, 色, 艸, 虍, 虫, 血, 行, 衣, 襾, 見, 角, 言, 谷, 豆, 豕, 豸, 貝, 赤, 走, 足, 身, 車, 辛, 辰, 辵, 邑, 酉, 釆, 里, 金, 長, 門, 阜, 隶, 隹, 雨, 靑, 非, 面, 革, 韋, 韭, 音, 頁, 風, 飛, 食, 首, 香, 馬, 骨, 高, 髟, 鬥, 鬯, 鬲, 鬼, 魚, 鳥, 鹵, 鹿, 麥, 麻, 黃, 黍, 黑, 黹, 黽, 鼎, 鼓, 鼠, 鼻, 齊, 齒, 龍, 龜, 龠 ]
'/bh': [ ㇀, ㇁, ㇂, ㇃, ㇄, ㇅, ㇆, ㇇, ㇈, ㇉, ㇊, ㇋, ㇌, ㇍, ㇎, ㇏, ㇐, ㇑, ㇒, , , ㇕, ㇖, ㇗, ㇘, ㇙, ㇚, ㇛, ㇜, ㇝, ㇞, ㇟, ㇠, ㇡, ㇢, ㇣]
'/bd': [ 、, 。, 「, 」, 『, 』, 【, 】, 〈, 〉, 《, 》, ₋, ⁻, ―, ˗, ˉ, _, , , , ¡, ‼, ⁉, ¿, ؟, ⁈, ⁇, 、, 。, 〃, 〄, 々, 〆, , 〒, 〓, , , 〖, 〗, 〘, 〙, 〚, 〛, 〜, 〝, 〞, 〟, 〠, 〰, 〱, 〲, , 〴, 〵, 〶, 〷, 〻, 〼, 〽 ]
'/bdz': [ ﹅, ﹆, ﹁, ﹂, ﹃, ﹄, ︙, ︱, ︻, ︼, ︗, ︘, ︵, ︶, ︷, ︸, ︹, ︺, ︿, ﹀, ︽, ︾, , ︲, ︳, ︴, ﹉, ﹊, ﹋, ﹌, , , , ﹇, ﹈, ︐, ︑, ︒, ︔, ︕, ︖ ]
#拼音、注音、声调
'/py': [ ā, á, ǎ, à, ō, ó, ǒ, ò, ê, ê̄, ế, ê̌, ề, ē, é, ě, è, ī, í, ǐ, ì, ū, ú, ǔ, ù, ü, ǖ, ǘ, ǚ, ǜ, ḿ, m̀, ń, ň, ǹ, ẑ, ĉ, ŝ, ŋ ]
'/pyd': [ Ā, Á, Ǎ, À, Ō, Ó, Ǒ, Ò, Ê, Ê̄, Ế, Ê̌, Ề, Ē, É, Ě, È, Ī, Í, Ǐ, Ì, Ū, Ú, Ǔ, Ù, Ü, Ǖ, Ǘ, Ǚ, Ǜ, Ḿ, M̀, Ń, Ň, Ǹ, Ẑ, Ĉ, Ŝ, Ŋ ]
'/zy': [ ㄅ, ㄆ, ㄇ, ㄈ, ㄉ, ㄊ, ㄋ, ㄌ, ㄍ, ㄎ, ㄏ, ㄐ, ㄑ, ㄒ, ㄓ, ㄔ, ㄕ, ㄖ, ㄗ, ㄘ, ㄙ, ㄧ, ㄨ, ㄩ, ㄚ, ㄛ, ㄜ, ㄝ, ㄞ, ㄟ, ㄠ, ㄡ, ㄢ, ㄣ, ㄤ, ㄥ, ㄦ, ㄪ, ㄫ, ㄬ, ㄭ, ㆠ, ㆡ, ㆢ, ㆣ, ㆤ, ㆥ, ㆦ, ㆧ, ㆨ, ㆩ, ㆪ, ㆫ, ㆬ, ㆭ, ㆮ, ㆯ, ㆰ, ㆱ, ㆲ, ㆳ, ㆴ, ㆵ, ㆶ, ㆷ ]
'/sd': [ ˉ, ˊ, ˇ, ˋ, ˆ, ˙, ˜, ˥, ˦, ˧, ˨, ˩, ꜀, ꜁, ꜂, ꜃, ꜄, ꜅, ꜆, ꜇, '〪', '〫', '〬', '〭' ]
#汉字+圈v弧
'/hzq': [ ㊀, ㊁, ㊂, ㊃, ㊄, ㊅, ㊆, ㊇, ㊈, ㊉, ㊊, ㊋, ㊌, ㊍, ㊎, ㊏, ㊐, ㊑, ㊒, ㊓, ㊔, ㊕, ㊖, ㊗, ㊘, ㊙, ㊚, ㊛, ㊜, ㊝, ㊞, ㊟, ㊠, ㊡, ㊢, ㊣, ㊤, ㊥, ㊦, ㊧, ㊨, ㊩, ㊪, ㊫, ㊬, ㊭, ㊮, ㊯, ㊰, ㉄, ㉅, ㉆, ㉇ ]
'/hzh': [ ㈠, ㈡, ㈢, ㈣, ㈤, ㈥, ㈦, ㈧, ㈨, ㈩, ㈪, ㈫, ㈬, ㈭, ㈮, ㈯, ㈰, ㈱, ㈲, ㈳, ㈴, ㈵, ㈶, ㈷, ㈸, ㈹, ㈺, ㈻, ㈼, ㈽, ㈾, ㈿, ㉀, ㉁, ㉂, ㉃ ]
#いろは順
'/iro': [ い, ろ, は, に, ほ, へ, と, ち, り, ぬ, る, を, わ, か, よ, た, れ, そ, つ, ね, な, ら, む, う, ゐ, の, お, く, や, ま, け, ふ, こ, え, て, あ, さ, き, ゆ, め, み, し, ゑ, ひ, も, せ, す ]
#假名
'/jm': [ あ, ぁ, い, ぃ, う, ぅ, え, ぇ, お, ぉ, か, ゕ, が, き, ぎ, く, ぐ, け, ゖ, げ, こ, ご, さ, ざ, し, じ, す, ず, せ, ぜ, そ, ぞ, た, だ, ち, ぢ, つ, っ, づ, て, で, と, ど, な, に, ぬ, ね, の, は, ば, ぱ, ひ, び, ぴ, ふ, ぶ, ぷ, へ, べ, ぺ, ほ, ぼ, ぽ, ま, み, む, め, も, や, ゃ, ゆ, ゅ, よ, ょ, ら, り, る, れ, ろ, わ, ゎ, ゐ, ゔ, ゑ, を, ん, ・, ー, ゝ, ゞ, ゟ ]
'/pjm': [ ア, ァ, イ, ィ, ウ, ゥ, エ, ェ, オ, ォ, カ, ヵ, ガ, キ, ギ, ク, グ, ケ, ヶ, ゲ, コ, ゴ, サ, ザ, シ, ジ, ス, ズ, セ, ゼ, ソ, ゾ, タ, ダ, チ, ヂ, ツ, ッ, ヅ, テ, デ, ト, ド, ナ, ニ, ヌ, ネ, , ハ, バ, パ, ヒ, ビ, ピ, フ, ブ, プ, ヘ, ベ, ペ, ホ, ボ, ポ, マ, ミ, ム, メ, モ, ヤ, ャ, ユ, ュ, ヨ, ョ, ラ, リ, ル, レ, ロ, ワ, ヮ, ヰ, ヸ, ヴ, ヱ, ヹ, ヲ, ヺ, ン, ・, ー, ヽ, ヾ, ヿ, ㇰ, ㇱ, ㇲ, ㇳ, ㇴ, ㇵ, ㇶ, ㇷ, ㇸ, ㇹ, ㇺ, ㇻ, ㇼ, ㇽ, ㇾ, ㇿ ]
'/jmk': [ か, ゕ, き, く, け, ゖ, こ, カ, ヵ, キ, ク, ケ, ヶ, コ ]
'/jmg': [ が, ぎ, ぐ, げ, ご, ガ, ギ, グ, ゲ, ゴ ]
'/jms': [ さ, し, す, せ, そ, サ, シ, ス, セ, ソ ]
'/jmz': [ ざ, じ, ず, ぜ, ぞ, ザ, ジ, ズ, ゼ, ゾ ]
'/jmt': [ た, ち, つ, っ, て, と, タ, チ, ツ, ッ, テ, ト ]
'/jmd': [ だ, ぢ, づ, で, ど, ダ, ヂ, ヅ, デ, ド ]
'/jmn': [ な, に, ぬ, ね, の, ん, ナ, ニ, ヌ, ネ, , ン ]
'/jmh': [ は, ひ, ふ, へ, ほ, ハ, ヒ, フ, ヘ, ホ ]
'/jmb': [ ば, び, ぶ, べ, ぼ, バ, ビ, ブ, ベ, ボ ]
'/jmp': [ ぱ, ぴ, ぷ, ぺ, ぽ, パ, ピ, プ, ペ, ポ ]
'/jmm': [ ま, み, む, め, も, マ, ミ, ム, メ, モ ]
'/jmy': [ や, ゃ, ゆ, ゅ, よ, ょ, ヤ, ャ, ユ, ュ, ヨ, ョ ]
'/jmr': [ ら, り, る, れ, ろ, ラ, リ, ル, レ, ロ ]
'/jmw': [ わ, ゐ, ゑ, を, ワ, ヰ, ヱ, ヲ ]
'/jma': [ あ, か, が, さ, ざ, た, だ, な, は, ば, ぱ, ま, や, ら, わ, ア, カ, ガ, サ, ザ, タ, ダ, ナ, ハ, バ, パ, マ, ヤ, ラ, ワ ]
'/jmi': [ い, き, ぎ, し, じ, ち, ぢ, に, ひ, び, ぴ, み, り, ゐ, イ, キ, ギ, シ, ジ, チ, ヂ, ニ, ヒ, ビ, ピ, ミ, リ, ヰ ]
'/jmu': [ う, く, ぐ, す, ず, つ, づ, ぬ, ふ, ぶ, ぷ, む, る, ウ, ク, グ, ス, ズ, ツ, ヅ, ヌ, フ, ブ, プ, ム, ル ]
'/jme': [ え, け, げ, せ, ぜ, て, で, ね, へ, べ, ぺ, め, れ, ゑ, エ, ケ, ゲ, セ, ゼ, テ, デ, ネ, ヘ, ベ, ペ, メ, レ, ヱ ]
'/jmo': [ お, こ, ご, そ, ぞ, と, ど, の, ほ, ぼ, ぽ, も, ろ, を, オ, コ, ゴ, ソ, ゾ, ト, ド, , ホ, ボ, ポ, モ, ロ, ヲ ]
#假名+圈
'/jmq': [ ㋐, ㋑, ㋒, ㋓, ㋔, ㋕, ㋖, ㋗, ㋘, ㋙, ㋚, ㋛, ㋜, ㋝, ㋞, ㋟, ㋠, ㋡, ㋢, ㋣, ㋤, ㋥, ㋦, ㋧, ㋨, ㋩, ㋪, ㋫, ㋬, ㋭, ㋮, ㋯, ㋰, ㋱, ㋲, ㋳, ㋴, ㋵, ㋶, ㋷, ㋸, ㋹, ㋺, ㋻, ㋼, ㋽, ㋾ ]
#假名+半角
'/jmbj': [ ア, ァ, イ, ィ, ウ, ゥ, エ, ェ, オ, ォ, カ, キ, ク, ケ, コ, サ, シ, ス, セ, ソ, タ, チ, ツ, ッ, テ, ト, ナ, ニ, ヌ, ネ, ノ, ハ, ヒ, フ, ヘ, ホ, マ, ミ, ム, メ, モ, ヤ, ャ, ユ, ュ, ヨ, ョ, ラ, リ, ル, レ, ロ, ワ, ヲ, ン, ・, ー, ゙, ゚ ]
#韩文
'/hw': [ ㄱ, ㄴ, ㄷ, ㄹ, ㅁ, ㅂ, ㅅ, ㅇ, ㅈ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ ]
#韩文+圈v弧
'/hwq': [ ㉠, ㉡, ㉢, ㉣, ㉤, ㉥, ㉦, ㉧, ㉨, ㉩, ㉪, ㉫, ㉬, ㉭, ㉮, ㉯, ㉰, ㉱, ㉲, ㉳, ㉴, ㉵, ㉶, ㉷, ㉸, ㉹, ㉺, ㉻, ㉼, ㉽, ㉾, ㉿ ]
'/hwh': [ ㈀, ㈁, ㈂, ㈃, ㈄, ㈅, ㈆, ㈇, ㈈, ㈉, ㈊, ㈋, ㈌, ㈍, ㈎, ㈏, ㈐, ㈑, ㈒, ㈓, ㈔, ㈕, ㈖, ㈗, ㈘, ㈙, ㈚, ㈛, ㈜, ㈝, ㈞ ]
# 中文标点符号表,来自 https://www.w3.org/TR/clreq/#tables_of_chinese_punctuation_marks
# 将点号、非夹、夹注、行间四个类别放在不同的列表中
'/dh': [。, , , 、, , , , ‼, , ⁇]
'/fj': [⸺, ——, ……, ⋯⋯, , -, , —, ·, ・, ‧, /, , , ]
'/jz': [「, 」, 『, 』, “, ”, , , , , 《, 》, 〈, 〉, 【, 】, 〖, 〗, , , , , , , «, », , , ⟨, ⟩]
'/hj': [_, , ●, •]
'/yd': [·, ・, •, ●]
# Unicode General Punctuation https://www.unicode.org/charts/PDF/U2000.pdf
# 将 Unicdoe 中的非 ASCII 英文标点列在此处,而实际上对应的中文标点与其共享码位
# 中英标点
'/bdzy': [, , , , —, ―, ‖, ‗, , , , , “, ”, „, ‟, †, ‡, •, ‣, , ‥, …, ‧, ‰, ‱, , ″, ‴, , ‶, ‷, ‸, , , ※, ‼, ‽, ‾, ‿, ⁀, , ⁂, , , ⁅, ⁆, ⁇, ⁈, ⁉, ⁊, ⁋, ⁌, ⁍, , ⁏, ⁐, ⁑, ⁒, , ⁔, ⁕, ⁖, ⁗, ⁘, ⁙, , ⁛, ⁜, ⁝, ⁞]
#动物界
'/dwj': [🐶, 🐮, 🐵, 🙈, 🙉, 🙊, 🐒, 🐔, 🐴, 🐷, 🐽, 🐭, 🦐, 🦀, 🐢, 🐱, 🐹, 🐰, 🐻, 🐼, 🐨, 🐧, 🐦, 🐤, 🐣, 🐥, 🐯, 🦁, 🐸, 🐙, 🦆, 🦅, 🦉, 🦇, 🐺, 🐗, 🦄, 🐝, 🐛, 🦋, 🐌, 🐞, 🐜, 🕷, 🦂, 🐍, 🦎, 🦑, 🐠, 🐟, 🐡, 🐬, 🐳, 🐊, 🐆, 🐅, 🐃, 🐂, 🐄, 🐪, 🐫, 🐘, 🦏, 🦍, 🐐, 🐏, 🐑, 🐎, 🐖, 🐀, 🐁, 🐓, 🦃, 🕊, 🐕, 🐩, 🐈, 🐇, 🐿, 🦆, 🦅, 🦉, 🦇, 🐺, 🐗, 🦄, 🐴, 🐝, 🐛, 🐞, 🪲, 🦟, 🐚, 🐌, 🦋, 🐜, 🕷️, 🐢, 🐍, 🦎, 🦂, 🦀, 🦑, 🐙, 🦐, 🦞, 🦪, 🐠, 🐟, 🐡, 🪼, 🐬, 🦈, 🐋, 🐊, 🐆, 🐅, 🐃, 🐂, 🐄, 🦬, 🦌, 🐪, 🐫, 🐘, 🦏, 🦍, 🦧, 🦣, 🐎, 🐖, 🐐, 🐏, 🐑, 🐕, 🐩, 🐈, 🐈‍⬛️, 🐇, 🐁, 🐀, 🐿️, 🐉, 🐒, 🦙, 🦛, 🫏, 🫎, 🦖, 🦕, 🦡, 🦝, 🦨, 🦫, 🦦, 🦭, 🦥, 🐓, 🦃, 🕊️, 🦩, 🪿, 🦢, 🦜, 🦤, 🦚, 🐦‍⬛]
#表情
'/bq': [ 😀, 😁, 😂, 🤣, 😃, 😄, 😅, 😆, 😉, 😊, 😋, 😎, 😍, 😘, 😗, 😙, 😚, ☺, 🙂, 🤗, 🤩, 🤔, 🤨, 😐, 😑, 😶, 🙄, 😏, 😣, 😥, 😮, 🤐, 😯, 😪, 😫, 😴, 😌, 😛, 😜, 😝, 🤤, 😒, 😓, 😔, 😕, 🙃, 🤑, 😲, ☹, 🙁, 😖, 😞, 😟, 😤, 😢, 😭, 😦, 😧, 😨, 😩, 🤯, 😬, 😰, 😱, 😳, 🤪, 😵, 😠, 😡, 🤬, 😷, 🤒, 🤕, 🤢, 🤮, 🤧, 😇, 🤠, 🤡, 🤥, 🤫, 🤭, 🧐, 🤓 ]
#天气
'/tq': [☀️, 🌤️, ⛅️, 🌦️, 🌥️, ☁️, 🌨️, 🌧️, 🌩️, ⛈️, ❄️, 💨, 🌪️, 🌫️, 🌊]
#国旗
'/gq': [🏳️, 🏴, 🏴‍☠️, 🏁, 🚩, 🏳️‍🌈, 🏳️‍⚧️, 🇺🇳, 🇦🇺, 🇨🇦, 🇨🇳, 🇩🇪, 🇭🇰, 🇯🇵, 🇳🇿, 🇹🇼, 🇺🇸]
#手势
'/ss': [👌, 👍, 👎, 👊, 🤝, ✌️, 💪, 🙏, ✊, 👏, 👋, 🤞, ✋, 🤚, 🖖, 🤙, 🖕, 🤟, ☝️, 👆, 👇, 👈, 👉, 🤛, 🤜, 🤲, 🤘, 🙌, 👐, ✍️, 💅]
#按键
'/aj': [⌘, ⌥, ⇧, ⌃, ⎋, ⇪, , ⌫, ⌦, ↩︎, ⏎, ␣, ⏏, ⇟, ⇞]
#特殊符号
'/tsfh': [©, ®, ℗, ⓘ, ℠, ™, ℡, ␡, ♂, ♀, ☉, ☊, ☋, ☌, ☍, ☐, ☑︎, ☒, ☜, ☝, ☞, ☟, ✎, ✄, ♻, ⚐, ⚑, ⚠]
#常用
'/cy': [👌, 👍, 😂, 😅, 😡, 😮, 😱, 😭, 😘, 😰, 💩]
#中华
'/zh': [🧧, 🥮, 🧨, 🧮]
#早餐
'/zc': [🍜, 🍚, 🍲, 🥘, 🥟, 🥠, 🥡, 🥢]
#串串
'/cc': [🍢, 🍡]
#体育器材
'/tyqc': [🏒, 🏸, 🏓, 🏑, 🏏, ⛳️, 🏹, ⚽️, 🏀, 🏈, ⚾️, 🥎️, 🎾, 🏐, 🏉, 🎱, ⛸️, 🛼, 🎿, 🎳, 🥏, 🥍, 🛹, 🤿, 🪂, 🛷, 🥌, 🪃, 🪁]
#运动员
'/ydy': [⛷️, 🏂🏻, 🏋🏻, 🤺, 🤼🏻, 🤸🏻, ⛹🏻, 🤾🏻, 🏌🏻, 🏄🏻, 🏊🏻, 🤽🏻, 🚣🏻, 🏇🏻, 🚴🏻, 🚵🏻, 🧗🏻, 🤹🏻]
#动物脸
'/dwl': [🐶, 🐱, 🐭, 🐹, 🐰, 🦊, 🐻, 🐻‍❄️, 🐼, 🐨, 🐯, 🦁, 🐮, 🐷, 🐽, 🐸, 🐵]
#包包
'/bb': [👝, 👛, 👜, 💼, 🧳, 🎒]
#午餐/晚餐
'/wc': [🍛, 🍲, 🍝, 🍜, 🥘, 🍣, 🍱, 🍘, 🍙, 🍚, 🥡]
#景点
'/jd': [🗽, 🏰, 🗼, 🗻, 🏯, 🏝️, 🏖️, 🌁, 🌉, 🏞️]
#器官
'/qg': [👁️, 👂🏻, 👃🏻, 👄, 🦷, 🧠, 🫁, 🫀, 🦵🏻, 🦶🏻, 🖐🏻, 👅]
#圆形
'/yx': [🔴, 🟠, 🟡, 🟢, 🔵, 🟣, 🟤, ⚫️, ⚪️]
#纸币
'/zb': [💵, 💶, 💷, 💴]
#夜空
'/yk': [🌙, 💫, ⭐️, 🌟, ✨, 🌛, 🌜]
#自然
'/zr': [🔥, 💧, 🌬️, 🫧, ☀️, 🌤️, ⛅️, 🌦️, 🌥️, ☁️, 🌨️, 🌧️, 🌩️, ⛈️, ❄️, 💨, 🌪️, 🌫️, 🌊, 🧊, 🪨]
#娱乐
'/yule': [🎮, 🎰, 🎲, 🎯, 🎳, 🎧, 🎤️, 🎪, 🎫, 🎟️, ♟️, 🕹️, 🖲️, 🪀, 🪩]
#宗教
'/zj': [✝️, ☪️, 🕉️, ☸️, 🔯, 🕎, ☯️, ☦️, 🪯, 🛐, ⛪️, 🕌, 🕍, 🕋, ⛩️, 🛕]
#家鸡/鸡鸡
'/jj': [🦆, 🐓, 🦃, 🐔, 🐤, 🐣, 🐥, 🦚, 🪿]
#工具
'/gj': [⚙️, 🔩, ⛏️, 🛠️, ⚒️, 🔨, 🔧, ⛓️, 🧰, 🪒, 🪚, 🪛, 🪜, 🪡]
#帽子
'/mz': [👒, 🧢, 🎩, 🎓, ⛑️, 🪖]
#甜心/桃心
'/tx': [❤️, 🧡, 💛, 💚, 💙, 🩵, 🩷, 💜, 🤎, 🖤, 🩶, 🤍]
#数码
'/sm': [⌚️, 📱, 💻, ⌨️, 🖥️, 🖨️, 🖱️, 📷, 📹, 💾, 💽, 💿, 📀]
#早点
'/zd': [🍳, 🥚, 🧀, 🥖, 🥛, 🍯, 🥪, 🥫, 🥯, 🧇, 🫓]
#时分
'/sf': [🕛, 🕧, 🕐, 🕜, 🕑, 🕝, 🕒, 🕞, 🕓, 🕟, 🕔, 🕠, 🕕, 🕡, 🕖, 🕢, 🕗, 🕣, 🕘, 🕤, 🕙, 🕥, 🕚, 🕦]
#月亮
'/yl': [🌕, 🌖, 🌗, 🌘, 🌑, 🌒, 🌓, 🌔]
#服装
'/fz': [🧥, 👚, 👕, 👖, 🩳, 👔, 👗, 👘, 🥻, 🩲, 👙, 🩱, 🥼]
#水果
'/sg': [🍏, 🍎, 🍐, 🍊, 🍋, 🍌, 🍉, 🍇, 🍓, 🫐, 🍈, 🍒, 🍑, 🍍, 🥝, 🥑, 🥥, 🥭]
#植物
'/zw': [🌲, 🌳, 🎄, 🌵, 🌴, 🌱, 🌿, ☘️, 🍀, 🎍, 🪴, 🌾, 🥬, 🪻]
#乐器
'/yq': [🎻, 🎸, 🎹, 🎷, 🎺, 🥁, 🪕, 🪘, 🪗, 🪈, 🪇]
#武器
'/wq': [🔫, 🗡️, ⚔️, 🔪, 🛡️, 🪓, 🚀]
#汽车
'/qc': [🚗, 🚕, 🚙, 🚌, 🚎, 🏎️, 🚓, 🚑, 🚒, 🚐, 🚚, 🚛, 🎢, 🛻, 🚔, 🚍, 🚘, 🚖, 🛺]
#火车
'/hc': [🚄, 🚅, 🚝, 🚆, 🚂, 🚉, 🚈, 🚇, 🚊]
#公交车
'/gjc': [🚞, 🚋, 🚃, 🚟]
#奖牌
'/jp': [🏅, 🎖️, 🥇, 🥈, 🥉, 🏆]
#球类
'/ql': [⚽️, 🏀, 🏈, 🏐, 🏉, ⚾️, 🥎️, 🎾, 🎱, 🪀, 🏓, 🏸, 🏒, 🏑, 🏏, 🛹, 🥍]
#甜点
'/td': [🍯, 🍰, 🍮, 🎂, 🍭, 🍬, 🍫, 🍩, 🍪, 🍦, 🧁]
#十二生肖
'/sesx': [🐁, 🐀, 🐂, 🐃, 🐄, 🦬, 🐅, 🐆, 🐇, 🐉, 🐍, 🐎, 🐏, 🐐, 🐑, 🐒, 🦧, 🦍, 🦃, 🐓, 🐕, 🦮, 🐕‍🦺, 🐖, 🐗]
#节日色彩
'/jrsc': [🎊, 🎉, 🪅, 🎏, 🎎, 🏮, 🎐, 🧧, 🎁, 🧨, 🎇, 🎆, 🎑, 🎄, 🧑🏻‍🎄]
#粗粮
'/cl': [🌽, 🥔, 🍠, 🥜, 🌰]
#精灵
'/jl': [🧙🏻, 🧝🏻, 🧛🏻, 🧟, 🧞, 🧜🏻, 🧚🏻, 🦹🏻]
#船只
'/cz': [🚢, ⛴️, 🛳️, 🛥️, 🚤, ⛵️, 🛶, ⚓️]
#花朵
'/hd': [🌸, 🌺, 🌼, 🌻, 🌷, 🌹, 💐, 🥀, 🪷, 🪻]
#色彩
'/sc': [🍅, 🍆, 🥒, 🥕, 🌶️, 🥦, 🥗, 🥬, 🫒, 🫑, 🫘, 🫛]
#叶子
'/yz': [🍃, 🍂, 🍁, 🌱, 🌿, 🥬]
#虫子
'/chz': [🐛, 🪱, 🐞, 🪲, 🪳, 🦗, 🦟, 🐜, 🪰, 🐌, 🐝]
#血型
'/xx': [🅰️, 🅱️, 🅾️, 🆎️]
#西餐
'/xc': [🍕, 🥓, 🧀, 🥖, 🥐, 🍝, 🌯, 🌮, 🥙, 🍟, 🍔, 🌭, 🥞, 🥪, 🥯, 🧇, 🫕]
#调料
'/tl': [🧄, 🫚, 🧅, 🧂, 🧀]
#酒水
'/js': [🍷, 🥃, 🍺, 🍶, 🍾, 🍸]
#雪
'/xue': [❄️, 🌨️, ☃️, ⛄️, 🧊]
#小零食
'/xls': [🍭, 🍬, 🍫, 🍿, 🍩, 🍪]
#电器
'/dq': [💡, 📺, ☎️, 📟, 📞, 📠, 📻, 🕰️, 📡, 🔦]
'/exz': [👡, 👢, 👞, 👟, 🥾, 🥿, 👠, 🛼, ⛸️]
#颜色
'/ys': [🟥, 🟧, 🟨, 🟩, 🟦, 🟪, 🟫, ⬛️, ⬜️, 🔴, 🟠, 🟡, 🟢, 🔵, 🟣, 🟤, ⚫️, ⚪️, ❤️, 🧡, 💛, 💚, 💙, 🩵, 🩷, 💜, 🤎, 🖤, 🩶, 🤍]
#餐饮
'/yp': [🧋, 🍹, 🧃, 🍸, 🍵, ☕️, 🥛, 🍷, 🥃, 🍶, 🥂, 🍾, 🍻, 🍺, 🧉]
#餐具
'/cj': [🥄, 🍴, 🍽️, 🥣, 🥢, 🫖]
#发型
'/fx': [🦲, 🦰, 🦱, 🦳]
'/eyl': [🐠, 🐟, 🐡, 🪼, 🐬, 🐳, 🐋, 🦈, 🦭, 🦦]
#鸟类
'/niao': [🦆, 🦅, 🦉, 🦇, 🐓, 🦃, 🕊️, 🐧, 🐦, 🦚, 🦜, 🦩, 🦤, 🦢, 🪿, 🐦‍⬛]
#面包
'/mb': [🍞, 🥐, 🥖, 🥨, 🥯, 🍩, 🥮]
#点心
'/dx': [🍮, 🍩, 🍪, 🍧, 🍨, 🍦, 🍰, 🧁, 🧇, 🧆]

365
wanxiang_t9.schema.yaml Normal file
View File

@@ -0,0 +1,365 @@
# Rime schema
# encoding: utf-8
schema:
schema_id: wanxiang_t9
name: 万象・仓九
version: "LTS"
author:
- amzxyz
- morse
description: |
仓输入法:万象拼音九宫格方案
dependencies:
- wanxiang_mixedcode #中英文混合词汇
- wanxiang_reverse # 部件拆字,反查及辅码
# 开关
# reset: 默认状态。注释掉后,切换窗口时不会重置到默认状态。
# states: 方案选单显示的名称。可以注释掉,仍可以通过快捷键切换。
# abbrev: 默认的缩写取 states 的第一个字符abbrev 可自定义一个字符
switches:
- name: ascii_mode # 中英输入状态
states: [ 中文, 英文 ]
- name: ascii_punct # 中英标点,可以在中文输入状态输入英文符号
states: [ 中标, 英标 ]
- name: full_shape #全角、半角字符输出
states: [ 半角, 全角 ]
- name: emoji #候选出现emoji滤镜会显示在相应的候选后面万象侧重于tips提示避免候选被占用因此默认为reset: 0归属opencc emoji滤镜
states: [表情关, 表情开]
- name: chinese_english #候选进入翻译模式滤镜会显示在相应的候选后面万象侧重于tips提示避免候选被占用归属opencc 翻译滤镜
states: [ 翻译关, 翻译开 ]
- options: [ raw_input, tone_display, full_pinyin ] #开启后在输入编码的位置实时转换为带声调全拼或者不带声调全拼不开启则采用系统配置原始编码影响的是preedit_format,归属super_preedit.lua
states: [ 原编码, 有声调, 无声调 ]
# reset: 2 #对于开关组从0开始数第几个就reset几可设为默认
- options: [ s2s, s2t, s2hk, s2tw ] # 简繁转换开关组,可以在一个空选项和多个实际“- simplifier@s2hk”引入的项目之前切换这是一个开关组你可以将其中任意一个s2s等设置为toggle快捷键多次按下将轮询
states: [ 简体, 通繁, 港繁, 臺繁 ]
- name: tone_hint #开启后在候选的注释里面实时显示全拼声调不开启则采用系统配置影响的是comment_format归属super_comment.lua
states: [ 读音关, 读音开 ]
- name: super_tips #开启后在输入编码后面的提示区显示实时的提示数据受tips数据库影响表情、翻译、车牌、符号等对应关系数据并可实现句号上屏不开启则默认影响的是segment.prompt参数归属super_tips.lua
states: [ 提示关, 提示开 ]
reset: 1
# 输入引擎
engine:
processors:
- lua_processor@*super_tips #超级提示模块:表情、简码、翻译、化学式、等等靠你想象
- lua_processor@*partial_commit #通过ctrl+1~0局部提交10个字以内的句子的前几个字一般为正确的前几个使用时要遵循合理的分词结构能促进后续编码打出正确的词汇
- lua_processor@*super_sequence*P #手动排序,高亮候选 ctrl+j左移动 ctrl+k 右移动 ctrl+l 移除位移 ctrl+p 置顶
- lua_processor@*limit_repeated #用于限制最大候选长度以及最大重复输入声母编码长度,避免性能异常
- lua_processor@*backspace_limit #防止连续 Backspace 在编码为空时删除已上屏内容
- ascii_composer #处理英文模式及中英文切换
- recognizer #与 matcher 搭配,处理符合特定规则的输入码,如网址、反查等 tags
- key_binder #在特定条件下将按键绑定到其他按键,如重定义逗号、句号为候选翻页、开关快捷键等
- lua_processor@*key_binder #绑定按键扩展能力,支持正则扩展将按键生效情景更加细化
- speller #拼写处理器,接受字符按键,编辑输入
- punctuator #符号处理器,将单个字符按键直接映射为标点符号或文字
- selector #选字处理器,处理数字选字键〔可以换成别的哦〕、上、下候选定位、换页
- navigator #处理输入栏内的光标移动
- express_editor #编辑器,处理空格、回车上屏、回退键
segmentors:
- ascii_segmentor #标识英文段落〔譬如在英文模式下〕字母直接上屛
- matcher #配合 recognizer 标识符合特定规则的段落,如网址、反查等,加上特定 tag
- abc_segmentor #标识常规的文字段落,加上 abc 这个 tag
- affix_segmentor@wanxiang_reverse #反查 tag
- punct_segmentor #标识符号段落〔键入标点符号用〕加上 punct 这个 tag
- fallback_segmentor #标识其他未标识段落必须放在最后帮助tag模式切换后回退重新处理
translators:
- punct_translator #配合 punct_segmentor 转换标点符号
- script_translator #脚本翻译器,用于拼音、粤拼等基于音节表的输入方案
- lua_translator@*version_display #输入'/wx',显示万象项目网址和当前版本号
- lua_translator@*shijian #农历、日期、节气、节日、时间、周、问候模板等等,触发清单看下文
- lua_translator@*unicode #通过输入大写U引导并输入Unicode编码获得汉字输出
- lua_translator@*number_translator #数字、金额大写通过输入大写R1234获得候选输出
- lua_translator@*super_calculator #超级计算器Lua内查看高级用法
- table_translator@custom_phrase #自定义短语 custom_phrase.txt用于置顶自定义编码候选词
- table_translator@chengyu #简码成语词汇表导入
- table_translator@wanxiang_mixedcode #中英等混合词汇表导入
- table_translator@wanxiang_reverse #挂接部件组字和笔画反查
filters:
- lua_filter@*super_sequence*F #手动排序,高亮候选 ctrl+j左移动 ctrl+k 右移动 ctrl+0 移除位移
- reverse_lookup_filter@radical_reverse_lookup #部件拆字滤镜放在super_comment前面进一步被超级注释处理以获得拼音编码的提示
- lua_filter@*super_comment_preedit #超级注释模块、超级preedit支持错词提示、辅助码显示部件组字读音注释有声调、无声调全拼编码的转换支持个性化配置和关闭相应的功能详情搜索super_comment_preedit进行详细配置
- simplifier@emoji #Emoji滤镜
- simplifier@s2t #简繁切换通繁
- simplifier@s2tw #简繁切换台繁
- simplifier@s2hk #简繁切换港繁
- simplifier@chinese_english #中英翻译滤镜
- lua_filter@*super_lookup #字词输入中反查辅助筛选
- lua_filter@*super_filter #功能太多详见Lua文件
- uniquifier # 去重
super_comment: # 超级注释模块,子项配置 true 开启false 关闭
candidate_length: 1 # 候选词辅助码提醒的生效长度0为关闭 但同时清空其它,应当使用上面开关来处理
corrector_type: "comment" # 错音措字,随意更换左右括号,比如"comment" 不加括号为无括号comment占位不能动
chaifen: "chaifen" # 拆分显示,随意更换左右括号,比如"chaifen" 不加括号为无括号chaifen占位不能动
# Tips 配置项
tips:
# 禁用的 tips 类型,初始化 tips 数据库的时候会直接忽略相关规则,修改部署后生效
# 可选项为:偏旁,符号,化学式,时间,符号,组字,翻译,表情,货币,车牌
disabled_types: []
#在8105基础上你可以通过黑白名单微调你自己的字符集过滤清单主数据库位于lua/charset.bin不可编辑
charsetlist: []
charsetblacklist: []
#shijian:仅仅作为提示使用编码已经写死引导键可以在key_binder下修改前缀
#时间osj 或者 /sj
#日期orq 或者 /rq
#农历onl 或者 /nl
#星期oxq 或者 /xq
#今年第几周oww 或者 /ww
#节气ojq 或者 /jq
#日期+时间odt 或者 /dt
#时间戳ott 或者 /tt
#大写N日期N20250315 或者N0312不带年
#节日ojr 或者 /jr
#问候模板:/day 或者 oday
# 通用日期时间格式化函数(供 /rq、/sj、/dt、N0101、N20150101 场景复用)
# 支持转义:
# \X —— 转义单个字符 X按字面量输出如 \Y \m \H 等)
# [[...]] —— 区块整体按字面量输出
#
# 约定占位符:
# 【日期】
# Y 四位年份 0000-9999 例2025
# y 两位年份 00-99 例25
# m 月(前导零) 01-12 例02
# n 月(不带前导零) 1-12 例2
# d 日(前导零) 01-31 例09
# j 日(不带前导零) 1-31 例9
#
# 【时间】
# H 24小时前导零 00-23 例08
# G 24小时不带零 0-23 例8
# I 12小时前导零 01-12 例08
# l 12小时不带零 1-12 例8 (注意是小写 L
# M 分钟(前导零) 00-59 例05
# S 秒(前导零) 00-59 例09
# p am/pm小写 am / pm
# P AM/PM大写 AM / PM
# 【时区】
# O 带冒号格式 +08:00、-04:30、+05:45
# o 不带冒号格式 +0800、-0430、+0545
date_formats:
- "Y年m月d日"
- "Y-m-d"
- "Y/m/d"
- "Y.m.d"
- "Ymd"
- "Y年n月j日"
- "y年n月j日"
- "n月j日"
time_formats:
- "H:M"
- "H点M分"
- "H:M:S"
- "H时M分S秒"
- "下午I:M"
- "I:M P"
datetime_formats:
- "Y-m-d H:M:S"
- "Y-m-dTH:M:S O"
- "YmdHMS"
- "Y年m月d日 H点M分"
- "y/m/d I:M p"
# Lua 配置:计算器触发关键字
calculator:
trigger: "V"
# 主翻译器,拼音
translator:
dictionary: wanxiang # 挂载主词库
# packs: user #导入根目录下名称为user.dict.yaml的自定义固定词典
prism: wanxiang_t9 # 多方案共用一个词库时,为避免冲突,需要用 prism 指定一个名字。
enable_completion: true # 启用候选词补全
# user_dict: zrm.userdb # 用户词典的文件名称
# db_class: tabledb #开启后就不会产生wanxiang.userdb这样的文件夹会直接输出文本wanxiang.txt同时无法使用同步能力可设 tabledb文本或 userdb二进制
enable_user_dict: true # 是否开启自动调频,即开启用户词典
enable_encoder: true #是否开启自动造词
enable_sentence: false #是否开启自动造句
enable_correction: false #是否开启自动纠错
encode_commit_history: true # 预留历史上屏自动编码成词
contextual_suggestions: false #模型预测,假设模型里面有的四个字的词汇 现在智能 而首选组合 现在只能 当你输入 现在 上屏后下一次输入zhi neng就会输出智能前提是没有权重更高的了很明显这与你的预期“现在只能”不符。很明显实际上又要预测又要连续句子放一起是很难优雅的。
max_homophones: 5
max_homographs: 5
core_word_length: 4 # >0 启用,按段学词 + 相邻段拼接
max_word_length: 7 # >0 启用,过长短语不记整词,只加元素权重
initial_quality: 3 #初始质量拼音的权重应该比英文大
spelling_hints: 30 #将注释以词典code字符串形式完全暴露通过super_comment.lua完全接管灵活配置。
always_show_comments: true # Rime 默认在 preedit 等于 comment 时取消显示 comment这里强制一直显示供super_comment.lua做判断用。
comment_format: {comment} #将注释以词典字符串形式完全暴露通过super_preedit.lua完全接管灵活配置。
#disable_user_dict_for_patterns: #如果你开启调频需要一并考虑这个配置是否需要基本的6码3字不调频你可以自定义目前的逻辑是依然记录用户词但满足规则的不输出不被使用
# - "^[a-z]{1,6}"
# 自定义短语
custom_phrase:
dictionary: ""
user_dict: custom_phrase #需要手动创建 custom_phrase.txt 文件
db_class: stabledb #可设 tabledb文本或 userdb二进制
enable_completion: false #补全提示
enable_sentence: false #禁止造句
initial_quality: 99 #custom_phrase 的权重应该比 pinyin 和 wanxiang_en 大
# 简码词库导入位于dicts得chengyu.txt文件词库
chengyu:
dictionary: ""
user_dict: dicts/chengyu
db_class: stabledb
enable_sentence: false
enable_completion: false
initial_quality: 1.3
# 中文、英文、数字、符号等混合词汇
wanxiang_mixedcode:
dictionary: wanxiang_mixedcode
db_class: stabledb
enable_completion: true
enable_sentence: false
initial_quality: 2
comment_format:
- xform/^.+$//
# Emoji
emoji:
option_name: emoji
opencc_config: emoji.json
inherit_comment: false # 在反查中emoji 返回空注释
#中文转英文
chinese_english:
option_name: chinese_english
opencc_config: chinese_english.json
tips: char
inherit_comment: false
# 简繁切换
s2t:
option_name: s2t
opencc_config: s2t.json # s2t.json | s2hk.json | s2tw.json | s2twp.json
tips: none # 转换提示: all 都显示 | char 仅单字显示 | none 不显示。
tags: [ abc ] # 限制在对应 tag不对其他如反查的内容做简繁转换
s2hk:
opencc_config: s2hk.json
option_name: s2hk
tags: [abc]
s2tw:
opencc_config: s2tw.json
option_name: s2tw
tags: [abc]
# 部件拆字反查
wanxiang_reverse:
tag: wanxiang_reverse
dictionary: wanxiang_reverse
db_class: stabledb
enable_user_dict: false
prefix: "`" # 反查前缀(反查时前缀会消失影响打英文所以设定为两个字母,或可改成一个非字母符号),与 recognizer/patterns/radical_lookup 匹配
tips: "〔反查:部件|笔画〕"
# 部件拆字滤镜
radical_reverse_lookup:
tags: [ wanxiang_reverse ] #起作用tag范围
overwrite_comment: true #是否覆盖其他提示
dictionary: wanxiang #带音调的词典
wanxiang_lookup: #设置归属于super_lookup.lua
tags: [ abc ] # 检索当前tag的候选
key: "`" # 输入中反查引导符,要添加到 speller/alphabet
lookup: [ wanxiang_reverse ] #反查滤镜数据库,万象都合并为一个了
# 处理符合特定规则的输入码,如网址、反查
recognizer:
import_preset: default # 从 default.yaml 继承通用的
patterns: # 再增加方案专有的:
punct: "^/([0-9]|10|[A-Za-z]+)$" # 响应 symbols.yaml 的 symbols
wanxiang_reverse: "^`[A-Za-z]*$" # 响应部件拆字与笔画的反查,与 wanxiang_reverse/prefix 匹配
#add_user_dict: "^ac[A-Za-z/`']*$" #引导式造词
unicode: "^U[a-f0-9]+" # U 作为触发前缀,响应 lua_translator@unicode输出 Unicode 字符
number: "^R[0-9]+[.]?[0-9]*" # R 作为触发前缀, 响应 lua_translator@number_translator数字金额大写
lunar: "^N[0-9]{1,8}" # N 作为触发前缀,响应 lua_translator@shijian公历转农历输入 N20250515 得到「二〇二五年五月十五」
calculator: "^V.*$" # V 作为触发前缀,计算器功能引导
punctuator:
digit_separators: ",." #数字分隔符,系统逻辑是在中文状态下输入数字后继续输入句号按下两次即输入半角状态
__include: wanxiang_symbols:/symbol_table # 从 wanxiang_symbols.yaml 导入所有符号配置
__patch: t9_sym
t9_sym:
half_shape/+:
"1": [1, "@", ".", "/", ":", "_", "-", "#"]
"@": [1, "@", , , 、, ……, ]
"#": [0, "#", "$", "%", "^", "&", "*", "(", ")"]
# 从 default 继承快捷键
key_binder:
import_preset: default # 从 default.yaml 继承通用的
sequence: # Lua 配置:手动排序的快捷键 super_sequence.lua不要用方向键各种冲突一定要避免冲突
up: "Control+j" # 上移
down: "Control+k" # 下移
reset: "Control+l" # 重置
pin: "Control+p" # 置顶
# Lua 配置: shijian.lua 的引导符,涉及:日期、时间、节日、节气、生日、问候模板等功能
shijian_keys: ["/", "o"]
# Lua 配置: 超级tips上屏按键
tips_key: "period" #修改时候去default找
# Lua 配置: 以词定字(上屏当前词句的第一个或最后一个字),和中括号翻页有冲突
select_first_character: "bracketleft" # 左中括号 [
select_last_character: "bracketright" # 右中括号 ]
bindings: # 也可以再增加方案专有的
- { when: has_menu, accept: 1, send: apostrophe }
#当tab第一个字补码正确后可以使用Ctrl+tab进行上屏并依次补码
- { when: composing, accept: "Control+Tab", send_sequence: '{Home}{Shift+Right}{1}{Shift+Right}' }
- { match: "^.*`$", accept: "`", send_sequence: '{BackSpace}{Home}{`}{`}{End}' }
# 拼写设定
speller:
# table_translator翻译器支持自动上屏。例如 “zmhu”可以自动上屏“怎么回事”
# auto_select: true
# auto_select_pattern: ^[a-z]+/|^[a-df-zA-DF-Z]\w{3}|^e\w{4}
# 如果不想让什么标点直接上屏,可以加在 alphabet或者编辑标点符号为两个及以上的映射alphabet就是将字符纳入输入编码的范畴
alphabet: zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA987654321`/\
initials: zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA987654321
delimiter: " '" # 系统配置,第一位<空格>是拼音之间的分隔符;第二位<'>表示可以手动输入单引号来分割拼音。
visual_delimiter: " " # super_preedit.lua配置是否让分隔符号跟着一起转换例如nǐ'hǎo 在实际使用中表现出视觉拥挤我们可以让delimiter平时是'转换为拼音的时候使用空格nǐ hǎo更符合实际。
tone_isolate: true # super_preedit.lua配置是否将数字声调从转换后拼音中隔离出来true=隔离, false 直接参与转换例如nǐ3
algebra:
- xlit/āáǎàōóǒòēéěèīíǐìūúǔùǖǘǚǜüńňǹḿm̀/aaaaooooeeeeiiiiuuuuvvvvvnnnmmm/
- xform/^(.*);.*$/$1/
- derive/^ng$/eng/
- xform/^n$/en/
- xform/^m$/me/
- abbrev/^([a-z]).+$/$1/
- abbrev/^([zcs]h).+$/$1/
- derive/^([nl])ve$/$1ue/
- derive/^([jqxy])u/$1v/
- derive/un$/uen/
- derive/ui$/uei/
- derive/iu$/iou/
- derive/([aeiou])ng$/$1gn/
- derive/([dtngkhrzcs])o(u|ng)$/$1o/
- derive/ong$/on/
- derive/ao$/oa/
- derive/([iu])a(o|ng?)$/a$1$2/
- derive/[abc]/2/
- derive/[def]/3/
- derive/[hgi]/4/
- derive/[jkl]/5/
- derive/[omn]/6/
- derive/[pqrs]/7/
- derive/[tuv]/8/
- derive/[wxyz]/9/
grammar:
language: wanxiang-lts-zh-hans
collocation_max_length: 8 #命中的最长词组
collocation_min_length: 2 #命中的最短词组搭配词频健全的词库时候应当最小值设为3避开2字高频词
collocation_penalty: -6 #默认-12 对常见搭配词组施加的惩罚值。较高的负值会降低这些搭配被选中的概率,防止过于频繁地出现某些固定搭配。
non_collocation_penalty: -17 #默认-12 对非搭配词组施加的惩罚值。较高的负值会降低非搭配词组被选中的概率,避免不合逻辑或不常见的词组组合。
weak_collocation_penalty: -24 #默认-24 对弱搭配词组施加的惩罚值。保持默认值通常是为了有效过滤掉不太常见但仍然合理的词组组合。
rear_penalty: -18 #默认-18 对词组中后续词语的位置施加的惩罚值。较高的负值会降低某些词语在句子后部出现的概率,防止句子结构不自然。

269
weasel.yaml Normal file
View File

@@ -0,0 +1,269 @@
# Weasel settings
# encoding: utf-8
config_version: "LTS"
# [app_options]
# 针对特定应用的设置
app_options:
cmd.exe:
ascii_mode: true
ascii_punct: true
idea64.exe:
ascii_mode: false
ascii_punct: true
Code.exe:
ascii_mode: false
ascii_punct: true
Bandizip.exe:
ascii_mode: true # 英文模式
7zFM.exe:
ascii_mode: true # 英文模式
firefox.exe:
inline_preedit: true # 行内显示预编辑区:规避 <https://github.com/rime/weasel/issues/946>
# cmd.exe:
# ascii_mode: true # 英文模式
# conhost.exe:
# ascii_mode: true
# windowsterminal.exe:
# ascii_mode: true
# wt.exe:
# ascii_mode: true
# pwsh.exe:
# ascii_mode: true
# powershell.exe:
# ascii_mode: true
# mintty.exe:
# ascii_mode: true
# nvim-qt.exe:
# ascii_mode: true
# vim_mode: true # vim 模式, Esc <C-c> <C-[> 切换到 ascii 状态
# [End of <app_options>]
# [global settings]
show_notifications: true # 是否显示状态变化的通知truefalseoption_list方案内的开头 option
show_notifications_time: 1200 # 通知显示的时间,单位 ms
global_ascii: false # 切换为 ascii 模式时是否影响所有窗口truefalse
# [End of <global settings>]
# [style]
# 字体;候选项、候选窗口的行为、布局及样式
style:
color_scheme: win11_light # 默认配色方案
# 全局字体
# 格式字体1:起始码位:结束码位:字重:字形,字体2……字体会依次 fallback
# 详细设定请参考 <https://github.com/rime/weasel/wiki/字體設定>
font_face: "Segoe UI Emoji, Microsoft YaHei, SF Pro, Noto Color Emoji"
label_font_face: "Microsoft YaHei" # 标签字体
comment_font_face: "Microsoft YaHei" # 注释字体
font_point: 12 # 全局字体字号
label_font_point: 11 # 标签字体字号,不设定 fallback 到 font_point
comment_font_point: 11 # 注释字体字号,不设定 fallback 到 font_point
inline_preedit: true # 行内显示预编辑区truefalse
preedit_type: composition # 预编辑区内容composition编码 preview选中的候选preview_all全部候选
fullscreen: false # 候选窗口全屏显示truefalse
horizontal: true # 候选项横排truefalse
vertical_text: false # 竖排文本truefalse
# text_orientation: horizontal # 文本排列方向,效果和 `vertical_text` 相同horizontalvertical
vertical_text_left_to_right: false # 竖排方向是否从左到右truefalse
vertical_text_with_wrap: false # 文本竖排模式下自动换行truefalse
vertical_auto_reverse: false # 文本竖排模式下候选窗口位于光标上方时倒序排列truefalse
label_format: "%s." # 标签字符:例如 %s. 效果为 1. 2. 3. ....
mark_text: "" # 标记字符,显示在选中的候选标签前,需要在配色方案中指定颜色;如该项为空字符串 "" 而配色方案中 hilited_mark_color 非透明色,则显示 Windows 11 输入法风格标记
ascii_tip_follow_cursor: false # 切换 ASCII 模式时,提示跟随鼠标,而非输入光标
enhanced_position: true # 无法定位候选框时在窗口左上角显示候选框truefalse
display_tray_icon: false # 托盘显示独立于语言栏的额外图标truefalse
antialias_mode: default # 次像素反锯齿设定defaultforce_dwordcleartypegrayscalealiased
candidate_abbreviate_length: 30 # 候选项略写,超过此数字则用省略号代替。设置为 0 则不启用此功能
# mouse_hover_ms: 0 # ! 已弃用。鼠标悬停选词响应时间ms设置为 0 时禁用该功能
hover_type: semi_hilite # 鼠标在候选窗口悬停时none无动作hilite选中鼠标下的候选semi_hilite高亮鼠标下的候选
paging_on_scroll: true # 在候选窗口上滑动滚轮的行为true翻页false (选中下一个候选)
click_to_capture: false # 鼠标点击候选项创建截图truefalse
layout:
align_type: center # 标签、候选文字、注解文字之间的相对对齐方式
max_height: 2800 # 候选框最大高度、宽度。超过设定值会尝试自动折叠,设置为 0 不启用此功能
max_width: 1400 # 2800
min_height: 0 # 候选框最小高度、宽度
min_width: 50 #80
#type: horizontal # 布局类型;功能近似 style 下的窗口控制选项 horizontal; vertical
border_width: 1 # 边框宽度,别名 `border`
border: 1
margin_x: 8 # 主体元素和候选框的左右、上下边距,为负值时,不显示候选框
margin_y: 8
spacing: 18 # inline_preedit 为 false 时,编码区域和候选区域的间距
candidate_spacing: 15 # 候选项之间的间距
hilite_spacing: 6 # 候选项和相应标签的间距,候选项与注解文字之间的距离
hilite_padding: 6 # 高亮区域和内部文字的间距,影响高亮区域大小
hilite_padding_y: 5 # 高亮区域和内部文字的左右、上下间距,如无特殊指定则依 hilite_padding 设置
hilite_padding_x: 5
shadow_offset_x: "-8" # 阴影绘制的偏离距离
shadow_offset_y: "8"
shadow_radius: 8 # 阴影区域半径,为 0 不显示阴影;需要同时在配色方案中指定非透明的阴影颜色
corner_radius: 8 # 候选窗口圆角半径
round_corner: 8 # 候选背景色块圆角半径,别名 `hilited_corner_radius`
preset_color_schemes:
jianchun:
name: 简纯
author: amzxyz
back_color: '0xf2f2f2'
border_color: '0xCE7539'
text_color: '0x3c647e'
hilited_text_color: '0x3c647e'
hilited_back_color: '0x797954'
hilited_comment_text_color: '0xffffff'
hilited_candidate_text_color: '0xffffff'
hilited_candidate_back_color: '0xCE7539'
hilited_label_color: '0xdedede'
candidate_text_color: '0x000000'
comment_text_color: '0x000000'
label_color: '0x91897e'
win11_light:
name: "Win11浅色 / Win11light"
text_color: 0x191919
label_color: 0x191919
hilited_label_color: 0x191919
back_color: 0xf9f9f9
border_color: 0x009e5a00
hilited_mark_color: 0xc06700
hilited_candidate_back_color: 0xf0f0f0
shadow_color: 0x20000000
win11_dark:
name: "Win11暗色 / Win11Dark"
text_color: 0xf9f9f9
label_color: 0xf9f9f9
back_color: 0x2C2C2C
hilited_label_color: 0xf9f9f9
border_color: 0x002C2C2C
hilited_mark_color: 0xFFC24C
hilited_candidate_back_color: 0x383838
shadow_color: 0x20000000
mac_light:
name: "Mac 白"
text_color: 0x000000
back_color: 0xffffff
border_color: 0xe9e9e9
label_color: 0x999999
hilited_text_color: 0x000000
hilited_back_color: 0xffffff
candidate_text_color: 0x000000
comment_text_color: 0x999999
hilited_candidate_text_color: 0xffffff
hilited_comment_text_color: 0xdddddd
hilited_candidate_back_color: 16740656
hilited_label_color: 0xffffff
wechat:
name: "微信Wechat"
text_color: 0x424242
label_color: 0x999999
back_color: 0xFFFFFF
border_color: 0xFFFFFF
comment_text_color: 0x999999
candidate_text_color: 0x3c3c3c
hilited_comment_text_color: 0xFFFFFF
hilited_back_color: 0x79af22
hilited_text_color: 0xFFFFFF
hilited_label_color: 0xFFFFFF
hilited_candidate_back_color: 0x79af22
shadow_color: 0x20000000
Lumk_light:
name: "鹿鸣Lumk light"
author: "Lumk X <x@xx.cc>"
back_color: 0xF9F9F9
border_color: 0xE2E7F5
candidate_text_color: 0x121212
comment_text_color: 0x8E8E8E
hilited_candidate_back_color: 0xECE4FC
hilited_candidate_label_color: 0xB18FF4
hilited_candidate_text_color: 0x7A40EC
hilited_label_color: 0xA483EC
hilited_mark_color: 0x7A40EC
label_color: 0x888785
text_color: 0x8100EB
shadow_color: 0x20000000
amber-7:
name: 淡白/weasel
author: 五笔小筑 <wubixiaozhu@126.com>
# 背景设置
back_color: 0xffffff # 窗口背景
border_color: 0xE99321 # 窗口边框
shadow_color: 0x00000000 # 窗口阴影
# 内选区域
text_color: 0xE99321 # 文字
hilited_text_color: 0x2238dc # 编码
hilited_back_color: 0xffffff # 背景
hilited_shadow_color: 0x00000000 # 阴影
# 以下两项在 inline_preedit: false 时生效
nextpage_color: 0x0000FF # 翻页箭头颜色:下一页;不设置则不显示箭头
prevpage_color: 0x0000FF # 翻页箭头颜色:上一页;不设置则不显示箭头
# 激活候选项
hilited_mark_color: 0x00000000 # 激活标签
hilited_label_color: 0x2021FF #序号文字
hilited_candidate_text_color: 0x2021FF #候选文字
hilited_comment_text_color: 0x000000 #提示文字
hilited_candidate_back_color: 0xECF1FC #激活背景
hilited_candidate_border_color: 0xCFDCFD #激活边框
hilited_candidate_shadow_color: 0x00000000 #激活阴影
# 其它候选项
label_color: 0xE99321 #序号文字
candidate_text_color: 0xE99321 #候选文字
comment_text_color: 0x000000 #提示文字
candidate_back_color: 0xffffff #候选背景
candidate_border_color: 0xffffff #候选边框
candidate_shadow_color: 0x00000000 #候选阴影
win10gray:
name: win10灰win10gray
author: 五笔小筑 <wubixiaozhu@126.com>
back_color: 0xfff4f4f4
shadow_color: 0xf7606060
border_color: 0xff305c3c
text_color: 0xff000000
hilited_text_color: 0xff000000
hilited_back_color: 0x4ff4f4f4
hilited_shadow_color: 0x00000000
hilited_mark_color: 0xffd77800
hilited_label_color: 0xff555555
hilited_candidate_text_color: 0xff000000
hilited_comment_text_color: 0xff555555
hilited_candidate_back_color: 0x4fcccccc
hilited_candidate_border_color: 0x00000000
hilited_candidate_shadow_color: 0x00000000
label_color: 0xff888888
candidate_text_color: 0xff222222
comment_text_color: 0xff888888
candidate_back_color: 0x00000000
candidate_border_color: 0x00000000
candidate_shadow_color: 0x00000000
mint_light_blue:
name: "蓝水鸭Mint Light Blue"
author: Mintimate <"Mintimate's Blog">
text_color: 0x6495ed
back_color: 0xefefef
label_color: 0xcac9c8
border_color: 0xefefef
shadow_color: 0xb4000000
comment_text_color: 0xcac9c8
candidate_text_color: 0x424242
hilited_text_color: 0xed9564
hilited_back_color: 0xefefef
hilited_candidate_back_color: 0xed9564
hilited_candidate_text_color: 0xefefef
hilited_candidate_label_color: 0xcac9c8
hilited_label_color: 0xcac9c8
hilited_comment_text_color: 0xefefef
nextpage_color: 0x0000FF
prevpage_color: 0x0000FF

4056
简纯+.trime.yaml Normal file

File diff suppressed because it is too large Load Diff