🚀 Build beautiful text-based UIs in Emacs with HTML/CSS-like syntax
ETAF (Emacs Text-based Application Framework) is a comprehensive framework for building rich text-based user interfaces in Emacs. It brings web development concepts like DOM, CSS, and reactive components to the Emacs ecosystem, enabling developers to create sophisticated UI components using familiar HTML/CSS-like syntax.
- 🏗️ HTML-like Templating - Write UI using S-expression based TML (Template Markup Language)
- 🎨 CSS Support - Full CSS parsing, cascade algorithm, and computed styles
- 📦 Component System - Vue 2 Options API and Vue 3 Composition API support with reactive components
- 🔄 Reactive System - ref, computed, watch, and watchEffect for state management
- 🌳 Virtual DOM - Vue 3-inspired virtual DOM with diff/patch algorithm for efficient updates
- 🎯 Tailwind CSS - Built-in support for Tailwind utility classes
- 📐 Layout Engine - Box model and Flexbox layout support
- 📝 Smart Typesetting - Integrated Knuth-Plass algorithm for hybrid CJK and Latin text justification
- ⚡ Performance Optimized - Rule indexing and style caching
- 📊 Performance Monitoring - Built-in profiling tool to optimize first-screen loading time
ETML Template → Compiler (etaf-etml) → VNode Tree (Virtual DOM with metadata) ↓ Renderer extracts clean DOM ↓ CSSOM → Render Tree → Layout Tree → Buffer String The pipeline follows Vue 3's architecture:
- Template (ETML): S-expression based markup
- Compiler: Converts ETML to VNode tree with metadata
- Virtual DOM (VNode): Stores tag metadata, event handlers, state
- Renderer: Extracts clean DOM from VNode
- CSSOM, Render Tree, Layout: Existing CSS and layout pipeline
- Buffer String: Final text with properties for interactivity
(require 'etaf) ;; Simple rendering (etaf-paint-to-buffer "*demo*" '(div :class "container" (h1 :style "color: blue" "Hello ETAF!") (p "Build beautiful UIs in Emacs"))) ;; With Tailwind CSS classes (etaf-paint-to-buffer "*demo*" '(div :class "flex items-center p-2 bg-blue-500" (span :class "text-white font-bold" "Styled with Tailwind!")))(setq my-data '(:name "Alice" :items ("Apple" "Banana" "Cherry"))) (etaf-paint-to-buffer "*demo*" '(div (h1 "Hello, {{ name }}!") (ul (li :e-for "item in items" "{{ item }}"))) my-data);; Define a component (etaf-define-component my-button :props '(:label :disabled) :template '(button :class "btn" "{{ label }}")) ;; Use the component (etaf-paint-to-buffer "*demo*" '(my-button :label "Click Me"))(let* ((count (etaf-ref 0)) (doubled (etaf-computed (lambda () (* 2 (etaf-ref-get count)))))) (etaf-ref-get count) ;; => 0 (etaf-ref-set count 5) (etaf-computed-get doubled)) ;; => 10| Document | Description |
|---|---|
| User Manual | Complete guide for using ETAF |
| Developer Manual | Architecture and extension guide |
| Component System | Vue 3-style component system and reactive state management |
| Architecture | System architecture and module relationships |
| Data Structures | Detailed data structure documentation |
| Event Model | Interactive pseudo-classes and event system |
| Virtual DOM | Vue 3-inspired virtual DOM system |
| Performance Monitoring | Performance profiling tool for optimizing first-screen loading |
| ETAF-EORM | Multi-database ORM (SQLite, PostgreSQL, MySQL) inspired by Diesel |
- Clone the repository:
git clone https://github.com/Kinneyzhang/etaf.git- Add to your Emacs configuration:
(add-to-list 'load-path "/path/to/etaf") (require 'etaf)Run interactive component demos:
;; Component system examples - Options API and Composition API (load-file "examples/etaf-component-examples.el") M-x etaf-component-demoExample files:
examples/etaf-component-examples.el- Component system examples (Options API & Composition API)examples/etaf-table-example.el- Table component examples (sorting, pagination, selection)examples/etaf-tailwind-example.el- Tailwind CSS examplesexamples/etaf-layout-example.el- Layout system examplesexamples/etaf-render-example.el- Render examplesexamples/etaf-css-example.el- CSS examples
GNU General Public License v3.0 or later.
ETAF(Emacs Text-based Application Framework)是一个在 Emacs 中构建丰富文本界面的综合框架。它将 DOM、CSS 和响应式组件等 Web 开发概念引入 Emacs 生态系统,使开发者能够使用熟悉的 HTML/CSS 语法创建复杂的 UI 组件。
- 🏗️ 类 HTML 模板 - 使用基于 S-expression 的 TML(模板标记语言)编写 UI
- 🎨 CSS 支持 - 完整的 CSS 解析、层叠算法和计算样式
- 📦 组件系统 - 同时支持 Vue 2 选项式 API 和 Vue 3 组合式 API 的响应式组件
- 🔄 响应式系统 - ref、computed、watch 和 watchEffect 状态管理
- 🌳 虚拟 DOM - 参考 Vue 3 设计的虚拟 DOM,支持 diff/patch 算法实现高效更新
- 🎯 Tailwind CSS - 内置 Tailwind 工具类支持
- 📐 布局引擎 - 盒模型和 Flexbox 布局支持
- 📝 智能排版 - 集成 Knuth-Plass 算法,支持 CJK 与拉丁系语言的混合排版
- ⚡ 性能优化 - 规则索引和样式缓存
- 📊 性能监控 - 内置性能分析工具,用于优化首屏加载时间
(require 'etaf) ;; 简单渲染 (etaf-paint-to-buffer "*demo*" '(div :class "container" (h1 :style "color: blue" "Hello ETAF!") (p "在 Emacs 中构建精美 UI"))) ;; 使用 Tailwind CSS 类 (etaf-paint-to-buffer "*demo*" '(div :class "flex items-center p-2 bg-blue-500" (span :class "text-white font-bold" "Tailwind 样式!")))ETAF 支持 Vue 风格的模板指令:
| 指令 | 说明 | 示例 |
|---|---|---|
{{ expr }} | 文本插值 | "Hello, {{ name }}" |
:e-if | 条件渲染 | (p :e-if "visible" "Text") |
:e-else-if | 多条件渲染 | (p :e-else-if "other" "Alt") |
:e-else | 默认分支 | (p :e-else "Default") |
:e-for | 列表渲染 | (li :e-for "item in items" "{{ item }}") |
:e-show | 显示/隐藏 | (div :e-show "visible" "Content") |
(setq my-data '(:name "Alice" :items ("苹果" "香蕉" "樱桃"))) (etaf-paint-to-buffer "*demo*" '(div (h1 "你好,{{ name }}!") (ul (li :e-for "item in items" "{{ item }}"))) my-data);; 定义组件 (etaf-define-component my-button :props '(:label :disabled) :template '(button :class "btn" "{{ label }}")) ;; 使用组件 (etaf-paint-to-buffer "*demo*" '(my-button :label "点击我"));; 创建响应式引用 (let* ((count (etaf-ref 0)) (doubled (etaf-computed (lambda () (* 2 (etaf-ref-get count)))))) (etaf-ref-get count) ;; => 0 (etaf-ref-set count 5) (etaf-computed-get doubled)) ;; => 10;; 直接使用 Tailwind 类 (etaf-paint-to-buffer "*demo*" '(div :class "flex items-center justify-between bg-white rounded-lg shadow-md p-2" (h1 :class "text-lg font-bold text-gray-900" "标题") (button :class "bg-blue-500 text-white px-2 py-1 rounded" "按钮")))支持的 Tailwind 功能:
- 响应式前缀:
sm:,md:,lg:,xl:,2xl: - 状态变体:
hover:,focus:,active:(需要 etaf-event 模块) - 颜色系统:完整的 Tailwind 调色板
- 间距、Flexbox、圆角、阴影等
- 水平方向默认使用字符宽度(cw),使用px后缀指定像素(如
w-20px)
ETAF 提供完整的事件模型来支持交互式伪类选择器:
(require 'etaf-event) ;; 初始化事件系统 (etaf-event-init) ;; 注册可交互元素(需要 uuid 属性) (let ((button '(button ((uuid . "btn-1") (class . "primary")) "Click Me"))) (etaf-event-register-element "btn-1" button 100 120) ;; 添加事件监听器 (etaf-event-add-listener "btn-1" 'hover-enter (lambda (uuid data) (message "Button hovered!"))) ;; CSS 选择器会自动使用事件状态 ;; button:hover 只在鼠标悬停时匹配 (etaf-css-selector-query dom "button:hover"))支持的交互式伪类:
:hover- 鼠标悬停:active- 激活状态(鼠标按下):focus- 焦点状态:disabled/:enabled- 禁用/启用状态
详见 事件模型文档。
ECSS 提供统一的字符串格式来表达 CSS 规则,选择器使用原生 CSS 语法,样式属性使用 Tailwind 类名。
(require 'etaf-ecss) ;; 统一格式(推荐):选择器{Tailwind类名} (etaf-ecss "div>p:nth-child(odd){pl-6px pr-2 py-1 border border-gray-500}") ;; => "div>p:nth-child(odd) { padding-left: 6px; padding-right: 2cw; ... }" (etaf-ecss ".card{flex items-center bg-blue-500 p-4}") ;; => ".card { display: flex; align-items: center; ... }" ;; 构建样式表 (etaf-ecss ".container{flex items-center w-800px}" ".box{bg-blue-500 p-4}" "nav>a{text-white}")ETAF 集成了 Knuth-Plass 排版算法(etaf-kp),实现了 CJK 与拉丁系语言的混合排版,支持智能断词和文本对齐。
(require 'etaf-kp) ;; 设置排版语言(默认为 "en_US") (setq etaf-kp-latin-lang "en_US") ;; 设置排版参数(可选) ;; 参数依次为:拉丁语单词间的理想/拉伸/压缩像素宽度, ;; 拉丁语与 CJK 间的理想/拉伸/压缩像素宽度, ;; CJK 字符间的理想/拉伸/压缩像素宽度 (etaf-kp-param-set 7 3 2 5 2 1 0 2 0) ;; 将文本按指定像素宽度排版(自动换行和对齐) (etaf-kp-pixel-justify "This is a test string with English words and 中文字符 mixed together." 400) ;; 在像素范围内寻找最优排版 (etaf-kp-pixel-range-justify "测试文本 test text 测试" 300 500) ;; 返回 (排版后文本 . 最优像素值) ;; 在 ETAF 布局中使用(通过 etaf-pixel-wrap) (etaf-paint-to-buffer "*demo*" '(div :style "width: 400px" (p "Long text that will be automatically wrapped and justified 这是一段会被自动换行和对齐的长文本。")))支持的语言包括:英语、德语、法语、西班牙语、中文、日文、韩文等(完整列表见 dictionaries/ 目录)。
| 文档 | 说明 |
|---|---|
| 用户手册 | 完整的使用指南 |
| 开发者手册 | 架构和扩展指南 |
| 组件系统 | Vue 3 风格的组件系统和响应式状态管理 |
| 架构文档 | 系统架构和模块关系 |
| 数据结构 | 详细的数据结构文档 |
| 事件模型 | 交互式伪类和事件系统 |
| 虚拟 DOM | 参考 Vue 3 设计的虚拟 DOM 系统 |
| 性能监控 | 性能分析工具,用于优化首屏加载时间 |
| ETAF-EORM | 参考 Diesel 设计的 多数据库 ORM(SQLite、PostgreSQL、MySQL) |
| 模块 | 说明 |
|---|---|
etaf.el | 主入口,高层 API |
etaf-etml.el | TML 到 DOM 转换、模板指令、编译器(生成 VNode) |
etaf-vdom.el | 虚拟 DOM (VNode),存储标签元数据和交互处理器 |
etaf-component.el | 组件系统、响应式系统(ref、computed、watch) |
etaf-table.el | 功能丰富的表格组件(排序、分页、选择、筛选) |
etaf-event.el | 事件模型,支持交互式伪类(:hover, :focus 等) |
etaf-css.el | CSS 对象模型(CSSOM)主入口 |
etaf-render.el | 渲染树构建(从 VNode 提取的 DOM + CSSOM) |
etaf-layout.el | 盒模型和布局计算 |
etaf-layout-string.el | 布局树到最终文本字符串的转换 |
etaf-tailwind.el | Tailwind CSS 支持 |
etaf-ecss.el | Emacs 风格的 CSS 表达式 |
etaf-perf.el | 性能监控和分析工具 |
etaf-eorm.el | 多数据库 ORM 库(SQLite、PostgreSQL、MySQL),参考 Diesel 设计 |
etaf-kp.el | Knuth-Plass 排版算法实现,支持 CJK 与拉丁系语言的混合排版 |
etaf-pixel.el | 像素级字符串操作,集成 etaf-kp 实现文本自动换行和对齐 |
- 克隆仓库:
git clone https://github.com/Kinneyzhang/etaf.git- 添加到 Emacs 配置:
(add-to-list 'load-path "/path/to/etaf") (require 'etaf)运行交互式组件演示:
;; 组件系统示例 - 选项式 API 和组合式 API (load-file "examples/etaf-component-examples.el") M-x etaf-component-demo示例文件:
examples/etaf-component-examples.el- 组件系统示例(选项式 API 和组合式 API)examples/etaf-table-example.el- 表格组件示例(排序、分页、选择)examples/etaf-tailwind-example.el- Tailwind CSS 示例examples/etaf-layout-example.el- 布局系统示例examples/etaf-render-example.el- 渲染示例examples/etaf-css-example.el- CSS 示例
运行测试套件:
cd tests emacs -batch -l etaf-ert.el -l etaf-css-tests.el -f ert-run-tests-batch-and-exit欢迎贡献代码、报告问题或提出改进建议!
GNU General Public License v3.0 或更高版本。