1 //this file is part of MimeTools (plugin for Notepad++)
2 //Copyright (C)2019 Don HO <don.h@free.fr>
3 //
4 //
5 // Enhance Base64 features, and rewrite Base64 encode/decode implementation
6 // Copyright 2019 by Paul Nankervis <paulnank@hotmail.com>
7 //
8 //
9 //This program is free software; you can redistribute it and/or
10 //modify it under the terms of the GNU General Public License
11 //as published by the Free Software Foundation; either
12 //version 2 of the License, or (at your option) any later version.
13 //
14 //This program is distributed in the hope that it will be useful,
15 //but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //GNU General Public License for more details.
18 //
19 //You should have received a copy of the GNU General Public License
20 //along with this program; if not, write to the Free Software
21 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 module npp_mimetools.mimeTools;
23 
24 
25 private static import core.stdc.string;
26 private static import core.sys.windows.basetsd;
27 private static import core.sys.windows.winbase;
28 private static import core.sys.windows.windef;
29 private static import core.sys.windows.winnt;
30 private static import core.sys.windows.winuser;
31 private static import npp_api.pluginfunc.basic_interface;
32 private static import npp_api.pluginfunc.npp_msgs;
33 private static import npp_api.pluginfunc.scintilla_msg;
34 private static import npp_api.pluginfunc.string;
35 private static import npp_api.powereditor.misc.pluginsmanager.plugininterface;
36 private static import npp_mimetools.b64;
37 private static import npp_mimetools.qp;
38 private static import npp_mimetools.url;
39 private static import npp_mimetools.saml;
40 
41 enum IDD_ABOUTBOX = 250;
42 enum IDC_STATIC = -1;
43 
44 enum PLUGIN_NAME = npp_api.pluginfunc..string.c_wstring!(`MIME Tools Sample`);
45 
46 core.sys.windows.windef.HINSTANCE _hInst;
47 
48 enum npp_api.powereditor.misc.pluginsmanager.plugininterface.FuncItem[] main_menu_items_def =
49 [
50 	{
51 		_itemName: `Base64 Encode`w,
52 		_pFunc: &.convertToBase64FromAscii,
53 		_init2Check: false,
54 		_pShKey: null,
55 	},
56 	{
57 		_itemName: `Base64 Encode with padding`w,
58 		_pFunc: &.convertToBase64FromAscii_pad,
59 		_init2Check: false,
60 		_pShKey: null,
61 	},
62 	{
63 		_itemName: `Base64 Encode with Unix EOL`w,
64 		_pFunc: &.convertToBase64FromAscii_B64Format,
65 		_init2Check: false,
66 		_pShKey: null,
67 	},
68 	{
69 		_itemName: `Base64 Encode by line`w,
70 		_pFunc: &.convertToBase64FromAscii_byline,
71 		_init2Check: false,
72 		_pShKey: null,
73 	},
74 	{
75 		_itemName: `Base64 Decode`w,
76 		_pFunc: &.convertToAsciiFromBase64,
77 		_init2Check: false,
78 		_pShKey: null,
79 	},
80 	{
81 		_itemName: `Base64 Decode strict`w,
82 		_pFunc: &.convertToAsciiFromBase64_strict,
83 		_init2Check: false,
84 		_pShKey: null,
85 	},
86 	{
87 		_itemName: `Base64 Decode by line`w,
88 		_pFunc: &.convertToAsciiFromBase64_whitespaceReset,
89 		_init2Check: false,
90 		_pShKey: null,
91 	},
92 	{
93 		_pFunc: null,
94 	},
95 	{
96 		_itemName: `Quoted-printable Encode`w,
97 		_pFunc: &.convertToQuotedPrintable,
98 		_init2Check: false,
99 		_pShKey: null,
100 	},
101 	{
102 		_itemName: `Quoted-printable Decode`w,
103 		_pFunc: &.convertToAsciiFromQuotedPrintable,
104 		_init2Check: false,
105 		_pShKey: null,
106 	},
107 	{
108 		_pFunc: null,
109 	},
110 	{
111 		_itemName: `URL Encode`w,
112 		_pFunc: &.convertURLMinEncode,
113 		_init2Check: false,
114 		_pShKey: null,
115 	},
116 	{
117 		_itemName: `Full URL Encode`w,
118 		_pFunc: &.convertURLFullEncode,
119 		_init2Check: false,
120 		_pShKey: null,
121 	},
122 	{
123 		_itemName: `URL Decode`w,
124 		_pFunc: &.convertURLDecode,
125 		_init2Check: false,
126 		_pShKey: null,
127 	},
128 	{
129 		_pFunc: null,
130 	},
131 	{
132 		_itemName: `SAML Decode`w,
133 		_pFunc: &.convertSamlDecode,
134 		_init2Check: false,
135 		_pShKey: null,
136 	},
137 	{
138 		_pFunc: null,
139 	},
140 	{
141 		_itemName: `About`w,
142 		_pFunc: &.about,
143 		_init2Check: false,
144 		_pShKey: null,
145 	},
146 ];
147 
148 nothrow @nogc
149 core.sys.windows.windef.HWND getCurrentScintillaHandle()
150 
151 	do
152 	{
153 		static import npp_api.pluginfunc.npp_msgs;
154 
155 		int currentEdit;
156 		npp_api.pluginfunc.npp_msgs.send_NPPM_GETCURRENTSCINTILLA(nppData._nppHandle, currentEdit);
157 
158 		return (currentEdit == 0) ? (nppData._scintillaMainHandle) : (nppData._scintillaSecondHandle);
159 	}
160 
161 nothrow
162 void convertAsciiToBase64(size_t wrapLength, bool padFlag, bool byLineFlag)
163 
164 	do
165 	{
166 		static import core.sys.windows.windef;
167 		static import npp_api.pluginfunc.scintilla_msg;
168 		static import npp_mimetools.b64;
169 
170 		core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle();
171 		size_t selectedLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla);
172 
173 		if (selectedLength == 0) {
174 			return;
175 		}
176 
177 		char[] selectedText = new char[selectedLength];
178 		npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla);
179 		npp_api.pluginfunc.scintilla_msg.send_SCI_GETTARGETTEXT(hCurrScintilla, &(selectedText[0]));
180 
181 		size_t bufferLength = (selectedLength + 2) / 3 * 4 + 1;
182 
183 		if (wrapLength > 0) {
184 			bufferLength += bufferLength / wrapLength;
185 		}
186 
187 		char[] encodedText = new char[bufferLength + 1];
188 
189 		int len = npp_mimetools.b64.base64Encode(encodedText, selectedText, selectedLength - 1, wrapLength, padFlag, byLineFlag);
190 		encodedText[len] = '\0';
191 
192 		npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla);
193 		npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(encodedText[0]));
194 	}
195 
196 extern (C)
197 nothrow
198 void convertToBase64FromAscii()
199 
200 	do
201 	{
202 		.convertAsciiToBase64(0, false, false);
203 	}
204 
205 extern (C)
206 nothrow
207 void convertToBase64FromAscii_pad()
208 
209 	do
210 	{
211 		.convertAsciiToBase64(0, true, false);
212 	}
213 
214 extern (C)
215 nothrow
216 void convertToBase64FromAscii_B64Format()
217 
218 	do
219 	{
220 		.convertAsciiToBase64(64, true, false);
221 	}
222 
223 extern (C)
224 nothrow
225 void convertToBase64FromAscii_byline()
226 
227 	do
228 	{
229 		.convertAsciiToBase64(0, false, true);
230 	}
231 
232 nothrow
233 void convertBase64ToAscii(bool strictFlag, bool whitespaceReset)
234 
235 	do
236 	{
237 		static import core.sys.windows.windef;
238 		static import core.sys.windows.winuser;
239 		static import npp_api.pluginfunc.scintilla_msg;
240 		static import npp_api.pluginfunc.string;
241 		static import npp_mimetools.b64;
242 
243 		core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle();
244 		size_t selectedLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla);
245 
246 		if (selectedLength == 0) {
247 			return;
248 		}
249 
250 		char[] selectedText = new char[selectedLength];
251 		npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla);
252 		npp_api.pluginfunc.scintilla_msg.send_SCI_GETTARGETTEXT(hCurrScintilla, &(selectedText[0]));
253 
254 		char[] decodedText = new char[selectedLength];
255 
256 		int len = npp_mimetools.b64.base64Decode(decodedText, selectedText, selectedLength - 1, strictFlag, whitespaceReset);
257 
258 		if (len < 0) {
259 			core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Problem!`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`Base64`)[0]), core.sys.windows.winuser.MB_OK);
260 		} else {
261 			decodedText[len] = '\0';
262 			npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla);
263 			npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(decodedText[0]));
264 		}
265 	}
266 
267 extern (C)
268 nothrow
269 void convertToAsciiFromBase64()
270 
271 	do
272 	{
273 		.convertBase64ToAscii(false, false);
274 	}
275 
276 extern (C)
277 nothrow
278 void convertToAsciiFromBase64_strict()
279 
280 	do
281 	{
282 		.convertBase64ToAscii(true, false);
283 	}
284 
285 extern (C)
286 nothrow
287 void convertToAsciiFromBase64_whitespaceReset()
288 
289 	do
290 	{
291 		.convertBase64ToAscii(false, true);
292 	}
293 
294 extern (C)
295 nothrow
296 void convertURLMinEncode()
297 
298 	do
299 	{
300 		.convertURLEncode(false);
301 	}
302 
303 extern (C)
304 nothrow
305 void convertURLFullEncode()
306 
307 	do
308 	{
309 		.convertURLEncode(true);
310 	}
311 
312 nothrow
313 void convertURLEncode(bool encodeAll)
314 
315 	do
316 	{
317 		static import core.stdc.string;
318 		static import core.sys.windows.windef;
319 		static import npp_api.pluginfunc.scintilla_msg;
320 		static import npp_mimetools.url;
321 
322 		core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle();
323 		size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla);
324 
325 		if (bufLength == 0) {
326 			return;
327 		}
328 
329 		char[] selectedText = new char[bufLength];
330 		char[] pEncodedText = new char[bufLength * 3];
331 		npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0]));
332 
333 		size_t len = npp_mimetools.url.AsciiToUrl(pEncodedText, selectedText, encodeAll);
334 		size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla);
335 		size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla);
336 
337 		if (end < start) {
338 			size_t tmp = start;
339 			start = end;
340 			end = tmp;
341 		}
342 
343 		npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start);
344 		npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end);
345 		npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(pEncodedText[0]));
346 		npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len);
347 	}
348 
349 extern (C)
350 nothrow
351 void convertURLDecode()
352 
353 	do
354 	{
355 		static import core.stdc.string;
356 		static import core.sys.windows.windef;
357 		static import core.sys.windows.winuser;
358 		static import npp_api.pluginfunc.scintilla_msg;
359 		static import npp_api.pluginfunc.string;
360 		static import npp_mimetools.url;
361 
362 		core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle();
363 		size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla);
364 
365 		if (bufLength == 0) {
366 			return;
367 		}
368 
369 		char[] selectedText = new char[bufLength];
370 		npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0]));
371 		char[] pDecodedText = new char[bufLength];
372 
373 		size_t len = npp_mimetools.url.UrlToAscii(pDecodedText, selectedText);
374 
375 		if (len == 0) {
376 			core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Encoding Invalid!`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`URL Decode`)[0]), core.sys.windows.winuser.MB_OK);
377 		} else {
378 			size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla);
379 			size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla);
380 
381 			if (end < start) {
382 				size_t tmp = start;
383 				start = end;
384 				end = tmp;
385 			}
386 
387 			npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start);
388 			npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end);
389 			npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(pDecodedText[0]));
390 			npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len);
391 		}
392 	}
393 
394 enum qpOp
395 {
396 	qp_encode,
397 	qp_decode,
398 }
399 
400 nothrow
401 void quotedPrintableConvert(.qpOp op)
402 
403 	do
404 	{
405 		static import core.stdc.string;
406 		static import core.sys.windows.windef;
407 		static import core.sys.windows.winuser;
408 		static import npp_api.pluginfunc.scintilla_msg;
409 		static import npp_api.pluginfunc.string;
410 		static import npp_mimetools.qp;
411 
412 		core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle();
413 		size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla);
414 
415 		if (bufLength == 0) {
416 			return;
417 		}
418 
419 		char[] selectedText = new char[bufLength];
420 		npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0]));
421 
422 		string qpText;
423 		npp_mimetools.qp.QuotedPrintable qp;
424 
425 		if (op == .qpOp.qp_decode) {
426 			qpText = qp.decode(selectedText);
427 
428 			if (qpText == null) {
429 				core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`It's not a valid Quoted-printable text`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`Quoted-printable decode error`)[0]), core.sys.windows.winuser.MB_OK);
430 
431 				return;
432 			}
433 		} else {
434 			qpText = qp.encode(selectedText);
435 		}
436 
437 		if (qpText ==  null) {
438 			core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Problem!`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`Quoted-printable encoding`)[0]), core.sys.windows.winuser.MB_OK);
439 		} else {
440 			size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla);
441 			size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla);
442 
443 			if (end < start) {
444 				size_t tmp = start;
445 				start = end;
446 				end = tmp;
447 			}
448 
449 			npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start);
450 			npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end);
451 			npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, core.stdc..string.strlen(&(qpText[0])), &(qpText[0]));
452 			npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + core.stdc..string.strlen(&(qpText[0])));
453 		}
454 	}
455 
456 extern (C)
457 nothrow
458 void convertToAsciiFromQuotedPrintable()
459 
460 	do
461 	{
462 		.quotedPrintableConvert(.qpOp.qp_decode);
463 	}
464 
465 extern (C)
466 nothrow
467 void convertToQuotedPrintable()
468 
469 	do
470 	{
471 		.quotedPrintableConvert(.qpOp.qp_encode);
472 	}
473 
474 extern (Windows)
475 nothrow @nogc
476 core.sys.windows.windef.BOOL dlgProc(core.sys.windows.windef.HWND hwnd, core.sys.windows.windef.UINT message, core.sys.windows.windef.WPARAM wParam, core.sys.windows.windef.LPARAM lParam)
477 
478 	do
479 	{
480 		static import core.sys.windows.windef;
481 		static import core.sys.windows.winuser;
482 
483 		switch (message) {
484 			case core.sys.windows.winuser.WM_COMMAND:
485 				switch (core.sys.windows.windef.LOWORD(wParam)) {
486 					case core.sys.windows.winuser.IDCLOSE:
487 						core.sys.windows.winuser.EndDialog(hwnd, 0);
488 
489 						return core.sys.windows.windef.TRUE;
490 
491 					default:
492 						break;
493 				}
494 
495 				return core.sys.windows.windef.FALSE;
496 
497 			default:
498 				break;
499 		}
500 
501 		return core.sys.windows.windef.FALSE;
502 	}
503 
504 extern (C)
505 nothrow @nogc
506 void about()
507 
508 	do
509 	{
510 		static import core.sys.windows.windef;
511 		static import core.sys.windows.winuser;
512 
513 		core.sys.windows.windef.HWND hSelf = core.sys.windows.winuser.CreateDialogParamW(_hInst, core.sys.windows.winuser.MAKEINTRESOURCEW(.IDD_ABOUTBOX), nppData._nppHandle, cast(core.sys.windows.winuser.DLGPROC)(&.dlgProc), 0);
514 
515 		// Go to center
516 		core.sys.windows.windef.RECT rc;
517 		core.sys.windows.winuser.GetClientRect(nppData._nppHandle, &rc);
518 		core.sys.windows.windef.POINT center;
519 		int w = rc.right - rc.left;
520 		int h = rc.bottom - rc.top;
521 		center.x = rc.left + w / 2;
522 		center.y = rc.top + h / 2;
523 		core.sys.windows.winuser.ClientToScreen(nppData._nppHandle, &center);
524 
525 		core.sys.windows.windef.RECT dlgRect;
526 		core.sys.windows.winuser.GetClientRect(hSelf, &dlgRect);
527 		int x = center.x - (dlgRect.right - dlgRect.left) / 2;
528 		int y = center.y - (dlgRect.bottom - dlgRect.top) / 2;
529 
530 		core.sys.windows.winuser.SetWindowPos(hSelf, core.sys.windows.winuser.HWND_TOP, x, y, (dlgRect.right - dlgRect.left), (dlgRect.bottom - dlgRect.top), core.sys.windows.winuser.SWP_SHOWWINDOW);
531 	}
532 
533 extern (C)
534 nothrow
535 void convertSamlDecode()
536 
537 	do
538 	{
539 		static import core.stdc.string;
540 		static import core.sys.windows.windef;
541 		static import core.sys.windows.winuser;
542 		static import npp_api.pluginfunc.scintilla_msg;
543 		static import npp_api.pluginfunc.string;
544 
545 		core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle();
546 		size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla);
547 
548 		if (bufLength == 0) {
549 			return;
550 		}
551 
552 		char[] selectedText = new char[bufLength];
553 		char[] samlDecodedText = new char[npp_mimetools.saml.SAML_MESSAGE_MAX_SIZE];
554 		npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0]));
555 
556 		int len = npp_mimetools.saml.samlDecode(samlDecodedText, selectedText);
557 
558 		switch (len) {
559 			case 0:
560 				core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode returned zero size.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK);
561 
562 				break;
563 
564 			case npp_mimetools.saml.SAML_DECODE_ERROR_URLDECODE:
565 				core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Could not URL Decode text.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK);
566 
567 				break;
568 
569 			case npp_mimetools.saml.SAML_DECODE_ERROR_BASE64DECODE:
570 				core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Could not BASE64 Decode text after URL Decoding.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK);
571 
572 				break;
573 
574 			case npp_mimetools.saml.SAML_DECODE_ERROR_INFLATE:
575 				core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Could not inflate text after BASE64 Decoding.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK);
576 
577 				break;
578 
579 			default:
580 				size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla);
581 				size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla);
582 
583 				if (end < start) {
584 					size_t tmp = start;
585 					start = end;
586 					end = tmp;
587 				}
588 
589 				npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start);
590 				npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end);
591 				npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(samlDecodedText[0]));
592 				npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len);
593 		}
594 	}
595 
596 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(PLUGIN_NAME, .main_menu_items_def);