d0vgan / nppexec

NppExec (plugin for Notepad++)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Running updated script after editing npes_saved.txt file

David-Maisonave opened this issue · comments

Hi Vitaliy,
Because of language highlighting, and everything else Npp adds as an editor, I modify the npes_saved.txt file directly. I have shortcut keys for each main script listed under the Macro menu, as the following snapshot shows:
NppExecScripts_MenuAndShortcutKeysFor_Execute_Debug_Build_and_Help

But when I modify the npes_saved.txt and run the script, the old version of the script runs. To get it to pickup the changes, I have to run [Execute NppExec Script].
Is there any way to get NppExec to pickup the changes before running the script?
If not, I like to create an update that would have NppExec check the date stamp on the file, and if it has changed since the last run, have it reload the file automatically before running the script.
Is it alright with you if I make that type of pull request?
If I make that change, I'll see if I can include the other changes we talked about in the other thread.

con_colour msg = ...
con_colour err = ...
con_colour highlight = (id) (value) (rgb) (IBU) //Allow scripts to use 11-20 so it doesn't interfere with user GUI settings.
con_custom_msg_ready (value to set or empty string to disable) // Should only effect running script
con_exclude_empty (0/1) // Should only effect running script
con_exclude_dup (0/1) // Should only effect running script
con_colour local err = ... msg = ...  //Anything set with local, will only apply to the running script

I would also like to add the following:

  1. help_all command that would be an alias for "Help All". That would allow npe_cmdalias to work for Help All.
  2. Give con_save the same option that text_saveto has.
  3. Have option to reset env_set PATH when script ends.
  4. And / Or , add option to npe_queue to specify a command to run when script ends. This command should run even if the user kills the script via ctrl-c or ctrl-break.

Please let me know what you think.
Thanks

But when I modify the npes_saved.txt and run the script, the old version of the script runs. To get it to pickup the changes, I have to run [Execute NppExec Script].
Is there any way to get NppExec to pickup the changes before running the script?

Currently the file modification is detected only at the moment of opening the DoExecDlg. This is done in CDoExecDlg::checkScriptFile() by means of g_scriptFileChecker.
I agree with you that it would be better to use the following technique instead:
https://docs.microsoft.com/en-us/windows/win32/fileio/obtaining-directory-change-notifications
With this new approach, there will be no need in CFileModificationChecker class at all and this class can be completely removed.

Is it alright with you if I make that type of pull request?

Yes, I approve it!

If I make that change, I'll see if I can include the other changes we talked about in the other thread.

Just let's avoid temptation to put everything in one pull request. Let's rather use separate pull requests for separate things: this makes the code reviews simplier as well as the development of separate features clearer.

help_all command that would be an alias for "Help All". That would allow npe_cmdalias to work for Help All.

The "help" command itself is available only in NppExec's Console and is not supported by CScriptEngine. Why would one want to call "help" or "help all" from within NppExec's script? I mean, "help" is just an informational command supposed to be run directly from the Console.
As for "help all", there is a file "doc\NppExec\NppExec_HelpAll.txt" that can be opened via Plugins -> NppExec -> Help/Docs. This file is equal to the output of "help all".

Give con_save the same option that text_saveto has.

What is the purpose of saving the Console's content in a different encoding?

Have option to reset env_set PATH when script ends.

What about env_set local PATH ?

And / Or , add option to npe_queue to specify a command to run when script ends. This command should run even if the user kills the script via ctrl-c or ctrl-break.

Isn't npe_queue +s applicable for this?

What is the purpose of saving the Console's content in a different encoding?

With the programming language (Elena) script I'm working on, I need to save the content of the console to a project file, so that Elena can build the script. But it fails if the file was not saved as UTF-8. As a workaround I had to do the following:

con_save $(ProjectFileName)
text_load  $(ProjectFileName)
text_save $(ProjectFileName) :u

But I would like to be able to do just one call con_save $(ProjectFileName) :u. Moreover, having them have the same options would be more consistent.

Why would one want to call "help" or "help all" from within NppExec's script?

I use it in the script to create alias so the user doesn't have to memorize the specific syntex. In my script, I have an alias for help npe_cmdalias h =help. I want to have an alias for help all as well, but it's not possible if it's a two word command.

What about env_set local PATH ?

That's the first thing I tried.
But after getting the PrintMsgReady, when I checked the path on the console via echo $(SYS.PATH) or cmd /c echo path = %PATH% it did not display the changed path.
At that time I assume env_set local PATH was not working at all, but today I created a tiny script to prove or disprove it, and I realized it does work, but not exactly as I expected.

::TestOnlyScript1
echo  $(SYS.PATH)
env_set local PATH =C:\foofoo\;$(SYS.PATH);
echo  $(SYS.PATH)
cmd /c echo path = %PATH%

When I run the above NppExec script, the output does show the changed path, but after I get the PrintMsgReady, I don't see the changed path any more.
I understand the logic better now. The local environmental variables are only applied while the script is running, and are removed before the PrintMsgReady.

But that logic triggers issues in that a user can't reliably re-execute commands from the script. For example, my script sets the following alias npe_cmdalias r =$(ExecuteCMD).
This allows the user to execute the command again without having to run the entire script. That command will fail if it requires the changed path, or other changed environmental variables like LIB and INCLUDE.

Can we add a session level option to both env_set and set?
Example usage:

env_set session PATH =C:\Program Files\Go\bin\;$(SYS.PATH);
set session ExecuteCMD=go.exe run "$(FULL_CURRENT_PATH)"

When the session option is used, have the environmental variable and regular variables be available for the console session until another script is executed from the menu.
I like this option for the regular variables as well, because right now I have to use non-local variables in order to access them after the script gets the PrintMsgReady. But those variables clutters the variable list when running other scripts.

FYI:
I see 2 issues I believe are bugs. Do you want me open a separate issue for them?

  1. set local always displays the same content as set. It displays both local and non-local variables.
         ::TestOnlyScript2
         set local MyLocalVariableFor_TestOnlyScript_2 = Good bye
         set TestOnlyScript_2_Var1 = Good bye from variable 1
         set TestOnlyScript_2_Var2 = Good bye from variable 2
         echo **************************************
         echo Here are the local variables....
         set local
         echo **************************************
         echo Here are all the variables
         set
         echo **************************************
    
  2. sci_find does not work, or fails intermittently. I got this to work one time,and there after it never worked again. I tried it with NPE_SF_NEXT, NPE_SF_WHOLEWORD, and NPE_SF_SETSEL. The following code fails, with the file getting open, and the view switches to the file, but the key word is not found, and the cursor remains in last positon.
         npp_open C:\Program Files\Notepad++\plugins\NppExec\doc\NppExec\NppExec_HelpAll.txt
         npp_switch C:\Program Files\Notepad++\plugins\NppExec\doc\NppExec\NppExec_HelpAll.txt
         sci_find 0 "sci_find"
    

But I would like to be able to do just one call con_save $(ProjectFileName) :u

OK.
Looks like I need to have a TODO list for this since it already contains several items:

  1. Make the "NppExec_Guide" to be an HTML instead of plain text.
  2. Add an ability to save the last executed script. (Note: if the last executed was anonymous - i.e. unnamed, executed directly from NppExec's Console - this script should probably be saved into a file e.g. "npes_last.txt").
  3. Make con_save to support an encoding parameter.

I'm not sure when I'll be doing these changes, but surely they need to be present in the TODO list.

I want to have an alias for help all as well

Aliases are possible for commands recognized by CScriptEngine. Thus, all the code around help, help <command>, help all need to be moved from ConsoleDlg::IsConsoleHelpCommand to a new method CScriptEngine::DoHelp.
This looks like an item 4 for the TODO list, not sure when I'll be doing it.

Can we add a session level option to both env_set and set?

I see no harm in setting global variables when needed. In fact, the purpose of "global" variables is to be available everywhere. If some of them still exist after a script has ended - well, it's OK, it's their nature.
You know, it took me some time to understand the idea of "session" variables and I'm still not sure I understand it completely. To me, "global" and "local" variables are enough, I am not sure we need to complicate things by introducing one more level of variables.

set local always displays the same content as set

True. Probably it was broken during some refactoring (NppExec already survived through several waves of refactorings).
Should be fixed now in 8d667f3

sci_find does not work, or fails intermittently

No, it works. Please look at the flags of the sci_find and at the examples with flags. Generally speaking, sci_find is almost useless with no flags specified - its behavior is completely controlled by the specified flags.

I see no harm in setting global variables when needed.

I can work around the global variables, but I didn't have a good workaround for the environmental variables.
But I just figured how to get them clean on each run using env_unset both before and after the script.

::TestOnlyScript1
env_unset  PATH
echo  $(SYS.PATH)
env_set PATH =C:\foofoo\;$(SYS.PATH);
echo  $(SYS.PATH)
cmd /c echo path = %PATH%
env_unset  PATH

I can run the above script over and over again, and the PATH doesn't get duplicates. I'll need to the same thing for LIB & INCLUDE.

No, it works. Please look at the flags of the sci_find and at the examples with flags.

0 is a flag.
I actually copied and pasted the examples in NppExec_HelpAll.txt. One of the examples is sci_find 0 "some text".
As I stated in my post, I tested the other flags as well. All of the following was tested individually.

sci_find NPE_SF_SETSEL "$(CURRENT_WORD)"
sci_find NPE_SF_NEXT "$(CURRENT_WORD)"
sci_find NPE_SF_WHOLEWORD "$(CURRENT_WORD)"
sci_find 0 "$(CURRENT_WORD)"

However, after testing it with 0, I didn't try to test it with one of the other flags and with a static string.
I just did, and it does work with the flag. Either the help text should get updated, or the function should be fixed to work with 0.

But this still leaves me with a problem. It doesn't work when I try using it with a select word as in my above examples.
Do you know why this sci_find NPE_SF_SETSEL "$(CURRENT_WORD)" doesn't work?
I get the following output in the console before calling sci_find, so I know CURRENT_WORD does have an expected value.
Searching help on word "npp_switch" for file type .exec

Scintilla uses SCFIND_NONE to represent zero for the sci_find (SCI_FINDTEXT) API. But that one is missing in NppExecEngine.cpp:101.
Since I'm there already, I can added for an update.
I'm going to try to put some break points on NppExec to see what's it doing when $(CURRENT_WORD) is used.

To find & select the next occurrence:

set local flags ~ NPE_SF_NEXT | NPE_SF_INWHOLETEXT | NPE_SF_SETSEL
sci_find $(flags) "$(CURRENT_WORD)"

or

sci_find NPE_SF_NEXT|NPE_SF_INWHOLETEXT|NPE_SF_SETSEL "$(CURRENT_WORD)"

To find & print all occurrences in NppExec's Console:

sci_find NPE_SF_INWHOLETEXT|NPE_SF_PRINTALL "$(CURRENT_WORD)"

Hi Vitaliy,
You seemed so convincing in your post, that I figured I must be doing something wrong, and I ran a small test script which revealed the problem.

::TestOnlyScript1
echo CURRENT_WORD = "$(CURRENT_WORD)"
npp_open C:\Program Files\Notepad++\plugins\NppExec\doc\NppExec\NppExec_HelpAll.txt
echo CURRENT_WORD = "$(CURRENT_WORD)"
npp_switch C:\Program Files\Notepad++\plugins\NppExec\doc\NppExec\NppExec_HelpAll.txt
set local flags ~ NPE_SF_NEXT | NPE_SF_INWHOLETEXT | NPE_SF_SETSEL
sci_find $(flags) "$(CURRENT_WORD)"

If you have a file open (like npes_saved.txt) and you select a word and run above script, you'll notice the CURRENT_WORD changes after opening the help file.
I thought the CURRENT_WORD would be static and applied to the file that was active when the script started.
But it's dynamic, and changes when the active file changes.

I got it now.

Thanks for your help.

SCFIND_NONE is used to do a search with the default setting. The default setting is to start a case-insensitive literal search from the current position.
NPE_SF_NEXT starts the search at current position +1.

::Script1
npp_open C:\Program Files\Notepad++\plugins\NppExec\doc\NppExec\NppExec_HelpAll.txt
set local flags ~ NPE_SF_NEXT | NPE_SF_INWHOLETEXT | NPE_SF_SETSEL
sci_find $(flags) "help all"

::Script2
npp_open C:\Program Files\Notepad++\plugins\NppExec\doc\NppExec\NppExec_HelpAll.txt
set local flags ~ NPE_SF_INWHOLETEXT | NPE_SF_SETSEL
sci_find $(flags) "help all"

If you run these two two scripts with NppExec_HelpAll.txt closed, you'll see that Script1 finds the second "help all", and skips the first one. Where as Script2 finds the first "help all".

With that said, I now agree you don't need NPE_SF_NONE, because if the user doesn't specify NPE_SF_SETSEL or NPE_SF_SETPOS, nothing appears to happens. That's why sci_find 0 "help all" doesn't work, but sci_find 35651584 "help all" does work.
To start a search from current position, the user can exclude NPE_SF_NEXT, like in Script2 or sci_find NPE_SF_SETSEL "help all"

I"m trying to use NPE_SF_PRINTALL, but it doesn't actually do what the name implies. As the document states, it starts from current position.
So I'm trying to move the current position to the start of the document. I looked through the document, but I can't find a function to do that, other then using sci_sendmsg SCI_GOTOLINE 0.
I'm tying to avoid using sci_sendmsg, because when it crashes, it takes down the entire program (Noted++).

Am I correct, in that sci_sendmsg is the only way to move the current line position?
If so, can't a try-catch be placed around the code that executes sci_sendmsg in NppExec?

Sorry, but one more post.
There seems to be some bugs around NPE_SF_INWHOLETEXT.
I did not want to use NPE_SF_INWHOLETEXT on my search because I wanted to be able to do a partial search. But when I run the very first search without it, the search fails.
I put it back on, and tested to see if I could still find partial words, and it did. I see two issues with this.

  1. NPE_SF_INWHOLETEXT is only supposed to return whole words, so this should fail sci_find NPE_SF_INWHOLETEXT|NPE_SF_SETSEL "hel"
  2. Performing the first search should not require NPE_SF_INWHOLETEXT. To duplicate this issue you have to close notepad++ and reopen it. At that point searches fail until NPE_SF_INWHOLETEXT is included. After doing a search with that flag include, all other searches seem to work without it, until you restart notepad++.

can't a try-catch be placed around the code that executes sci_sendmsg in NppExec?

Unfortunately, no, as sci_sendmsg is just a wrapper around Win API SendMessage. Thus, wrong parameters may lead to stack corruption or to out-of-boundaries reading/wriing that can't be catched by any try/catch.
The solution to this problem is simple: don't pass wrong parameters :) Actually, it is the question of what you are passing to Scintilla and what Scintilla is expecting to receive and to return. When you carefully follow the Scintilla API described in https://www.scintilla.org/ScintillaDoc.html , there is no chance for sci_sendmsg to lead to crach or hang. And in rare cases when it happens, it happens only because something was done wrong (not following the Scintilla API exactly).

I"m trying to use NPE_SF_PRINTALL

The NPE_SF_PRINTALL alone prints all occurrences starting from the current position.
The NPE_SF_PRINTALL|NPE_SF_NEXT prints all occurrences starting from the current position + 1.
The NPE_SF_PRINTALL|NPE_SF_INSELECTION prints all occurrences in the selected text.
The NPE_SF_PRINTALL|NPE_SF_INWHOLETEXT prints all occurrences in the whole text (starting from the beginning of the document).
There are no hidden stones, no magic, it does exactly what the specified flags tell it to do.

NPE_SF_INWHOLETEXT is only supposed to return whole words

Why do you think so? The NPE_SF_INWHOLETEXT and NPE_SF_WHOLEWORD are different flags. When NPE_SF_WHOLEWORD is not explicitly specified, NPE_SF_INWHOLETEXT finds parts of words.

Performing the first search should not require NPE_SF_INWHOLETEXT

It does not require it. If the search fails for you, most likely there are no further occurrences of the text being searched for starting from the current positon. It is expectable that Find First/Find Next does not find anything when you are at the end of your document.
Finally, if you don't trust the implementation of sci_find, you can always debug the CScriptEngine::doSciFindReplace to see what is actually happening inside of it.

By the way, the first two items of the TODO list (mentioned above) are implemented:

  1. Make the "NppExec_Guide" to be an HTML instead of plain text.
    1f39042

  2. Add an ability to save the last executed script. (Note: if the last executed was anonymous - i.e. unnamed, executed directly from NppExec's Console - this script should probably be saved into a file e.g. "npes_last.txt").
    69ffae7
    24dcd6c

Thus, wrong parameters may lead to stack corruption or to out-of-boundaries reading/wriing that can't be catched by any try/catch.

That could be said for any try-catch. I used Scintilla on a program I maintained, upgraded and used myself for about 8 years in my old job. I put try-catch on any Scintilla call where the user's input could cause a crash, and I never had any problems with it.
I also use Scintilla on my RegexAssistant program, and I do the same there as well.
One way you can find out if your try-catch is leaving the code unstable, is by running the program with the debugger, and looping your code with different data that you know will cause it to crash. That should reveal any issues.
FYI: The VS debugger has the option to ignore handled exceptions so the code can run through 1000's of loops without stopping on each triggered exception.

The NPE_SF_PRINTALL|NPE_SF_INWHOLETEXT prints all occurrences in the whole text (starting from the beginning of the document).

Oooh. I misunderstood the meaning of NPE_SF_INWHOLETEXT. I thought it was associated with Scintilla option SCFIND_WHOLEWORD. I did not realized NPE_SF_WHOLEWORD was there as well. The wording is very similar.

By the way, the first two items of the TODO list (mentioned above) are implemented:
Thank you. I really can use #2.

Did you use any tool to convert the guide to an HTML?

On a separate topic, I'm using your MsgTest program as a template for the plugin I"m creating. It was very help as a launching point for the plugin.
One thing I'm worried about is the scenario where the user doesn't have NppExec install, and they try installing my plugin.

Do you know if there is a way to configure it so NppExec is installed when my plugin gets installed?

I put try-catch on any Scintilla call where the user's input could cause a crash, and I never had any problems with it.

Hmm, please implement a protection around a call like this:

sci_sendmsg SCI_GETTEXTRANGE 0 "123"

And yes, I know that a string "123" is certainly not a pointer to a Sci_TextRange structure, but this is an exact example of what I meant by "Warning: incorrect usage of this command may crash Notepad++ !!!".

Did you use any tool to convert the guide to an HTML?

Nope, I've just edit it in a text editor, adding HTML tags.

Do you know if there is a way to configure it so NppExec is installed when my plugin gets installed?

I'm not aware of it.
But anyway, your plugin can simply detect whether NppExec.dll exists and show a message asking to install it if it doesn't.

Hi Vitaliy,
I'm sorry it took me so long to get back to you. It took me a while to find this thread again.

sci_sendmsg SCI_GETTEXTRANGE 0 "123"

I tried your example, and much to my surprise, I could not catch the exception with neither C++ try-catch nor with SEH __try-__except.

And you're right, in that even if you were able to catch this type of exception, the state of program could be unpredictable.

However, that doesn't mean you can't put a try-catch on SendSciMsg to handle errors that can be caught by C++ catch.
Generally, you can safely exit a function or a process after a C++ catch, because it can safely unwind the code from the catch point.


LRESULT CSciMessager::SendSciMsg(UINT uMsg, WPARAM wParam , LPARAM lParam )
{
	try	
	{
		return ::SendMessage( m_hSciWnd, uMsg, wParam, lParam );
	} catch ( std::exception &e )	
	{
		::MessageBoxA( m_hSciWnd, e.what(), "Sintilla Exception!", MB_OK | MB_ICONERROR );
	} catch ( ... )	
	{
		::MessageBox( m_hSciWnd, _T( "(C++) Sintilla Exception thrown!\nVerify input paramenters are valid." ), _T( "Sintilla Exception!" ), MB_OK | MB_ICONERROR );
	}
	return NULL;
}

I'm closing this since #1 and #2 are done, and #3 & #4 are not needed because I can use env_unset at the start and at the end of the script.
However, I do get the following error message when calling env_unset before anything has been set.

- can not unset this environment variable: $(SYS.LIB)
- can not unset this environment variable: $(SYS.INCLUDE)

As a workaround, I have to turn off and on the console out-put.

::ExecuteTaskBasedOnFileExtension
npp_console -
env_unset  PATH
env_unset  LIB
env_unset  INCLUDE
npp_console +

It would be nice if there was an option to disable this type of error reporting.

Forgot to hit the close button. :-)

By the way, please keep me updated regarding the development of the NppExec's script to compile/run anything, as well as regarding any updates to the warning/error regular expression!

I currently have about 45 programming languages working with the script, but I don't think I'm going to go further on the script because of the speed and because it really needs a GUI interface so the user can modified installation paths, as well as adding new languages.

The script really started to slow down when I reached about 30 languages. I moved a big section to a sub script, and that really improved it, but I want it to start the ExecuteCMD faster. So I'm working on a plugin based on your NppExecPluginMsgTester project, and I'm coping the data from the script to the new plugin. I've already tested the plugin with 19 languages, and it runs so much faster. It starts to execute the runner almost instantly.
The plugin (RunAny_ProgrammingLanguage) still uses NppExec script, put it creates a small script unique to the program language, and then it calls npeMsgr.NpeExecute( &nep ) to run the script.

I'll still post an update for the original script, but I have to clean it up a little before I do that.
I'm going to upload the program to github soon, and I'll let you know when it's uploaded.

The main reason I haven't uploaded the plugin yet, is because I'm not happy with the current name (RunAny_ProgrammingLanguage).
I can't seem to come up with a better name that would describe the plugin's main purpose.

Do you have any suggestions for the name of the new plugin?

The name could be "RunAnything" that assumes wider abilities not limited by just compiling. For example, it might allow to apply some transformation to an .html of .xml file and to open it in a given browser.
In terms of source files, the name could be "RunAnySourceFile".
In terms of an action, the name could be "CompileOrRun" or even "CORE: Compile Or Run/Execute".

I've just seemed to face an undesired behavior from the new regex-based part of CWarningAnalyzer::match...
When cmd is running in NppExec's Console and a dir command is given, this output:

19.10.2021  18:26    <DIR>          .
19.10.2021  18:26    <DIR>          ..
04.03.2019  23:46            75 334 fparser.html
16.08.2021  08:51            42 084 NppExec.txt
08.08.2021  13:11           191 710 NppExec_HelpAll.txt

is all treated as error messages.
Here is an example of how the WarningAnalyzer works in this case:

; Console's line double-clicked
; WarningAnalyzer info
; {
;    Input line: "16.08.2021  08:51            42 084 NppExec.txt"
;    Match result: true
;    Active filter: ""
;    * Parsed File Name: "16.08.2021"
;    * Parsed Line Number: 8
;    * Parsed Char Position: 16
; }

The name could be "RunAnything"

I like that name. I also like a variation on your second one. (RunAnySourceCode).
I'm going to make up my mind today, and upload it after I make name change.
Thank you.

When cmd is running in NppExec's Console and a dir command is given, this output:

I couldn't reproduce the issue. Can you please post a snapshot of the issue?
Are you running the version of NppExec from the source code tip?

I couldn't reproduce the issue

Probably it's because you have a MM/DD/YYYY date format. Whereas mine date format is DD.MM.YYYY.
I believe you can "emulate" it using

npe_console local -- m-
cmd /c echo 19.10.2021  18:26    ^<DIR^>          .
cmd /c echo 19.10.2021  18:26    ^<DIR^>          ..
cmd /c echo 04.03.2019  23:46            75 334 fparser.html
cmd /c echo 16.08.2021  08:51            42 084 NppExec.txt
cmd /c echo 08.08.2021  13:11           191 710 NppExec_HelpAll.txt

npe_console local -- m-
cmd /c echo 19.10.2021 18:26 ^<DIR^> .
cmd /c echo 04.03.2019 23:46 75 334 fparser.html

With that, I'm able to reproduce it.

I should be able to modify the regex to exclude the line with <DIR^>, because that's not a file name.
The lines with file names might be a little tricky.
I'll get back to you on this by COB today.

Merry Christmas,
Sorry for taking so long to get back to you, but I was trying to complete implementation on RunAnything.
I finally posted the code today, but at this time, it only supports 80% languages the script supports.
It took me much more time then I anticipated to implement this using a database.
For reference purposes I did include the original NppExec script file npes_saved.txt in the repository.

A need a little more time to look into the above regex date format issue.