Skip to content

Commit 3a97512

Browse files
committed
fixed DeBUG Window crash when closed by function.
1 parent b70e99e commit 3a97512

File tree

1 file changed

+103
-167
lines changed

1 file changed

+103
-167
lines changed

src/MultiReplacePanel.cpp

Lines changed: 103 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -4934,216 +4934,151 @@ bool MultiReplace::compileLuaReplaceCode(const std::string& luaCode)
49344934
return true;
49354935
}
49364936

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)
49384938
{
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
49644955
setLuaVariable(_luaState, "FPATH", vars.FPATH);
49654956
setLuaVariable(_luaState, "FNAME", vars.FNAME);
49664957
setLuaVariable(_luaState, "MATCH", vars.MATCH);
49674958

4968-
// 4) Set REGEX flag
4959+
// 5) REGEX flag
49694960
lua_pushboolean(_luaState, regex);
49704961
lua_setglobal(_luaState, "REGEX");
49714962

4972-
// 5) If regex is enabled, push CAP variables
4963+
// 6) CAP# globals (regex only)
49734964
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; }
49834969

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());
49914976
}
4992-
4993-
// Set CAP# in Lua
49944977
std::string capName = "CAP" + std::to_string(i);
4995-
setLuaVariable(_luaState, capName, capValue);
4978+
setLuaVariable(_luaState, capName, capVal);
49964979
capNames.push_back(capName);
49974980
}
49984981
}
49994982

5000-
// 6) Execute pre-compiled Lua chunk
4983+
// 7) Run pre-compiled chunk
50014984
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();
50214994
return false;
50224995
}
50234996

5024-
// 7) Retrieve resultTable
4997+
// 8) resultTable
50254998
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();
50375009
return false;
50385010
}
50395011

5040-
// 8) Extract 'result'
5041-
lua_getfield(_luaState, -1, "result");
5012+
// 9) result & skip
5013+
lua_getfield(_luaState, -1, "result"); // push result
50425014
if (lua_isnil(_luaState, -1)) {
50435015
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;
50445020
}
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
50545022

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
50645026

5065-
// 10) Pop resultTable
5066-
lua_pop(_luaState, 1);
5027+
// (resultTable left on stack until the very end, then dropped by restoreStack)
50675028

5068-
// 11) Gather CAP variable info, then remove them from Lua
5029+
// 10) CAP variable dump & cleanup
50695030
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
50745033

50755034
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 + "\tNumber\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 + "\tBoolean\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 + "\tNumber\t" + os.str() + "\n\n";
5038+
} else if (lua_isboolean(_luaState, -1)) {
5039+
bool b = lua_toboolean(_luaState, -1);
5040+
capVariablesStr += capName + "\tBoolean\t" + (b ? "true" : "false") + "\n\n";
5041+
} else if (lua_isstring(_luaState, -1)) {
50895042
capVariablesStr += capName + "\tString\t" + lua_tostring(_luaState, -1) + "\n\n";
5090-
}
5091-
else {
5043+
} else {
50925044
capVariablesStr += capName + "\t<nil>\n\n";
50935045
}
5046+
lua_pop(_luaState, 1); // pop CAP value
50945047

5095-
lua_pop(_luaState, 1);
5096-
// Remove the global
5097-
lua_pushnil(_luaState);
5048+
lua_pushnil(_luaState); // clear global
50985049
lua_setglobal(_luaState, capName.c_str());
50995050
}
51005051

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) {
51065058
globalLuaVariablesMap.clear();
51075059
captureLuaGlobals(_luaState);
51085060

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 + "\tString\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 + "\tNumber\t" + oss.str() + "\n\n";
5122-
5123-
}
5124-
else if (var.type == LuaVariableType::Boolean) {
5125-
luaGlobalsStr += var.name + "\tBoolean\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 + "\tString\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 + "\tNumber\t" + os.str() + "\n\n";
5069+
} else if (v.type == LuaVariableType::Boolean) {
5070+
globalsStr += v.name + "\tBoolean\t" + (v.booleanValue ? "true" : "false") + "\n\n";
51265071
}
51275072
}
51285073

5129-
// Combine CAP variables and captured globals
5130-
std::string combinedVariablesStr = capVariablesStr + luaGlobalsStr;
5131-
5132-
// Refresh UI as in original code
51335074
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
51415078
}
51425079

5143-
// pop DEBUG or non-boolean
5144-
lua_pop(_luaState, 1);
5145-
5146-
// 13) Return success
5080+
// 12) Success
5081+
restoreStack();
51475082
return true;
51485083
}
51495084

@@ -5925,8 +5860,11 @@ LRESULT CALLBACK MultiReplace::DebugWindowProc(HWND hwnd, UINT msg, WPARAM wPara
59255860
break;
59265861

59275862
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+
}
59305868

59315869
// Save the window position and size before closing
59325870
RECT rect;
@@ -6009,7 +5947,6 @@ void MultiReplace::CopyListViewToClipboard(HWND hListView) {
60095947
}
60105948
}
60115949

6012-
/*
60135950
void MultiReplace::CloseDebugWindow() {
60145951
// Triggers the WM_CLOSE message for the debug window, handled in DebugWindowProc
60155952
if (hDebugWnd != NULL) {
@@ -6028,8 +5965,7 @@ void MultiReplace::CloseDebugWindow() {
60285965
PostMessage(hDebugWnd, WM_CLOSE, 0, 0);
60295966
}
60305967
}
6031-
*/
6032-
5968+
/*
60335969
void MultiReplace::CloseDebugWindow()
60345970
{
60355971
if (!hDebugWnd) return; // nothing to do
@@ -6048,7 +5984,7 @@ void MultiReplace::CloseDebugWindow()
60485984
60495985
SendMessage(hwnd, WM_CLOSE, 0, 0); // synchronous → window really gone
60505986
}
6051-
5987+
*/
60525988

60535989
#pragma endregion
60545990

0 commit comments

Comments
 (0)