1 //this file is part of notepad++ 2 //Copyright (C)2003 Don HO <donho@altern.org> 3 // 4 //This program is free software; you can redistribute it and/or 5 //modify it under the terms of the GNU General Public License 6 //as published by the Free Software Foundation; either 7 //version 2 of the License, or (at your option) any later version. 8 // 9 //This program is distributed in the hope that it will be useful, 10 //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 //GNU General Public License for more details. 13 // 14 //You should have received a copy of the GNU General Public License 15 //along with this program; if not, write to the Free Software 16 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 /** 18 * プラグインの定義から自動的にインターフェイスをミックスインするためのもの 19 * 20 * Author: dokutoku, https://twitter.com/dokutoku3 21 * License: GPL-2.0 or later 22 */ 23 module npp_api.pluginfunc.extra_interfece; 24 25 26 version (Windows): 27 version (Not_betterC): 28 29 private static import core.sys.windows.windef; 30 private static import npp_api.PowerEditor.MISC.PluginsManager.PluginInterface; 31 private static import npp_api.pluginfunc.config_file; 32 private static import npp_api.pluginfunc.menu; 33 private static import std.traits; 34 35 enum current_mixin_version = 0.001; 36 37 /** 38 * ToDo: 39 */ 40 struct npp_plugin_definition 41 { 42 //immutable string released = null; 43 44 float mixin_version = current_mixin_version; 45 46 npp_api.pluginfunc.config_file.config_type_t config_type = npp_api.pluginfunc.config_file.config_type_t.none; 47 48 /** 49 * Plugin name 50 */ 51 string name = null; 52 53 /** 54 * Plugin version 55 */ 56 float version_number = 0.001; 57 58 /** 59 * version version string 60 */ 61 string version_string = null; 62 63 /** 64 * Author name 65 */ 66 string author = null; 67 68 /** 69 * plugin config file info 70 */ 71 npp_api.pluginfunc.config_file.plugin_config_info config_info; 72 73 /** 74 * menu list 75 */ 76 npp_api.pluginfunc.menu.menu_item_t[] menu_items = null; 77 78 //ToDo: export? 79 80 invariant 81 { 82 } 83 } 84 85 mixin template npp_main_menu(npp_api.pluginfunc.menu.menu_item_t[] main_menu_items) 86 { 87 private static import npp_api.pluginfunc.menu; 88 89 static if (!__traits(compiles, .main_menu_def)) { 90 /* 91 * main menu 92 */ 93 enum npp_api.PowerEditor.MISC.PluginsManager.PluginInterface.FuncItem[main_menu_items.length] main_menu_def = npp_api.pluginfunc.menu.create_main_menu!(main_menu_items.length)(main_menu_items); 94 npp_api.PowerEditor.MISC.PluginsManager.PluginInterface.FuncItem[main_menu_items.length] main_menu = main_menu_def; 95 } 96 } 97 98 mixin template npp_menu_actions(npp_api.pluginfunc.menu.menu_item_t[] menu_container) 99 { 100 private static import npp_api.pluginfunc.menu; 101 102 static if (!__traits(compiles, .sub_menu_actions_def)) { 103 /* 104 * sub menu actions 105 */ 106 enum sub_menu_actions_def = npp_api.pluginfunc.menu.create_sub_menu_actions(menu_container); 107 static assert(sub_menu_actions_def.length == npp_api.pluginfunc.menu.count_sub_menu_ids(menu_container)); 108 npp_api.pluginfunc.menu.menu_action[sub_menu_actions_def.length] sub_menu_actions = .sub_menu_actions_def; 109 } 110 } 111 112 mixin template npp_menu_index(npp_api.pluginfunc.menu.menu_item_t[] menu_container) 113 { 114 private static import npp_api.pluginfunc.menu; 115 116 static if (!__traits(compiles, .menu_index_def)) { 117 /* 118 * 119 */ 120 enum menu_index_length = npp_api.pluginfunc.menu.count_all_menu_items(menu_container); 121 enum npp_api.pluginfunc.menu.sub_menu_index[menu_index_length] menu_index_def = npp_api.pluginfunc.menu.create_menu_index!(menu_index_length)(menu_container); 122 npp_api.pluginfunc.menu.sub_menu_index[menu_index_length] menu_index = .menu_index_def; 123 124 /* 125 * メニュー部分のインデックスを返す 126 */ 127 template search_menu_index(string id) 128 { 129 enum size_t search_menu_index = npp_api.pluginfunc.menu.search_menu_index(.menu_index_def, id); 130 } 131 132 template search_index(string id) 133 { 134 enum size_t search_index = npp_api.pluginfunc.menu.search_index(.menu_index_def, id); 135 static assert(menu_index_length >= search_index); 136 } 137 } 138 139 static assert(.menu_index_def.length == npp_api.pluginfunc.menu.count_all_menu_items(menu_container)); 140 } 141 142 mixin template npp_autoload(npp_api.pluginfunc.config_file.config_type_t config_type, npp_api.pluginfunc.config_file.setting_item[] settings) 143 { 144 private static import std.algorithm; 145 private static import npp_api.pluginfunc.config_file; 146 private static import npp_api.pluginfunc.ini_setting; 147 148 static if ((!__traits(compiles, .auto_settings)) && (settings.length != 0)) { 149 static if (config_type == npp_api.pluginfunc.config_file.config_type_t.ini) { 150 enum auto_settings_def = npp_api.pluginfunc.ini_setting.convert_setting!(settings.length)(settings); 151 npp_api.pluginfunc.ini_setting.ini_setting_item[settings.length] auto_settings = auto_settings_def; 152 enum wstring[] setting_ids = npp_api.pluginfunc.ini_setting.create_setting_idetifiers(auto_settings_def); 153 154 deprecated 155 alias setting_identifiers = .setting_ids; 156 157 deprecated 158 alias search_setting_identifier_index = .search_setting_id_index; 159 160 size_t search_setting_id_index(wstring[] id_list, wstring id) 161 162 do 163 { 164 for (size_t i = 0; i < id_list.length; i++) { 165 if (std.algorithm.cmp(id_list[i], id) == 0) { 166 return i; 167 } 168 } 169 170 assert(0); 171 } 172 173 deprecated 174 alias search_setting_identifier = .search_setting_id; 175 176 template search_setting_id(wstring id) 177 { 178 enum search_setting_id = search_setting_id_index(.setting_ids, id); 179 static assert(auto_settings_def.length > search_setting_id); 180 } 181 } else static if (config_type == npp_api.pluginfunc.config_file.config_type_t.none) { 182 } else { 183 static assert(false); 184 } 185 } 186 } 187 188 mixin template menu_checked_list(size_t main_menu_length, npp_api.pluginfunc.menu.sub_menu_index[] menu_index) 189 { 190 private static import npp_api.pluginfunc.menu; 191 192 static if (!__traits(compiles, .menu_index_checked_def)) { 193 deprecated 194 alias menu_index_checked_identifiers = .menu_index_checked_ids; 195 196 deprecated 197 alias main_menu_checked_identifiers = .main_menu_checked_ids; 198 199 enum wstring[] menu_index_checked_ids = npp_api.pluginfunc.menu.create_menu_index_checked_id(menu_index); 200 enum wstring[] main_menu_checked_ids = npp_api.pluginfunc.menu.create_main_menu_checked_id(menu_index); 201 } 202 } 203 204 /** 205 * menu_index_checkedからmain_menu_checkedへコピーする 206 */ 207 pure nothrow @safe @nogc 208 void update_main_menu_checked(size_t main_menu_length, size_t menu_index_length)(ref npp_api.PowerEditor.MISC.PluginsManager.PluginInterface.FuncItem[main_menu_length] main_menu, const ref npp_api.pluginfunc.menu.sub_menu_index[menu_index_length] menu_index) 209 210 in 211 { 212 } 213 214 do 215 { 216 for (size_t i = 0, j = 0; i < menu_index.length; i++) { 217 if (menu_index[i].depth == 1) { 218 main_menu[j]._init2Check = menu_index[i].func_item._init2Check; 219 j++; 220 } 221 } 222 } 223 224 mixin template npp_plugin_config(npp_api.pluginfunc.config_file.config_type_t type) 225 { 226 static if (!__traits(compiles, .plugin_config_file)) { 227 static if (type == npp_api.pluginfunc.config_file.config_type_t.ini) { 228 npp_api.pluginfunc.ini_setting.npp_ini_session plugin_config_file; 229 } else static if (type == npp_api.pluginfunc.config_file.config_type_t.none) { 230 } else { 231 static assert(false); 232 } 233 } 234 } 235 236 mixin template npp_DLLMain(npp_api.pluginfunc.config_file.config_type_t type, wstring[] menu_index_checked_ids, alias menu_index) 237 { 238 private static import core.sys.windows.basetsd; 239 private static import core.sys.windows.dll; 240 private static import core.sys.windows.windef; 241 private static import core.sys.windows.winnt; 242 private static import npp_api.pluginfunc.config_file; 243 244 static if (!__traits(compiles, .DllMain)) { 245 pragma(mangle, "DllMain") 246 extern (Windows) 247 export core.sys.windows.windef.BOOL DllMain(core.sys.windows.basetsd.HANDLE hModule, core.sys.windows.windef.DWORD reasonForCall, core.sys.windows.winnt.LPVOID lpReserved) 248 249 do 250 { 251 switch (reasonForCall) { 252 case core.sys.windows.winnt.DLL_PROCESS_ATTACH: 253 core.sys.windows.dll.dll_process_attach(hModule); 254 255 static if (__traits(compiles, .pluginInit)) { 256 .pluginInit(hModule); 257 } 258 259 break; 260 261 case core.sys.windows.winnt.DLL_PROCESS_DETACH: 262 static if ((type != npp_api.pluginfunc.config_file.config_type_t.none) && (menu_index_checked_ids.length != 0)) { 263 plugin_config_file.write_menu_checked(menu_index); 264 } 265 266 static if (__traits(compiles, .pluginCleanUp)) { 267 .pluginCleanUp(); 268 } 269 270 core.sys.windows.dll.dll_process_detach(hModule); 271 272 break; 273 274 case core.sys.windows.winnt.DLL_THREAD_ATTACH: 275 core.sys.windows.dll.dll_thread_attach(true, true); 276 277 break; 278 279 case core.sys.windows.winnt.DLL_THREAD_DETACH: 280 core.sys.windows.dll.dll_thread_detach(true, true); 281 282 break; 283 284 default: 285 break; 286 } 287 288 return core.sys.windows.windef.TRUE; 289 } 290 } 291 } 292 293 mixin template npp_setInfo(alias nppData, npp_api.pluginfunc.config_file.plugin_config_info config_info, alias plugin_config_file, alias auto_settings, alias main_menu, alias menu_index) 294 if (is(typeof(nppData) == npp_api.PowerEditor.MISC.PluginsManager.PluginInterface.NppData) && std.traits.isStaticArray!(typeof(main_menu)) && std.traits.isStaticArray!(typeof(menu_index))) 295 { 296 private static import npp_api.pluginfunc.config_file; 297 private static import npp_api.pluginfunc.extra_interfece; 298 private static import npp_api.PowerEditor.MISC.PluginsManager.PluginInterface; 299 private static import std.utf; 300 301 static if (!__traits(compiles, .setInfo)) { 302 pragma(mangle, "setInfo") 303 extern (C) 304 nothrow 305 export void setInfo(npp_api.PowerEditor.MISC.PluginsManager.PluginInterface.NppData notpadPlusData) 306 307 do 308 { 309 nppData = notpadPlusData; 310 311 static if (__traits(compiles, .gshared_nppData)) { 312 .gshared_nppData = notpadPlusData; 313 } 314 315 try { 316 static if (config_info.type != npp_api.pluginfunc.config_file.config_type_t.none) { 317 enum directory_name = std.utf.toUTF16(config_info.directory_name); 318 enum file_name = std.utf.toUTF16(config_info.file_name); 319 enum section_name = std.utf.toUTF16(config_info.ini_section_name); 320 plugin_config_file = npp_api.pluginfunc.ini_setting.npp_ini_session(nppData._nppHandle, directory_name, file_name, section_name); 321 322 static if (main_menu.length != 0) { 323 plugin_config_file.auto_load(auto_settings, menu_index); 324 } else { 325 plugin_config_file.auto_load(auto_settings); 326 } 327 } 328 329 static if (main_menu.length != 0) { 330 npp_api.pluginfunc.extra_interfece.update_main_menu_checked(main_menu, menu_index); 331 } 332 } catch (Exception e) { 333 //ToDo: 334 } 335 336 static if (__traits(compiles, .pluginSetInfo)) { 337 .pluginSetInfo(notpadPlusData); 338 } 339 } 340 } 341 } 342 343 mixin template npp_beNotified(alias nppData, alias main_menu, alias menu_index, alias menu_index_def, alias sub_menu_actions) 344 { 345 private static import std.traits; 346 private static import npp_api.scintilla.Scintilla; 347 private static import npp_api.PowerEditor.MISC.PluginsManager.Notepad_plus_msgs; 348 private static import npp_api.pluginfunc.menu; 349 350 static if (!__traits(compiles, .beNotified) && (npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def) != 0)) { 351 static if (__traits(compiles, .pluginBeNotified) && !std.traits.hasFunctionAttributes!(.pluginBeNotified, "@nogc")) { 352 pragma(mangle, "beNotified") 353 extern (C) 354 nothrow 355 export void beNotified(npp_api.scintilla.Scintilla.SCNotification* notifyCode) 356 357 do 358 { 359 /+ 360 if (notifyCode == null) { 361 return; 362 } 363 +/ 364 365 switch ((*notifyCode).nmhdr.code) { 366 case npp_api.PowerEditor.MISC.PluginsManager.Notepad_plus_msgs.NPPN_TBMODIFICATION: 367 //init submenu 368 enum required = npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def); 369 npp_api.pluginfunc.menu.init_submenu(nppData._nppHandle, main_menu, menu_index, sub_menu_actions, required); 370 371 break; 372 373 default: 374 break; 375 } 376 377 .pluginBeNotified(*notifyCode); 378 } 379 } else { 380 pragma(mangle, "beNotified") 381 extern (C) 382 nothrow @nogc 383 export void beNotified(npp_api.scintilla.Scintilla.SCNotification* notifyCode) 384 385 do 386 { 387 /+ 388 if (notifyCode == null) { 389 return; 390 } 391 +/ 392 393 switch ((*notifyCode).nmhdr.code) { 394 case npp_api.PowerEditor.MISC.PluginsManager.Notepad_plus_msgs.NPPN_TBMODIFICATION: 395 //init submenu 396 enum required = npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def); 397 npp_api.pluginfunc.menu.init_submenu(nppData._nppHandle, main_menu, menu_index, sub_menu_actions, required); 398 399 break; 400 401 default: 402 break; 403 } 404 405 static if (__traits(compiles, .pluginBeNotified)) { 406 .pluginBeNotified(*notifyCode); 407 } 408 } 409 } 410 } 411 } 412 413 mixin template npp_messageProc(alias sub_menu_actions_def) 414 if (std.traits.isArray!(typeof(sub_menu_actions_def))) 415 { 416 private static import core.sys.windows.windef; 417 private static import core.sys.windows.winuser; 418 private static import npp_api.pluginfunc.menu; 419 private static import npp_api.pluginfunc.basic_interface; 420 421 static if ((!__traits(compiles, .messageProc)) && (sub_menu_actions_def.length != 0)) { 422 pragma(mangle, "messageProc") 423 extern (C) 424 nothrow 425 export core.sys.windows.windef.LRESULT messageProc(core.sys.windows.windef.UINT Message, core.sys.windows.windef.WPARAM wParam, core.sys.windows.windef.LPARAM lParam) 426 427 do 428 { 429 if (Message == core.sys.windows.winuser.WM_COMMAND) { 430 int id = core.sys.windows.windef.LOWORD(wParam); 431 432 if (npp_api.pluginfunc.menu.sub_menu_action(id, .sub_menu_actions)) { 433 return core.sys.windows.windef.TRUE; 434 } 435 } 436 437 static if (__traits(compiles, .pluginMessageProc)) { 438 if (pluginMessageProc(Message, wParam, lParam)) { 439 return core.sys.windows.windef.TRUE; 440 } else { 441 return core.sys.windows.windef.FALSE; 442 } 443 } else { 444 return core.sys.windows.windef.TRUE; 445 } 446 } 447 } 448 } 449 450 mixin template npp_plugin_interface(.npp_plugin_definition plugin_def) 451 { 452 private static import std.utf; 453 private static import npp_api.pluginfunc.basic; 454 private static import npp_api.pluginfunc.string; 455 private static import npp_api.pluginfunc.basic_interface; 456 private static import npp_api.pluginfunc.extra_interfece; 457 458 static assert(npp_api.pluginfunc.extra_interfece.current_mixin_version >= plugin_def.mixin_version); 459 enum plugin_name = npp_api.pluginfunc..string.c_wstring!(std.utf.toUTF16(plugin_def.name)).idup; 460 461 mixin npp_api.pluginfunc.basic_interface.npp_nppData!(); 462 mixin npp_api.pluginfunc.basic.plugin_messageBox!(plugin_name); 463 mixin npp_api.pluginfunc.extra_interfece.npp_menu_actions!(plugin_def.menu_items); 464 mixin npp_api.pluginfunc.extra_interfece.npp_main_menu!(plugin_def.menu_items); 465 mixin npp_api.pluginfunc.extra_interfece.npp_messageProc!(sub_menu_actions_def); 466 mixin npp_api.pluginfunc.extra_interfece.npp_menu_index!(plugin_def.menu_items); 467 mixin npp_api.pluginfunc.extra_interfece.npp_autoload!(plugin_def.config_info.type, plugin_def.config_info.settings); 468 mixin npp_api.pluginfunc.extra_interfece.menu_checked_list!(.main_menu.length, .menu_index_def); 469 mixin npp_api.pluginfunc.extra_interfece.npp_plugin_config!(plugin_def.config_info.type); 470 mixin npp_api.pluginfunc.extra_interfece.npp_DLLMain!(plugin_def.config_info.type, .menu_index_checked_ids, .menu_index); 471 472 //ToDo: 473 static if (__traits(compiles, .plugin_config_file) && __traits(compiles, .auto_settings)) { 474 mixin npp_api.pluginfunc.extra_interfece.npp_setInfo!(.nppData, plugin_def.config_info, .plugin_config_file, .auto_settings, .main_menu, .menu_index); 475 } 476 477 mixin npp_api.pluginfunc.extra_interfece.npp_beNotified!(.nppData, .main_menu, .menu_index, .menu_index_def, .sub_menu_actions); 478 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(plugin_name, main_menu_def); 479 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(); 480 }