@@ -4934,216 +4934,151 @@ bool MultiReplace::compileLuaReplaceCode(const std::string& luaCode)
4934
4934
return true ;
4935
4935
}
4936
4936
4937
- bool MultiReplace::resolveLuaSyntax (std::string& inputString, const LuaVariables& vars, bool & skip, bool regex)
4937
+ bool MultiReplace::resolveLuaSyntax (std::string& inputString, const LuaVariables& vars, bool & skip, bool regex)
4938
4938
{
4939
- // 1) Ensure the Lua environment is initialized
4940
- if (!_luaState) {
4941
- return false ;
4942
- }
4943
-
4944
- // 2) Push numeric globals
4945
- lua_pushinteger (_luaState, vars.CNT );
4946
- lua_setglobal (_luaState, " CNT" );
4947
-
4948
- lua_pushinteger (_luaState, vars.LCNT );
4949
- lua_setglobal (_luaState, " LCNT" );
4950
-
4951
- lua_pushinteger (_luaState, vars.LINE );
4952
- lua_setglobal (_luaState, " LINE" );
4953
-
4954
- lua_pushinteger (_luaState, vars.LPOS );
4955
- lua_setglobal (_luaState, " LPOS" );
4956
-
4957
- lua_pushinteger (_luaState, vars.APOS );
4958
- lua_setglobal (_luaState, " APOS" );
4959
-
4960
- lua_pushinteger (_luaState, vars.COL );
4961
- lua_setglobal (_luaState, " COL" );
4962
-
4963
- // 3) Push string globals
4939
+ // 1) Stack-checkpoint
4940
+ const int stackBase = lua_gettop (_luaState);
4941
+ auto restoreStack = [this , stackBase]() { lua_settop (_luaState, stackBase); };
4942
+
4943
+ // 2) Ensure Lua state exists
4944
+ if (!_luaState) { return false ; }
4945
+
4946
+ // 3) Numeric globals
4947
+ lua_pushinteger (_luaState, vars.CNT ); lua_setglobal (_luaState, " CNT" );
4948
+ lua_pushinteger (_luaState, vars.LCNT ); lua_setglobal (_luaState, " LCNT" );
4949
+ lua_pushinteger (_luaState, vars.LINE ); lua_setglobal (_luaState, " LINE" );
4950
+ lua_pushinteger (_luaState, vars.LPOS ); lua_setglobal (_luaState, " LPOS" );
4951
+ lua_pushinteger (_luaState, vars.APOS ); lua_setglobal (_luaState, " APOS" );
4952
+ lua_pushinteger (_luaState, vars.COL ); lua_setglobal (_luaState, " COL" );
4953
+
4954
+ // 4) String globals
4964
4955
setLuaVariable (_luaState, " FPATH" , vars.FPATH );
4965
4956
setLuaVariable (_luaState, " FNAME" , vars.FNAME );
4966
4957
setLuaVariable (_luaState, " MATCH" , vars.MATCH );
4967
4958
4968
- // 4) Set REGEX flag
4959
+ // 5) REGEX flag
4969
4960
lua_pushboolean (_luaState, regex);
4970
4961
lua_setglobal (_luaState, " REGEX" );
4971
4962
4972
- // 5) If regex is enabled, push CAP variables
4963
+ // 6) CAP# globals ( regex only)
4973
4964
std::vector<std::string> capNames;
4974
- if (regex)
4975
- {
4976
- for (int i = 1 ; i <= MAX_CAP_GROUPS; ++i)
4977
- {
4978
- sptr_t length = send (SCI_GETTAG, i, 0 , true );
4979
- if (length < 0 ) {
4980
- // No more captures
4981
- break ;
4982
- }
4965
+ if (regex) {
4966
+ for (int i = 1 ; i <= MAX_CAP_GROUPS; ++i) {
4967
+ sptr_t len = send (SCI_GETTAG, i, 0 , true );
4968
+ if (len < 0 ) { break ; }
4983
4969
4984
- std::string capValue;
4985
- if (length > 0 ) {
4986
- std::vector<char > buffer (length + 1 , ' \0 ' );
4987
- sptr_t result = send (SCI_GETTAG, i, reinterpret_cast <sptr_t >(buffer.data ()), false );
4988
- if (result >= 0 ) {
4989
- capValue.assign (buffer.data ());
4990
- }
4970
+ std::string capVal;
4971
+ if (len > 0 ) {
4972
+ std::vector<char > buf (len + 1 , ' \0 ' );
4973
+ if (send (SCI_GETTAG, i,
4974
+ reinterpret_cast <sptr_t >(buf.data ()), false ) >= 0 )
4975
+ capVal.assign (buf.data ());
4991
4976
}
4992
-
4993
- // Set CAP# in Lua
4994
4977
std::string capName = " CAP" + std::to_string (i);
4995
- setLuaVariable (_luaState, capName, capValue );
4978
+ setLuaVariable (_luaState, capName, capVal );
4996
4979
capNames.push_back (capName);
4997
4980
}
4998
4981
}
4999
4982
5000
- // 6) Execute pre-compiled Lua chunk
4983
+ // 7) Run pre-compiled chunk
5001
4984
lua_rawgeti (_luaState, LUA_REGISTRYINDEX, _luaCompiledReplaceRef);
5002
- if (lua_pcall (_luaState, 0 , LUA_MULTRET, 0 ) != LUA_OK)
5003
- {
5004
- const char * errMsg = lua_tostring (_luaState, -1 );
5005
- if (errMsg)
5006
- {
5007
- // Optional console log
5008
- std::cerr << " [Lua Error] " << errMsg << std::endl;
5009
-
5010
- // Show a message box if user enabled it
5011
- if (isLuaErrorDialogEnabled)
5012
- {
5013
- std::wstring error_message = Encoding::utf8ToWString (errMsg);
5014
- MessageBox (nppData._nppHandle ,
5015
- error_message.c_str (),
5016
- LM.get (L" msgbox_title_use_variables_syntax_error" ).c_str (),
5017
- MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
5018
- }
5019
- }
5020
- lua_pop (_luaState, 1 ); // pop the error message
4985
+ if (lua_pcall (_luaState, 0 , LUA_MULTRET, 0 ) != LUA_OK) {
4986
+ const char * err = lua_tostring (_luaState, -1 );
4987
+ if (err && isLuaErrorDialogEnabled) {
4988
+ MessageBox (nppData._nppHandle ,
4989
+ Encoding::utf8ToWString (err).c_str (),
4990
+ LM.get (L" msgbox_title_use_variables_syntax_error" ).c_str (),
4991
+ MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
4992
+ }
4993
+ restoreStack ();
5021
4994
return false ;
5022
4995
}
5023
4996
5024
- // 7) Retrieve resultTable
4997
+ // 8) resultTable
5025
4998
lua_getglobal (_luaState, " resultTable" );
5026
- if (!lua_istable (_luaState, -1 ))
5027
- {
5028
- // If missing or not a table
5029
- lua_pop (_luaState, 1 );
5030
- if (isLuaErrorDialogEnabled)
5031
- {
5032
- std::wstring errorMsg = LM.get (L" msgbox_use_variables_execution_error" ,
5033
- { Encoding::utf8ToWString (inputString.c_str ()) });
5034
- std::wstring errorTitle = LM.get (L" msgbox_title_use_variables_execution_error" );
5035
- MessageBox (nppData._nppHandle , errorMsg.c_str (), errorTitle.c_str (), MB_OK);
5036
- }
4999
+ if (!lua_istable (_luaState, -1 )) {
5000
+ if (isLuaErrorDialogEnabled) {
5001
+ std::wstring msg =
5002
+ LM.get (L" msgbox_use_variables_execution_error" ,
5003
+ { Encoding::utf8ToWString (inputString.c_str ()) });
5004
+ MessageBox (nppData._nppHandle , msg.c_str (),
5005
+ LM.get (L" msgbox_title_use_variables_execution_error" ).c_str (),
5006
+ MB_OK);
5007
+ }
5008
+ restoreStack ();
5037
5009
return false ;
5038
5010
}
5039
5011
5040
- // 8) Extract ' result'
5041
- lua_getfield (_luaState, -1 , " result" );
5012
+ // 9) result & skip
5013
+ lua_getfield (_luaState, -1 , " result" ); // push result
5042
5014
if (lua_isnil (_luaState, -1 )) {
5043
5015
inputString.clear ();
5016
+ } else if (lua_isstring (_luaState, -1 ) || lua_isnumber (_luaState, -1 )) {
5017
+ std::string res = lua_tostring (_luaState, -1 );
5018
+ if (regex) { res = escapeForRegex (res); }
5019
+ inputString = res;
5044
5020
}
5045
- else if (lua_isstring (_luaState, -1 ) || lua_isnumber (_luaState, -1 ))
5046
- {
5047
- std::string result = lua_tostring (_luaState, -1 );
5048
- if (regex) {
5049
- result = escapeForRegex (result);
5050
- }
5051
- inputString = result;
5052
- }
5053
- lua_pop (_luaState, 1 ); // pop "result"
5021
+ lua_pop (_luaState, 1 ); // pop result
5054
5022
5055
- // 9) Extract 'skip'
5056
- lua_getfield (_luaState, -1 , " skip" );
5057
- if (lua_isboolean (_luaState, -1 )) {
5058
- skip = (lua_toboolean (_luaState, -1 ) != 0 );
5059
- }
5060
- else {
5061
- skip = false ;
5062
- }
5063
- lua_pop (_luaState, 1 ); // pop "skip"
5023
+ lua_getfield (_luaState, -1 , " skip" ); // push skip
5024
+ skip = lua_isboolean (_luaState, -1 ) && lua_toboolean (_luaState, -1 );
5025
+ lua_pop (_luaState, 1 ); // pop skip
5064
5026
5065
- // 10) Pop resultTable
5066
- lua_pop (_luaState, 1 );
5027
+ // (resultTable left on stack until the very end, then dropped by restoreStack)
5067
5028
5068
- // 11) Gather CAP variable info, then remove them from Lua
5029
+ // 10) CAP variable dump & cleanup
5069
5030
std::string capVariablesStr;
5070
-
5071
- for (const auto & capName : capNames)
5072
- {
5073
- lua_getglobal (_luaState, capName.c_str ());
5031
+ for (const auto & capName : capNames) {
5032
+ lua_getglobal (_luaState, capName.c_str ()); // push CAP value
5074
5033
5075
5034
if (lua_isnumber (_luaState, -1 )) {
5076
- double numVal = lua_tonumber (_luaState, -1 );
5077
- // capVariablesStr += capName + "\tNumber\t" + std::to_string(numVal) + "\n\n";
5078
-
5079
- std::ostringstream numStream;
5080
- numStream << std::fixed << std::setprecision (8 ) << numVal;
5081
- capVariablesStr += capName + " \t Number\t " + numStream.str () + " \n\n " ;
5082
-
5083
- }
5084
- else if (lua_isboolean (_luaState, -1 )) {
5085
- bool boolVal = (lua_toboolean (_luaState, -1 ) != 0 );
5086
- capVariablesStr += capName + " \t Boolean\t " + (boolVal ? " true" : " false" ) + " \n\n " ;
5087
- }
5088
- else if (lua_isstring (_luaState, -1 )) {
5035
+ double n = lua_tonumber (_luaState, -1 );
5036
+ std::ostringstream os; os << std::fixed << std::setprecision (8 ) << n;
5037
+ capVariablesStr += capName + " \t Number\t " + os.str () + " \n\n " ;
5038
+ } else if (lua_isboolean (_luaState, -1 )) {
5039
+ bool b = lua_toboolean (_luaState, -1 );
5040
+ capVariablesStr += capName + " \t Boolean\t " + (b ? " true" : " false" ) + " \n\n " ;
5041
+ } else if (lua_isstring (_luaState, -1 )) {
5089
5042
capVariablesStr += capName + " \t String\t " + lua_tostring (_luaState, -1 ) + " \n\n " ;
5090
- }
5091
- else {
5043
+ } else {
5092
5044
capVariablesStr += capName + " \t <nil>\n\n " ;
5093
5045
}
5046
+ lua_pop (_luaState, 1 ); // pop CAP value
5094
5047
5095
- lua_pop (_luaState, 1 );
5096
- // Remove the global
5097
- lua_pushnil (_luaState);
5048
+ lua_pushnil (_luaState); // clear global
5098
5049
lua_setglobal (_luaState, capName.c_str ());
5099
5050
}
5100
5051
5101
- // 12) Check if DEBUG == true
5102
- lua_getglobal (_luaState, " DEBUG" );
5103
- if (lua_isboolean (_luaState, -1 ) && lua_toboolean (_luaState, -1 ))
5104
- {
5105
- // For performance, only capture globals if DEBUG is on
5052
+ // 11) DEBUG flag & window
5053
+ lua_getglobal (_luaState, " DEBUG" ); // push DEBUG
5054
+ bool debugOn = lua_isboolean (_luaState, -1 ) && lua_toboolean (_luaState, -1 );
5055
+ lua_pop (_luaState, 1 ); // pop DEBUG
5056
+
5057
+ if (debugOn) {
5106
5058
globalLuaVariablesMap.clear ();
5107
5059
captureLuaGlobals (_luaState);
5108
5060
5109
- // Build debug string for captured globals
5110
- std::string luaGlobalsStr;
5111
- luaGlobalsStr += " Global Lua variables:\n\n " ;
5112
- for (const auto & pair : globalLuaVariablesMap) {
5113
- const LuaVariable& var = pair.second ;
5114
- if (var.type == LuaVariableType::String) {
5115
- luaGlobalsStr += var.name + " \t String\t " + var.stringValue + " \n\n " ;
5116
- }
5117
- else if (var.type == LuaVariableType::Number) {
5118
- // luaGlobalsStr += var.name + "\tNumber\t" + std::to_string(var.numberValue) + "\n\n";
5119
- std::ostringstream oss;
5120
- oss << std::fixed << std::setprecision (8 ) << var.numberValue ;
5121
- luaGlobalsStr += var.name + " \t Number\t " + oss.str () + " \n\n " ;
5122
-
5123
- }
5124
- else if (var.type == LuaVariableType::Boolean) {
5125
- luaGlobalsStr += var.name + " \t Boolean\t " + (var.booleanValue ? " true" : " false" ) + " \n\n " ;
5061
+ std::string globalsStr = " Global Lua variables:\n\n " ;
5062
+ for (const auto & p : globalLuaVariablesMap) {
5063
+ const LuaVariable& v = p.second ;
5064
+ if (v.type == LuaVariableType::String) {
5065
+ globalsStr += v.name + " \t String\t " + v.stringValue + " \n\n " ;
5066
+ } else if (v.type == LuaVariableType::Number) {
5067
+ std::ostringstream os; os << std::fixed << std::setprecision (8 ) << v.numberValue ;
5068
+ globalsStr += v.name + " \t Number\t " + os.str () + " \n\n " ;
5069
+ } else if (v.type == LuaVariableType::Boolean) {
5070
+ globalsStr += v.name + " \t Boolean\t " + (v.booleanValue ? " true" : " false" ) + " \n\n " ;
5126
5071
}
5127
5072
}
5128
5073
5129
- // Combine CAP variables and captured globals
5130
- std::string combinedVariablesStr = capVariablesStr + luaGlobalsStr;
5131
-
5132
- // Refresh UI as in original code
5133
5074
refreshUIListView ();
5134
-
5135
- // Show debug window
5136
- int response = ShowDebugWindow (combinedVariablesStr);
5137
- if (response == 3 ) { // "Stop" pressed
5138
- lua_pop (_luaState, 1 ); // pop DEBUG
5139
- return false ;
5140
- }
5075
+ int resp = ShowDebugWindow (capVariablesStr + globalsStr);
5076
+ if (resp == 3 ) { restoreStack (); return false ; } // “Stop”
5077
+ if (resp == -1 ) { restoreStack (); return false ; } // window closed
5141
5078
}
5142
5079
5143
- // pop DEBUG or non-boolean
5144
- lua_pop (_luaState, 1 );
5145
-
5146
- // 13) Return success
5080
+ // 12) Success
5081
+ restoreStack ();
5147
5082
return true ;
5148
5083
}
5149
5084
@@ -5925,8 +5860,11 @@ LRESULT CALLBACK MultiReplace::DebugWindowProc(HWND hwnd, UINT msg, WPARAM wPara
5925
5860
break ;
5926
5861
5927
5862
case WM_CLOSE:
5928
- // Handle the window close button (X)
5929
- debugWindowResponse = 3 ; // Set to the value that indicates the "Stop" button was pressed
5863
+ // Only set debugWindowResponse to -1 if not already set by a button
5864
+ if (debugWindowResponse == -1 ) {
5865
+ // Closed by X, Alt+F4, or CloseDebugWindow()
5866
+ debugWindowResponse = -1 ;
5867
+ }
5930
5868
5931
5869
// Save the window position and size before closing
5932
5870
RECT rect;
@@ -6009,7 +5947,6 @@ void MultiReplace::CopyListViewToClipboard(HWND hListView) {
6009
5947
}
6010
5948
}
6011
5949
6012
- /*
6013
5950
void MultiReplace::CloseDebugWindow () {
6014
5951
// Triggers the WM_CLOSE message for the debug window, handled in DebugWindowProc
6015
5952
if (hDebugWnd != NULL ) {
@@ -6028,8 +5965,7 @@ void MultiReplace::CloseDebugWindow() {
6028
5965
PostMessage (hDebugWnd, WM_CLOSE, 0 , 0 );
6029
5966
}
6030
5967
}
6031
- */
6032
-
5968
+ /*
6033
5969
void MultiReplace::CloseDebugWindow()
6034
5970
{
6035
5971
if (!hDebugWnd) return; // nothing to do
@@ -6048,7 +5984,7 @@ void MultiReplace::CloseDebugWindow()
6048
5984
6049
5985
SendMessage(hwnd, WM_CLOSE, 0, 0); // synchronous → window really gone
6050
5986
}
6051
-
5987
+ */
6052
5988
6053
5989
#pragma endregion
6054
5990
0 commit comments