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_ids(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 id)
133 		{
134 			enum size_t search_menu_index = npp_api.pluginfunc.menu.search_menu_index(.menu_index_def, id);
135 		}
136 
137 		template search_index(string id)
138 		{
139 			enum size_t search_index = npp_api.pluginfunc.menu.search_index(.menu_index_def, id);
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_ids = npp_api.pluginfunc.ini_setting.create_setting_idetifiers(auto_settings_def);
158 
159 			deprecated
160 			alias setting_identifiers = .setting_ids;
161 
162 			deprecated
163 			alias search_setting_identifier_index = .search_setting_id_index;
164 
165 			size_t search_setting_id_index(wstring[] id_list, wstring id)
166 
167 				do
168 				{
169 					for (size_t i = 0; i < id_list.length; i++) {
170 						if (std.algorithm.cmp(id_list[i], id) == 0) {
171 							return i;
172 						}
173 					}
174 
175 					assert(0);
176 				}
177 
178 			deprecated
179 			alias search_setting_identifier = .search_setting_id;
180 
181 			template search_setting_id(wstring id)
182 			{
183 				enum search_setting_id = search_setting_id_index(.setting_ids, id);
184 				static assert(auto_settings_def.length > search_setting_id);
185 			}
186 		} else static if (config_type == npp_api.pluginfunc.config_file.config_type_t.none) {
187 		} else {
188 			static assert(false);
189 		}
190 	}
191 }
192 
193 mixin template menu_checked_list(size_t main_menu_length, npp_api.pluginfunc.menu.sub_menu_index[] menu_index)
194 {
195 	private static import npp_api.pluginfunc.menu;
196 
197 	static if (!__traits(compiles, .menu_index_checked_def)) {
198 		deprecated
199 		alias menu_index_checked_identifiers = .menu_index_checked_ids;
200 
201 		deprecated
202 		alias main_menu_checked_identifiers = .main_menu_checked_ids;
203 
204 		enum wstring[] menu_index_checked_ids = npp_api.pluginfunc.menu.create_menu_index_checked_id(menu_index);
205 		enum wstring[] main_menu_checked_ids = npp_api.pluginfunc.menu.create_main_menu_checked_id(menu_index);
206 	}
207 }
208 
209 /**
210  * menu_index_checkedからmain_menu_checkedへコピーする
211  */
212 pure nothrow @safe @nogc
213 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)
214 
215 	in
216 	{
217 	}
218 
219 	do
220 	{
221 		for (size_t i = 0, j = 0; i < menu_index.length; i++) {
222 			if (menu_index[i].depth == 1) {
223 				main_menu[j]._init2Check = menu_index[i].func_item._init2Check;
224 				j++;
225 			}
226 		}
227 	}
228 
229 mixin template npp_plugin_config(npp_api.pluginfunc.config_file.config_type_t type)
230 {
231 	static if (!__traits(compiles, .plugin_config_file)) {
232 		static if (type == npp_api.pluginfunc.config_file.config_type_t.ini) {
233 			npp_api.pluginfunc.ini_setting.npp_ini_session plugin_config_file;
234 		} else static if (type == npp_api.pluginfunc.config_file.config_type_t.none) {
235 		} else {
236 			static assert(false);
237 		}
238 	}
239 }
240 
241 mixin template npp_DLLMain(npp_api.pluginfunc.config_file.config_type_t type, wstring[] menu_index_checked_ids, alias menu_index)
242 {
243 	private static import core.sys.windows.basetsd;
244 	private static import core.sys.windows.dll;
245 	private static import core.sys.windows.windef;
246 	private static import core.sys.windows.winnt;
247 	private static import npp_api.pluginfunc.config_file;
248 
249 	static if (!__traits(compiles, .DllMain)) {
250 		pragma(mangle, "DllMain")
251 		extern (Windows)
252 		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)
253 
254 			do
255 			{
256 				static import core.sys.windows.dll;
257 				static import core.sys.windows.windef;
258 				static import core.sys.windows.winnt;
259 
260 				switch (reasonForCall) {
261 					case core.sys.windows.winnt.DLL_PROCESS_ATTACH:
262 						core.sys.windows.dll.dll_process_attach(hModule);
263 
264 						static if (__traits(compiles, .pluginInit)) {
265 							.pluginInit(hModule);
266 						}
267 
268 						break;
269 
270 					case core.sys.windows.winnt.DLL_PROCESS_DETACH:
271 						static if ((type != npp_api.pluginfunc.config_file.config_type_t.none) && (menu_index_checked_ids.length != 0)) {
272 							plugin_config_file.write_menu_checked(menu_index);
273 						}
274 
275 						static if (__traits(compiles, .pluginCleanUp)) {
276 							.pluginCleanUp();
277 						}
278 
279 						core.sys.windows.dll.dll_process_detach(hModule);
280 
281 						break;
282 
283 					case core.sys.windows.winnt.DLL_THREAD_ATTACH:
284 						core.sys.windows.dll.dll_thread_attach(true, true);
285 
286 						break;
287 
288 					case core.sys.windows.winnt.DLL_THREAD_DETACH:
289 						core.sys.windows.dll.dll_thread_detach(true, true);
290 
291 						break;
292 
293 					default:
294 						break;
295 				}
296 
297 				return core.sys.windows.windef.TRUE;
298 			}
299 	}
300 }
301 
302 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)
303 	if (is(typeof(nppData) == npp_api.powereditor.misc.pluginsmanager.plugininterface.NppData) && std.traits.isStaticArray!(typeof(main_menu)) && std.traits.isStaticArray!(typeof(menu_index)))
304 {
305 	private static import npp_api.powereditor.misc.pluginsmanager.plugininterface;
306 	private static import npp_api.pluginfunc.extra_interfece;
307 	private static import npp_api.pluginfunc.config_file;
308 
309 	static if (!__traits(compiles, .setInfo)) {
310 		pragma(mangle, "setInfo")
311 		extern (C)
312 		nothrow
313 		export void setInfo(npp_api.powereditor.misc.pluginsmanager.plugininterface.NppData notpadPlusData)
314 
315 			do
316 			{
317 				static import std.utf;
318 				static import npp_api.pluginfunc.extra_interfece;
319 
320 				nppData = notpadPlusData;
321 
322 				static if (__traits(compiles, .gshared_nppData)) {
323 					.gshared_nppData = notpadPlusData;
324 				}
325 
326 				try {
327 					static if (config_info.type != npp_api.pluginfunc.config_file.config_type_t.none) {
328 						enum directory_name = std.utf.toUTF16(config_info.directory_name);
329 						enum file_name = std.utf.toUTF16(config_info.file_name);
330 						enum section_name = std.utf.toUTF16(config_info.ini_section_name);
331 						plugin_config_file = npp_api.pluginfunc.ini_setting.npp_ini_session(nppData._nppHandle, directory_name, file_name, section_name);
332 
333 						static if (main_menu.length != 0) {
334 							plugin_config_file.auto_load(auto_settings, menu_index);
335 						} else {
336 							plugin_config_file.auto_load(auto_settings);
337 						}
338 					}
339 
340 					static if (main_menu.length != 0) {
341 						npp_api.pluginfunc.extra_interfece.update_main_menu_checked(main_menu, menu_index);
342 					}
343 				} catch (Exception e) {
344 					//ToDo:
345 				}
346 
347 				static if (__traits(compiles, .pluginSetInfo)) {
348 					.pluginSetInfo(notpadPlusData);
349 				}
350 			}
351 	}
352 }
353 
354 mixin template npp_beNotified(alias nppData, alias main_menu, alias menu_index, alias menu_index_def, alias sub_menu_actions)
355 {
356 	private static import std.traits;
357 	private static import npp_api.scintilla.scintilla;
358 	private static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs;
359 	private static import npp_api.pluginfunc.menu;
360 
361 	static if (!__traits(compiles, .beNotified) && (npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def) != 0)) {
362 		static if (__traits(compiles, .pluginBeNotified) && !std.traits.hasFunctionAttributes!(.pluginBeNotified, "@nogc")) {
363 			pragma(mangle, "beNotified")
364 			extern (C)
365 			nothrow
366 			export void beNotified(npp_api.scintilla.scintilla.SCNotification* notifyCode)
367 
368 				do
369 				{
370 					static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs;
371 					static import npp_api.pluginfunc.menu;
372 
373 					/+
374 					if (notifyCode == null) {
375 						return;
376 					}
377 					+/
378 
379 					switch ((*notifyCode).nmhdr.code) {
380 						case npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.NPPN_TBMODIFICATION:
381 							//init submenu
382 							enum required = npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def);
383 							npp_api.pluginfunc.menu.init_submenu(nppData._nppHandle, main_menu, menu_index, sub_menu_actions, required);
384 
385 							break;
386 
387 						default:
388 							break;
389 					}
390 
391 					.pluginBeNotified(*notifyCode);
392 				}
393 		} else {
394 			pragma(mangle, "beNotified")
395 			extern (C)
396 			nothrow @nogc
397 			export void beNotified(npp_api.scintilla.scintilla.SCNotification* notifyCode)
398 
399 				do
400 				{
401 					static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs;
402 					static import npp_api.pluginfunc.menu;
403 
404 					/+
405 					if (notifyCode == null) {
406 						return;
407 					}
408 					+/
409 
410 					switch ((*notifyCode).nmhdr.code) {
411 						case npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.NPPN_TBMODIFICATION:
412 							//init submenu
413 							enum required = npp_api.pluginfunc.menu.allocate_sub_menu_length(menu_index_def);
414 							npp_api.pluginfunc.menu.init_submenu(nppData._nppHandle, main_menu, menu_index, sub_menu_actions, required);
415 
416 							break;
417 
418 						default:
419 							break;
420 					}
421 
422 					static if (__traits(compiles, .pluginBeNotified)) {
423 						.pluginBeNotified(*notifyCode);
424 					}
425 				}
426 		}
427 	}
428 }
429 
430 mixin template npp_messageProc(alias sub_menu_actions_def)
431 	if (std.traits.isArray!(typeof(sub_menu_actions_def)))
432 {
433 	private static import core.sys.windows.windef;
434 	private static import core.sys.windows.winuser;
435 	private static import npp_api.pluginfunc.menu;
436 	private static import npp_api.pluginfunc.basic_interface;
437 
438 	static if ((!__traits(compiles, .messageProc)) && (sub_menu_actions_def.length != 0)) {
439 		pragma(mangle, "messageProc")
440 		extern (C)
441 		nothrow
442 		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)
443 
444 			do
445 			{
446 				static import core.sys.windows.windef;
447 				static import core.sys.windows.winuser;
448 				static import npp_api.pluginfunc.menu;
449 				static import npp_api.pluginfunc.basic_interface;
450 
451 				if (Message == core.sys.windows.winuser.WM_COMMAND) {
452 					int id = core.sys.windows.windef.LOWORD(wParam);
453 
454 					if (npp_api.pluginfunc.menu.sub_menu_action(id, .sub_menu_actions)) {
455 						return core.sys.windows.windef.TRUE;
456 					}
457 				}
458 
459 				static if (__traits(compiles, .pluginMessageProc)) {
460 					if (pluginMessageProc(Message, wParam, lParam)) {
461 						return core.sys.windows.windef.TRUE;
462 					} else {
463 						return core.sys.windows.windef.FALSE;
464 					}
465 				} else {
466 					return core.sys.windows.windef.TRUE;
467 				}
468 			}
469 	}
470 }
471 
472 mixin template npp_plugin_interface(.npp_plugin_definition plugin_def)
473 {
474 	private static import std.utf;
475 	private static import npp_api.pluginfunc.basic;
476 	private static import npp_api.pluginfunc.string;
477 	private static import npp_api.pluginfunc.basic_interface;
478 	private static import npp_api.pluginfunc.extra_interfece;
479 
480 	static assert(npp_api.pluginfunc.extra_interfece.current_mixin_version >= plugin_def.mixin_version);
481 	enum plugin_name = npp_api.pluginfunc..string.c_wstring!(std.utf.toUTF16(plugin_def.name)).idup;
482 
483 	mixin npp_api.pluginfunc.basic_interface.npp_nppData!();
484 	mixin npp_api.pluginfunc.basic.plugin_messageBox!(plugin_name);
485 	mixin npp_api.pluginfunc.extra_interfece.npp_menu_actions!(plugin_def.menu_items);
486 	mixin npp_api.pluginfunc.extra_interfece.npp_main_menu!(plugin_def.menu_items);
487 	mixin npp_api.pluginfunc.extra_interfece.npp_messageProc!(sub_menu_actions_def);
488 	mixin npp_api.pluginfunc.extra_interfece.npp_menu_index!(plugin_def.menu_items);
489 	mixin npp_api.pluginfunc.extra_interfece.npp_autoload!(plugin_def.config_info.type, plugin_def.config_info.settings);
490 	mixin npp_api.pluginfunc.extra_interfece.menu_checked_list!(.main_menu.length, .menu_index_def);
491 	mixin npp_api.pluginfunc.extra_interfece.npp_plugin_config!(plugin_def.config_info.type);
492 	mixin npp_api.pluginfunc.extra_interfece.npp_DLLMain!(plugin_def.config_info.type, .menu_index_checked_ids, .menu_index);
493 
494 	//ToDo:
495 	static if (__traits(compiles, .plugin_config_file) && __traits(compiles, .auto_settings)) {
496 		mixin npp_api.pluginfunc.extra_interfece.npp_setInfo!(.nppData, plugin_def.config_info, .plugin_config_file, .auto_settings, .main_menu, .menu_index);
497 	}
498 
499 	mixin npp_api.pluginfunc.extra_interfece.npp_beNotified!(.nppData, .main_menu, .menu_index, .menu_index_def, .sub_menu_actions);
500 	mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(plugin_name, main_menu_def);
501 	mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!();
502 }