#+TITLE: liberime [开发中]

* 简介

liberime 是一个 Emacs 动态模块，提供了 librime 库绑定。目前只实现了几
个方法，理想情况是暴露所有 librime 的 API 到 emacs-lisp.

* 安装

** 依赖
可在[[https://github.com/rime/librime#packaging-status][此处]]查看 ~librime~ 的发行版打包状况。
*** 依赖说明
1. Emacs 需要启用动态模块支持，一般是在编译的时候使用 --with-modules
   选项。
2. librime 版本 > 1.3.2
*** 非Msys2环境的Windows用户
release中提供了带依赖的打包文件，请参考后续「预编译」一节。如果在Msys2环境中使用Emacs，请参考下列流程安装依赖。
*** Windows 系统下使用 msys2 安装依赖
   #+BEGIN_SRC shell
   pacman -Sy --overwrite "*" --needed base-devel zip \
          ${MINGW_PACKAGE_PREFIX}-gcc                 \
          ${MINGW_PACKAGE_PREFIX}-librime             \
          ${MINGW_PACKAGE_PREFIX}-librime-data        \
          ${MINGW_PACKAGE_PREFIX}-rime-wubi           \
          ${PACKAGE_PREFIX}-rime-emoji                \
          ${MINGW_PACKAGE_PREFIX}-rime-double-pinyin
   #+END_SRC

   将 opencc 包自带的文件链接到 rime-data/opencc 目录下，解决无法输入
   简体中文的问题。

   #+BEGIN_SRC shell
   ln -s ${MINGW_PREFIX}/share/opencc/* ${MINGW_PREFIX}/share/rime-data/opencc
   #+END_SRC
*** MacOS/Linux 用户安装依赖

在对应的包管理器中安装 ~librime~ 即可。

如Homebrew:  ~brew install librime~ 
** 预编译（推荐）
可以在[[https://github.com/emacs-rime/liberime/releases][release]]中下载预编译好的二进制文件。注意，没有标明 ~-with-deps~ 的压缩包里均仅包含 ~liberime-core~ 的二进制文件。

需要在配置中将 ~liberime-module-file~ 指向 ~liberime-core~ 二进制文件：

#+begin_src elisp
(setq liberime-module-file "/PATH/TO/YOUR/liberime-core.suffix")
#+end_src
*** Linux
可以下载 ~linux-aarch64~ ~linux-arm64~ ~linux-armhf~ ~linux-x86_64~ 架构的压缩包，提取 ~/lib/liberime-core.so~ 。需要在配置中将 ~liberime-module-file~ 指向 ~liberime-core.so~ 文件。
*** MacOS
可以下载 ~macos-arm64~ ~macos-x86_64~ 架构的压缩包，提取 ~/lib/liberime-core.dylib~ 。需要将 ~liberime-module-file~ 指向这个 ~liberime-core.dylib~ 文件。
*** Windows

如果你的 Emacs 位于 MSYS2 环境中，可以下载 ~clang-arm64~ ~clang-x86_64~ ~ucrt-x86_64~ ~x86_64~ 架构的压缩包，提取 ~/bin/liberime-core.dll~ 。需要将 ~liberime-module-file~ 指向 ~liberime-core.dll~ 文件。

如果你的 Emacs 不位于 MSYS2 环境中，请选择下载上述架构的 ~-with-deps~ 压缩包，里面附带了所需的 ~.DLL~ 文件和 ~opencc~ 文件，具体如下：
- 相关的依赖 ~DLL~ 文件与 ~liberime-core.dll~ 一并放置于 ~/bin~ 文件夹中。需要将 ~liberime-module-file~ 指向其中的 ~liberime-core.dll~ 文件。
- 相关的 ~rime-data~ 文件夹放置于 ~/share~ 文件夹中，里面有 ~opencc~ 文件夹和 ~librime~ 内置的输入方案。需要将 ~liberime-shared-data-dir~ 变量指向这个 ~rime-data~ 文件夹。
  #+begin_src elisp
(setq liberime-shared-data-dir "/PATH/TO/YOUR/rime-data")
#+end_src
** 手动编译
也可以根据以下指南自行编译 ~liberime-core~ 文件。
*** Linux 系统下编译 liberime:

   #+BEGIN_SRC shell
   export EMACS_MAJOR_VERSION = 26  # 按实际情况更改
   make
   #+END_SRC

*** Mac (Darwin) 系统下编译 liberime:
1. Mac 下编译 librime, 需要安装 Xcode (good luck), 可以参考：
   [[https://github.com/rime/librime/blob/master/README-mac.md]] 
2. 环境变量 RIME_PATH 的取值设置为 librime 所在的目录，比如：
   #+begin_src shell
   export RIME_PATH=~/Develop/others/librime
   #+end_src
3. 编译 liberime:

   #+BEGIN_SRC shell
   export EMACS_MAJOR_VERSION = 26  # 按实际情况更改
   make
   #+END_SRC

*** Windows 系统下使用 msys2 编译 liberime
1. 打开 MSYS2 MinGW 终端
2. 切换到 liberime 所在的目录
3. 运行下面的命令

   #+BEGIN_SRC shell
   export EMACS_MAJOR_VERSION = 26  # 按实际情况更改
   make
   #+END_SRC

* 使用
** Emacs 配置
#+BEGIN_SRC emacs-lisp
(require 'pyim)
(require 'liberime nil t)
(setq default-input-method "pyim")
(with-eval-after-load "liberime"
  (liberime-try-select-schema "luna_pinyin_simp")
  (setq pyim-default-scheme 'rime-quanpin))
#+END_SRC

用户也可以通过 Rime 配置文件 (默认为：~/.emacs.d/rime/default.custom.yaml) 
来设置默认 schema，设置方式可以参考：
https://gist.github.com/merrickluo/553f39c131d0eb717cd59f72c9d4b60d

注意事项：
1. 一般情况下，liberime 和 [[https://github.com/tumashu/pyim][pyim]] 配合使用
2. 默认情况下，liberime 会自动搜索 rime 共享数据目录（shared_data_dir）和   rime 用户数据目录（user_data_dir）, 用户也可以使用下面两个变量强制设置：
   1. liberime-shared-data-dir
   2. liberime-user-data-dir
3. Window 用户不要将 shared_data_dir 设置为小狼毫的 data 目录，因为小狼毫自带的 OpenCC 文件无法用于 msys2 编译的 liberime, 会出现无法输入简体中文的问题。

*** 加载时自动编译
#+BEGIN_SRC emacs-lisp
(let ((liberime-auto-build t))
  (require 'liberime nil t))
#+END_SRC

*** 延迟启动（第三方 require 场景）
默认情况下，加载 liberime 会在文件末尾自动调用 ~(liberime-load)~ ，即在
=require= 时就启动 rime 引擎，并读取 ~liberime-user-data-dir~ 、
~liberime-module-file~ 等变量。如果 =require= 是由第三方包（如 pyim）发起的，
你就无法用上面的 =let= 把它包裹起来以在加载前设置这些变量。此时可将
~liberime-load-on-require~ 设为 nil，之后自行调用 ~liberime-load~ ：
#+BEGIN_SRC emacs-lisp
(setq liberime-load-on-require nil)   ; 需在 liberime 加载前设置
(with-eval-after-load 'liberime
  (setq liberime-user-data-dir "/PATH/TO/YOUR/rime")
  (liberime-load))
#+END_SRC

如需静默启动时的提示信息，可设置 ~(setq liberime-verbose nil)~ 。

** 部署 Rime

手动修改 librime 配置后，可以调用 ~(liberime-deploy)~ 重新部署。

** 同步 Rime 词库
使用 liberime 存在词库跟系统输入法不一致的问题，可以使用 rime 词库同步
功能来变相的解决。

1. 设置 sync_dir 目录 (默认修改 $HOME/.emacs.d/rime/installation.yaml 文件)
2. 运行 liberime-sync 函数，比如：将其加入 ~after-init-hook~ 中。
   #+begin_src emacs-lisp
   (add-hook 'after-init-hook #'liberime-sync)
   #+end_src

Rime 同步功能的其它信息可以参考：[[https://github.com/rime/home/wiki/UserGuide#%E5%90%8C%E6%AD%A5%E7%94%A8%E6%88%B6%E8%B3%87%E6%96%99][Rime 同步用户资料]]。

** liberime-search 的 FULL-CONTEXT 参数

~liberime-search~ 的第 5 个可选参数 ~FULL-CONTEXT~ 让调用方获得 Rime 候选
对输入码的消费结构，而不只是候选文本列表。传非 ~nil~ 时返回 plist：

- ~:commit~ —— Rime 自动上屏的文本。形码等定长码 schema 在码超长时会顶出
  已完成的字，该字不再出现在候选菜单中；无自动上屏时为 ~nil~。
- ~:full~ —— 完整消耗输入码的候选（整词）。
- ~:prefix~ —— 只消耗输入码最短非空前缀的候选（如拼音输入 ~nihaoshijie~
  时，单字候选 ~你~ 只消耗 ~ni~）。
- ~:remainder~ —— ~:prefix~ 消耗后剩下的码后缀（如 ~haoshijie~），可递归
  展开。
- ~:remaining-input~ —— 本次输入的原始码串（~get_input~ 的返回值），不依
  附于任何前缀候选；用于判断 ~:commit~ 是否可信：提交后仍有未消费输入且
  无候选时，~:commit~ 只是自动上屏的前缀，不能作为完整展开。
- ~:schema-id~ / ~:schema-name~ —— 临时 session 实际使用的 schema（及
  ~:is-disabled~、~:is-composing~、~:is-ascii-mode~、~:is-full-shape~、
  ~:is-simplified~、~:is-traditional~、~:is-ascii-punct~ 等选项状态），让
  调用方可以按产生候选的实际状态做缓存 key。

例如拼音 schema 下 ~(liberime-search "nihaoshijie" nil nil nil t)~ 可能返
回 ~:full~ = ~("你好世界")~、~:prefix~ = 单字候选（~你~ 等，只消耗
~ni~）、~:remainder~ = ~"haoshijie"~。这些数据让 liberime-regexp 之类的
调用方可以把 Rime 码递归展开为正则表达式。向后兼容：不传该参数时行为与
旧版一致（返回候选文本列表）。

** 多 session 与 SESSION 参数

librime 原生支持多个相互独立的 session（各自持有 composition、候选和
schema）。liberime 现将其暴露给 Elisp：

- ~(liberime-session-create &optional SCHEMA_ID)~ —— 创建临时 session，返
  回其 id；指定 ~SCHEMA_ID~ 时该 session 使用此 schema（对 user config 无
  任何持久化痕迹）。librime 会在 5 分钟不活动后自动回收闲置 session，
~liberime-finalize~ 也会清空全部 session。
- ~(liberime-session-destroy SESSION)~ —— 销毁临时 session。

以下函数接受尾部可选参数 ~SESSION~（~nil~ 表示默认 session，行为与旧版
一致）：~liberime-search~（~SESSION~ 非 ~nil~ 时复用该 session 查询，不再
创建/销毁临时 session）、~liberime-process-key~、~liberime-simulate-key-sequence~、
~liberime-process-event~、~liberime-get-context~、~liberime-get-status~、
~liberime-get-commit~、~liberime-get-input~、~liberime-clear-composition~、
~liberime-commit-composition~、~liberime-select-candidate~、
~liberime-get-candidates~。

例如，一个 session 内连续查询多个码（避免反复创建/销毁临时 session 的开
销），或让两个 session 使用不同 schema 互不干扰：

#+begin_src emacs-lisp
  (let ((s1 (liberime-session-create "egret_py"))
        (s2 (liberime-session-create "luna_pinyin_simp")))
    (liberime-search "ni" nil nil nil t s1)
    (liberime-search "ni" nil nil nil t s2)
    (liberime-session-destroy s1)
    (liberime-session-destroy s2))
#+end_src
