# aifei-enjoy-plugin
**Repository Path**: jfinal/aifei-enjoy-plugin
## Basic Information
- **Project Name**: aifei-enjoy-plugin
- **Description**: 让IDEA支持enjoy语法
- **Primary Language**: Kotlin
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2026-05-11
- **Last Updated**: 2026-05-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Enjoy Template - IntelliJ IDEA 插件
[](https://plugins.jetbrains.com)
[]()
[](LICENSE)
**Enjoy Template** 是一款 IntelliJ IDEA 插件,为 [JFinal Enjoy](https://jfinal.com) 模板引擎提供完整的语言支持。Enjoy 是 JFinal 框架内置的高性能模板引擎,语法简洁优雅,广泛应用于 Java Web 开发中的页面渲染。
## 功能特性
### 语法高亮
- Enjoy 指令(`#if`、`#for`、`#define`、`#switch` 等)和表达式的完整语法高亮
- HTML 模板内容与 Enjoy 指令的分层高亮显示
- 自定义颜色方案:`Settings → Editor → Color Scheme → Enjoy`
- 支持块注释、行注释、字符串的语法着色
### 代码补全
- 输入 `#` 时自动弹出指令补全列表
- 支持所有 Enjoy 指令的智能补全:
- 控制流:`#if`、`#else if`、`#else`、`#end`、`#switch`、`#case`、`#default`
- 循环:`#for`、`#break`、`#continue`
- 函数定义:`#define`
- 输出:`#()`、`#(expr)`
- 注释:`##`(行注释)、`#** #`(块注释)
- 其他:`#include`、`#set`、`#return`、`#render` 等
- 模板内自定义函数(`#define` 定义的函数)的跨文件补全
### 跳转到定义
- `Ctrl + 点击`(macOS: `Cmd + 点击`)`#define` 或 `#@` 函数调用,可跳转到函数定义处
- 支持跨文件的函数定义解析
- 支持 `#@name(...)` 和 `#@name?(...)`(空安全调用)两种语法
### 括号匹配
- 自动匹配 `{}`、`()`、`[]` 括号对
- 高亮显示匹配的括号
### 代码格式化
- Enjoy 代码块的自动缩进和格式化
- `Ctrl + Alt + L`(macOS: `Cmd + Alt + L`)格式化当前文件
### 语法检查(Annotator)
- `#else` / `#else if` 必须出现在 `#if` 块内
- `#break` / `#continue` 必须出现在 `#for` 循环内
- `#case` / `#default` 必须出现在 `#switch` 块内
- `#return` 必须出现在 `#define` 函数内
- 函数调用是否匹配已定义的模板函数
### 注释切换
- `Ctrl + /`(macOS: `Cmd + /`)切换行注释 `##`
- `Ctrl + Shift + /`(macOS: `Cmd + Shift + /`)切换块注释 `#** #`
### 可自定义文件扩展名
- 默认关联 `.enjoy` 文件
- 可在设置中添加任意扩展名(如 `.html`、`.tpl`、`.jfinal` 等)
- 配置路径:`Settings → Tools → Enjoy Template`
## 使用方法
### 基本使用
打开任意 `.enjoy` 文件即可自动激活所有功能。Enjoy 指令和 HTML 内容将分别以不同的语法高亮显示。
### 配置文件扩展名
如果你的项目中使用了非 `.enjoy` 的扩展名(例如 `.html` 或 `.tpl`),可以手动关联:
1. 打开 `Settings → Tools → Enjoy Template`
2. 点击 **+** 按钮添加新的扩展名(不带点号,如 `html`)
3. 选中扩展名后点击 **-** 按钮可移除
4. 点击 **Apply** 或 **OK** 保存
> 注意:至少需要保留一个扩展名。
### 定义和调用模板函数
**定义函数:**
```enjoy
#define sayHello(name)
Hello, #(name)!
#end
```
**调用函数:**
```enjoy
#@sayHello("World")
```
**空安全调用(函数不存在时不报错):**
```enjoy
#@sayHello?("World")
```
使用 `Ctrl + 点击`(macOS: `Cmd + 点击`)函数名即可跳转到定义处。
### 代码补全
在 `.enjoy` 文件中输入 `#` 后,插件会自动弹出指令补全列表。对于项目中已定义的 `#define` 函数,也会出现在补全列表中。
### 语法验证
插件会在编辑器中实时标记语法错误,例如:
- 在 `#if` 块外使用 `#else` 会显示红色波浪线
- 在 `#for` 循环外使用 `#break` 会被标记
- 调用未定义的函数会显示警告
## 项目结构
```
src/main/kotlin/io/github/ysjsgzq/
├── EnjoyFileType.kt 文件类型定义
├── EnjoyIcons.kt 插件图标
├── EnjoyLanguage.kt 语言定义(TemplateLanguage)
├── annotator/
│ └── EnjoyAnnotator.kt 语法检查器
├── brace/
│ └── EnjoyBraceMatcher.kt 括号匹配
├── comment/
│ └── EnjoyCommenter.kt 注释切换
├── completion/
│ ├── EnjoyCompletionConfidence.kt 补全置信度(允许自动弹出)
│ ├── EnjoyCompletionContributor.kt 代码补全贡献者
│ ├── EnjoyCompletionSupport.kt 补全支持
│ └── EnjoyTypedHandler.kt 输入 `#` 触发补全
├── formatting/
│ ├── EnjoyBlock.kt 格式化块
│ └── EnjoyFormattingModelBuilder.kt 格式化模型
├── highlight/
│ ├── EnjoyColorSettingsPage.kt 颜色方案配置页
│ ├── EnjoyEditorHighlighter.kt 编辑器高亮器(分层高亮)
│ ├── EnjoySyntaxHighlighter.kt 语法高亮器
│ └── EnjoySyntaxHighlighterFactory.kt
├── lexer/
│ └── EnjoyLexer.kt 手写词法分析器(4 状态状态机)
├── parser/
│ ├── EnjoyElementTypes.kt PSI 元素类型
│ ├── EnjoyParser.kt 手写递归下降解析器
│ ├── EnjoyParserDefinition.kt 解析器定义
│ └── EnjoyTemplateFileElementTypes.kt 模板文件元素类型
├── psi/
│ ├── EnjoyFile.kt 文件 PSI 元素
│ ├── EnjoyFileViewProvider.kt 双 PSI 树文件视图提供者
│ ├── EnjoyPsiElement.kt PSI 元素基类
│ ├── EnjoyTokenType.kt Token 类型
│ └── EnjoyTokens.kt Token 常量和 TokenSet
├── reference/
│ └── EnjoyFuncCallReference.kt 函数调用引用解析
└── settings/
├── EnjoyConfigurable.kt 设置页面 UI
└── EnjoySettings.kt 设置持久化
```
## 技术架构
### 模板语言架构
本插件实现了 IntelliJ 的 **Template Language** 机制。`.enjoy` 文件拥有**双 PSI 树**:
- **Enjoy PSI 树**:解析 Enjoy 指令和表达式
- **HTML PSI 树**:解析 HTML 模板内容
`EnjoyFileViewProvider` 继承自 `ConfigurableTemplateLanguageFileViewProvider`,负责创建和管理这两棵树。`EnjoyEditorHighlighter` 通过 `LayeredLexerEditorHighlighter` 将 HTML 高亮叠加到 `HTML_TEXT` Token 上。
### 词法分析器
手写的 4 状态状态机(非 JFlex 生成),位于 `lexer/EnjoyLexer.kt`:
- **HTML 状态**:解析 HTML 模板内容
- **EXPR 状态**:解析 `#(...)` 表达式
- **BLOCK_COMMENT 状态**:解析 `#** #` 块注释
- 状态编码:将解析模式、括号深度和 `awaitingOuterLParen` 标志编码为单个整数
### 解析器
手写的递归下降解析器(非 Grammar-Kit BNF),位于 `parser/EnjoyParser.kt`。使用 `parseFileContent(builder, stopTokens)` 模式,每个块指令(如 `#if`)传递其停止 Token 集合(`ELSE_IF`、`ELSE`、`END`)以正确解析嵌套结构。
## 开发指南
### 环境要求
- JDK 17+
- IntelliJ IDEA(推荐使用 2025.3+)
- Gradle 9.5.0(已内置 Gradle Wrapper)
### 常用命令
```bash
# 构建项目
./gradlew build
# 在沙箱 IDE 中运行插件(用于调试)
./gradlew runIde
# 运行所有测试
./gradlew check
# 运行单个测试类
./gradlew test --tests "io.github.ysjsgzq.lexer.EnjoyLexerTest"
# 运行单个测试方法
./gradlew test --tests "io.github.ysjsgzq.lexer.EnjoyLexerTest.testMethodName"
# 验证插件兼容性
./gradlew verifyPlugin
```
## 兼容性
- **IntelliJ IDEA** 2025.3+
- **其他 JetBrains IDE**:支持所有包含 `com.intellij.modules.xml` 模块的 IDE
- **依赖插件**:`com.intellij.java`、`com.intellij.modules.xml`
## 相关链接
- [JFinal 官方网站](https://jfinal.com)
- [JFinal Enjoy 模板引擎文档](https://jfinal.com/doc)
- [IntelliJ Platform SDK](https://plugins.jetbrains.com/docs/intellij)
- [JetBrains Marketplace](https://plugins.jetbrains.com)
## 致谢
本项目 **完全由 AI 编程工具完成**,无任何人工编写代码:
- **[Codex](https://openai.com/codex)** 完成了约 60% 的开发工作
- **[Claude Code](https://claude.ai/claude-code)** + **[mimo-v2.5-pro](https://platform.xiaomimimo.com/)**、**[Claude Code](https://claude.ai/claude-code)** + **[GLM](https://open.bigmodel.cn/)** 完成了剩余 40% 的开发工作
感谢 **小米公司** 赠送的 Token Plan Pro 月卡套餐,为本项目提供了强大的 AI 编程支持。
小米模型平台:[https://platform.xiaomimimo.com/](https://platform.xiaomimimo.com/)
## 许可证
[Apache License 2.0](LICENSE)