[Pull Request] Regex logic to handle errors and warnings displayed on console
David-Maisonave opened this issue · comments
I created pull request #51, to add the Regex logic.
I tested it on 18 languages by creating Hello World source files with errors.
If you like to test it, I have the source file in this zip file. BadHelloWorld.zip
I used the following NppExec script to test each file:
// * Run any file base on the file extension type
// ** If script file, run it (using *[Run Handler]*)
// ** If source code, compile and run
// ** If Unknown type display a message or modifty this script to perform some other default behavior
// ** If needed, add additional if conditions for other file types, and the desired execution behavior
// *** Saving current file *******************************
NPP_SAVE
// *** Turn off internal messages
npe_console local m- --
// *** Option: Set to 1 to turn on console logging which is saved in $(CURRENT_DIRECTORY)
set NppExecConsoleLogging=0
// ToDo: For non-default installations, modify below paths to match your COMPILER or LANGUAGE RUNNER installation
// *** Compilers *******************************
// set CppCompilerPath=C:\DMC\dm\bin
// set CppCompiler="$(CppCompilerPath)\dmc.exe"
set CppCompilerPath=C:\MinGW\bin
set CppCompiler="$(CppCompilerPath)\g++.exe"
set C_Compiler="$(CppCompilerPath)\gcc.exe"
set FortranCompiler="$(CppCompilerPath)\gfortran.exe"
set AdaCompiler="$(CppCompilerPath)\xx.exe"
set ObjC_Compiler="$(CppCompilerPath)\gcc.exe"
set CSharpCompiler="C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc"
set VbCompiler="C:\Program Files (x86)\Microsoft Visual Studio\Shared\Packages\Microsoft.Net.Compilers.2.6.1\tools\vbc.exe"
set JavaCompiler="C:\Program Files\Java\jdk1.8.0_202\bin\javac.exe"
set D_CompilerPath=C:\D\dmd2\windows\bin64
set MimPath=C:\Nim\bin
// *** Language Runners *******************************
set JavaRunner="C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe"
set AwkRunner="C:\Program Files (x86)\GnuWin32\bin\gawk.exe"
set AutoItRunner="C:\Program Files (x86)\AutoIt3\AutoIt3.exe"
set AutoHotKeyRunner="C:\Program Files\AutoHotkey\AutoHotkey.exe"
set R_Runner="C:\Program Files\R\R-4.1.1\bin\x64\Rscript.exe"
set RubyRunner="C:\Ruby30-x64\bin\Ruby.exe"
set RubyWRunner="C:\Ruby30-x64\bin\RubyW.exe"
set LuaRunnerX86="C:\Program Files (x86)\Lua\5.1\lua.exe"
set LuaRunnerX64="C:\Program Files\Lua\lua54.exe"
// *** Set common variables *******************************
set local ext ~ strlower $(EXT_PART)
set obj =$(CURRENT_DIRECTORY)\$(NAME_PART)
set CompiledBinary=$(obj).exe
set ExecuteBinary="$(CompiledBinary)"
set CompileIt =""
set PostCompile =Echo Compile Success
set NameOfItemToRun =$(NAME_PART)$(EXT_PART)
if $(ext) == .cmd
cmd /c if not exist "$(CURRENT_DIRECTORY)\$(NAME_PART).cmd" exit 1
if $(EXITCODE) == 0
cmd /c $(CURRENT_DIRECTORY)\$(NAME_PART).cmd
goto :ShowRunStatusResults
endif
endif
cmd /c if not exist "$(CURRENT_DIRECTORY)\BuildProject.cmd" exit 1
if $(EXITCODE) == 0
cmd /c $(CURRENT_DIRECTORY)\BuildProject.cmd
goto :ShowRunStatusResults
endif
cmd /c if not exist "$(CURRENT_DIRECTORY)\..\BuildProject.cmd" exit 1
if $(EXITCODE) == 0
cmd /c $(CURRENT_DIRECTORY)\..\BuildProject.cmd
goto :ShowRunStatusResults
endif
cmd /c if not exist "$(CURRENT_DIRECTORY)\..\..\BuildProject.cmd" exit 1
if $(EXITCODE) == 0
cmd /c $(CURRENT_DIRECTORY)\..\..\BuildProject.cmd
goto :ShowRunStatusResults
endif
// ToDo: If your script file type is not listed below, create a new *[Run Handler]* by appending a new "else if" block specifying how to handle it.
// *** Common script file types *[Run Handler]* *******************************
if $(ext) == .awk
$(AwkRunner) -f "$(FULL_CURRENT_PATH)"
else if $(ext) == .au3
$(AutoItRunner) "$(FULL_CURRENT_PATH)"
else if $(ext) == .ahk
$(AutoHotKeyRunner) "$(FULL_CURRENT_PATH)"
else if $(ext) == .bat
cmd /c ("$(FULL_CURRENT_PATH)")
else if $(ext) == .cmd
cmd /c ("$(FULL_CURRENT_PATH)")
else if $(ext) == .go
C:\Program Files\Go\bin\go.exe run "$(FULL_CURRENT_PATH)"
else if $(ext) == .py
python "$(FULL_CURRENT_PATH)"
else if $(ext) == .pyw
pythonw "$(FULL_CURRENT_PATH)"
else if $(ext) == .ps1
powershell -executionpolicy bypass -File "$(FULL_CURRENT_PATH)"
else if $(ext) == .r
$(R_Runner) "$(FULL_CURRENT_PATH)"
else if $(ext) == .rb
$(RubyRunner) "$(FULL_CURRENT_PATH)"
else if $(ext) == .rbw
$(RubyWRunner) "$(FULL_CURRENT_PATH)"
else if $(ext) == .lua
cmd /c if not exist $(LuaRunnerX64) exit 1
if $(EXITCODE) == 0
$(LuaRunnerX64) "$(FULL_CURRENT_PATH)"
else
$(LuaRunnerX86) "$(FULL_CURRENT_PATH)"
endif
else if $(ext) == .inputrc
NPP_RUN cmd
else if $(ext) == .vbs
echo "*** Using CScript to get output to NppExec console window ***"
cscript.exe "$(FULL_CURRENT_PATH)"
else if $(ext) == .js
node "$(FULL_CURRENT_PATH)"
else if $(ext) == .php
php "$(FULL_CURRENT_PATH)"
// *** Common source code file types needing to be compiled before running associated binaries *******************************
else if $(ext) == .cs
set CompileIt =$(CSharpCompiler) "$(FULL_CURRENT_PATH)"
goto :CompileAndExecute
else if $(ext) == .vb
set CompileIt =$(VbCompiler) "$(FULL_CURRENT_PATH)"
goto :CompileAndExecute
else if $(ext) == .c
env_set local PATH = $(path);$(CppCompilerPath);
set CompileIt =$(C_Compiler) -c "$(FULL_CURRENT_PATH)"
set PostCompile =$(C_Compiler) "$(obj).o" -o "$(CompiledBinary)"
goto :CompileAndExecute
else if $(ext) == .cpp
env_set local PATH = $(path);$(CppCompilerPath);
set CompileIt =$(CppCompiler) -c "$(FULL_CURRENT_PATH)"
set PostCompile =$(CppCompiler) "$(obj).o" -o "$(CompiledBinary)"
goto :CompileAndExecute
else if $(ext) == .d
env_set local PATH = $(path);$(D_CompilerPath);
set CompileIt =$(D_CompilerPath)\dmd.exe -i -run "$(FULL_CURRENT_PATH)"
goto :CompileAndExecute
else if $(ext) == .nim
env_set local PATH = $(path);$(MimPath);
set CompileIt =$(MimPath)\nim c --verbosity:0 "$(FULL_CURRENT_PATH)"
goto :CompileAndExecute
else if $(ext) == .f90
env_set local PATH = $(path);$(CppCompilerPath);
set CompileIt =$(FortranCompiler) "$(FULL_CURRENT_PATH)" -o $(NAME_PART)
goto :CompileAndExecute
else if $(ext) == .java
set CompileIt =$(JavaCompiler) "$(FULL_CURRENT_PATH)"
set ExecuteBinary=$(JavaRunner) $(NAME_PART)
set CompiledBinary=$(NAME_PART).class
goto :CompileAndExecute
else if $(ext) == .m
env_set local PATH = $(path);$(CppCompilerPath);$(CppCompilerPath)\include;
set CompileIt =$(ObjC_Compiler) -I"c:/GNUstep/GNUstep/System/Library/Headers" -L "c:/GNUstep/GNUstep/System/Library/Libraries" -o $(NAME_PART) "$(FULL_CURRENT_PATH)" -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
set CompileIt =$(ObjC_Compiler) `gnustep-config --objc-flags` -o $(NAME_PART) "$(FULL_CURRENT_PATH)" -L /GNUstep/System/Library/Libraries -lobjc -lgnustep-base
set CompileIt =$(ObjC_Compiler) --objc-gc -Wall -Werror -g -v "$(FULL_CURRENT_PATH)" -lobjc -o $(NAME_PART)
goto :CompileAndExecute
else if $(ext) == .objc
env_set local PATH = $(path);$(CppCompilerPath);
set CompileIt =$(CppCompiler) -c
set PostCompile =$(CppCompiler) "$(obj).o" -o "$(CompiledBinary)"
// --------------------------------------------------------------------------------------
// ToDo: ********** If needed, append your new *[Run Handler]* HERE by adding another "else if" block to handle your file extension type. **********
// --------------------------------------------------------------------------------------
// Example #1 *[Run Handler]* for files with extension .foo, where MyFooScriptRunner.exe is an executable that knows what to do with (.foo) files.
else if $(ext) == .foo
MyFooScriptRunner.exe "$(FULL_CURRENT_PATH)"
// --------------------------------------------------------------------------------------
// Example #2 *[Run Handler]* for files with extension .foobar, where DOS knows how to handle (.foobar) files.
else if $(ext) == .foobar
cmd /c "$(FULL_CURRENT_PATH)"
// --------------------------------------------------------------------------------------
// Example #3 *[Run Handler]* for files with extension .axter, that is compiled by "a++.exe" which is stored in folder "C:\Program Files\axter". The binary created is of type (*.exe)
else if $(ext) == .axter
// Add the compiler folder to PATH so (if needed) it can access other associated binaries in order to compile or link
env_set local PATH = $(path);"C:\Program Files\axter";
// Set the compile command so the common handler knows how to compile the file
set CompileIt ="C:\Program Files\axter\a++.exe" "$(FULL_CURRENT_PATH)"
// Call the common handler which will compile and then execute the newly created *.exe file.
goto :CompileAndExecute
// --------------------------------------------------------------------------------------
// Note:
// If binary created is NOT *.exe type, reset CompiledBinary to appropriate binary name.
// If compiler has a link phase, use PostCompile to set link details
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
// *** None of the if conditions were able to handle the file type, so notify user with a warning *******************************
else
// If needed, replace the following line with desired default behavior
set local msg ~ strunescape Warning: Unknown file type!\t[$(EXT_PART)]\nAdd file extension handler to NppExec script.
messagebox `$(msg)` : "File Type Warning" : warn
// Example alternate default behavior
// cmd /c "$(FULL_CURRENT_PATH)"
endif
// *** Show if successful run
:ShowRunStatusResults
if $(EXITCODE) == 0
echo =============== SUCCESS =============== ===============
echo ********** Success running $(NameOfItemToRun) **********
else
echo ============ Run ERROR! =============== ===============
echo !!!! Error: $(NameOfItemToRun) failed with error: $(EXITCODE) !!!!
echo $(FULL_CURRENT_PATH) : 1
endif
goto :END
// *** Common Compile handler wrapper *******************************
:CompileAndExecute
echo Compiling '$(NAME_PART)' to create '$(CompiledBinary)'
echo $(CompileIt)
$(CompileIt)
if $(EXITCODE) == 0
$(PostCompile)
if $(EXITCODE) == 0
set NameOfItemToRun=$(CompiledBinary)
echo Running $(ExecuteBinary) ...
cmd /C if exist "$(CompiledBinary)" $(ExecuteBinary)
goto :ShowRunStatusResults
else
echo =========== Link ERROR! =============== ===============
echo !!!! Error: Linker error $(FULL_CURRENT_PATH) with error: $(EXITCODE) !!!!
echo Linker Command=$(PostCompile)
endif
else
echo ======== Compile ERROR! =============== ===============
echo !!!! Error: Failed to compile $(FULL_CURRENT_PATH) with error: $(EXITCODE) !!!!
echo Compiler Command=$(CompileIt)
endif
:END
if $(NppExecConsoleLogging) == 1
con_save $(CURRENT_DIRECTORY)\LoggingNppExecuteConsole.tmp
cmd /c echo ************************************************************************************************************************************************************************************>>$(CURRENT_DIRECTORY)\LoggingNppExecuteConsole.log
cmd /c echo ***>>$(CURRENT_DIRECTORY)\LoggingNppExecuteConsole.log
cmd /c type $(CURRENT_DIRECTORY)\LoggingNppExecuteConsole.tmp >> $(CURRENT_DIRECTORY)\LoggingNppExecuteConsole.log
endif
echo ===================================== ===============
Let me know if you have any questions.
Associated update complete
There were a lot of changes in NppExec during this month, and I believe now the plugin is in a release candidate state.
The built-in RegExp-based filter for compiler error messages is disabled by default to avoid an impact on performance.
It is recommended to enable this filter locally, right before running a compiler or an interpreter: "npe_console local -- x+".
Do you have any changes to the regular expressions used by this filter?
By the way, I've made some performance tests to understand why the all-in-one compilation script (that you initially created) requires noticeable time to be executed.
The short answer is: use npe_console -
to disable the output and to make it very fast.
The longer answer is: the CScriptEngine itself is fast enough, but the Rich Edit control (responsible for all the text in NppExec's Console) is sooooo slooooooow...
Here is a simple example. Consider the following NppExec's script:
npp_console ?
npp_console -
npe_console local m+
:1
goto 1
If you execute it as is, it is lightning-fast, it shows "GOTO was performed more than 10000 times" almost immediately. This is the performance of the CScriptEngine itself.
Now, let's close NppExec's Console and modify this script:
npp_console ?
//npp_console -
npe_console local m+
:1
goto 1
This second version prints "GOTO: 1" to a hidden RichEdit window 10000 times. You might think that a hidden RichEdit window should not take much time to repaint itself while adding these lines, but in reality this version takes much longer than the previous one! This is the performance of the CScriptEngine plus Rich Edit control.
I also did some profiling using Visual Studio - and most of the time is indeed spent within the Rich Edit control!
Here is the profiling statistics:
Function Name Total CPU [unit, %] Self CPU [unit, %] Module
| - ConsoleDlg::RichEditWndProc 4556 (44,06%) 24 (0,23%) NppExec.dll
| - CNppExecCommandExecutor::BackgroundExecuteThreadFunc 1538 (14,87%) 0 (0,00%) NppExec.dll
| - CNppExecCommandExecutor::ExpirableCommand::Execute 1538 (14,87%) 0 (0,00%) NppExec.dll
| - CNppExecCommandExecutor::OnDoExecDlgCommand::subExecute 1533 (14,83%) 0 (0,00%) NppExec.dll
| - CNppExecCommandExecutor::ScriptableCommand::OnDoExecDlg 1533 (14,83%) 0 (0,00%) NppExec.dll
| - CNppExecCommandExecutor::RunScriptEngine 1490 (14,41%) 0 (0,00%) NppExec.dll