Is there a SCI_SETLINE type message (How to update a line)
-
@Paul-Baker said in Is there a SCI_SETLINE type message (How to update a line):
If you see any errors, please let me know.
You are leaking memory; you allocate new C-style strings, but you never delete them.
Recommendation: Save yourself some grief and use the fact that as of C++17 you can modify the data of a std::string. (You can even overwrite the trailing null that comes one after the length, so long as you overwrite it with another null.)
// Get the current line. lineLen = endPos - strPos; std::string lineText(lineLen, 0); ::SendMessage(curScint, SCI_SETTARGETRANGE, strPos, endPos); ::SendMessage(curScint, SCI_GETTARGETTEXT, 0, reinterpret_cast<LPARAM>(lineText.data())); // Do something. ::SendMessage(curScint, SCI_REPLACETARGET, static_cast<WPARAM>(-1), reinterpret_cast<LPARAM>(lineText.data()));
-
@Coises Thanks, I struggled with that. I’ll try your suggestions.
-
@Paul-Baker said in Is there a SCI_SETLINE type message (How to update a line):
I’m not a c++ guy
Maybe you should consider writing your plugin in a language you are comfortable in?
Caveat: Perhaps getting started without a template could be a hurdle…Or consider scripting instead of a plugin?
There’s no shame in scripting. :-) -
@Paul-Baker Updated without mem leaks
void updateCOBOLComments() { // Get handle to Scintilla editor int currentEdit; ::SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)¤tEdit); HWND curScint = (currentEdit == 0) ? nppData._scintillaMainHandle : nppData._scintillaSecondHandle; // Get selection start and end positions. // If selectionStr and selectionEnd are equal then there is no selection, // just process the line the caret is on. int strSel = (int)::SendMessage(curScint, SCI_GETSELECTIONSTART, 0, 0); int endSel = (int)::SendMessage(curScint, SCI_GETSELECTIONEND, 0, 0); // Get the line numbers associated with the start and end positions. // The strLine and endLine may be the same line. int strLine = (int)::SendMessage(curScint, SCI_LINEFROMPOSITION, strSel, 0); int endLine = (int)::SendMessage(curScint, SCI_LINEFROMPOSITION, endSel, 0); size_t lineLen; std::string lineText = ""; int strPos; int endPos; for (int lineNum = strLine; lineNum <= endLine; lineNum++) { // Calculate line size by getting the line start and end positions strPos = (int) ::SendMessage(curScint, SCI_POSITIONFROMLINE, lineNum, 0); endPos = (int) ::SendMessage(curScint, SCI_GETLINEENDPOSITION, lineNum, 0); // Get the current line. lineLen = endPos - strPos + 1; lineText.resize(lineLen, ' '); ::SendMessage(curScint, SCI_SETTARGETRANGE, strPos, endPos); ::SendMessage(curScint, SCI_GETTARGETTEXT, 0, reinterpret_cast<LPARAM>(lineText.data())); // ********************************* // ** Modify lineText as needed., * // ********************************* ::SendMessage(curScint, SCI_REPLACETARGET, static_cast<WPARAM>(-1), reinterpret_cast<LPARAM>(lineText.data())); } return; }
-
@Alan-Kilborn No shame… haha… I use to be a scripting basher (no pub intended). My comfortable language is java, then python. Imperative languages are all similar, if-then-else. There are lots of how to blogs for creating npp plugins using cpp and I did not want to make a project out of it. I’m sure there are easy ways to do this for many languages, I just took the path of least resistance. All comments appreciated. Thanks!
-
@Paul-Baker said in Is there a SCI_SETLINE type message (How to update a line):
My comfortable language is java
In that case I recommend this C# plugin template.
I’ve used it for two plugins and helped the development of another. C# is great, and very similar to Java.
-
@Paul-Baker said in Is there a SCI_SETLINE type message (How to update a line):
/* . . . */ int strSel = (int)::SendMessage(curScint, SCI_GETSELECTIONSTART, 0, 0); int endSel = (int)::SendMessage(curScint, SCI_GETSELECTIONEND, 0, 0);
Those type casts are only safe for 32-bit plugins. Scintilla has supported multi-gigabyte files since 4.1.6 (the current version is 5.4.1). While a character position beyond
0x7fffffff
isn’t likely, a 64-bit application would immediately crash if your plugin made one of the above calls in a document over 2 GB in size.It’s best to store all position values as the dynamically sized
Sci_Position
type (an alias forintptr_t
, which is what the API functions actually return).The type definition is probably in your project files already; all recent versions of the main Scintilla header include
Sci_Position.h
. -
@rdipardo Thank you!!! I’ll make that change.
-
@Mark-Olson said in Is there a SCI_SETLINE type message (How to update a line):
In that case I recommend this C# plugin template
Hi Mark, thank you and everyone that has helped me get started with Visual Studio and NPP Plugin development. I looked into c# and yes it is easier.
Here is the same logic I’ve been working on in c#. All works well.
static void toggleCobolComment() { // Get selection start and end positions. // If selStr and selEnd are equal then there is no selection, // just process the line the caret is on. var strSel = editor.GetSelectionStart(); var strEnd = editor.GetSelectionEnd(); // Get the line numbers associated with the start and end positions. // The strLine and endLine may be the same line. var strLine = editor.LineFromPosition(strSel); var endLine = editor.LineFromPosition(strEnd); string lineText = ""; char[] lineTextAsChars; int lineLen = 0; int strPos = 0; int endPos = 0; // Loop through each line and toggle the comment char "*" // in column 7. Skip lines that are shorter than 7 characters. for (var lineNum = strLine; lineNum <= endLine; lineNum++) { // Calculate line size by getting the line start and end positions strPos = editor.PositionFromLine(lineNum); endPos = editor.GetLineEndPosition(lineNum); // Get the current line length lineLen = endPos - strPos + 1; // Skip lines that are empty. if (lineLen <= 6) continue; // Get line text and convert to char array editor.SetTargetRange(strPos, endPos); lineText = editor.GetTargetText(); lineTextAsChars = lineText.ToCharArray(); // Toggle comment character. if (lineTextAsChars[6] == '*') lineTextAsChars[6] = ' '; else lineTextAsChars[6] = '*'; // Convert char array back to string // and update line in editor. lineText = new string(lineTextAsChars); editor.ReplaceTarget(lineText.Length, lineText); } return; }
Thanks again… This thread is closed (for me).
-
@Paul-Baker
I’m glad it’s working!One note I would make (not just for you, for the general public) is that
interacting with Scintilla is really slow compared to the .NET runtime and if you are concerned about performance, you will be much faster if you just slurp all the text out in one go, process it in C#, and then dump it all back into the file. -
@Mark-Olson said in Is there a SCI_SETLINE type message (How to update a line):
much faster if you just slurp all the text out in one go, process it in C#, and then dump it all back into the file
…and watch your change-history go “all orange”, registering every character in the file as “changed”. Secondary concern: It also nullifies a plugin’s opportunity to provide step-by-step undo for possible individual modifications it makes.
For me this would be a big problem, and I wouldn’t use a plugin that did this to me.
Sure, for some people this would be absolutely no problem.
But I wouldn’t make this approach a general recommendation.