Chapter 174 · XUI 专业控件

CodeEdit 词法高亮

CodeEdit 语法高亮系统:Theme 主题、Token 映射、Style 样式、Language Registry。

174

概念

语法高亮由三层协作:
• Language Registry:注册语言词法分析器(Lexer)
• Token:词法分析输出的 Token 流(关键字/字符串/注释等)
• Theme:Token Kind → Style 映射,Style 定义前景/背景/粗体/斜体
• TokenBuffer:缓存当前可见行 Token,避免重复分析

API 速查

函数说明
int xuiCodeThemeCreate(xui_code_theme* ppTheme)创建主题
int xuiCodeThemeSetDefault(xui_code_theme pTheme)默认配色
int xuiCodeThemeSetStyle(xui_code_theme pTheme, int iStyleId, const xui_code_style_t* pStyle)设置样式
int xuiCodeThemeMapTokenKind(xui_code_theme pTheme, int iTokenKind, int iStyleId)Token→Style 映射
int xuiCodeThemeGetTokenStyle(xui_code_theme pTheme, int iTokenKind, xui_code_style_t* pStyle)查询 Token 样式
int xuiCodeEditSetTheme(xui_widget pW, xui_code_theme pTheme)应用主题
int xuiCodeEditSetStyle(xui_widget pW, int iStyleId, const xui_code_style_t* pStyle)覆盖单个样式
xui_code_token_buffer xuiCodeEditGetTokenBuffer(xui_widget pW)Token 缓存
xui_code_language_registry xuiCodeEditGetLanguageRegistry(xui_widget pW)语言注册表

编译本章示例

gcc -O2 -I. -o ch174.exe ch174_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch174.exe

示例:自定义暗色主题

xui_code_theme pTheme;
xuiCodeThemeCreate(&pTheme);

// 关键字:蓝色粗体
xui_code_style_t kwStyle = { 0 };
kwStyle.iForeground = 0x569CD6FF;
kwStyle.bBold = 1;
xuiCodeThemeSetStyle(pTheme, 1, &kwStyle);
xuiCodeThemeMapTokenKind(pTheme, 1, 1); // KEYWORD→Style1

// 字符串:橙色
xui_code_style_t strStyle = { 0 };
strStyle.iForeground = 0xCE9178FF;
xuiCodeThemeSetStyle(pTheme, 2, &strStyle);
xuiCodeThemeMapTokenKind(pTheme, 2, 2); // STRING→Style2

// 注释:绿色斜体
xui_code_style_t cmtStyle = { 0 };
cmtStyle.iForeground = 0x6A9955FF;
cmtStyle.bItalic = 1;
xuiCodeThemeSetStyle(pTheme, 3, &cmtStyle);
xuiCodeThemeMapTokenKind(pTheme, 3, 3);

xuiCodeEditSetTheme(pEditor, pTheme);

完整代码

将以下代码保存为 ch174_main.c,编译后运行即可看到自定义暗色主题下的语法高亮效果:

#include "xge.h"
#include "xui.h"

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x1E1E1EFF);
    xui_vec2_t pos;
    xgeMouseGet(&pos.x, &pos.y);
    xuiInputPointerMove(g_pCtx, pos.x, pos.y);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, pos.x, pos.y, 0);
    else
        xuiInputPointerUp(g_pCtx, pos.x, pos.y, 0);
    xuiUpdate(g_pCtx, xgeGetDelta());
    xuiLayout(g_pCtx);
    xuiRender(g_pCtx, NULL, NULL, 0);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = { 0 };
    d.iWidth = 900; d.iHeight = 640;
    d.sTitle = "ch174 - Syntax Highlight";
    d.iFlags = XGE_INIT_VSYNC;
    xgeInit(&d);

    xuiCreate(&g_pCtx);
    extern const xui_proxy_t tXgeProxy;
    xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
    xuiSetViewportSize(g_pCtx, 900, 640);

    // 创建编辑器
    xui_code_edit_desc_t desc = { 0 };
    xui_widget pEditor;
    xuiCodeEditCreate(g_pCtx, &pEditor, &desc);
    xuiCodeEditSetLanguage(pEditor, "c");

    // 创建自定义暗色主题
    xui_code_theme pTheme;
    xuiCodeThemeCreate(&pTheme);

    // 关键字:蓝色粗体
    xui_code_style_t kwStyle = { 0 };
    kwStyle.iForeground = 0x569CD6FF;
    kwStyle.bBold = 1;
    xuiCodeThemeSetStyle(pTheme, 1, &kwStyle);
    xuiCodeThemeMapTokenKind(pTheme, 1, 1);

    // 字符串:橙色
    xui_code_style_t strStyle = { 0 };
    strStyle.iForeground = 0xCE9178FF;
    xuiCodeThemeSetStyle(pTheme, 2, &strStyle);
    xuiCodeThemeMapTokenKind(pTheme, 2, 2);

    // 注释:绿色斜体
    xui_code_style_t cmtStyle = { 0 };
    cmtStyle.iForeground = 0x6A9955FF;
    cmtStyle.bItalic = 1;
    xuiCodeThemeSetStyle(pTheme, 3, &cmtStyle);
    xuiCodeThemeMapTokenKind(pTheme, 3, 3);

    // 应用主题
    xuiCodeEditSetTheme(pEditor, pTheme);

    // 设置示例代码
    const char* sCode =
        "// XGE Theme Demo\n"
        "#include <stdio.h>\n"
        "\n"
        "int main(void) {\n"
        "    const char* msg = \"Hello\";\n"
        "    printf(\"%s\\n\", msg);\n"
        "    return 0;\n"
        "}\n";
    xuiCodeEditSetText(pEditor, sCode);

    xui_widget pRoot = xuiGetRootWidget(g_pCtx);
    xuiWidgetAddChild(pRoot, pEditor);
    xuiWidgetSetRect(pEditor, (xui_rect_t){0, 0, 900, 640});

    xgeRun(onFrame, NULL);
    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • xuiCodeThemeCreate:创建空主题对象,随后通过 SetStyle 填充各 Token 样式。
  • SetStyle + MapTokenKind:先定义 StyleId 对应的前景色/粗体/斜体,再将 TokenKind 映射到该 Style。
  • xuiCodeEditSetTheme:将主题应用到编辑器,立即重新着色整个文档。
  • 增量高亮:编辑时仅重新分析受影响的行,不会全文重新词法分析。

要点与陷阱

  • StyleId:主题内样式 ID 自定义,TokenKind 映射到 StyleId。
  • SetStyle 覆盖:CodeEdit 级 SetStyle 优先于 Theme 中的定义。
  • 增量高亮:编辑时仅重新分析受影响的行,性能优异。
  • Language:切换语言后自动重新高亮整个文档。

进阶练习

  1. 主题切换器:ComboBox 选择亮色/暗色主题实时切换。
  2. 自定义语言:注册 JSON Lexer 实现键值对着色。
CodeEdit 词法高亮效果
图:CodeEdit 词法高亮渲染效果