 调度器)
桌面应用开发工具【免费下载链接】Notepad3Notepad like text editor based on the Scintilla source code. Notepad3 based on code from Notepad2 and MiniPath on code from metapath. Download Notepad3:项目地址https://gitcode.com/GitHub_Trending/no/Notepad3点击查看免费下载导读本文基于 Notepad3 仓库中的重构计划文档 plans/notepad3_refactoring.md完整梳理该项目对核心模块src/Notepad3.c的大型重构包括将 12,985 行的单体文件拆分为独立工具模块Notepad3Util.c/.h以及把 2,994 行的MsgCommand()巨型 switch 改造为 73 行薄调度器。读者将掌握大型 C 语言 Win32 项目行为不变前提下拆分巨型文件的完整方法论——从模块边界划分、风险分级、源码级调用点迁移到构建验证与冒烟测试策略。一、重构背景单体文件的维护困境1.1 重构前的核心数据根据 plans/notepad3_refactoring.md 的 Context 部分重构前src/Notepad3.c是项目中最大的源文件规模数据如下指标重构前数值Notepad3.c总行数12,985 行静态函数数量约 55 个静态变量数量约 60 个MsgCommand()行数2,994 行MsgCommand()switch case 数360 个这些代码横跨多个互不相关的关注点自动滚动Auto-Scroll、文件观察File Observation、位图加载Bitmap Loading、文本输入辅助Text Input Helpers、TinyExpr 表达式求值等全部堆叠在同一文件中。1.2 四大重构动机文档明确列出了推动本次重构的四点动机可导航性Navigability在 13K 行的文件中查找代码效率低下逻辑上成组的辅助函数应当归属各自独立的模块。可维护性MaintainabilityMsgCommand()单体巨型函数使得难以对单个命令组进行推理和修改。封装性Encapsulation自动滚动、文件观察、TinyExpr 等无关子系统的静态变量全部处于全局文件作用域掩盖了它们真实的作用域边界。一致性Consistency项目中其他模块如 src/Edit.c、src/Styles.c、src/Dialogs.c已经遵循清晰的.c/.h成对文件边界Notepad3.c是例外。1.3 不拆什么刻意保留在 Notepad3.c 的代码重构计划特别强调What NOT to extract以下代码被刻意保留在原文件因为它们与整个应用生命周期或全局状态深度耦合_InitGlobals()/_CleanUpResources()—— 核心应用生命周期函数触及所有子系统。消息队列辅助函数_MQ_AppendCmd、MQ_ExecuteNext—— 与定时器系统和 UI 更新紧密集成。UI 更新辅助函数_UpdateStatusbarDelayed、_UpdateToolbarDelayed、_UpdateTitlebarDelayed—— 依赖消息队列和复杂全局状态。_EditSubclassProc()—— Scintilla 子类化胶水代码应当紧邻MainWndProc。ParseCmdLnOption()—— 命令行解析与程序启动流程归属一处。MsgInitMenu()—— 读取 20 个状态变量来启用/禁用菜单项本质上是全局应用状态。这一明确划定不拆范围的决策恰恰是重构成功的关键——不是所有代码都适合拆分只有内聚性足够强的子系统才值得独立成模块。二、已完成的 Part 2MsgCommand() 薄调度器改造2.1 从 2,994 行 switch 到 73 行分发链文档记录MsgCommand()从2,994 行的巨型 switch 重构为73 行的薄调度器将 360 个 case 委派给10 个静态处理器函数仍保留在Notepad3.c中。这一改造已在当前仓库中落地见 src/Notepad3.c。调度器实际结构对应 src/Notepad3.c如下LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { // Language/theme menu range checks (inline) // Timer/notification cases (inline, return immediately) switch(iLoWParam) { case SCEN_CHANGE: ... return FALSE; ... } // Handler dispatch chain if (_HandleFileCommands(hwnd, umsg, wParam, lParam)) { return FALSE; } if (_HandleEncodingCommands(...)) { return FALSE; } ... return DefWindowProc(hwnd, umsg, wParam, lParam); }2.2 10 个处理器函数的职责划分文档给出的处理器分工表当前仓库中 10 个 handler 已全部实现行号见 src/Notepad3.cHandlerCase 数覆盖的命令范围_HandleFileCommands~27IDM_FILE_*—— 打开/保存/打印/收藏夹/grepWin源码位置 src/Notepad3.c_HandleEncodingCommands~10IDM_ENCODING_*、IDM_LINEENDINGS_*src/Notepad3.c_HandleEditBasicCommands~30IDM_EDIT_UNDO..CMD_VK_INSERT—— 撤销/重做/剪切/复制/粘贴/缩进src/Notepad3.c_HandleEditLineManipulation~42IDM_EDIT_ENCLOSESELECTION..IDM_EDIT_INSERT_GUID—— 行修改/排序/合并/大小写src/Notepad3.c_HandleEditTextTransform~45IDM_EDIT_LINECOMMENT..IDM_EDIT_HEX2CHAR—— 注释/编解码/转义/十六进制src/Notepad3.c_HandleEditFind~21IDM_EDIT_FINDMATCHINGBRACE..IDM_EDIT_GOTOLINE—— 查找/替换/书签src/Notepad3.c_HandleViewAndSettingsCommands~99IDM_VIEW_*、IDM_SET_*—— 视图/设置/渲染src/Notepad3.c_HandleHelpCommands~5IDM_HELP_*、IDM_SETPASSsrc/Notepad3.c_HandleCmdCommands~90CMD_*—— 键盘快捷键/导航/窗口定位src/Notepad3.c_HandleToolbarCommands~30IDT_*—— 通过s_ToolbarDispatch[]查找表分发src/Notepad3.c2.3 调度链的短路语义每个处理器遵循统一约定返回true表示已处理返回false则交给下一个处理器尝试。从 src/Notepad3.c 的分发链可以看到这是一个典型的责任链Chain of Responsibility模式命令 ID 按文件 → 编码 → 编辑基础 → 行操作 → 文本变换 → 查找 → 视图设置 → 帮助 → 快捷键 → 工具栏的顺序依次尝试匹配全部未命中才落入DefWindowProc。2.4 工具栏分发表消灭 40 个重复 case重构前有 40 个重复的IDT_*工具栏 case重构后用静态查找表s_ToolbarDispatch[]取代见 src/Notepad3.c。表中包含29 个标准条目将工具栏命令 ID 映射为菜单命令 ID例如static const struct { unsigned idt; unsigned idm; } s_ToolbarDispatch[] { { IDT_FILE_NEW, IDM_FILE_NEW }, { IDT_FILE_OPEN, IDM_FILE_OPEN }, { IDT_FILE_SAVE, IDM_FILE_SAVE }, { IDT_EDIT_UNDO, IDM_EDIT_UNDO }, { IDT_EDIT_CUT, IDM_EDIT_CUT }, { IDT_GREP_WIN_TOOL, IDM_GREP_WIN_SEARCH }, { IDT_VIEW_WORDWRAP, IDM_VIEW_WORDWRAP }, { IDT_VIEW_CHASING_DOCTAIL, IDM_VIEW_CHASING_DOCTAIL }, { IDT_VIEW_PIN_ON_TOP, IDM_SET_ALWAYSONTOP }, // ... 其余条目 };查找表分发的核心逻辑src/Notepad3.c遍历表命中后先通过IsCmdEnabled()检查菜单命令是否可用可用则SendWMCommand()转发不可用则SimpleBeep()提示。另外保留2 个特殊 case不经过查找表IDT_EDIT_COPY当复制命令不可用时降级为 COPYALL复制全部内容IDT_EDIT_CLEAR当清除命令不可用时降级为SciCall_ClearAll()。这种查找表 特例兜底的组合既消除了重复代码又保留了原有异常分支的行为语义是重构中行为零变化原则的典型体现。三、已完成的 Part 1Phases 1-3Notepad3Util 模块3.1 新模块总览Part 1 的前三个阶段已全部完成新增了 src/Notepad3Util.c349 行与 src/Notepad3Util.h50 行两个文件。项目文件 src/Notepad3.vcxproj 与 src/Notepad3.vcxproj.filters 中已注册ClCompile和ClInclude条目CLAUDE.md的核心模块表与.github/copilot-instructions.md的核心模块列表也同步更新。该模块被定位为从 Notepad3.c 提取的实用函数集合头文件 src/Notepad3Util.h 通过#include TypeDefs.h和#include SciCall.h保持与核心类型的关联。3.2 Phase 1位图/图片加载低风险约 100 行Phase 1 移入的三个位图加载函数函数职责NP3Util_LoadBitmapFile()从文件加载工具栏位图并校验尺寸合法性NP3Util_CreateScaledImageListFromBitmap()从位图创建 DPI 缩放的图像列表NP3Util_XXX_CreateScaledImageListFromBitmap()使用固定NUMTOOLBITMAPS的旧版变体同时NUMTOOLBITMAPS宏从Notepad3.c迁移到 src/Notepad3Util.h当前值为31。从源码看src/Notepad3Util.cNP3Util_LoadBitmapFile()的实现逻辑是先通过Path_IsExistingFile()检查文件存在再用LoadImage(..., LR_CREATEDIBSECTION | LR_LOADFROMFILE)加载随后用GetObject()读取位图尺寸校验bmWidth height * NUMTOOLBITMAPS——即位图宽度必须能容纳 31 个高度为 16 像素的图标单元否则弹出IDS_MUI_ERR_BITMAP警告框文件不存在则弹出IDS_MUI_ERR_LOADFILE错误提示。而两个*CreateScaledImageListFromBitmap()函数src/Notepad3Util.c展示了 DPI 适配的关键细节UINT const dpi Scintilla_GetWindowDPI(hWnd); if (!Settings.DpiScaleToolBar || (dpi USER_DEFAULT_SCREEN_DPI)) { return himl; // default DPI, we are done } // Scale button icons/images int const scx ScaleIntToDPI(hWnd, cx); int const scy ScaleIntToDPI(hWnd, cy); HIMAGELIST hsciml ImageList_Create(scx, scy, ILC_COLOR32 | ILC_MASK | ILC_HIGHQUALITYSCALE, ...);即仅在Settings.DpiScaleToolBar开启且系统 DPI 非 96 时才执行缩放逐个图标通过ImageList_GetIcon(..., ILD_TRANSPARENT | ILD_PRESERVEALPHA | ILD_SCALE)提取后再加入缩放后的图像列表——这解释了Settings.DpiScaleToolBar配置项在底层图像处理上的实际作用。3.3 Phase 2自动换行配置低风险约 100 行移入的三个换行配置函数函数职责NP3Util_SetWrapStartIndent()根据Settings.WordWrapIndent设置换行起始缩进NP3Util_SetWrapIndentMode()设置换行缩进模式same/indent/deep/fixedNP3Util_SetWrapVisualFlags(HWND)设置换行视觉标志符号从 src/Notepad3Util.c 可以看到WordWrapIndent配置值1-7的完整语义映射void NP3Util_SetWrapStartIndent(void) { int i 0; switch (Settings.WordWrapIndent) { case 1: i 1; break; // 固定 1 字符 case 2: i 2; break; // 固定 2 字符 case 3: i 1 * (iIndentWidth ? iIndentWidth : iTabWidth); break; // 1×缩进/制表宽度 case 4: i 2 * (iIndentWidth ? iIndentWidth : iTabWidth); break; // 2×缩进/制表宽度 default: break; } SciCall_SetWrapStartIndent(i); }而NP3Util_SetWrapIndentMode()src/Notepad3Util.c将WordWrapIndent 5/6/7分别映射为 Scintilla 的SC_WRAPINDENT_SAME/SC_WRAPINDENT_INDENT/SC_WRAPINDENT_DEEPINDENT其余值则走NP3Util_SetWrapStartIndent()并设置SC_WRAPINDENT_FIXED。可见Settings.WordWrapIndent是一个 1-7 的多模式枚举1/2 为固定字符数缩进、3/4 为按制表宽度倍数缩进、5/6/7 为 Scintilla 内建模式。NP3Util_SetWrapVisualFlags()src/Notepad3Util.c则负责Settings.ShowWordWrapSymbols与Settings.WordWrapSymbols的解析当WordWrapSymbols为 0 时自动回退为 22然后按个位数字1行尾箭头贴文本、2行尾箭头贴边缘和十位数字1行首箭头贴文本、2行首箭头贴边缘组合出SC_WRAPVISUALFLAG_*标志。3.4 Phase 3自动滚动中低风险约 200 行Phase 3 将中键自动滚动Firefox 风格的连续滚动完整移入Notepad3Util6 个静态变量迁移s_bAutoScrollMode、s_bAutoScrollHeld、s_dwAutoScrollStartTick、s_ptAutoScrollOrigin、s_ptAutoScrollMouse、s_dAutoScrollAccumY——全部封装进 src/Notepad3Util.c不再污染Notepad3.c的全局作用域。4 个常量迁移AUTOSCROLL_TIMER_MS(30)、AUTOSCROLL_DEADZONE(15)、AUTOSCROLL_DIVISOR(60.0)、AUTOSCROLL_CLICK_THRESHOLD_MS(200)定义于 src/Notepad3Util.h。核心滚动逻辑NP3Util_AutoScrollStart/Stop()、NP3Util_AutoScrollTimerProc()。状态访问器NP3Util_IsAutoScrollMode()、NP3Util_IsAutoScrollHeld()、NP3Util_GetAutoScrollStartTick()、NP3Util_SetAutoScrollHeld()、NP3Util_AutoScrollUpdateMouse()——专供_EditSubclassProc读取/修改状态。滚动算法细节src/Notepad3Util.c值得关注定时器每 30ms 触发一次先计算鼠标当前 Y 与起始 Y 的差值deltaY死区15 像素内的移动不产生滚动超出死区后速度与超出量成正比speed (deltaY - deadzone) / 60.0累积在s_dAutoScrollAccumY中累积量达到整行数时调用SciCall_LineScroll()滚动并扣除已滚动的部分。这种速度随距离递增 余数累积的设计实现了平滑的加速度滚动效果。3.5 Part 1 的净收益文档记录拆分后Notepad3.c从12,985 行降至 12,713 行。3.6 修改文件清单Part 1/Part 2 涉及的文件改动src/Notepad3.c —— 删除被提取的代码、更新调用点、新增#include Notepad3Util.hsrc/Notepad3Util.c —— 新建实现文件src/Notepad3Util.h —— 新建头文件src/Notepad3.vcxproj —— 新增ClCompile与ClInclude条目src/Notepad3.vcxproj.filters —— 新增 Source Files / Header Files 过滤器条目CLAUDE.md —— 更新核心模块表、新增 Menu/Command Architecture 章节.github/copilot-instructions.md—— 更新核心模块列表四、未完成的 Phases 4-6下一步迁移计划文档详细规划了剩余三个阶段的迁移方案当前仓库中这些函数仍在Notepad3.c内尚未迁移。4.1 Phase 4TinyExpr 表达式求值约 130 行中等风险待迁移的静态变量src/Notepad3.cs_dExpressiondouble—— 最近一次表达式求值结果s_iExprErrorte_int_t—— 最近一次表达式错误码待迁移函数与目标名当前函数新函数当前行号规模_EvalTinyExpr(bool qmark)NP3Util_EvalTinyExpr(bool)2968~150_InterpMultiSelectionTinyExpr(te_int_t*)NP3Util_InterpMultiSelectionTinyExpr(te_int_t*)11238~50需要新增的访问器NP3Util_GetLastExpression()—— 返回s_dExpression由_UpdateStatusbarDelayed读取NP3Util_GetLastExprError()—— 返回s_iExprError由_UpdateStatusbarDelayed读取需要更新的 3 处调用点行 7874文档记为 6839_EvalTinyExpr(false)—— 位于_HandleCmdCommands的CMD_ENTER_RETURNcase行 10057文档记为 8921_EvalTinyExpr(true)—— 位于_MsgNotifyFromEdit输入?字符时触发行 11601文档记为 10399s_dExpression _InterpMultiSelectionTinyExpr(s_iExprError)—— 位于_UpdateStatusbarDelayed依赖Settings.EvalTinyExprOnSelection、Encoding_SciCP、SciCall_*均通过头文件、te_interp()需在 Notepad3Util.c 中#include tinyexpr/tinyexpr.h、AllocMem/FreeMem通过Helpers.h。风险点状态栏代码目前直接读取s_dExpression/s_iExprError迁移后必须改用 getterte_interp()作用于 Scintilla 的原始字符缓冲区对编码敏感但迁移本身机制上是机械的。4.2 Phase 5文本输入辅助约 300 行中等风险待迁移的静态变量行 189s_SelectionBufferchar*—— 用于自动闭合括号/引号跟踪的动态分配缓冲区待迁移函数当前函数新函数当前行号规模_HandleAutoIndent(int)NP3Util_HandleAutoIndent(int)9401~45_HandleAutoCloseTags()NP3Util_HandleAutoCloseTags()9448~58_SaveSelectionToBuffer()NP3Util_SaveSelectionToBuffer()9508~16_EncloseSelectionBuffer(char,char)NP3Util_EncloseSelectionBuffer(char,char)9526~17_HandleInsertCheck(SCNotification*)NP3Util_HandleInsertCheck(...)9545~89_HandleDeleteCheck(SCNotification*)NP3Util_HandleDeleteCheck(...)9636~60明确跳过_IsIMEOpenInNoNativeMode()行 9696是#if 0包裹的死代码不迁移。需要新增的生命周期函数NP3Util_TextInputInit()—— 分配s_SelectionBuffer在MsgCreate中调用NP3Util_TextInputCleanup()—— 释放s_SelectionBuffer在_CleanUpResources中调用需要更新的 5 处调用点均位于_MsgNotifyFromEdit见 src/Notepad3.c行 9745_HandleInsertCheck(scn)行 9752_SaveSelectionToBuffer()行 9768_HandleDeleteCheck(scn)行 10048_HandleAutoIndent(ich)行 10053_HandleAutoCloseTags()依赖Settings.AutoIndent、Settings.AutoCloseQuotes、Settings.AutoCloseBrackets、Settings.AutoCloseTags全局配置、SciCall_*/Sci_*头文件、EditReplaceSelection()通过 src/Edit.h、AllocMem/FreeMem/ReAllocMem/SizeOfMem通过 src/Helpers.h。风险分析文档明确指出这些函数运行在 Scintilla 通知的热路径上SCN_MODIFIED、SCN_CHARADDED但每次按键只调用一次而非逐字符批量调用因此函数调用开销可忽略。主要风险在于确保s_SelectionBuffer的生命周期始终正确。4.3 Phase 6文件观察约 450 行高风险留到最后待迁移的静态变量行 531s_FileChgObsvrDataFCOBSRVDATA_T—— 包含事件句柄hEventFileChanged、hEventFileDeleted、文件元数据fdCurFile、代次计数器iObservationGeneration采用InterlockedCompareExchange/InterlockedIncrement的 seqlock 模式、后台工作线程句柄。在 Notepad3.c 中有 48 处非注释引用。待迁移函数当前函数新函数当前行号规模IsFileReadOnly()NP3Util_IsFileReadOnly()519~15IsFileChangedFlagSet()NP3Util_IsFileChangedFlagSet()535~4IsFileDeletedFlagSet()NP3Util_IsFileDeletedFlagSet()540~4RaiseFlagIfCurrentFileChanged()NP3Util_RaiseFlagIfCurrentFileChanged()545~50ResetFileObservationData(bool)NP3Util_ResetFileObservationData(bool)596~20IsFileVarLogFile()NP3Util_IsFileVarLogFile()—~10_ResetFileWatchingMode()NP3Util_ResetFileWatchingMode()—~10NotifyIfFileHasChanged()NP3Util_NotifyIfFileHasChanged()—~20WatchTimerProc(...)NP3Util_WatchTimerProc(...)—~15LogRotateTimerProc(...)NP3Util_LogRotateTimerProc(...)—~25AtomicSaveTimerProc(...)NP3Util_AtomicSaveTimerProc(...)—~50需要新增的生命周期函数NP3Util_FileObservationInit()—— 创建事件句柄替换InitInstance()中约 1843-1852 行的代码NP3Util_FileObservationCleanup()—— 销毁工作线程与事件句柄替换_CleanUpResources()中约 824-833 行的代码NP3Util_GetFileObservationData()—— 返回PFCOBSRVDATA_T指针供InstallFileWatching()访问结构体循环依赖及解决方案定时器回调会反向调用Notepad3.c中的函数——AtomicSaveTimerProc调用InstallFileWatching(false)和FileSave(FSF_SaveAlways)LogRotateTimerProc调用PostWMCommand(Globals.hwndMain, IDM_VIEW_CHASING_DOCTAIL)和InstallFileWatching(true)_ResetFileWatchingMode调用CheckCmd(GetMenu(...))。文档给出的解决方案是Notepad3Util.c已#include声明了这些函数的 src/Notepad3.h由链接器解析跨模块调用——这与Edit.c调用FileLoad()的模式完全相同。主要调用点更新约 48 处InitInstance()—— 事件创建改为NP3Util_FileObservationInit()src/Notepad3.c_CleanUpResources()—— 清理改为NP3Util_FileObservationCleanup()src/Notepad3.cInstallFileWatching()—— 直接结构体字段访问改为NP3Util_GetFileObservationData()-src/Notepad3.cMsgFileChangeNotify()—— 读取标志、重置观察数据_UpdateTitlebarDelayed()—— 调用IsFileChangedFlagSet()/IsFileDeletedFlagSet()MsgInitMenu()—— 调用IsFileReadOnly()_HandleViewAndSettingsCommands、_HandleCmdCommands—— 各种标志检查线程安全注意事项代次计数器使用InterlockedCompareExchange/InterlockedIncrement实现 seqlock 模式后台工作线程 vs UI 线程。从源码看src/Notepad3.cRaiseFlagIfCurrentFileChanged()正是通过读前取 generation → 比较文件元数据 → 读后再取 generation 比对的方式检测fdCurFile在并发ResetFileObservationData期间是否发生撕裂读取。迁移结构体不改变线程安全性但文档特别提醒NP3Util_GetFileObservationData()返回裸指针调用者不得在可能触发重新分配的操作之间缓存该指针。风险评级高—— 48 处引用点多为机械改名但InstallFileWatching()直接操纵结构体字段工作线程启动/取消、事件等待SetTimer()调用中的定时器过程函数指针必须同步更新线程正确性是关键。五、验证策略如何证明行为零变化重构的核心承诺是不改变任何行为文档为此设计了分阶段验证策略5.1 每阶段三重验证构建验证至少执行Build\Build_x64.cmd Debug确保无编译和链接错误Diff 审计执行git diff确认改动是纯机械移动不含任何逻辑变化按命令组冒烟测试Phase 4TinyExpr选中12后按?键验证结果被插入用列选择检查状态栏表达式显示Phase 5文本输入输入验证自动闭合引号输入{验证自动闭合括号在if (...) {后按 Enter 验证自动缩进输入div验证自动闭合/div在上按 Backspace 验证成对删除Phase 6文件观察在其他编辑器中修改文件 → Notepad3 必须提示重新加载启用日志跟踪模式CtrlShiftL→ 验证自动刷新测试原子保存Settings2.AtomicFileSave1测试文件删除检测快速开关文件 → 验证无定时器泄漏。5.2 全量验证全部阶段完成后执行Build\BuildAll.cmd Release覆盖全部 4 个平台对应 Build/BuildAll.cmd 及 Build 目录下的 x64/Win32/ARM64 构建脚本。六、预期最终结果重构前后的量化对比文档给出的最终预估指标指标重构前重构后全部阶段完成Notepad3.c行数12,985~11,700Notepad3Util.c行数0~1,250MsgCommand()行数2,994~73薄调度器工具栏 switch case40 个重复查找表Notepad3.c静态函数数~55~35七、可复用的重构方法论总结从 plans/notepad3_refactoring.md 和当前仓库源码中可以提炼出适用于大型 C 语言 Win32 项目的行为保持型重构要点先划边界再动手明确拆什么与不拆什么。生命周期函数、UI 状态密集型函数、与消息循环深度耦合的代码应留在原文件只有内聚性强、状态自包含的子系统位图、换行、自动滚动、表达式求值、文本输入、文件观察才适合提取。按风险分级排序低风险先行位图加载、换行配置中风险居中自动滚动、TinyExpr、文本输入高风险留到最后文件观察涉及 48 处引用和线程安全。每阶段独立验证构建 diff 审计 针对该功能组的冒烟测试把大规模重构分解为可独立回滚的小步骤。状态封装成访问器被提取模块的静态变量不暴露全局符号通过NP3Util_IsAutoScrollMode()这类访问器函数供外部读取保持封装性生命周期由Init/Cleanup函数管理。巨型 switch 转责任链360 case 的MsgCommand()拆成 10 个按命令族划分的处理器配合短路返回语义重复的工具栏 case 用查找表 特例兜底替代既消除重复又保留分支语义。循环依赖靠头文件与链接器消解跨模块回调如AtomicSaveTimerProc→InstallFileWatching通过#include Notepad3.h声明 链接器解析与项目现有模式Edit.c调用FileLoad()保持一致。截至当前仓库状态Part 1Phases 1-3与 Part 2 已落地Notepad3Util.c/.h已存在并被项目文件引用10 个 handler 与s_ToolbarDispatch[]已实现在 src/Notepad3.c 中Phases 4-6 的迁移对象仍位于Notepad3.c原位置属于文档规划的后续工作。赞分享桌面应用开发工具【免费下载链接】Notepad3Notepad like text editor based on the Scintilla source code. Notepad3 based on code from Notepad2 and MiniPath on code from metapath. Download Notepad3:项目地址https://gitcode.com/GitHub_Trending/no/Notepad3点击查看免费下载相关推荐PicoClaw Pipeline 重构实践将 1400 行单体 runTurn 拆分为职责清晰的多文件管线PicoClaw Pipeline 重构实践将 1400 行单体 runTurn 拆分为职责清晰的多文件管线 导读 本文基于 PicoClaw 开源仓库中的《人工智能AI 应用AI Agent交互助手工具调用MCP ClientsAgent 记忆omo/lazycodex 常量文件拆分实战delegate-task constants.ts 重构执行计划深度解析omo/lazycodex 常量文件拆分实战delegate task constants.ts 重构执行计划深度解析 在 omo/lazycodexoh人工智能AI Agent代码智能体多智能体MCP ClientsAgent 编排opencodex 大型文件重构零行为变更的模块拆分实战opencodex 大型文件重构零行为变更的模块拆分实战 本指南基于 opencodex 仓库 devlog/_fin/260723_large_file_r上一篇EIP-1014 Skinny CREATE2 深度解读确定性合约地址、Gas 计量与 Constantinople 落地下一篇gpui-kit 无样式单行输入控件 Input 完整指南状态模型、掩码校验与数字步进创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考