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 std.traits; 31 private static import npp_api.powereditor.misc.pluginsmanager.plugininterface; 32 private static import npp_api.pluginfunc.config_file; 33 private static import npp_api.pluginfunc.menu; 34 35 enum current_mixin_version = 0.001; 36 37 /** 38 * ToDo: 39 */ 40 struct npp_plugin_definition 41 { 42 static import npp_api.powereditor.misc.pluginsmanager.plugininterface; 43 static import npp_api.pluginfunc.config_file; 44 static import npp_api.pluginfunc.menu; 45 static import npp_api.pluginfunc.config_file; 46 47 //immutable string released = null; 48 49 float mixin_version = current_mixin_version; 50 51 npp_api.pluginfunc.config_file.config_type_t config_type = npp_api.pluginfunc.config_file.config_type_t.none; 52 53 /** 54 * Plugin name 55 */ 56 string name = null; 57 58 /** 59 * Plugin version 60 */ 61 float version_number = 0.001; 62 63 /** 64 * version version string 65 */ 66 string version_string = null; 67 68 /** 69 * Author name 70 */ 71 string author = null; 72 73 /** 74 * plugin config file info 75 */ 76 npp_api.pluginfunc.config_file.plugin_config_info config_info; 77 78 /** 79 * menu list 80 */ 81 npp_api.pluginfunc.menu.menu_item_t[] menu_items = null; 82 83 //ToDo: export? 84 85 invariant 86 { 87 } 88 } 89 90 mixin template npp_main_menu(npp_api.pluginfunc.menu.menu_item_t[] main_menu_items) 91 { 92 private static import npp_api.pluginfunc.menu; 93 94 static if (!__traits(compiles, .main_menu_def)) { 95 /* 96 * main menu 97 */ 98 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); 99 npp_api.powereditor.misc.pluginsmanager.plugininterface.FuncItem[main_menu_items.length] main_menu = main_menu_def; 100 } 101 } 102 103 mixin template npp_menu_actions(npp_api.pluginfunc.menu.menu_item_t[] menu_container) 104 { 105 private static import npp_api.pluginfunc.menu; 106 107 static if (!__traits(compiles, .sub_menu_actions_def)) { 108 /* 109 * sub menu actions 110 */ 111 enum sub_menu_actions_def = npp_api.pluginfunc.menu.create_sub_menu_actions(menu_container); 112 static assert(sub_menu_actions_def.length == npp_api.pluginfunc.menu.count_sub_menu_identifiers(menu_container)); 113 npp_api.pluginfunc.menu.menu_action[sub_menu_actions_def.length] sub_menu_actions = .sub_menu_actions_def; 114 } 115 } 116 117 mixin template npp_menu_index(npp_api.pluginfunc.menu.menu_item_t[] menu_container) 118 { 119 private static import npp_api.pluginfunc.menu; 120 121 static if (!__traits(compiles, .menu_index_def)) { 122 /* 123 * 124 */ 125 enum menu_index_length = npp_api.pluginfunc.menu.count_all_menu_items(menu_container); 126 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); 127 npp_api.pluginfunc.menu.sub_menu_index[menu_index_length] menu_index = .menu_index_def; 128 129 /* 130 * メニュー部分のインデックスを返す 131 */ 132 template search_menu_index(string identifier) 133 { 134 enum size_t search_menu_index = npp_api.pluginfunc.menu.search_menu_index(.menu_index_def, identifier); 135 } 136 137 template search_index(string identifier) 138 { 139 enum size_t search_index = npp_api.pluginfunc.menu.search_index(.menu_index_def, identifier); 140 static assert(menu_index_length >= search_index); 141 } 142 } 143 144 static assert(.menu_index_def.length == npp_api.pluginfunc.menu.count_all_menu_items(menu_container)); 145 } 146 147 mixin template npp_autoload(npp_api.pluginfunc.config_file.config_type_t config_type, npp_api.pluginfunc.config_file.setting_item[] settings) 148 { 149 private static import std.algorithm; 150 private static import npp_api.pluginfunc.config_file; 151 private static import npp_api.pluginfunc.ini_setting; 152 153 static if ((!__traits(compiles, .auto_settings)) && (settings.length != 0)) { 154 static if (config_type == npp_api.pluginfunc.config_file.config_type_t.ini) { 155 enum auto_settings_def = npp_api.pluginfunc.ini_setting.convert_setting!(settings.length)(settings); 156 npp_api.pluginfunc.ini_setting.ini_setting_item[settings.length] auto_settings = auto_settings_def; 157 enum wstring[] setting_identifiers = npp_api.pluginfunc.ini_setting.create_setting_idetifiers(auto_settings_def); 158 159 size_t search_setting_identifier_index(wstring[] identifier_list, wstring identifier) 160 161 do 162 { 163 for (size_t i = 0; i < identifier_list.length; i++) { 164 if (std.algorithm.cmp(identifier_list[i], identifier) == 0) { 165 return i; 166 } 167 } 168 169 assert(0); 170 } 171 172 template search_setting_identifier(wstring identifier) 173 { 174 enum search_setting_identifier = search_setting_identifier_index(.setting_identifiers, identifier); 175 static assert(auto_settings_def.length > search_setting_identifier); 176 } 177 } else static if (config_type == npp_api.pluginfunc.config_file.config_type_t.none) { 178 } else { 179 static assert(false); 180 } 181 } 182 } 183 184 mixin template menu_checked_list(size_t main_menu_length, npp_api.pluginfunc.menu.sub_menu_index[] menu_index) 185 { 186 private static import npp_api.pluginfunc.menu; 187 188 static if (!__traits(compiles, .menu_index_checked_def)) { 189 enum wstring[] menu_index_checked_identifiers = npp_api.pluginfunc.menu.create_menu_index_checked_identifier(menu_index); 190 enum wstring[] main_menu_checked_identifiers = npp_api.pluginfunc.menu.create_main_menu_checked_identifier(menu_index); 191 } 192 } 193 194 /** 195 * menu_index_checkedからmain_menu_checkedへコピーする 196 */ 197 pure nothrow @safe @nogc 198 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) 199 200 in 201 { 202 } 203 204 do 205 { 206 for (size_t i = 0, j = 0; i < menu_index.length; i++) { 207 if (menu_index[i].depth == 1) { 208 main_menu[j]._init2Check = menu_index[i].func_item._init2Check; 209 j++; 210 } 211 } 212 } 213 214 mixin template npp_plugin_config(npp_api.pluginfunc.config_file.config_type_t type) 215 { 216 static if (!__traits(compiles, .plugin_config_file)) { 217 static if (type == npp_api.pluginfunc.config_file.config_type_t.ini) { 218 npp_api.pluginfunc.ini_setting.npp_ini_session plugin_config_file; 219 } else static if (type == npp_api.pluginfunc.config_file.config_type_t.none) { 220 } else { 221 static assert(false); 222 } 223 } 224 } 225 226 mixin template npp_DLLMain(npp_api.pluginfunc.config_file.config_type_t type, wstring[] menu_index_checked_identifiers, alias menu_index) 227 { 228 private static import core.sys.windows.basetsd; 229 private static import core.sys.windows.dll; 230 private static import core.sys.windows.windef; 231 private static import core.sys.windows.winnt; 232 private static import npp_api.pluginfunc.config_file; 233 234 static if (!__traits(compiles, .DllMain)) { 235 pragma(mangle, "DllMain") 236 extern (Windows) 237 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) 238 239 do 240 { 241 static import core.sys.windows.dll; 242 static import core.sys.windows.windef; 243 static import core.sys.windows.winnt; 244 245 switch (reasonForCall) { 246 case core.sys.windows.winnt.DLL_PROCESS_ATTACH: 247 core.sys.windows.dll.dll_process_attach(hModule); 248 249 static if (__traits(compiles, .pluginInit)) { 250 .pluginInit(hModule); 251 } 252 253 break; 254 255 case core.sys.windows.winnt.DLL_PROCESS_DETACH: 256 static if ((type != npp_api.pluginfunc.config_file.config_type_t.none) && (menu_index_checked_identifiers.length != 0)) { 257 plugin_config_file.write_menu_checked(menu_index); 258 } 259 260 static if (__traits(compiles, .pluginCleanUp)) { 261 .pluginCleanUp(); 262 } 263 264 core.sys.windows.dll.dll_process_detach(hModule); 265 266 break; 267 268 case core.sys.windows.winnt.DLL_THREAD_ATTACH: 269 core.sys.windows.dll.dll_thread_attach(true, true); 270 271 break; 272 273 case core.sys.windows.winnt.DLL_THREAD_DETACH: 274 core.sys.windows.dll.dll_thread_detach(true, true); 275 276 break; 277 278 default: 279 break; 280 } 281 282 return core.sys.windows.windef.TRUE; 283 } 284 } 285 } 286 287 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) 288 if (is(typeof(nppData) == npp_api.powereditor.misc.pluginsmanager.plugininterface.NppData) && std.traits.isStaticArray!(typeof(main_menu)) && std.traits.isStaticArray!(typeof(menu_index))) 289 { 290 private static import npp_api.powereditor.misc.pluginsmanager.plugininterface; 291 private static import npp_api.pluginfunc.extra_interfece; 292 private static import npp_api.pluginfunc.config_file; 293 294 static if (!__traits(compiles, .setInfo)) { 295 pragma(mangle, "setInfo") 296 extern (C) 297 nothrow 298 export void setInfo(npp_api.powereditor.misc.pluginsmanager.plugininterface.NppData notpadPlusData) 299 300 do 301 { 302 static import std.utf; 303 static import npp_api.pluginfunc.extra_interfece; 304 305 nppData = notpadPlusData; 306 307 static if (__traits(compiles, .gshared_nppData)) { 308 .gshared_nppData = notpadPlusData; 309 } 310 311 try { 312 static if (config_info.type != npp_api.pluginfunc.config_file.config_type_t.none) { 313 enum directory_name = std.utf.toUTF16(config_info.directory_name); 314 enum file_name = std.utf.toUTF16(config_info.file_name); 315 enum section_name = std.utf.toUTF16(config_info.ini_section_name); 316 plugin_config_file = npp_api.pluginfunc.ini_setting.npp_ini_session(nppData._nppHandle, directory_name, file_name, section_name); 317 318 static if (main_menu.length != 0) { 319 plugin_config_file.auto_load(auto_settings, menu_index); 320 } else { 321 plugin_config_file.auto_load(auto_settings); 322 } 323 } 324 325 static if (main_menu.length != 0) { 326 npp_api.pluginfunc.extra_interfece.update_main_menu_checked(main_menu, menu_index); 327 } 328 } catch (Exception e) { 329 //ToDo: 330 } 331 332 static if (__traits(compiles, .pluginSetInfo)) { 333 .pluginSetInfo(notpadPlusData); 334 } 335 } 336 } 337 } 338 339 mixin template npp_beNotified(alias nppData, alias main_menu, alias menu_index, alias menu_index_def, alias sub_menu_actions) 340 { 341 private static import std.traits; 342 private static import npp_api.scintilla.scintilla; 343 private static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs; 344 private static import npp_api.pluginfunc.menu; 345 346 static if (!__traits(compiles, .beNotified) && (npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def) != 0)) { 347 static if (__traits(compiles, .pluginBeNotified) && !std.traits.hasFunctionAttributes!(.pluginBeNotified, "@nogc")) { 348 pragma(mangle, "beNotified") 349 extern (C) 350 nothrow 351 export void beNotified(npp_api.scintilla.scintilla.SCNotification* notifyCode) 352 353 do 354 { 355 static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs; 356 static import npp_api.pluginfunc.menu; 357 358 /+ 359 if (notifyCode == null) { 360 return; 361 } 362 +/ 363 364 switch ((*notifyCode).nmhdr.code) { 365 case npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.NPPN_TBMODIFICATION: 366 //init submenu 367 enum required = npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def); 368 npp_api.pluginfunc.menu.init_submenu(nppData._nppHandle, main_menu, menu_index, sub_menu_actions, required); 369 370 break; 371 372 default: 373 break; 374 } 375 376 .pluginBeNotified(*notifyCode); 377 } 378 } else { 379 pragma(mangle, "beNotified") 380 extern (C) 381 nothrow @nogc 382 export void beNotified(npp_api.scintilla.scintilla.SCNotification* notifyCode) 383 384 do 385 { 386 static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs; 387 static import npp_api.pluginfunc.menu; 388 389 /+ 390 if (notifyCode == null) { 391 return; 392 } 393 +/ 394 395 switch ((*notifyCode).nmhdr.code) { 396 case npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.NPPN_TBMODIFICATION: 397 //init submenu 398 enum required = npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def); 399 npp_api.pluginfunc.menu.init_submenu(nppData._nppHandle, main_menu, menu_index, sub_menu_actions, required); 400 401 break; 402 403 default: 404 break; 405 } 406 407 static if (__traits(compiles, .pluginBeNotified)) { 408 .pluginBeNotified(*notifyCode); 409 } 410 } 411 } 412 } 413 } 414 415 mixin template npp_messageProc(alias sub_menu_actions_def) 416 if (std.traits.isArray!(typeof(sub_menu_actions_def))) 417 { 418 private static import core.sys.windows.windef; 419 private static import core.sys.windows.winuser; 420 private static import npp_api.pluginfunc.menu; 421 private static import npp_api.pluginfunc.basic_interface; 422 423 static if ((!__traits(compiles, .messageProc)) && (sub_menu_actions_def.length != 0)) { 424 pragma(mangle, "messageProc") 425 extern (C) 426 nothrow 427 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) 428 429 do 430 { 431 static import core.sys.windows.windef; 432 static import core.sys.windows.winuser; 433 static import npp_api.pluginfunc.menu; 434 static import npp_api.pluginfunc.basic_interface; 435 436 if (Message == core.sys.windows.winuser.WM_COMMAND) { 437 int id = core.sys.windows.windef.LOWORD(wParam); 438 439 if (npp_api.pluginfunc.menu.sub_menu_action(id, .sub_menu_actions)) { 440 return core.sys.windows.windef.TRUE; 441 } 442 } 443 444 static if (__traits(compiles, .pluginMessageProc)) { 445 if (pluginMessageProc(Message, wParam, lParam)) { 446 return core.sys.windows.windef.TRUE; 447 } else { 448 return core.sys.windows.windef.FALSE; 449 } 450 } else { 451 return core.sys.windows.windef.TRUE; 452 } 453 } 454 } 455 } 456 457 mixin template npp_plugin_interface(.npp_plugin_definition plugin_def) 458 { 459 private static import std.utf; 460 private static import npp_api.pluginfunc.basic; 461 private static import npp_api.pluginfunc.string; 462 private static import npp_api.pluginfunc.basic_interface; 463 private static import npp_api.pluginfunc.extra_interfece; 464 465 static assert(npp_api.pluginfunc.extra_interfece.current_mixin_version >= plugin_def.mixin_version); 466 enum plugin_name = npp_api.pluginfunc..string.c_wstring!(std.utf.toUTF16(plugin_def.name)).idup; 467 468 mixin npp_api.pluginfunc.basic_interface.npp_nppData!(); 469 mixin npp_api.pluginfunc.basic.plugin_messageBox!(plugin_name); 470 mixin npp_api.pluginfunc.extra_interfece.npp_menu_actions!(plugin_def.menu_items); 471 mixin npp_api.pluginfunc.extra_interfece.npp_main_menu!(plugin_def.menu_items); 472 mixin npp_api.pluginfunc.extra_interfece.npp_messageProc!(sub_menu_actions_def); 473 mixin npp_api.pluginfunc.extra_interfece.npp_menu_index!(plugin_def.menu_items); 474 mixin npp_api.pluginfunc.extra_interfece.npp_autoload!(plugin_def.config_info.type, plugin_def.config_info.settings); 475 mixin npp_api.pluginfunc.extra_interfece.menu_checked_list!(.main_menu.length, .menu_index_def); 476 mixin npp_api.pluginfunc.extra_interfece.npp_plugin_config!(plugin_def.config_info.type); 477 mixin npp_api.pluginfunc.extra_interfece.npp_DLLMain!(plugin_def.config_info.type, .menu_index_checked_identifiers, .menu_index); 478 479 //ToDo: 480 static if (__traits(compiles, .plugin_config_file) && __traits(compiles, .auto_settings)) { 481 mixin npp_api.pluginfunc.extra_interfece.npp_setInfo!(.nppData, plugin_def.config_info, .plugin_config_file, .auto_settings, .main_menu, .menu_index); 482 } 483 484 mixin npp_api.pluginfunc.extra_interfece.npp_beNotified!(.nppData, .main_menu, .menu_index, .menu_index_def, .sub_menu_actions); 485 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(plugin_name, main_menu_def); 486 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(); 487 }