用 Clojure 给 Emacs 写插件
Emacs

Cloel

Cloel 是一个结合 Clojure 和 Elisp 的协同编程框架, 利用 Clojure 的生态和多线程能力来扩展 Emacs。

主要优势:

  1. 速度快: 耗时代码在外部 Clojure 进程执行, 避免卡住 Emacs
  2. 多线程: 利用 Clojure 的多线程, 保证快速响应
  3. Lisp 风格: 用 Clojure 写插件也能保持 Lisp 风格
  4. 强大生态: 可访问 JVM 和 Python 的软件包生态
  5. 低门槛: 开箱即用的框架, 简化 Emacs 的 Clojure 扩展开发

安装

  1. 安装 Clojure, 参考 官方手册

  2. 安装 parseedn

  3. 安装 Cloel Elisp 部分:
    • 克隆仓库并添加到 Emacs 配置:
      (add-to-list 'load-path "<path-to-cloel>")
      (require 'cloel)
      
  4. 安装 Cloel Clojure 部分:
    cd cloel
    clojure -X:jar
    clojure -X:install
    
  5. 测试:
    • 执行 M-x load-file 选择 cloel/demo/app.el
    • 执行 M-x cloel-demo-test
    • 如果显示 “Cloel rocks!” 则安装成功, 没有成功请查看 *cloel-demo-clojure-server* buffer 以反馈报错信息

版本更新

每次更新 Cloel 后都需要执行 clojure -X:jar; clojure -X:install 来更新 Clojure 代码, 避免版本升级后的兼容性问题。

开发

开发时可通过 grep “STEP” 关键字来理解 Demo 程序结构。

以下是 API 详情, 将 app 替换为你的应用名:

Elisp API:

  • cloel-register-app: 注册应用, 需要输入应用名和 Clojure 代码的路径, 应用名以 app 为例
  • cloel-app-start/stop/restart-process: 管理 Clojure 进程
  • cloel-app-send-message: Elisp 异步发送消息给 Clojure
  • cloel-app-call-async: Elisp 异步调用 Clojure 函数
  • cloel-app-call-sync: Elisp 同步调用 Clojure 函数

Clojure API:

  • cloel/start-server: 启动 Clojure 进程
  • cloel/elisp-show-message: Clojure 异步在 minibuffer 显示消息
  • cloel/elisp-get-var: Clojure 同步获取 Elisp 变量值
  • cloel/elisp-eval-async: Clojure 异步调用 Elisp 函数
  • cloel/elisp-eval-sync: Clojure 同步调用 Elisp 函数

Clojure 可以被重载的接口:

  • handle-client-async-call: 处理 Elisp 异步调用 Clojure 函数的接口
  • handle-client-sync-call: 处理 Elisp 同步调用 Clojure 函数的接口
  • handle-client-message: 处理 Elisp 异步发送消息给 Clojure 的接口
  • handle-client-connected: Client 连接上 Clojure 进程时的接口

在 Clojure 中, 我们可以使用 alter-var-root 在应用端重载上面的接口实现, 具体请看 demo/app.clj