【AI插件开发】Notepad++ AI插件开发实践:从Dock窗口集成到功能菜单实现

一、项目背景与技术选型

在上篇文章实现"选中即问AI"功能的基础上,本文重点解决AI对话窗口的集成与核心功能菜单的开发。通过Notepad++插件体系,我们将实现以下功能矩阵:

  • AI交互系统:支持自然语言提问与任务执行
  • 代码智能处理:代码解释、优化建议、注释生成
  • 配置管理系统:AI平台切换与参数调整
  • 即时交互体验:选中内容快速提问机制

在Dock窗口的实现方案选择上,经过对原生开发、第三方库集成和源码剥离三种方案的对比评估,最终采用Notepad++源码裁剪方案。该方案既能保持与宿主程序的UI风格一致性,又可避免引入额外依赖,但需要解决源码依赖链过长的问题。通过裁剪非核心模块(如NppDarkMode)和重构关键函数,成功实现了轻量化集成,Notepad++文件引用如下:

注 :项目已开源、镜像,欢迎使用及指正


二、Dock窗口集成关键技术

2.1 源码裁剪与适配

通过提取Notepad++的窗口管理核心模块,保留以下关键文件:

text 复制代码
Common.h
Docking.h 						// 停靠窗口基础定义
DockingDlgInterface.h  			// 对话框接口
dpiManagerV2.h 			 		// DPI自适应管理
StaticDialog.h 					// 静态对话框基类
dockingResource.h
dpiManagerV2.cpp
StaticDialog.cpp
NppDarkMode.cpp
NppDarkMode.h
Window.h

对NppDarkMode.cpp进行深度改造,仅保留版本检测功能,移除主题相关实现,最终获得精简的Windows版本检测模块:

cpp 复制代码
#include "NppDarkMode.h"

enum class SystemVersion
{
	Unknown,
	Windows10,
	Windows11
};

SystemVersion GetWindowsVersion()
{
	// 使用RtlGetVersion替代已废弃的GetVersionEx
	typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);

	OSVERSIONINFOW osInfo = { 0 };
	HMODULE hMod = GetModuleHandleW(L"ntdll.dll");
	if (hMod)
	{
		auto RtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(
			GetProcAddress(hMod, "RtlGetVersion"));
		if (RtlGetVersion) {
			osInfo.dwOSVersionInfoSize = sizeof(osInfo);
			if (RtlGetVersion(&osInfo) == 0)
			{ // STATUS_SUCCESS
				// Windows 11的版本号为10.0.22000+
				if (osInfo.dwMajorVersion == 10 &&
					osInfo.dwMinorVersion == 0)
				{
					if (osInfo.dwBuildNumber >= 22000)
					{
						return SystemVersion::Windows11;
					}
					else if (osInfo.dwBuildNumber >= 10240)
					{
						return SystemVersion::Windows10;
					}
				}
			}
		}
	}
	return SystemVersion::Unknown;
}

bool NppDarkMode::isWindows10() { return GetWindowsVersion() == SystemVersion::Windows10; }
bool NppDarkMode::isWindows11() { return GetWindowsVersion() == SystemVersion::Windows11; }
void NppDarkMode::setDarkTitleBar(HWND hwnd) {}

2.2 AI窗口类设计

构建AiAssistWnd继承自DockingDlgInterface,实现以下核心功能:

cpp 复制代码
class AiAssistWnd : public DockingDlgInterface {
public:
    // 构造/析构
    AiAssistWnd(HINSTANCE hInst, const NppData& nppData);
    
    // 窗口生命周期管理
    virtual void init();
    virtual INT_PTR run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam);
    
    // 业务功能接口
    void updateModelList(const std::vector<std::wstring>& models);
    void appendAnswer(const std::wstring& answer);
};

关键技术实现:

  1. DPI自适应布局 :通过dpiManagerV2实现控件动态缩放
  2. 富文本交互 :采用Msftedit.dll的RichEdit 4.1控件支持格式文本
  3. 线程安全通信 :使用SendMessage进行跨线程UI更新

依赖 <<abstract>> DockingDlgInterface +init() +run_dlgProc() +display() AiAssistWnd -HWND _hModelCombo -HWND _hInputEdit -HWND _hAnswerView +init() +updateModelList() +appendAnswer() +clearConversation() NppData -HWND _nppHandle -HWND _scintillaMainHandle -HWND _scintillaSecondHandle


三、核心菜单功能实现与关键技术解析

3.1 功能菜单架构设计

cpp 复制代码
// PluginDefinition.h
const int nbFunc = 6;  // 定义6个功能命令

// 功能原型声明
void PluginConfig();       // 参数配置
void OpenAiAssistWnd();    // 窗口控制
void ReadCode();           // 代码解读
void OptimizeCode();       // 代码优化
void AddCodeComment();     // 注释生成
void AskBySelectedText();  // 选中提问
关键技术要点:
  1. 命令标识体系 :nbFunc常量定义菜单项总数,保证命令索引的严格对应
  2. 功能隔离设计:每个功能对应独立函数,符合单一职责原则
  3. 动态加载机制 :通过commandMenuInit实现按需初始化

User Notepad Plugin AiAssistWnd DockingDlgInterface 点击"显示窗口"菜单 调用OpenAiAssistWnd() new() init() NPPM_DMMREGASDCKDLG 注册成功 显示Dock窗口 User Notepad Plugin AiAssistWnd DockingDlgInterface


3.2 菜单初始化实现

cpp 复制代码
// PluginDefinition.cpp
//
// Initialization of your plugin commands
// You should fill your plugins commands here
void commandMenuInit()
{

    //--------------------------------------------//
    //-- STEP 3. CUSTOMIZE YOUR PLUGIN COMMANDS --//
    //--------------------------------------------//
    // with function :
    // setCommand(int index,                      // zero based number to indicate the order of command
    //            TCHAR *commandName,             // the command name that you want to see in plugin menu
    //            PFUNCPLUGINCMD functionPointer, // the symbol of function (function pointer) associated with this command. The body should be defined below. See Step 4.
    //            ShortcutKey *shortcut,          // optional. Define a shortcut to trigger this command
    //            bool check0nInit                // optional. Make this menu item be checked visually
    //            );

    // 初始化数据
    g_pNppImp = new NppImp(g_nppData);

    // 初始化菜单
    ShortcutKey* pSck = new ShortcutKey[nbFunc];
    g_pShortcutKeys = pSck;
    size_t nCid = 0;
    setCommand(nCid, L"参数配置", PluginConfig, NULL, false); ++nCid;
    pSck[nCid] = { false, true, false, 'K' };
    setCommand(nCid, L"显示窗口", OpenAiAssistWnd, pSck + nCid, false); ++nCid;
    pSck[nCid] = { false, true, false, 'J' };
    setCommand(nCid, L"解读代码", ReadCode, pSck + nCid, false); ++nCid;
    pSck[nCid] = { false, true, false, 'Y' };
    setCommand(nCid, L"优化代码", OptimizeCode, pSck + nCid, false); ++nCid;
    pSck[nCid] = { false, true, false, 'Z' };
    setCommand(nCid, L"代码注释", AddCodeComment, pSck + nCid, false); ++nCid;
    pSck[nCid] = { false, true, false, 'A' };
    setCommand(nCid, L"选中即问", AskBySelectedText, pSck + nCid, false); ++nCid;
}
关键技术解析:
  1. setCommand参数详解:

    • index:菜单项位置索引(0-based)
    • commandName:菜单显示文本(支持多语言)
    • functionPointer:功能函数地址
    • shortcut:快捷键组合指针
    • check0nInit:初始选中状态
  2. 快捷键数据结构:

cpp 复制代码
struct ShortcutKey {
    bool isCtrl;
    bool isAlt;
    bool isShift;
    UCHAR key;
};
  1. 内存管理 :使用new动态分配快捷键数组,需在插件卸载时释放

3.3 窗口控制实现

cpp 复制代码
// PluginDefinition.cpp
// 打开Ai助手窗口
void OpenAiAssistWnd() {
    if (!g_pAiWnd) {
        g_pAiWnd = new AiAssistWnd((HINSTANCE)g_hModule, g_nppData);
        g_pAiWnd->init();
    }
    g_pAiWnd->display(true);  // 显示/激活窗口
}
关键技术要点:
  1. 单例模式 :通过全局指针g_pAiWnd确保窗口唯一性
  2. 资源绑定 :
    • g_hModule:插件DLL模块句柄
    • g_nppData:Notepad++核心数据结构
  3. 显示控制 :display(true)调用API实现窗口显示

否 是 用户触发窗口显示 窗口实例是否存在? 创建AiAssistWnd对象 调用init()方法 注册Dock窗口 初始化UI控件 调用display(true) 显示交互窗口


四、功能扩展与效果展示

4.1 插件菜单效果

4.2 AI交互窗口


五、总结说明

当前实现已构建起AI辅助开发的基础框架,后续可通过扩展AI引擎接口、优化交互流程、增强代码理解能力等方向持续演进,最终打造智能化的代码辅助工具。开发者可根据实际需求,参考本文提供的技术路径进行功能扩展和深度定制。

相关推荐
IT_陈寒23 分钟前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
yumgpkpm36 分钟前
Acceldata ODP(Open Data Platform)3.3.6.4(RHEL9)保姆级完整安装手册
大数据·人工智能·hive·hadoop·kafka·hbase·cloudera
程序员cxuan39 分钟前
腾讯又来一王炸,开源版 WorkBuddy 太夯了!
人工智能·后端·程序员
邓工说电1 小时前
智慧断路器安全吗?数据加密、离线保护与合规认证全解读
大数据·数据库·人工智能·智能断路器·炜晔科技
阿里云大数据AI技术1 小时前
Lance 数据检索怎么选,当然阿里云 Milvus 向量湖
人工智能
出海客1 小时前
跨境电商多语言客服知识库怎么建:资料结构、检索边界与人工升级
大数据·人工智能
xsd202411181 小时前
从自主导航到视觉读表:一台工业巡检机器人的全栈技术链路拆解
人工智能
袁哥大话安全1 小时前
巡隐WEBSHELL扫描软件
人工智能·安全·web
论文复现现场1 小时前
8卡4090能跑70B吗?Llama-2显存预算、QLoRA与通信瓶颈
人工智能·深度学习·分布式训练·llama·显存·qlora·算家云
酷虎软件2 小时前
如何用AI创作AI歌曲AI音乐
人工智能