01 快速入门

本章带你从零开始:准备环境、创建项目、编写第一个易狗程序并编译运行。

1.1 环境准备

易狗IDE 采用完整外置化架构,exe 只做 IDE 逻辑,所有资源以磁盘文件形式存放。你只需准备:

依赖版本要求说明
Go SDK1.25.0+用户程序编译必需;IDE 设置中可配置非 PATH 路径
操作系统Win/macOS/LinuxIDE 本体跨平台桌面应用开发
Delve (dlv)可选仅在使用调试器时需要
离线友好

用户程序编译使用 wails-template/vendor/ 离线依赖与 -mod=vendor 标志,无需配置 GOPROXY 即可编译。

1.2 创建项目

启动 IDE 后,在起始页选择「创建项目」。可从内置模板选择:

  • blank — 空白项目
  • console — 控制台程序
  • window — 窗口程序(含启动窗口设计文件 .ew
  • golib_demo — Go 库调用示例

1.3 第一个程序

项目创建后,主入口文件为 src/main.eg。打开编辑器编写:

src/main.eg
// 我的第一个易狗程序
函数 主函数() {
    打印("你好,易狗IDE!")
    变量 名字 := "道生易"
    打印("欢迎," + 名字)
}

1.4 编译运行

点击标题栏中间的编译运行按钮(播放图标,强调色高亮),IDE 会:

  1. 调用后端转译器,将 .eg 转 Go 代码
  2. 合并 .elib 扩展包源码(全局 libs/ + 项目 libs/
  3. 处理 @嵌入 块,生成 //line 错误定位指令
  4. 复制运行时模板到临时目录,写入用户代码
  5. go build 编译并运行
debug 模式

编译产物为 egruntime.exe(固定文件名,保留 DWARF 调试信息)。release 模式则生成带版本号产物并可选 UPX 压缩。

1.5 项目结构详解

创建项目后,IDE 会在指定目录生成完整的项目骨架。下表列出每个目录与关键文件的作用:

路径类型说明
src/main.eg源码程序主入口文件,包含 主函数(),转译后映射为 Go 的 main.mainImpl
src/*.ew设计文件窗口设计器生成的 JSON IR,描述组件树/属性/事件绑定
src/*.eg源码.ew 同名的代码文件,承载事件处理函数
src/module/源码用户自拆分模块,可被 main.eg 引用
src/include/源码跨项目共享模块,软链接或拷贝形式引入
libs/扩展项目级 .elib 支持库(与全局 libs/ 合并)
components/扩展项目级组件包,扩展窗口设计器组件箱
resources/资源图片、字体、音频等静态资源,编译时按需嵌入
lib/原生第三方 DLL、静态库,供 @嵌入 调用
go.modGoGo 模块定义,由 IDE 维护,用户一般不需手改
wails-template/WailsWails v3 框架模板与 vendor/ 离线依赖
wails-template/vendor/Go离线依赖目录,配合 -mod=vendor 免 GOPROXY 编译
.eg/project.eg.json元数据项目配置:名称/版本/调试器/编译选项
.eg/layout/*.ir.json元数据窗口设计器中间表示(IR)
.eg/memory/元数据AI 项目级记忆库,跨会话保留上下文
.eg/cache/元数据编译缓存(转译产物、依赖快照)
out/输出编译中间产物目录
bin/输出最终可执行文件输出目录
命名约定

.ew 与对应 .eg 必须同名同目录,IDE 才能在事件下拉中正确定位源码。例如 window_main.ewwindow_main.eg

1.6 IDE 界面介绍

易狗IDE 主界面采用经典的五区布局,各区职责明确:

区域位置主要功能
标题栏顶部三段布局:左侧为应用图标 + 应用名 + 保存/另存为/撤销/重做;中间为编译运行(播放图标,强调色高亮)+ 生成可执行文件 + 调试;右侧为关于/主题切换/代码片段/系统设置/分隔线/最小化/最大化/关闭
左侧文件树左 1项目文件树(src/libs/components),支持新建/重命名/删除;下方为层级列表(窗口设计器中组件树)
左侧工具面板左 24 个固定标签 + 插件追加标签(G7 插件面板):文件/项目/支持/AI
中间编辑器中央Monaco 编辑器,语言 ID 为 egou;窗口设计器作为同区切换标签
右侧属性面板三组属性(基本/外观/事件)+ 事件下拉;底部为事件定位组合框
底部输出面板底部输出/错误/提示/书签/历史/调试 六标签切换;编译错误可点击跳转(AI 不在输出面板,位于左侧工具面板第 4 个标签)
断点栏编辑器左行号栏(glyph margin):点击切换断点,F9 切换;当前执行行黄色高亮
单实例编辑器

Editor 为单实例复用设计:切换文件不会创建多个 Monaco 实例,而是复用同一编辑器并切换 model。断点、书签、折叠状态按 fileId 持久化到 localStorage,切换回来自动恢复。

1.7 常用快捷键速查表

快捷键功能说明
Ctrl+Click跳转到定义同文件函数/方法 + 跨文件 .elib 函数
F12跳转到定义与 Ctrl+Click 等价,键盘入口
Shift+F12查找引用gopls 提供,列出当前符号的所有引用位置
Ctrl+F2切换书签当前行打标/取消
Alt+F2下一个书签向后跳转
Alt+Shift+F2上一个书签向前跳转(F2 留给重命名)
F9切换断点调试时使用,Shift+点击也可添加
F5继续执行调试已启动时继续;未启动时启动调试
F10单步步过Next,不进入函数
F11单步步入Step,进入函数
Shift+F11单步步出StepOut,跳出当前函数
Ctrl+S手动保存自动保存 debounce 3s,仅对有路径文件生效
书签与断点区分

书签是导航标记(蓝色圆点),断点是调试停点(红色圆点)。两者共用 glyph margin,但功能独立:Ctrl+F2 切换书签,F9 切换断点。

1.8 gopls 语言服务器集成

自 v0.12.31 起,易狗IDE 接入 Go 官方语言服务器 gopls,让编辑器从"语法高亮 + 中文关键字补全"升级为真正的 IDE。v0.12.32 起将 gopls 内置到发布包 bin/tools/gopls/,用户零配置即可使用。

由于 gopls 只识别 .go 文件,后端维护一个影子工作区:把项目中的 .eg 文件按原结构镜像为 .go,gopls 在影子目录上工作,返回的路径自动映射回 .eg

LSP 能力触发方式说明
跳转定义F12 / Ctrl+Click跳转到符号定义处,支持 Go 标准库函数
查找引用Shift+F12列出当前符号的所有引用位置
悬浮提示鼠标悬停显示类型签名、文档注释
实时诊断编辑时自动编译错误、vet 问题以红波浪线标注
格式化格式化命令gofmt / goimports 风格
文档符号大纲面板列出当前文件的函数/类型/变量大纲
Go 标准库跳转

gopls 提供了对 Go 标准库(fmt / os / strings / strconv 等)的跳转与补全能力。在 @嵌入 块内输入 os. 即可触发标准库函数补全。gopls 未安装或启动失败时不阻断主流程,编辑器仍保留中文关键字补全与 egParser 诊断。

gopls 解析顺序

启动 LSP 时按三段回退查找 gopls:用户自定义路径 → 内置 bin/tools/gopls/ → 系统 PATH。可在系统设置 → 编译 → 语言服务器 (gopls) 中查看状态与配置路径。

02 语法规范

易狗IDE 采用 Go 原生语法关键词中文化,仿易语言用法。一切以 Go 语法及格式为准。

2.1 中文关键字

中文关键字Go 等价说明
函数func函数声明
变量var / :=变量声明
如果if条件分支(带否则块)
如果真if单分支条件,无 else 块,比 如果 更简洁
否则else否则分支
判断循环for条件循环
计次循环首for计数循环
变量循环首for range遍历循环(切片/映射等)
跳出循环break跳出当前循环
到循环尾continue跳过本次循环剩余部分,进入下一轮
选择switch多分支
情况case分支项
默认default默认分支
返回return返回
结束结束当前块

2.2 控制结构

如果 / 否则(输入「如果」会自动展开为完整骨架):

control.eg
如果 (age >= 18) {
    打印("已成年")
} 否则 {
    打印("未成年")
}

判断循环(输入「判断循环」自动展开):

loop.eg
判断循环 (i < 10) {
    打印(i)
    i = i + 1
}

选择(switch-case,输入「选择」自动展开 情况 + 默认 骨架):

switch.eg
选择 (day) {
情况 1: 打印("周一")
情况 2: 打印("周二")
默认: 打印("其他")
}

2.3 @嵌入 Go 原生混编

使用 @嵌入@结束 包裹 Go 原生代码块,实现中文与 Go 无缝混编:

mix.eg
函数 计算阶乘(n 整数) 整数 {
    @嵌入
        if n <= 1 {
            return 1
        }
        return n * factorial(n-1)
    @结束
}
注意

@嵌入 块内的代码原样保留至生成的 Go 文件,需符合 Go 语法。AST 编译器将 @嵌入/@结束 作为独立 Token 处理。

2.4 中文符号自动转换

编辑器自动将中文符号转换为英文等价物:

中文符号转换后
()()
【】[]
""""
,
.

2.5 缩进与注释

  • 缩进:2 或 4 空格(设置面板用 NSelect 切换,不用 NSlider)
  • 注释:Go 风格 //
  • 单引号:中文代码区禁止单引号字符串;但 @嵌入 块内 Go rune 字面量(如 'f')是合法的
  • 语言 ID:Monaco 编辑器中固定为 egou

2.6 编辑器增强功能

功能快捷键说明
跳转到定义Ctrl+Click / F12同文件函数/方法 + 跨文件 .elib 函数
切换书签Ctrl+F2下一个 Alt+F2,上一个 Alt+Shift+F2(F2 留给重命名)
切换断点F9Shift+点击也可添加断点
自动保存debounce 3s,仅对有路径的文件,无对话框
代码折叠按 fileId 持久化到 localStorage

2.7 数据类型

EGOU 采用混合模式:类型既可用 Go 原生写法(int/string/float64/bool…),也可用中文类型别名,二者等价、编译期自动转译。常用别名:整数int文本string逻辑bool小数float64字节byte字符rune结构体struct接口interface通道chan。复合类型用 Go 原生括号语法 + 内层中文类型自动替换:[]整数[]intmap[文本]整数map[string]int通道 整数chan int。数学四则(+ - * /)保持原生 Go。自定义类型仍用 @嵌入 + Go type

type.eg
// 自定义类型(@嵌入 Go 原生 type 关键字)
@嵌入
    type UserID int
    type Score float64
@结束

函数 主函数() {
    变量 uid = 1001      // Go 自动推断为 int
    变量 sc  = 98.5       // Go 自动推断为 float64
    打印(uid, sc)
}
type-cn.eg
// 中文类型别名(与 Go 原生等价,编译期自动转译)
变量 年龄 整数 = 18
变量 分数 小数 = 95.5
变量 已婚 逻辑 = 
变量 编号 []整数 = []整数{1, 2, 3}
函数 主函数() {
    打印(年龄, 分数, 已婚, 编号)
}
类型转换

类型转换需用 @嵌入 调用 Go 转换函数,如 int(f)string(n)strconv.Itoa(n) 等。中文语法本身不提供转换关键字。

布尔值

布尔值可用 @嵌入true/false,或 krnln 支持库的 取常量_真()/取常量_假()/ 是否作为中文关键字直接使用,以转译器实际支持为准。

2.8 运算符

类别运算符说明
算术+ - * / %加减乘除取模;+ 对文本为拼接
比较> < >= <= == !=返回布尔值
逻辑 仿易语言别名,以转译器实际支持为准。如不支持,可在 @嵌入 块内使用 && || !
赋值:= =:= 短声明(首次定义),= 重新赋值
复合赋值+= -= *= /= %=同 Go,op 后加 =
位运算& | ^ << >>需用 @嵌入 表达
取地址/解引用& *需用 @嵌入 表达
operator.eg
变量 a := 10
变量 b := 3
打印(a + b)            // 13
打印(a / b)            // 3(整数除法)
打印(a % b)            // 1

如果 (a > b  b != 0) {
    打印("条件成立")
}

a += 5                    // a 现在是 15

2.9 数组与切片

数组的声明与遍历需借助 @嵌入,因为中文语法不直接提供 [] 数组字面量语法。最常见做法是用切片 + append

slice.eg
函数 主函数() {
    @嵌入
        var nums []int = []int{1, 2, 3}
        nums = append(nums, 4, 5)
        fmt.Println("len=", len(nums), "cap=", cap(nums))
        for i, v range nums {
            fmt.Printf("nums[%d]=%d\n", i, v)
        }
    @结束
}
操作Go 函数说明
长度len(s)元素数量
容量cap(s)底层数组容量
追加append(s, x)返回新切片,需重新赋值
切片s[a:b]左闭右开区间
删除append(s[:i], s[i+1:]...)需用 @嵌入

2.10 函数详解

函数声明使用 函数 关键字,支持多返回值命名返回值可变参数闭包

func.eg
// 多返回值
函数 除法(a, b 整数) (整数, 文本) {
    如果 (b == 0) {
        返回 0, "除数不能为零"
    }
    返回 a / b, ""
}

// 命名返回值(裸返回)
函数 计算(x 整数) (结果 整数, 错误 文本) {
    结果 = x * 2
    返回                     // 裸返回
}

// 可变参数(@嵌入 Go 原生语法)
函数 求和(nums ...整数) 整数 {
    @嵌入
        var sum int
        for _, n range nums {
            sum += n
        }
        return sum
    @结束
}

// 闭包
函数 计数器() {
    @嵌入
        gen := func() func() int {
            i := 0
            return func() int {
                i++
                return i
            }
        }()
        fmt.Println(gen(), gen(), gen())  // 1 2 3
    @结束
}

2.11 面向对象

结构体、方法、嵌入、接口需用 @嵌入 表达 Go 原生语法,但调用方法/访问字段仍可在中文区域完成:

oop.eg
@嵌入
    type 学生 struct {
        姓名 string
        年龄 int
    }

    // 方法
    func (s *学生) 介绍() string {
        return fmt.Sprintf("我叫%s,今年%d岁", s.姓名, s.年龄)
    }

    // 接口
    type 介绍者 interface {
        介绍() string
    }
@结束

函数 主函数() {
    @嵌入
        s := &学生{姓名: "张三", 年龄: 18}
        fmt.Println(s.介绍())

        // 多态:接口变量接收结构体指针
        var p 介绍者 = s
        fmt.Println(p.介绍())
    @结束
}
概念Go 关键字说明
结构体struct字段集合,定义在 @嵌入 块中
方法func (recv) Name()接收者可为值或指针
嵌入匿名字段组合复用,无继承
接口interface隐式实现,鸭子类型

2.12 错误处理

Go 风格的多返回值错误处理是首选。配合 defer 资源清理与 panic/recover 处理不可恢复错误:

error.eg
函数 读文件(路径 文本) (文本, 文本) {
    @嵌入
        data, err := os.ReadFile(路径)
        if err != nil {
            return "", err.Error()
        }
        return string(data), ""
    @结束
}

函数 安全执行() {
    @嵌入
        defer func() {
            if r := recover(); r != nil {
                fmt.Println("捕获到 panic:", r)
            }
        }()
        panic("主动抛出")
    @结束
}
机制Go 关键字使用场景
错误返回error 类型可预期的错误,调用方需检查
延迟执行defer资源释放、收尾逻辑(LIFO 顺序)
恐慌panic()不可恢复错误,立即终止当前函数
恢复recover()仅在 defer 中有效,捕获 panic

2.13 包与导入

易狗IDE 提供两类导入:导入 Go 原生包(@嵌入)与导入 .elib 支持库(自动合并)。

import.eg
// Go 原生包导入(必须放在文件顶部 @嵌入 块)
@嵌入
    import (
        "fmt"
        "os"
        "strings"
        "strconv"
    )
@结束

// .elib 支持库自动可用,无需导入
// 例如 libs/golib 提供的 中文命令直接调用:
函数 主函数() {
    变量 s := 取文本中间("abc[123]def", "[", "]")
    打印(s)  // 123
}
导入规则

Go 包必须用 @嵌入 在文件顶部声明;.elib 支持库由转译器在编译时自动合并 source.eg,命令别名直接可用。用户扩展是附加的,不能替换内置库

03 窗口设计器

可视化窗口设计器采用三栏布局:左侧组件箱 + 层级列表,中间设计画布,右侧属性面板。

3.1 内置组件箱

15 个内置组件可直接拖拽到画布:

button · edit · textarea · label · checkbox · radio · listbox · combobox · switch · slider · progress · image · tabs · card · divider

3.2 设计画布

  • 网格对齐:可配置网格大小
  • 对齐辅助线:拖拽时实时显示
  • 等距分布提示:多选时显示
  • 多选 + 对齐工具栏:左/中/右/顶/中/底 + 水平/垂直等距分布
  • Tab 顺序编辑模式:切换 Tab 键焦点顺序

3.3 组件属性详解

属性面板分三组,左名右值,紧致排列:基本属性、外观属性、事件属性。下表列出所有组件通用的基本/外观属性

属性类型说明
name文本组件唯一标识,事件函数命名前缀(如 button1_onClick
caption文本显示文本(按钮、标签、窗口标题等)
x / y整数左上角坐标(相对于父容器)
width / height整数宽 / 高(像素)
visible布尔是否可见
enabled布尔是否可用(灰色禁用)
locked布尔设计器锁定(防止误拖动)
font对象字体(family/size/bold/italic)
color颜色背景色(#RRGGBB 或调色板)
border枚举边框样式(none/solid/dashed)
radius整数圆角像素值
组件特有属性
edit / textareaplaceholderreadonlymaxLengthmultiline(仅 textarea)
checkbox / radiocheckedgroup(radio 单选组)
listbox / comboboxitems(数组)、selectededitable(仅 combobox)
switchonlabel
sliderminmaxstepvalueorientation
progressvaluemaxindeterminate
imagesrcfit(cover/contain/fill)、alt
tabstabs(数组:title/content)、active
cardtitleshadowpadding
dividerorientation(horizontal/vertical)、thickness
属性面板布局

属性面板左名右值紧致排列,基本属性 / 外观属性 / 事件属性三组分开。最下方为事件下拉组合框,选择某事件时定位到窗口对应源码文件;没有事件代码时自动创建,有则直接定位显示。

3.4 组件事件

事件是组件与代码交互的入口。以下为常见事件参考,实际可用事件以属性面板事件下拉为准。事件处理函数命名规则由 IDE 在选择事件时自动生成。所有组件共享一组通用事件,部分组件另有特有事件:

通用事件触发时机典型参数
onClick单击
onDblClick双击
onChanged值改变(edit/checkbox/slider 等)
onKeyDown键盘按下key, mods
onKeyUp键盘抬起key, mods
onMouseMove鼠标移动x, y
onMouseDown鼠标按下button, x, y
onMouseUp鼠标抬起button, x, y
onFocus / onBlur获得/失去焦点
onResize尺寸改变w, h
组件特有事件
listbox / comboboxonSelect(选中项改变)
tabsonTabChange(活动标签切换)
slideronSlideStart / onSlideEnd
imageonLoad / onError
window_main.eg(事件函数)
// 按钮1 的单击事件
函数 button1_onClick() {
    打印("按钮被点击")
}

// 编辑框1 内容改变事件
函数 edit1_onChanged() {
    打印("内容已改变")
}

3.5 布局与对齐

易狗IDE 支持三种布局策略,可按场景组合使用:

布局方式说明适用场景
绝对定位x / y / width / height 直接指定像素固定尺寸窗口、对话框、表单
锚点 anchor组件相对父容器四边距离固定(top/bottom/left/right)窗口可缩放、组件跟随
弹性布局容器组件(card/tabs)内部按 row/column 流式排列多组件排列、列表项

设计器提供完整对齐工具栏,多选组件后一键对齐:

  • 水平对齐:左对齐 / 水平居中 / 右对齐
  • 垂直对齐:顶对齐 / 垂直居中 / 底对齐
  • 等距分布:水平等距 / 垂直等距
  • 等尺寸:等宽 / 等高 / 等大小
网格对齐

设计画布支持可配置网格大小,拖拽时实时显示对齐辅助线,多选时显示等距分布提示,让手动排版接近专业设计工具体验。

3.6 15 个组件逐一说明

组件用途关键属性关键事件
button按钮,触发动作caption / enabledonClick / onDblClick
edit单行文本输入placeholder / readonly / maxLengthonChanged / onKeyDown / onFocus
textarea多行文本输入placeholder / multiline / scrollonChanged / onKeyDown
label静态文本标签caption / alignonClick(少用)
checkbox复选框checked / captiononChanged
radio单选框(同组互斥)checked / grouponChanged
listbox列表框(多行选项)items / selected / multionSelect / onDblClick
combobox下拉组合框items / selected / editableonSelect / onChanged
switch开关(现代化复选)on / labelonChanged
slider滑块(范围选择)min / max / step / valueonChanged / onSlideStart / onSlideEnd
progress进度条value / max / indeterminate
image图片显示src / fit / altonLoad / onError / onClick
tabs标签页容器tabs / activeonTabChange
card卡片容器(分组)title / shadow / padding
divider分割线orientation / thickness
button 示例
// 在窗口设计器中拖入 button,name 设为 btnOK,caption 设为 "确定"
// 双击按钮或在属性面板事件下拉中选择 onClick 自动生成:
函数 btnOK_onClick() {
    打印("用户点击了确定")
}

3.7 .ew 窗口文件格式

.ew 是窗口设计文件,描述窗口与组件树,由窗口设计器维护。编译时由转译器生成 .ir.json 中间表示(IR),二者不同:.ew 面向设计器编辑,.ir.json 面向编译消费。IDE 自动维护,一般不需要手动编辑。以下为参考结构,实际文件格式以 IDE 生成为准:

window_main.ew
{
    "version": 1,
    "type": "window",
    "name": "window_main",
    "caption": "我的主窗口",
    "width": 800,
    "height": 600,
    "children": [
        {
            "type": "button",
            "name": "btnOK",
            "caption": "确定",
            "x": 320,
            "y": 520,
            "width": 80,
            "height": 32,
            "events": ["onClick"]
        },
        {
            "type": "edit",
            "name": "editName",
            "placeholder": "请输入姓名",
            "x": 100,
            "y": 100,
            "width": 200,
            "height": 28
        }
    ]
}
字段说明
versionIR 版本号,IDE 升级时向后兼容
type节点类型(window / button / edit ...)
name组件唯一标识,事件函数前缀
children子组件数组(递归结构)
events该组件已绑定的事件名列表
手动编辑风险

.ew 文件由窗口设计器维护,手动编辑可能导致 IR 与设计器不一致。如确需修改,编辑后请关闭并重新打开窗口设计器以重新加载 IR。

3.8 外置组件包

通过 components/ 目录声明式注册外置组件,支持 SVG 图标 + preview HTML:

components/我的组件包/components/日期选择器/config.json
{
    "type": "datepicker",
    "label": "日期选择器",
    "icon": "icon.svg",
    "props": { ... },
    "events": [ ... ],
    "preview": "preview.html"
}

preview.html 支持 {{propName}} 占位符,运行时替换为真实属性值实现真实预览。SVG 图标通过 v-html 加载并受 CSS 尺寸限制。

3.9 组件分组

同组组件共享虚线 outline,分组标识色共 8 色:红、蓝、绿、黄、紫、橙、青、粉。用于在设计器中视觉区分逻辑相关的组件(如同一表单的字段)。

04 AI 助手

AI 助手参考 Reasonix 等开源项目,深度溶合 IDE。5 Agent 协作完成开发任务。

4.1 五 Agent 角色

角色名称职责
planner架构规划分析需求、设计模块、拆分任务
coder代码生成根据规划编写 EGOU 代码
reviewer代码审查检查代码质量、风格、潜在问题
ui_builderUI 设计窗口布局、控件配置、事件绑定
fixer错误修复根据编译错误诊断并修复

4.2 危险工具人机确认

AI 调用工具按风险分三级:

  • safe — 自动执行
  • moderate — 自动执行
  • dangerous — 必须 30 秒内人机确认

危险工具包括:write_file / delete_file / run_build / run_command / overwrite_file。确认事件通过 ai-tool-confirm 通道从 Go 传至 JS,前端调用 ConfirmToolCall(requestID, approved) 回调。

4.3 BuildAndFix 自动修复

当编译失败时,fixer Agent 自动介入,根据编译错误诊断并修复代码:

  • 默认最多 3 轮修复
  • 阶段事件build-startbuild-failedfix-startfix-appliedbuild-success / max-rounds-exceeded

4.4 AI 设置

系统设置 → AI 设置中可配置:

  • 多模型添加(支持不同 LLM 提供商)
  • Skills 技能库
  • 智能体 Agent
  • 用户规则(自定义提示词)

4.5 能力徽章

AI 能力以固定颜色徽章标识(6 种):

能力颜色
chat#63b3ed 蓝
code_gen#9f7aea 紫
debug#f56565 红
explain#48bb78 绿
plan#ecc94b 黄
ui_design#ed89c1 粉

4.6 AI 5 Agent 角色详解

AI 助手以 5 Agent 协作模式完成开发任务,每个角色有明确的输入/输出边界:

角色键名输入输出典型场景
架构师planner需求描述 / 现有代码模块拆分图 / 任务清单 / 接口定义新项目立项、大功能重构、技术选型
编码员coder架构师的规划 / 单个任务.eg 源码 / .ew 设计文件按规划实现功能、补全函数体
审查员reviewercoder 产出的代码审查意见 / 风险点 / 改进建议提交前 review、规范检查、漏洞扫描
UI 设计师ui_builder布局需求 / 组件规格.ew 设计文件 / 组件树窗口布局、控件配置、事件绑定
错误修复师fixer编译错误 / 运行异常修复后的代码 / 诊断报告BuildAndFix 自动修复、错误诊断
协作流程

典型协作链:架构师拆分任务 → 编码员实现 → 审查员审查 → UI 设计师布局 → 错误修复师修复。任一环节发现问题可回溯到上游 Agent 修正。

4.7 AI 使用流程

  1. 发起对话:左侧面板切换到「AI」标签,输入问题或需求
  2. 指定角色:在输入框前用 @planner / @coder / @reviewer / @ui_builder / @fixer 显式指定 Agent;不指定时由 AI 自动判断
  3. 选择上下文:用 #文件名 引用具体文件作为上下文,或勾选「整项目」让 AI 全局分析
  4. 查看建议:AI 输出代码时,每段建议右侧有 接受 / 拒绝 按钮
  5. 接受修改:点击「接受」会直接写入对应文件;点击「拒绝」则丢弃该段建议
  6. 触发工具:AI 调用工具(read_file / write_file / run_build 等)时,按风险等级自动或人机确认执行
  7. 多轮迭代:基于 AI 输出继续追问,直到满意为止
AI 对话示例
@planner #src/main.eg
帮我设计一个文件浏览器功能,左侧目录树,右侧文件预览。

@coder
按 planner 的规划实现 DirTree 组件的事件绑定。

@reviewer
检查我刚写的 window_main.eg 是否有内存泄漏风险。

4.8 AI 最佳实践

场景是否适合 AI说明
从零搭建 CRUD 模块✅ 推荐样板代码 AI 写得又快又准
中文语法→Go 包调用转换✅ 推荐AI 熟悉 Go 生态,能推荐合适库
正则 / 复杂字符串处理✅ 推荐AI 擅长,并能给出测试用例
窗口设计器布局初稿✅ 推荐让 ui_builder 角色生成 .ew 草案
核心业务算法⚠️ 谨慎AI 写完必须人工 review,关键路径要补测试
安全相关代码(加密/鉴权)❌ 不推荐AI 可能引入漏洞,建议人工编写并审查
性能关键路径❌ 不推荐AI 倾向写"能跑"的代码,性能需人工调优
模糊需求 / 无明确输入❌ 不推荐AI 容易臆造,先和架构师 Agent 对齐
Prompt 技巧

1. 明确角色:用 @角色 指定 Agent;2. 给出上下文:用 #文件 引用相关代码;3. 说清目标:写"实现 X 功能"而非"帮我看下";4. 分步迭代:复杂任务拆成多轮,每轮聚焦一步;5. 要求测试:让 AI 同时给出测试用例。

安全红线

AI 调用 run_command / overwrite_file / delete_file 等危险工具时会弹出 30 秒倒计时确认框。务必核对命令内容再点确认,避免误删项目文件。

05 扩展系统

易狗IDE 有 4 种扩展机制,IDE 纯净化,所有资源外置,用户共享共建生态。

5.1 .elib 支持库

声明式提供中文命令/函数。双层结构:全局库(exe 同级 libs/)+ 项目库(<项目>/libs/)。

libs/golib/
libs/golib/
├── package.json       # 包元信息(name/version/author)
├── commands.json      # 命令定义
└── source.eg          # 源码

IDE 启动时扫描 <项目>/libs/*/commands.json,与内置支持库合并。转译时自动合并 source.eg,剥离重复声明,中文别名 → 英文键映射注册到 transpiler。用户扩展是附加的,不能替换内置库

5.2 组件包

声明式扩展窗口设计器组件,详见第 3 章 · 外置组件包

components/我的组件包/
components/<包名>/
├── package.json                    # 包元数据
└── components/
    └── <组件名>/
        ├── config.json             # type/label/icon/props/events/preview
        └── icon.svg                # 图标(可选)

5.3 插件

编程式扩展 IDE 功能,通过 activate(api) 接口注册:

plugins/my-plugin/main.js
export function activate(api) {
    // 注册自定义左侧面板(G7 插件面板)
    api.registerPanel({
        "icon": "🔧",
        "label": "我的工具",
        "render": renderPanel
    });

    // 注册命令
    api.registerCommand("my.cmd", handler);
}

G7 插件面板按钮以 emoji 字符串为 icon,追加在左侧菜单 4 个固定标签之后。

5.4 项目模板

声明式定义新建项目模板:

templates/window/template.json
{
    "name": "窗口程序",
    "description": "带启动窗口的桌面应用",
    "files": ["main.eg", "启动窗口.eg", "启动窗口.ew"]
}

5.5 扩展机制对比

类型目录注册方式用途
支持库libs/commands.json 声明式提供中文命令/函数
组件包components/config.json 声明式窗口设计器组件
插件plugins/activate(api) 编程IDE 功能扩展
项目模板templates/template.json 声明式新建项目模板

5.6 .elib 支持库开发指南

支持库以目录形式组织,最小单元包含三个文件。下表说明每个文件职责:

文件必需说明
package.json包元信息(name/version/author/description)
commands.json命令定义:中文名 / 英文键 / 参数签名 / 返回类型
source.eg命令实现源码,转译时合并到用户项目
README.md使用说明
examples/示例代码
libs/golib/commands.json
{
    "package": "golib",
    "version": "1.0.0",
    "commands": [
        {
            "zh": "取文本中间",
            "en": "GetMidStr",
            "params": [
                {"name": "源文本", "type": "string"},
                {"name": "左边界", "type": "string"},
                {"name": "右边界", "type": "string"}
            ],
            "returns": "string"
        }
    ]
}
libs/golib/source.eg
函数 取文本中间(源文本, 左边界, 右边界) {
    @嵌入
        i := strings.Index(源文本, 左边界)
        if i < 0 { return "" }
        i += len(左边界)
        j := strings.Index(源文本[i:], 右边界)
        if j < 0 { return "" }
        return 源文本[i : i+j]
    @结束
}
放置位置作用范围说明
全局 libs/<name>/(exe 同级)所有项目IDE 启动时扫描,与内置库合并
项目 <project>/libs/<name>/仅当前项目覆盖同名全局库的 source.eg(命令定义仍合并)
不能替换内置库

用户扩展是附加的:同名命令时,内置库优先;用户库命令与内置库命令冲突时,用户库不会被注册。如需替换内置行为,请在用户代码中重新定义同名函数(局部覆盖)。

5.7 组件包开发

组件包通过声明式 JSON 注册自定义组件。一个组件包可包含多个组件,每个组件独立目录:

components/我的组件包/components/日期选择器/config.json
{
    "type": "datepicker",
    "label": "日期选择器",
    "icon": "icon.svg",
    "defaultSize": {"w": 160, "h": 32},
    "props": {
        "value":     {"type": "string",  "default": ""},
        "format":   {"type": "string",  "default": "yyyy-MM-dd"},
        "minDate": {"type": "string",  "default": ""},
        "maxDate": {"type": "string",  "default": ""}
    },
    "events": ["onChange", "onFocus", "onBlur"],
    "preview": "preview.html"
}
字段必需说明
type组件类型键,全 IDE 唯一
label组件箱显示名
iconSVG 图标路径(相对组件目录)
defaultSize拖入画布时的默认宽高
props属性定义,每项含 type / default
events事件名列表,决定属性面板事件下拉项
preview预览 HTML 路径,支持 {{propName}} 占位
发布组件包

把整个组件包目录打包为 zip,放到 IDE 的 components/ 或项目 components/ 下重启 IDE 即可识别。可通过 GitHub 仓库分发,用户克隆到 components/ 即完成安装。

5.8 插件开发

插件通过 JS 模块的 activate(api) 入口注册 IDE 功能。API 提供注册面板、命令、菜单、状态栏等能力:

plugins/git-status/main.js
export function activate(api) {
    // 注册左侧面板(G7 插件面板,emoji 图标)
    api.registerPanel({
        "icon": "📊",
        "label": "Git 状态",
        "render": renderGitPanel
    });

    // 注册命令(Ctrl+Shift+P 调用)
    api.registerCommand("git.commit", commitAll);
    api.registerCommand("git.push", pushToRemote);

    // 注册菜单项
    api.registerMenuItem("file/save", {
        "label": "提交并推送",
        "command": "git.commit"
    });

    // 生命周期:插件卸载时清理
    api.onDeactivate(() => {
        clearInterval(timer);
    });
}

function renderGitPanel(container) {
    container.innerHTML = "<div>Loading...</div>";
    refreshStatus(container);
}
function commitAll() { /* ... */ }
function pushToRemote() { /* ... */ }
API说明
api.registerPanel(opts)注册左侧面板,opts 含 icon/label/render
api.registerCommand(id, fn)注册命令,可通过快捷键或命令面板触发
api.registerMenuItem(group, opts)注册菜单项到指定分组
api.registerStatusBar(item)注册状态栏项
api.onActivate(fn) / api.onDeactivate(fn)生命周期钩子
api.openFile(path) / api.saveFile()调用 IDE 内部能力
api.runBuild()触发编译(dangerous,需人机确认)

5.9 模板开发

项目模板由 template.json + 模板文件组成,新建项目时 IDE 复制文件并替换占位符:

templates/计算器/template.json
{
    "name": "计算器",
    "description": "标准计算器应用模板",
    "icon": "icon.svg",
    "files": ["main.eg", "window_main.eg", "window_main.ew"],
    "variables": {
        "PROJECT_NAME": {"prompt": "项目名称", "default": "mycalc"},
        "AUTHOR":       {"prompt": "作者", "default": "匿名"}
    }
}
templates/计算器/main.eg(占位符示例)
// 项目:{{PROJECT_NAME}}
// 作者:{{AUTHOR}}
函数 主函数() {
    打印("{{PROJECT_NAME}} 启动")
}
占位符来源说明
{{PROJECT_NAME}}用户输入项目名,也用于目录名
{{AUTHOR}}用户输入作者名
{{DATE}}系统创建日期(yyyy-MM-dd)
{{EGOU_VERSION}}IDE当前 IDE 版本号(如 v0.12.32)
模板发布

将整个模板目录打包为 zip,放到 IDE 的 templates/ 下重启 IDE 即可在新建项目对话框中看到。模板间可继承:在 template.json 中加 "extends": "blank" 可复用基础模板文件。

06 调试器

基于 Delve (dlv) headless 模式集成调试器,通过 JSON-RPC over TCP 控制。

6.1 调试架构

调试链路
前端 DebugPanel.vue
    ↓ F5 / F10 / F11 / Shift+F11
App.vue → IDEService.DebugContinue / Next / Step / StepOut
    ↓
internal/app/debug.go
    ↓
internal/debugger/client.go(JSON-RPC over TCP)
    ↓
dlv headless 子进程
    ↓
egruntime.exe(带 DWARF 调试信息)

6.2 断点

  • 设置断点:编辑器行号栏(glyph margin)点击切换,或 F9
  • Shift + 点击:添加断点(与书签区分)
  • 当前执行行:黄色背景高亮
  • 断点按文件隔离:Editor 单实例复用,切换文件时同步断点

6.3 //line 断点映射

.eg 源码通过 //line 指令映射到生成的 Go 代码。调试时:

  1. 用户在 .eg 文件设置断点 → 前端记录行号
  2. 启动调试时传给后端 → 后端通过 //line 指令计算对应 Go 文件:行号
  3. 调用 dlv CreateBreakpoint 设置断点

6.4 入口断点

设计决策

调试启动时自动在 main.mainImpl(转译后的主函数)设置断点并 continue,避免 dlv 默认停在 Go runtime 入口导致 no source for PC 错误。

6.5 调试快捷键

快捷键功能等价 dlv 命令
F5继续执行(DebugContinue)continue
F9切换当前行断点break / clear
F10单步步过(Next)next
F11单步步入(Step)step
Shift+F11单步步出(StepOut)stepout
Ctrl+Shift+F5重启调试restart
Shift+F5停止调试exit

6.6 Delve 调试器配置

Delve 以 headless 子进程方式运行,IDE 通过 JSON-RPC over TCP 与之通信。配置项位于 .eg/project.eg.json

.eg/project.eg.json(调试器部分)
{
    "debug": {
        "enabled": true,
        "port": 8585,
        "initBreakpoint": "main.mainImpl",
        "autoContinue": true,
        "maxArrayLoads": 64,
        "logLevel": "info"
    }
}
选项默认值说明
enabledtrue是否启用调试器集成
port8585dlv headless 监听端口
initBreakpointmain.mainImpl调试启动时的入口断点(避免停在 runtime)
autoContinuetrue设置入口断点后立即 continue
maxArrayLoads64切片/数组变量最多加载元素数
logLevelinfodlv 日志级别(debug/info/warn/error)
Delve 安装

Delve 为可选依赖。如未安装,IDE 设置 → 调试器面板提供「自动安装」按钮,会执行 go install github.com/go-delve/delve/cmd/dlv@latest。也可在设置中指定 dlv 可执行文件的非 PATH 路径。

6.7 断点类型与条件断点

断点类型设置方式说明
普通断点行号栏点击 / F9执行到该行即暂停
条件断点右键断点 → 编辑条件满足表达式时才暂停,如 i == 100
命中计数断点右键断点 → 命中次数第 N 次命中时暂停(用于循环定位)
入口断点自动设置main.mainImpl,避免 dlv 停在 runtime
函数断点调试面板 → 函数名按函数名设置,无需源码行号
条件断点示例
// 在循环中只在 i=50 时停下
判断循环 (i < 100) {
    打印(i)            // ← 此行设条件断点:i == 50
    i++
}

6.8 变量查看与监视

调试面板(左侧工具面板「调试」标签)分四个区域:

区域说明
变量当前作用域的局部变量与参数,可展开嵌套结构
监视用户添加的监视表达式,每步自动求值
调用栈当前调用栈,点击栈帧切换作用域
断点所有断点列表,可批量启用/禁用/删除
  • 鼠标悬停:编辑器中变量悬停 0.5s 显示当前值
  • 添加监视:选中表达式右键 → 添加到监视,或直接在监视区输入
  • 修改变量值:双击变量值可临时修改(仅支持基础类型)
  • 展开嵌套:struct / slice / map 可递归展开,受 maxArrayLoads 限制

6.9 调用栈分析

调用栈面板显示当前线程的所有栈帧,从顶(当前函数)到底(入口函数):

调用栈示例
main.mainImpl()             src/main.eg:12    ← 当前
module.计算阶乘(5)          src/module/math.eg:8
module.计算阶乘(4)          src/module/math.eg:8
module.计算阶乘(3)          src/module/math.eg:8
main.mainImpl()             src/main.eg:10
runtime.main()              Go runtime
  • 点击栈帧:编辑器跳转到该帧对应源码行,变量区切换到该帧作用域
  • 行号映射:通过 //line 指令将 Go 行号映射回 .eg 源码行号
  • 递归识别:同函数多次出现在栈中可识别递归调用深度
栈帧切换限制

切换栈帧只能查看变量与源码,不能在该帧执行表达式求值。如需检查上层帧的中间状态,建议在调用处加断点重新运行。

07 编译发布

易狗IDE 支持 debug / release 双模式编译,并提供 garble 混淆与 UPX 压缩保护用户产品。

7.1 编译模式

模式产物名特性
debugegruntime.exe固定文件名,保留 DWARF(可调试)
releaseegruntime-v1.0.1-release.exe含版本号,patch 自增,UPX 可选,garble 可选

7.2 IDE 自身安全策略

  • 不用 UPX:避免杀毒软件误报
  • garble -tiny(不含 -literals):避免 TrojanSpy/Stealer 误报
  • SHA256 校验:构建产物输出校验值

7.3 用户产品防护三档

档位garble 选项说明
off普通 go build,无混淆
basic(默认)garble -tiny基础混淆
fullgarble -literals -tiny完整混淆(含字面量)

7.4 UPX 压缩

UPX 仅用于用户产品

UPX 可选,使用修改过魔数/节区名的 upx-egou.exe,避免被逆向工具识别。每次编译注入随机密钥,防止批量逆向。IDE 本身不使用 UPX。

7.5 错误处理

编译错误采用结构化解析与中文翻译:

  • 解析正则^(.+?):(\d+):(\d+):\s*(.+)$
  • 中文翻译:20 条规则(如 undefined:未定义:
  • 前端跳转:错误条目可点击跳转到对应文件行

7.6 静态编译标志

IDE 静态编译参数
-tags production,netgo,osusergo -trimpath -buildvcs=false \
-ldflags "-w -s"
构建脚本

强制使用 python scripts/build.py,禁用 PowerShell 批量写文件。

7.7 用户项目结构

myego/
myego/
├── .eg/                         # IDE 项目元数据(隐藏目录)
│   ├── project.eg.json          # 项目配置
│   ├── layout/                  # 窗口布局描述(IR)
│   │   └── mainwindow.ir.json
│   ├── memory/                  # AI 项目记忆
│   └── cache/                   # 编译缓存
├── src/                         # 源代码目录
│   ├── main.eg                  # 主入口文件
│   ├── window_main.ew           # 主窗口设计文件
│   ├── window_main.eg           # 主窗口代码(事件处理)
│   ├── module/                  # 用户模块
│   └── include/                 # 引用其它共享模块
├── resources/                   # 项目专用资源
├── lib/                         # 第三方库(DLL/静态库)
├── libs/                        # .elib 扩展包
├── out/                         # 编译输出(临时)
└── bin/                         # 最终可执行文件

7.8 debug 模式详解

debug 模式面向开发调试,保留完整调试信息,编译速度快:

特性说明
产物名egruntime.exe(固定,便于调试器复用)
调试信息保留 DWARF,可被 dlv 读取
编译优化关闭(-gcflags="all=-N -l"),变量不被优化掉
输出目录临时目录(系统 temp 下随机子目录),运行结束后清理
启动速度快(无 garble / UPX 后处理)
体积较大(含调试符号)
临时目录策略

debug 产物放在系统临时目录的随机子目录下,避免污染项目 bin/。每次编译复用同一临时目录可加速增量编译,可在设置中开启「保留临时目录」便于排查。

7.9 release 模式详解

release 模式面向最终发布,产物含版本号,可选混淆压缩:

特性说明
产物名egruntime-v<major>.<minor>.<patch>-release.exe
版本号来源.eg/project.eg.jsonversion 字段;每次 release 编译 patch 自增
调试信息剥离(-ldflags="-w -s"),体积更小
编译优化开启(默认 -O2
输出目录项目 bin/
混淆可选 garble(off / basic / full)
压缩可选 UPX(upx-egou.exe,魔数改写)
校验输出 SHA256 校验文件(*.exe.sha256
release 产物示例
bin/
├── egruntime-v1.0.0-release.exe          # 主产物
├── egruntime-v1.0.0-release.exe.sha256   # SHA256 校验
├── egruntime-v1.0.1-release.exe          # patch 自增后
└── egruntime-v1.0.1-release.exe.sha256

7.10 编译选项表

编译选项在 .eg/project.eg.jsonbuild 段配置:

选项说明示例
targetOS / GOOS目标操作系统windows / darwin / linux
targetArch / GOARCH目标 CPU 架构amd64 / arm64 / 386
ldflags链接器标志-w -s -X main.version=1.0.0
tags构建标签production,netgo,osusergo
trimpath移除源码路径true(release 默认)
mod模块模式vendor(默认,离线)
garble混淆档位off / basic / full
upxUPX 压缩true / false
upxLevelUPX 压缩级别1-9(默认 7
交叉编译限制

启用 CGO 的项目交叉编译需要对应平台的 C 工具链。纯 Go 项目(多数易狗项目)可直接 GOOS=linux GOARCH=arm64 go build。UPX 压缩在 macOS 上对 arm64 二进制支持有限,建议在目标平台本地编译后压缩。

7.11 发布检查清单

release 编译前请逐项确认,避免发布后才发现问题:

检查项说明
版本号正确project.eg.json 的 version 已更新,无 patch 自增冲突
资源完整resources/ 中图片/字体/配置已全部包含
无 debug 输出代码中 打印() 调用是否需要移除或改为日志文件
图标已设置Windows 平台需 .sysorsrc 嵌入图标
权限声明manifest 文件(如需管理员权限)已嵌入
混淆档位商业产品建议 full,开源产品可选 off
UPX 选项评估杀软误报风险,必要时关闭 UPX 改用 garble
SHA256 校验发布包附带 .sha256 文件,供用户验证完整性
多平台测试Win/macOS/Linux 至少各跑一次冒烟测试
更新日志devlog.html 已添加新版本条目
Python 构建脚本

项目根目录提供 scripts/build.py,自动化执行:清理 bin/ → release 编译 → 生成 SHA256 → 复制资源 → 打包 zip。强制使用 Python 而非 PowerShell,避免编码与文件损坏问题。

08 @嵌入混编详解

@嵌入 / @结束 是易狗IDE 的核心混编机制,让中文语法与 Go 原生代码无缝共存。本章深入讲解语法规则、错误定位与最佳实践。

8.1 @嵌入/@结束 语法规则

规则说明
成对出现@嵌入 必须配 @结束,否则转译报错
原样保留块内代码原样输出到生成的 Go 文件,不做任何转译
可嵌套位置函数体内 / 函数体外(全局)/ 文件顶部(import / type / var 声明)
AST Token编译器将 @嵌入@结束 作为独立 Token 识别
缩进块内缩进自由,但建议比外层多 4 空格保持可读
中文符号块内不进行中文符号转换,必须用英文符号

8.2 中文与 Go 混编示例

函数内混编(最常见,在中文函数体内插入 Go 代码片段):

函数内混编
函数 读配置(路径 文本) 文本 {
    @嵌入
        data, err := os.ReadFile(路径)
        if err != nil {
            return ""
        }
        return string(data)
    @结束
}

全局混编(在函数外声明 type / var / import / const):

全局混编
@嵌入
    import (
        "fmt"
        "os"
        "sync"
    )

    type Config struct {
        Name string
        Path string
    }

    var (
        cache = map[string]string{}
        mu    sync.Mutex
    )
@结束

函数 主函数() {
    fmt.Println("OK")  // 直接调用 fmt,因为已 import
}

8.3 //line 错误定位指令

转译器在每个 @嵌入 块前后生成 //line 指令,让 Go 编译器与 dlv 调试器的错误/断点能映射回 .eg 源码行:

转译产物(main.go 片段)
//line src/main.eg:5
func 读配置(路径 string) string {
//line src/main.eg:6
    data, err := os.ReadFile(路径)
//line src/main.eg:7
    if err != nil {
//line src/main.eg:8
        return ""
    }
}
  • 编译错误:Go 报错时会引用 .eg 文件名与行号,IDE 输出面板点击直接跳转
  • 调试断点:在 .eg 设的断点通过 //line 映射到 Go 行号,dlv 据此停点
  • 调用栈:调用栈面板显示 .eg 文件:行号,而非 Go 文件

8.4 混编最佳实践

场景建议原因
简单分支/循环用纯中文语法可读性高,编辑器有自动展开
调用 Go 标准库@嵌入中文语法无包调用语法
声明 struct/interface@嵌入中文语法不提供类型声明
声明 import@嵌入(文件顶部)必须用 Go 原生 import 语法
复杂业务逻辑优先纯中文,必要时混编保持代码风格一致
性能关键路径可用 @嵌入 写 Go 原生避免转译层开销(虽极小)
闭包 / goroutine必须用 @嵌入中文语法无对应关键字
最小混编原则

能用纯中文表达就别用 @嵌入@嵌入 块越少,代码风格越统一,AI 辅助也越准确。把 @嵌入 限制在「调用 Go 库」与「声明类型」两类场景即可。

8.5 常见混编陷阱与解决方案

陷阱表现解决方案
块内用了中文符号Go 编译报错(如 unexpected token@嵌入 块内必须用英文符号,关闭中文输入法
忘记 @结束转译报错「未闭合的 @嵌入 块」检查配对,IDE 会在 @嵌入 处高亮未闭合
块内引用中文变量名变量可见(Go 支持 UTF-8 标识符),但 Go 库函数可能不认混编块内传参时确保变量名一致
import 重复声明Go 编译报错 imported and not used 或重复转译器自动去重,但用户代码若手动 import 同一包会冲突
块内 return 但函数签名不匹配Go 编译报错类型不匹配检查 @嵌入 块内 return 的值与函数声明的返回类型一致
行号映射错位调试断点不停或停错行确保 @嵌入 块前后无空行被吞掉,必要时清理缓存重编译
块内用了单引号字符串Go 不支持单引号字符串,报错改用双引号;注意 @嵌入 块内单引号 rune 字面量(如 'f')是合法的,仅单引号字符串不合法
最易踩坑

新手最常犯的错误:@嵌入 块内用中文逗号 。Go 编译器报错信息晦涩(通常为 syntax error: unexpected newline, expecting comma or )),但实际是中文逗号未被转换。建议在 IDE 设置中开启「输入法自动切换」插件,进入 @嵌入 块自动切英文。

09 实战教程:计算器应用

本章通过一个标准计算器应用,串联项目创建、窗口设计、代码编写、编译发布全流程。完成后你将掌握易狗IDE 的核心开发节奏。

9.1 创建项目

  1. 启动 IDE,起始页 →「创建项目」
  2. 模板选择「window」(窗口程序)
  3. 项目名填 mycalc,路径选择 E:\dev\mycalc(路径避免中文与空格)
  4. 点击「创建」,IDE 生成项目骨架:src/main.eg + src/window_main.ew + src/window_main.eg

9.2 设计计算器界面

双击 src/window_main.ew 打开窗口设计器,按以下布局拖入组件:

组件namecaption/属性位置 (x,y,w,h)
editeditDisplayreadonly=true, align=right20,20,260,40
buttonbtn7caption="7"20,80,60,40
buttonbtn8caption="8"90,80,60,40
buttonbtn9caption="9"160,80,60,40
buttonbtnDivcaption="/"230,80,50,40
buttonbtn4caption="4"20,130,60,40
buttonbtn5caption="5"90,130,60,40
buttonbtn6caption="6"160,130,60,40
buttonbtnMulcaption="*"230,130,50,40
buttonbtn1caption="1"20,180,60,40
buttonbtn2caption="2"90,180,60,40
buttonbtn3caption="3"160,180,60,40
buttonbtnSubcaption="-"230,180,50,40
buttonbtn0caption="0"20,230,130,40
buttonbtnEqcaption="="160,230,60,40
buttonbtnAddcaption="+"230,230,50,40
buttonbtnClearcaption="C"20,280,260,40

每拖入一个按钮,在属性面板 name 改为对应名称,caption 改为对应字符。设计完成后窗口大小约 300×340

设计完成保存后,src/window_main.ew 会记录窗口组件树。以下是参考结构(实际文件格式以 IDE 生成为准):

src/window_main.ew(参考结构)
{
    "type": "window",
    "name": "window_main",
    "caption": "计算器",
    "size": {"w": 300, "h": 340},
    "children": [
        {"type": "edit", "name": "editDisplay", "readonly": true, "align": "right", "rect": [20,20,260,40]},
        {"type": "button", "name": "btn7", "caption": "7", "rect": [20,80,60,40]},
        {"type": "button", "name": "btn8", "caption": "8", "rect": [90,80,60,40]}
    ]
}
.ew 与 .ir.json 的区别

.ew窗口设计文件,记录组件树与属性,由窗口设计器读写;.ir.json编译中间表示(IR),由转译器在编译时生成。两者不要混淆,用户只需编辑 .ew

9.3 编写计算逻辑

双击 src/window_main.eg,IDE 自动生成空事件函数。补充逻辑:

src/window_main.eg
// 计算器状态(变量声明用类型推断,不写中文类型别名)
变量 当前显示 = ""
变量 上一个操作数 = ""
变量 待执行运算 = ""
变量 刚按等号 = 

// 数字按钮事件
函数 btn0_onClick()  { 追加数字("0") }
函数 btn1_onClick()  { 追加数字("1") }
函数 btn2_onClick()  { 追加数字("2") }
函数 btn3_onClick()  { 追加数字("3") }
函数 btn4_onClick()  { 追加数字("4") }
函数 btn5_onClick()  { 追加数字("5") }
函数 btn6_onClick()  { 追加数字("6") }
函数 btn7_onClick()  { 追加数字("7") }
函数 btn8_onClick()  { 追加数字("8") }
函数 btn9_onClick()  { 追加数字("9") }

函数 追加数字(d) {
    如果 (刚按等号) {
        当前显示 = ""
        刚按等号 = 
    }
    当前显示 = 当前显示 + d
    刷新显示()
}

// 运算符按钮事件
函数 btnAdd_onClick() { 选择运算("+") }
函数 btnSub_onClick() { 选择运算("-") }
函数 btnMul_onClick() { 选择运算("*") }
函数 btnDiv_onClick() { 选择运算("/") }

// 且/或是仿易语言别名,以转译器实际支持为准;此处用嵌套如果替代
函数 选择运算(op) {
    如果 (待执行运算 != "") {
        如果 (当前显示 != "") {
            计算结果()
        }
    }
    上一个操作数 = 当前显示
    待执行运算 = op
    当前显示 = ""
}

// 等号按钮
函数 btnEq_onClick() {
    计算结果()
    刚按等号 = 
}

函数 计算结果() {
    如果 (上一个操作数 == "") {
        返回
    }
    如果 (待执行运算 == "") {
        返回
    }
    如果 (当前显示 == "") {
        返回
    }
    @嵌入
        // @嵌入块内是 Go 原生代码,可用 && || ! 逻辑运算符
        // 中文变量名由转译器处理,可直接引用
        a, err1 := strconv.ParseFloat(上一个操作数, 64)
        b, err2 := strconv.ParseFloat(当前显示, 64)
        if err1 != nil || err2 != nil {
            当前显示 = "错误"
            return
        }
        var r float64
        switch 待执行运算 {
        case "+": r = a + b
        case "-": r = a - b
        case "*": r = a * b
        case "/":
            if b == 0 {
                当前显示 = "除数不能为零"
                return
            }
            r = a / b
        }
        当前显示 = strconv.FormatFloat(r, 'f', -1, 64)
    @结束
    刷新显示()
    上一个操作数 = ""
    待执行运算 = ""
}

// 清除按钮
函数 btnClear_onClick() {
    当前显示 = ""
    上一个操作数 = ""
    待执行运算 = ""
    刚按等号 = 
    刷新显示()
}

// 刷新编辑框显示
函数 刷新显示() {
    设置组件属性("editDisplay", "text", 当前显示)
}
事件函数由 IDE 自动生成

事件函数名(如 btn7_onClick)与组件 name + 事件名的对应关系、函数签名、绑定方式均由 IDE 在窗口设计器属性面板中自动生成,无需手写。实际命名格式与可绑定事件以 IDE 属性面板/支持库为准。

布尔值 真/假

示例中保留了 / 作为布尔字面量。布尔值推荐使用 true/false,或调用 krnln 支持库的 取常量_真() / 取常量_假()/ 是否作为关键字以转译器实际支持为准。

设置组件属性

设置组件属性(组件名, 属性名, 值) 是 egou 支持库 widget 分类下的命令,实际命令名、参数顺序与可用属性以 egou 支持库 widget 分类为准。也可在窗口设计器属性面板直接设置。

@嵌入块内的单引号与中文变量

@嵌入 块内是 Go 原生代码,'f' 是合法的 Go rune 字面量(表示 FormatFloat 的格式动词);中文代码区则禁止单引号字符串。@嵌入 块内引用中文变量名(如 上一个操作数)由转译器自动处理,可直接使用。

9.4 编译运行

  1. 标题栏模式切换选「debug
  2. 点击编译运行按钮(播放图标)
  3. 编译输出面板显示转译 + go build 进度
  4. 成功后弹出计算器窗口,测试各按钮功能
  5. 如有 bug,在 计算结果 函数内 F9 设断点,F5 启动调试

9.5 发布应用

  1. 测试通过后,模式切换选「release
  2. .eg/project.eg.json 设置 version: "1.0.0"garble: "basic"upx: true
  3. 点击编译按钮,生成 bin/egruntime-v1.0.0-release.exe
  4. 双击 exe 验证最终发布版可独立运行
  5. 分发 egruntime-v1.0.0-release.exe + .sha256 给用户
UPX 误报

如最终 exe 被杀软误报,先关闭 UPX 重编译;若仍误报,把 garble 从 full 降到 basic(移除 -literals)。商业发布建议申请杀软白名单。

10 常见问题 FAQ

本章汇总用户高频问题与解决方案,按类别组织。遇到问题先在这里查找,多数情况已有标准答案。

10.1 编译相关

问题原因解决方案
编译卡在 downloading 不动Go 默认走 GOPROXY,网络受限易狗项目用 -mod=vendor,无需 GOPROXY。检查 wails-template/vendor/ 是否完整;如缺失,从备份恢复或重新安装 IDE
cannot find packagevendor 缺包或 go.mod 损坏不要手动改 go.mod;在 IDE 设置中点「修复依赖」让 IDE 重建 vendor
undefined: fmt用了 Go 包但未 import在文件顶部用 @嵌入 块声明 import "fmt"
Go SDK 版本太低IDE 要求 1.25.0+,本机装的旧版设置 → Go SDK 路径,指向新版 Go;或下载 IDE 自带的 Go SDK 包
release 编译慢garble + UPX 双重处理耗时开发阶段用 debug;release 关闭 UPX 仅用 garble 可加速 2-3 倍
交叉编译报 CGO 错误项目用了 CGO(如 sqlite)安装目标平台 C 工具链;或在目标平台本地编译

10.2 运行相关

问题原因解决方案
egruntime.exe 找不到debug 模式产物在临时目录,被清理重新点击编译运行;或在设置中开启「保留临时目录」
程序启动闪退主函数 panic,无 recover主函数 加 defer recover;或用 debug 模式启动看输出面板错误
路径含中文导致报错Go 工具链对中文路径支持有限项目路径避免中文与空格;可用 E:\dev\mycalc 而非 E:\我的项目\计算器
窗口一闪而过主函数末尾未等待Wails 窗口程序主函数会自动阻塞;控制台程序需 打印() 后加等待
中文乱码控制台编码非 UTF-8Windows 控制台执行 chcp 65001;或用日志文件输出替代控制台
调试器启动失败dlv 未安装或端口被占设置 → 调试器 → 自动安装 dlv;或修改 port: 8586 避开占用

10.3 设计器相关

问题原因解决方案
组件不显示在画布组件 visible=false 或被其他组件遮挡检查属性面板 visible;用层级列表调整 z-order
属性面板空白未选中任何组件在画布或层级列表点选组件;点空白处会取消选中
事件下拉为空组件未保存到 .ewCtrl+S 保存窗口设计文件,重新选中组件
拖拽组件位置不对父容器不是预期的拖拽前先点选目标父容器(如 card),新组件会成为其子节点
设计器打不开 .ewIR 文件损坏从备份恢复;或用文本编辑器打开 .ew 检查 JSON 合法性
对齐工具栏灰色未多选组件Shift+点击 或 框选多个组件后对齐工具栏激活

10.4 AI 相关

问题原因解决方案
AI 无响应模型 API key 未配置或网络问题设置 → AI 设置 → 添加模型并填 key;测试网络连通性
AI 响应很慢模型本身的推理速度换用更快的模型;或在 AI 设置中关闭「深度思考」
AI 写的代码无法编译AI 不熟悉易狗语法细节@coder 角色而非通用 chat;提供 #示例.eg 作为参考
Agent 切换无效角色名拼写错误使用 @planner / @coder / @reviewer / @ui_builder / @fixer 五个标准名
AI 误删文件危险工具未确认就执行检查 30 秒倒计时确认框;可在设置中关闭 dangerous 自动执行
BuildAndFix 死循环fixer 改不动同一错误默认最多 3 轮;如需手动介入,按 Esc 中断 AI

10.5 扩展相关

问题原因解决方案
.elib 加载失败commands.json 格式错误用 JSON 校验工具检查;查看 IDE 启动日志(输出面板 → 系统)
自定义命令不识别source.eg 未实现该命令commands.json 中声明的命令必须在 source.eg 有对应 函数 实现
组件包冲突两个包定义了同 type检查 config.jsontype 全局唯一;移除冲突包
插件 activate 不执行JS 语法错误或 API 调用错打开开发者工具(Ctrl+Shift+I)看 console 错误
模板新建项目缺文件template.json files 列表不全补全 files 数组;模板目录下文件需与列表一致
升级 IDE 后扩展失效API 不兼容查看 devlog.html 的破坏性变更;按新版 API 调整扩展
获取更多帮助

1. 官方文档:本页面就是完整文档;2. 开发日志devlog.html 记录每次更新;3. QQ 群:1071098978 技术交流;4. GitHub Issues提交 bug 与建议