Skip to content

Commit 6f3d57b

Browse files
authored
add new Notepad message NPPM_ADDSCNMODIFIEDFLAGS (#376)
* add new Notepad message NPPM_ADDSCNMODIFIEDFLAGS * remove unneeded include Enums.h from NotepadPlusWrapper.h * Add an add_modification_flag test to test invalid values * Fix test_scintillawrapper_int_int_stringresult_in_callback_getCurLine is calling wrong function
1 parent 4c86653 commit 6f3d57b

File tree

7 files changed

+71
-2
lines changed

7 files changed

+71
-2
lines changed

NppPlugin/include/Notepad_plus_msgs.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,34 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64, PF_ARM64 };
990990
// lParam[out]: language file name string receives all copied native language file name string
991991
// Return the number of char copied/to copy
992992

993+
#define NPPM_ADDSCNMODIFIEDFLAGS (NPPMSG + 117)
994+
// BOOL NPPM_ADDSCNMODIFIEDFLAGS(0, unsigned long scnMotifiedFlags2Add)
995+
// Add the necessary SCN_MODIFIED flags so that your plugin will receive the SCN_MODIFIED notification for these events, enabling your specific treatments.
996+
// By default, Notepad++ only forwards SCN_MODIFIED with the following 5 flags/events:
997+
// SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT | SC_PERFORMED_UNDO | SC_PERFORMED_REDO | SC_MOD_CHANGEINDICATOR to plugins.
998+
// If your plugin needs to process other SCN_MODIFIED events, you should add the required flags by sending this message to Notepad++. You can send it immediately after receiving NPPN_READY,
999+
// or only when your plugin needs to listen to specific events (to avoid penalizing Notepad++'s performance). Just ensure that the message is sent only once.
1000+
// wParam: 0 (not used)
1001+
// lParam[in]: scnMotifiedFlags2Add - Scintilla SCN_MODIFIED flags to add.
1002+
// Return TRUE
1003+
//
1004+
// Example:
1005+
//
1006+
// extern "C" __declspec(dllexport) void beNotified(SCNotification* notifyCode)
1007+
// {
1008+
// switch (notifyCode->nmhdr.code)
1009+
// {
1010+
// case NPPN_READY:
1011+
// {
1012+
// // Add SC_MOD_BEFOREDELETE and SC_MOD_BEFOREINSERT to listen to the 2 events of SCN_MODIFIED
1013+
// ::SendMessage(nppData._nppHandle, NPPM_ADDSCNMODIFIEDFLAGS, 0, SC_MOD_BEFOREDELETE | SC_MOD_BEFOREINSERT);
1014+
// }
1015+
// break;
1016+
// ...
1017+
// }
1018+
// ...
1019+
// }
1020+
9931021
// For RUNCOMMAND_USER
9941022
#define VAR_NOT_RECOGNIZED 0
9951023
#define FULL_CURRENT_PATH 1

PythonScript/python_tests/tests/test_NotepadCallbackTestCase.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import time
44
import tempfile
55
import os
6-
from Npp import notepad, editor, NOTIFICATION, LANGTYPE, SCINTILLANOTIFICATION
6+
from Npp import notepad, editor, NOTIFICATION, LANGTYPE, SCINTILLANOTIFICATION, MODIFICATIONFLAGS
77

88
globalCallbackCalled = False
99

@@ -188,5 +188,29 @@ def callback_with_disallowed_sync_method(self, args):
188188
notepad.activateBufferID(self.oldBufferID)
189189
self.callbackCalled = True
190190

191+
def callback_editor_before_modified(self, args):
192+
flags = args["modificationType"]
193+
self.assertTrue((flags & MODIFICATIONFLAGS.BEFOREDELETE != 0) or (flags & MODIFICATIONFLAGS.BEFOREINSERT != 0))
194+
self.callbackCalled = True
195+
196+
def test_add_modification_flags(self):
197+
original_mask = editor.getModEventMask()
198+
self.assertTrue(notepad.addModificationFlags(MODIFICATIONFLAGS.BEFOREDELETE | MODIFICATIONFLAGS.BEFOREINSERT))
199+
editor.setModEventMask(MODIFICATIONFLAGS.BEFOREDELETE | MODIFICATIONFLAGS.BEFOREINSERT)
200+
editor.callback(lambda a: self.callback_editor_before_modified(a), [SCINTILLANOTIFICATION.MODIFIED])
201+
editor.write('A')
202+
self.poll_for_callback()
203+
self.assertTrue(self.callbackCalled, "BEFOREINSERT test failed, callback not called")
204+
self.callbackCalled = False
205+
editor.undo()
206+
self.poll_for_callback()
207+
self.assertTrue(self.callbackCalled, "BEFOREDELETE test failed, callback not called")
208+
editor.setModEventMask(original_mask)
209+
210+
def test_add_modification_flags_invalid(self):
211+
with self.assertRaises(RuntimeError):
212+
notepad.addModificationFlags(0x800000)
213+
214+
191215

192216
suite = unittest.TestLoader().loadTestsFromTestCase(NotepadCallbackTestCase)

PythonScript/python_tests/tests/test_ScintillaWrapperTestCase.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ def callback_scintillawrapper_int_int_stringresult_getCurLine(self, args):
664664
self.callbackCalled = True
665665

666666
def test_scintillawrapper_int_int_stringresult_in_callback_getCurLine(self):
667-
editor.callback(lambda args: self.callback_scintillawrapper_int_int_stringresult_getLine(args), [SCINTILLANOTIFICATION.MODIFIED])
667+
editor.callback(lambda args: self.callback_scintillawrapper_int_int_stringresult_getCurLine(args), [SCINTILLANOTIFICATION.MODIFIED])
668668
editor.write("One\r\nTwo\r\nThree")
669669
self.poll_for_callback()
670670
self.assertEqual(self.callbackCalled, True)

PythonScript/src/NotepadPlusWrapper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "MainThread.h"
1515
#include "ScintillaCallbackCounter.h"
1616
#include "InvalidValueProvidedException.h"
17+
#include "Enums.h"
1718

1819
namespace NppPythonScript
1920
{
@@ -1124,6 +1125,13 @@ bool NotepadPlusWrapper::isAutoIndention() {
11241125
return static_cast<bool>(callNotepad(NPPM_ISAUTOINDENTON));
11251126
}
11261127

1128+
bool NotepadPlusWrapper::addModificationFlags(uint32_t flags) {
1129+
if ((flags & ~PYSCR_SC_MODEVENTMASKALL) != 0) {
1130+
throw InvalidValueProvidedException("Provided flags value is not a valid MODIFICATION enum value.");
1131+
}
1132+
return static_cast<bool>(callNotepad(NPPM_ADDSCNMODIFIEDFLAGS, 0, static_cast<LPARAM>(flags)));
1133+
}
1134+
11271135
bool NotepadPlusWrapper::isSingleView() const
11281136
{
11291137
HWND splitter_hwnd = FindWindowEx(m_nppHandle, NULL, L"splitterContainer", NULL);

PythonScript/src/NotepadPlusWrapper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,8 @@ class NotepadPlusWrapper
869869
boost::python::object NotepadPlusWrapper::getExternalLexerAutoIndentMode(const char* externalLexerName);
870870
bool NotepadPlusWrapper::setExternalLexerAutoIndentMode(const char* externalLexerName, AutoIndentMode indentMode);
871871
bool NotepadPlusWrapper::isAutoIndention();
872+
873+
bool NotepadPlusWrapper::addModificationFlags(uint32_t flags);
872874

873875
bool isSingleView() const;
874876
void flashWindow(UINT count, DWORD timeout) const;

PythonScript/src/NotepadPython.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ void export_notepad()
134134
.def("getExternalLexerAutoIndentMode", &NotepadPlusWrapper::getExternalLexerAutoIndentMode, boost::python::args("externalLexerName"), "Get ExternalLexerAutoIndentMode for an installed external programming language.")
135135
.def("setExternalLexerAutoIndentMode", &NotepadPlusWrapper::setExternalLexerAutoIndentMode, boost::python::args("externalLexerName", "indentMode"), "Set ExternalLexerAutoIndentMode for an installed external programming language.")
136136
.def("isAutoIndention", &NotepadPlusWrapper::isAutoIndention, "Returns True if autoindention is enabled else False")
137+
.def("addModificationFlags", &NotepadPlusWrapper::addModificationFlags, boost::python::args("flags"), "Returns True if successful, else False")
137138

138139
.def("isSingleView", &NotepadPlusWrapper::isSingleView, "True if only one view is used, False otherwise")
139140
.def("flashWindow", &NotepadPlusWrapper::flashWindow, boost::python::args("count", "milliseconds"), "Flashes notepad++ for the given count and timeout");

docs/source/notepad.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ Notepad++ Object
2929
*view* is 0 or 1.
3030

3131

32+
.. method:: notepad.addModificationFlags(flags)
33+
34+
A bitwise OR combination of values from the :class:`MODIFICATIONFLAGS` enum.
35+
36+
37+
3238
.. method:: notepad.allocateCmdID(numberRequested) -> int
3339

3440
Allocates a range of Command ID for use in WM_COMMAND. Mainly used internally by plugins.

0 commit comments

Comments
 (0)