New API to fix eventual regression regarding SCN_MODIFIED for some plugins
-
From v8.7.6, Notepad++ forwards only SCN_MODIFIED with the following 5 notification flags SC_MOD_DELETETEXT, SC_MOD_INSERTTEXT, SC_PERFORMED_UNDO, SC_PERFORMED_REDO and SC_MOD_CHANGEINDICATOR to plugins.
So if your plugin processes the events of SCN_MODIFIED other than the above 5 ones, for example SC_MOD_DELETETEXT and SC_MOD_INSERTTEXT, then it’s broken with v8.7.6 and later versions.
To remedy this “regression” of v8.7.6, a new message
NPPM_ADDSCNMODIFIEDFLAGS
is introduced in v8.7.7 for plugins which process the events of SCN_MODIFIED other than 5 default ones. All you need is add the notifications you need by sending this message to Notepad++, just after recieving NPPN_READY.New message:
BOOL NPPM_ADDSCNMODIFIEDFLAGS(0, unsigned long scnMotifiedFlags2Add)
Description:
Add needed SCN_MODIFIED flags so your plugin will recieve the notification SCN_MODIFIED of these events for your specific treatments.
By default, Notepad++ only forwards SCN_MODIFIED with the following 5 flags/events SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT | SC_PERFORMED_UNDO | SC_PERFORMED_REDO | SC_MOD_CHANGEINDICATOR to plugins.
If your plugin need to process other events of SCN_MODIFIED, you should add the flags you need by sending this message to Notepad++, just after recieving NPPN_READY.- wParam: 0 (not used)
- lParam[in]: scnMotifiedFlags2Add- Scintilla SCN_MODIFIED flags to add.
- Return TRUE
Example:
extern "C" __declspec(dllexport) void beNotified(SCNotification* notifyCode) { switch (notifyCode->nmhdr.code) { case NPPN_READY: { // Add SC_MOD_BEFOREDELETE and SC_MOD_BEFOREINSERT notifications ::SendMessage(nppData._nppHandle, NPPM_ADDSCNMODIFIEDFLAGS, 0, SC_MOD_BEFOREDELETE | SC_MOD_BEFOREINSERT); } break; ... } ... }
-
D donho pinned this topic on
-
@donho
nitpicking - since these notifications are used in lparam, they are actually intptr_t and not uintptr_t. -
@donho said in New API to fix eventual regression for some plugins:
From v8.7.6, Notepad++ forwards only the following 5 default notification SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT | SC_PERFORMED_UNDO | SC_PERFORMED_REDO | SC_MOD_CHANGEINDICATOR to plugins.
I know what you wrote isn’t what you meant, but if taken literally that statement will cause many plugin authors to panic and/or give up hope.
There are many notifications Scintilla sends on which plugins depend. (For example, I believe any usable implementation of elastic tabstops — not just mine — must process SCN_UPDATEUI; setting custom tabstops in Scintilla is slow enough that it’s essential to do it only for visible lines. To do that, you have to monitor display changes, such as scrolling. SCN_UPDATEUI is also the reasonable place to “batch” any kind of processing that is better done all at once that one bit at a time.)
The flags you are processing in NPPM_ADDSCINTILLANOTIFS are the bits of the Event Mask for one specific notification, SCN_MODIFIED.
I don’t mean to be crabby about it… it’s just that, as written, your statement is inaccurate, and I fear it could be misinterpreted as meaning what it says.
So if your plugin processes other notifications than the above 5 ones, for example SC_MOD_DELETETEXT and SC_MOD_INSERTTEXT, then it’s broken with v8.7.6 and later version.
You gave as examples events that you say are already included. I think you meant SC_MOD_BEFOREDELETE and SC_MOD_BEFOREINSERT.
Perhaps it would be best to say that plugins should enable all SCN_MODIFIED events they wish to monitor? The five you gave are the default for now… why assume they won’t change again?
-
@Coises said in New API to fix eventual regression for some plugins:
The five [modification flags] are the default for now… why assume they won’t change again?
It would be best to expose the default flags to the plugin interface, e.g.,
#define DEFAULT_SC_MOD_FLAGS /* SC_MOD_DELETETEXT | ...., etc. */
Then plugins can just do a bitwise operation on
DEFAULT_SC_MOD_FLAGS
to discover what’s available and what’s not.If the defaults change in the future, just edit the interface header file. Since there’s not going to be a companion
*_GET_SC_MOD_FLAGS
message, it’s better than nothing. -
@rdipardo said in New API to fix eventual regression for some plugins:
Since there’s not going to be a companion
*_GET_SC_MOD_FLAGS
message, it’s better than nothing.If for some reason a plugin wants to know what event mask is set but doesn’t want to specify its own events, SCI_GETMODEVENTMASK will tell it. (Note that the reason we can’t just use SCI_SETMODEVENTMASK instead of this new message is that Notepad++ turns the mask off — sets it to zero to suppress all SCN_MODIFIED notifications — and back on under various conditions to improve efficiency. I suppose it could save the value when it does that and then restore it, but that’s not the approach that was chosen.) I’m not sure if the default event mask is set during NPPN_READY (I haven’t parsed the code that far yet); if I’m reading the code correctly, it doesn’t change during NPPM_ADDSCINTILLANOTIFS processing, so either you would get the default then or you would get nothing meaningful. You could get the end result of all plugins’ additions during any subsequent command or notification.
The intent, though, is that you just tell Notepad++ which SCN_MODIFIED events you need enabled. My suggestion was to define “best practice” as including all the events you need, even if they are currently included in the defaults.
-
I’m glad @donho is responding so quickly to the needs of the plugin community. Thanks!
@Coises said in New API to fix eventual regression for some plugins:
I know what you wrote isn’t what you meant, but if taken literally that statement will cause many plugin authors to panic and/or give up hope.
There are many notifications Scintilla sends on which plugins depend.
Agree with this. I think that before this API is released in the wild, the message should be renamed to
NPPM_ADDSCNMODIFIEDFLAGS
. That name is about the same length and more clearly communicates the intent of the message. -
@Coises said in New API to fix eventual regression for some plugins:
I know what you wrote isn’t what you meant, but if taken literally that statement will cause many plugin authors to panic and/or give up hope.
I was there momentarily, but your post explains it perfectly and the only time in PythonScript scripts or my own C++ plugins I use
SCN_MODIFIED
is when I’m looking forSC_MOD_INSERT/DELETETEXT
. Indeed a quick check of functionality in N++ 8.7.6 shows I’m still working fine.Also, your
SCI_GETMODEVENTMASK
hint is useful. I used NppExec to get it:SCI_SENDMSG SCI_GETMODEVENTMASK echo $(MSG_RESULT)
and in N++ pre 8.7.6 it is = 8388607(which I didn’t bother “decoding”),
while in N++ 8.7.6 it is = 16483 (which from your link equates to the 5 messages N++ still forwards by default).Cheers.
-
@Coises
You’re absolutely right about it - it was not accurate at all.
I’ve reworded the announcement title & content to make it more consistent and clearer.Thank you everyone for providing your valuable opinions.
Please let me know if there are any other points that could be improved. -
D donho referenced this topic on
-
@donho said in New API to fix eventual regression regarding SCN_MODIFIED for some plugins:
Please let me know if there are any other points that could be improved.
One observation and one technical question.
Observation:
A small point, but the comments here still use adding SC_MOD_DELETETEXT and SC_MOD_INSERTTEXT as an example, when they are already part of the default. I think you meant to use SC_MOD_BEFOREDELETE and SC_MOD_BEFOREINSERT as examples. Also — and I understand you might not agree — would it not be better, as a matter of “future-proofing,” to illustrate best practice as explicitly enabling all SCN_MODIFIED events the plugin plans to use, even if they are (currently) part of the default set?
Technical question:
My plugin might or might not need SCN_MODIFIED events (including SC_MOD_BEFOREDELETE). Must NPPM_ADDSCNMODIFIEDFLAGS be sent in NPPN_READY, or can I wait and send it only if and when the user does something which enables the feature (elastic tabstops) that makes use of these events? I understand that once any plugin enables them, they will remain enabled for the entire session. I’m just wondering if I can avoid imposing the performance loss you documented on users who have Columns++ installed but don’t always (or perhaps never) use the elastic tabstops feature.
I’m a lot slower at getting things changed than you are… but my eventual goal now will be to eliminate using SC_MOD_BEFOREDELETE. (In my implementation of elastic tabstops, it has always been a work-around for a common case which exposes an underlying weakness in my design.) In the meantime I’d like to avoid making users pay a performance penalty, relative to unaugmented Notepad++, just for having the plugin installed.
-
@Coises said in New API to fix eventual regression regarding SCN_MODIFIED for some plugins:
A small point, but the comments here still use adding SC_MOD_DELETETEXT and SC_MOD_INSERTTEXT as an example, when they are already part of the default. I think you meant to use SC_MOD_BEFOREDELETE and SC_MOD_BEFOREINSERT as examples.
Fixed. Thank you for pointing out this issue.
Also — and I understand you might not agree — would it not be better, as a matter of “future-proofing,” to illustrate best practice as explicitly enabling all SCN_MODIFIED events the plugin plans to use, even if they are (currently) part of the default set?
What do you mean exactely “to illustrate best practice as explicitly enabling all SCN_MODIFIED events the plugin plans to use”?
My plugin might or might not need SCN_MODIFIED events (including SC_MOD_BEFOREDELETE). Must NPPM_ADDSCNMODIFIEDFLAGS be sent in NPPN_READY, or can I wait and send it only if and when the user does something which enables the feature (elastic tabstops) that makes use of these events? I understand that once any plugin enables them, they will remain enabled for the entire session. I’m just wondering if I can avoid imposing the performance loss you documented on users who have Columns++ installed but don’t always (or perhaps never) use the elastic tabstops feature.
I just modified the code for your specific requirement (and it’s a good one):
https://github.com/notepad-plus-plus/notepad-plus-plus/commit/d888fb5f1263f5ea036c610b6980e5c4381ce7ebSo yes, you can send NPPM_ADDSCNMODIFIEDFLAGS anytime you want now - even if you want to set the different events separately at the different time, according users’ need.
-
@donho said in New API to fix eventual regression regarding SCN_MODIFIED for some plugins:
What do you mean exactely “to illustrate best practice as explicitly enabling all SCN_MODIFIED events the plugin plans to use”?
I just mean, should examples and documentation suggest that if a plugin uses SC_MOD_INSERT (which is part of the default) and SC_MOD_BEFOREDELETE (which isn’t), it should send:
SC_MOD_INSERT | SC_MOD_BEFOREDELETE
and not just:
SC_MOD_BEFOREDELETE
so as not to assume SC_MOD_INSERT will always be part of the default? I understand that you might be so certain that the default will not change in the future that there is no point to this.Should a plugin care what the default mask is? I mention it because I personally don’t see any advantage to plugins being dependent on the default; it doesn’t hurt anything to specify every event that will be used. Once we give plugins the responsibility to declare which events they need enabled, why not routinely declare all of them instead of relying on a particular set of defaults?
So yes, you can send NPPM_ADDSCNMODIFIEDFLAGS anytime you want now - even if you want to set the different events separately at the different time, according users’ need.
Thank you. That makes me feel better about using this message (though I still hope to find time to re-design my way around it eventually).
-
@Coises said in New API to fix eventual regression regarding SCN_MODIFIED for some plugins:
Should a plugin care what the default mask is? I mention it because I personally don’t see any advantage to plugins being dependent on the default; it doesn’t hurt anything to specify every event that will be used. Once we give plugins the responsibility to declare which events they need enabled, why not routinely declare all of them instead of relying on a particular set of defaults?
you’re not wrong about this point.
However, the authors of concerning plugins won’t understand why SCN_MODIFIED works with their plugins work under v8.7.5 & previous versions but not under v8.7.6 & later version.
So the 5 events used by Notepad++ are listed to address to the regression for the historic reason,With the example you provided, plugins use SC_MOD_INSERT | SC_MOD_BEFOREDELETE or only SC_MOD_BEFOREDELETE will get the same effect. I don’t see any inconvenience about it.
Of course, you’re encouraged to improve the document of this message to make your point clearer, if it’s not too redundant.