Chapter 204 · 综合实战

实战:代码编辑器

CodeEdit + MenuBar + StatusBar + Tabs:构建完整的代码编辑环境。

204

项目概述

构建一个代码编辑器(类 VS Code 精简版):
• 编辑区:CodeEdit 多标签页
• 菜单栏:MenuBar(文件/编辑/视图/帮助)
• 状态栏:StatusBar(行号/编码/语言)
• 文件树:TreeView 侧边栏
• 终端:Terminal 底部面板

技术栈

模块XUI API
编辑器xuiCodeEditCreate + Lexer + Theme
标签页xuiTabsCreate(可关闭/拖拽排序)
菜单xuiMenuBarCreate + 快捷键
状态栏xuiStatusBarCreate(三段式)
文件树xuiTreeViewCreate(懒加载)
终端xuiTerminalCreate(ConPTY)

编译本章示例

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

核心代码:多标签编辑

// 打开文件到新标签
void OpenFile(const char* sPath) {
    // 创建 CodeEdit
    xui_code_edit_desc_t tDesc = { 0 };
    xui_widget pEdit;
    xuiCodeEditCreate(pCtx, &pEdit, &tDesc);

    // 加载文件内容
    char* sContent = ReadFile(sPath);
    xuiCodeEditSetText(pEdit, sContent);

    // 设置语法高亮
    xuiCodeEditSetLanguage(pEdit,
        GetLexerByExt(GetExt(sPath)));

    // 添加到标签页
    xuiTabsAddPage(pTabs, pEdit,
        GetFileName(sPath), 1);
}

// 保存当前文件(Ctrl+S)
void OnSave(void) {
    xui_widget pEdit =
        xuiTabsGetClientWidget(pTabs);
    const char* sText =
        xuiCodeEditGetText(pEdit);
    WriteFile(g_sCurrentPath, sText);
    xuiStatusBarAddText(pStatus,
        0, "已保存", 0.0f, 0, 0);
}

完整代码

将以下代码保存为 ch204_main.c,编译后运行即可看到简化版代码编辑器框架(标签页 + CodeEdit + 状态栏):

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

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x1e1e2e);
    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 = 960; d.iHeight = 640;
    d.sTitle = "ch204 - Code Editor";
    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, 960, 640);

    xui_widget pRoot;
xuiPanelCreate(g_pCtx, &pRoot, NULL);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 960, 640});

    /* 标签页 */
    xui_widget pTabs;
xuiTabsCreate(g_pCtx, &pTabs, NULL);
xuiWidgetAddChild(pRoot, pTabs);
    xuiWidgetSetRect(pTabs, (xui_rect_t){0, 0, 960, 600});
    xuiWidgetSetRect(pTabs, (xui_rect_t){0, 0, 960, 600});

    /* CodeEdit 编辑区 */
    xui_code_edit_desc_t tCE = {0};
    xui_widget pEdit;
    xuiCodeEditCreate(g_pCtx, &pEdit, &tCE);
    xuiCodeEditSetText(pEdit, "#include <stdio.h>\nint main() {\n    return 0;\n}");

    /* 状态栏 */
    xui_widget pStatus;
xuiPanelCreate(g_pCtx, &pStatus, NULL);
xuiWidgetAddChild(pRoot, pStatus);
    xuiWidgetSetRect(pStatus, (xui_rect_t){0, 600, 960, 40});
    xuiWidgetSetRect(pStatus, (xui_rect_t){0, 0, 960, 40});

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

代码讲解

  • Tabs:标签页容器,每个标签对应一个 CodeEdit 实例。
  • CodeEdit:代码编辑器控件,支持语法高亮、行号、虚拟化渲染。
  • 状态栏:底部显示光标位置、编码、保存状态等信息。
  • 大文件:CodeEdit 虚拟化渲染,仅绘制可见行,支持万行文件。

要点与陷阱

  • 大文件:CodeEdit 虚拟化渲染,仅绘制可见行。
  • Lexer:按扩展名选择词法高亮器,未知扩展用纯文本。
  • 修改标记:标签页显示未保存圆点,关闭时确认。
  • 查找替换:Ctrl+H 弹出查找面板,支持正则。

进阶练习

  1. 自动补全:输入时弹出候选列表(ComboBox 弹出层)。
  2. 分栏编辑:同一文件双视图对比。
实战:代码编辑器效果
图:实战:代码编辑器渲染效果