fix: MRU file history, bookmark, caret pos, selection maintenance.

This commit is contained in:
METANEOCORTEX\Kotti 2026-05-04 20:19:17 +02:00
parent 4c01932f94
commit 78108398fd
4 changed files with 66 additions and 18 deletions

View File

@ -2616,17 +2616,24 @@ bool MRU_Add(LPMRULIST pmru, LPCWSTR pszNew, cpi_enc_t iEnc, DocPos iPos, DocPos
int i = 0;
for (; i < pmru->iSize; ++i) {
if (_MRU_Compare(pmru, pmru->pszItems[i], pszNew) == 0) {
LocalFree(pmru->pszItems[i]); // StrDup()
pmru->pszItems[i] = NULL;
break;
}
}
i = min_i(i, pmru->iSize - 1);
// Detach the outgoing entry at slot i (deferred free — pszBookMarks parameter
// may alias pmru->pszBookMarks[i], so we must not free until after StrDup).
LPWSTR pszOldItem = pmru->pszItems[i];
pmru->pszItems[i] = NULL;
LPWSTR pszOldBookMarks = pmru->pszBookMarks[i];
pmru->pszBookMarks[i] = NULL;
for (; i > 0; i--) {
pmru->pszItems[i] = pmru->pszItems[i - 1];
pmru->iEncoding[i] = pmru->iEncoding[i - 1];
pmru->iCaretPos[i] = pmru->iCaretPos[i - 1];
pmru->iSelAnchPos[i] = pmru->iSelAnchPos[i - 1];
pmru->pszBookMarks[i] = pmru->pszBookMarks[i - 1];
pmru->bDirty[i] = pmru->bDirty[i - 1];
}
pmru->pszItems[0] = StrDup(pszNew); // LocalAlloc()
@ -2634,6 +2641,12 @@ bool MRU_Add(LPMRULIST pmru, LPCWSTR pszNew, cpi_enc_t iEnc, DocPos iPos, DocPos
pmru->iCaretPos[0] = (Settings.PreserveCaretPos ? iPos : -1);
pmru->iSelAnchPos[0] = (Settings.PreserveCaretPos ? iSelAnc : -1);
pmru->pszBookMarks[0] = (pszBookMarks ? StrDup(pszBookMarks) : NULL); // LocalAlloc()
pmru->bDirty[0] = true;
// Now safe to free old pointers (StrDup above made independent copies)
if (pszOldItem) { LocalFree(pszOldItem); }
if (pszOldBookMarks) { LocalFree(pszOldBookMarks); }
return true;
}
return false;
@ -2677,18 +2690,23 @@ bool MRU_AddPath(LPMRULIST pmru, const HPATHL hpth, bool bRelativePath, bool bUn
if (pmru) {
int i = 0;
bool const bAlreadyInList = MRU_FindPath(pmru, hpth, &i);
if (bAlreadyInList) {
LocalFree(pmru->pszItems[i]); // StrDup()
pmru->pszItems[i] = NULL;
} else {
if (!bAlreadyInList) {
i = (i < pmru->iSize) ? i : (pmru->iSize - 1);
}
// Detach the outgoing entry at slot i (deferred free — pszBookMarks parameter
// may alias pmru->pszBookMarks[i], so we must not free until after StrDupW).
LPWSTR pszOldItem = pmru->pszItems[i];
pmru->pszItems[i] = NULL;
LPWSTR pszOldBookMarks = pmru->pszBookMarks[i];
pmru->pszBookMarks[i] = NULL;
for (; i > 0; i--) {
pmru->pszItems[i] = pmru->pszItems[i - 1];
pmru->iEncoding[i] = pmru->iEncoding[i - 1];
pmru->iCaretPos[i] = pmru->iCaretPos[i - 1];
pmru->iSelAnchPos[i] = pmru->iSelAnchPos[i - 1];
pmru->pszBookMarks[i] = pmru->pszBookMarks[i - 1];
pmru->bDirty[i] = pmru->bDirty[i - 1];
}
HPATHL hpth_cpy = Path_Copy(hpth);
@ -2701,9 +2719,14 @@ bool MRU_AddPath(LPMRULIST pmru, const HPATHL hpth, bool bRelativePath, bool bUn
pmru->iCaretPos[0] = (Settings.PreserveCaretPos ? iPos : -1);
pmru->iSelAnchPos[0] = (Settings.PreserveCaretPos ? iSelAnc : -1);
pmru->pszBookMarks[0] = (pszBookMarks ? StrDupW(pszBookMarks) : NULL); // LocalAlloc()
pmru->bDirty[0] = true;
Path_Release(hpth_cpy);
// Now safe to free old pointers (StrDupW above made independent copies)
if (pszOldItem) { LocalFree(pszOldItem); }
if (pszOldBookMarks) { LocalFree(pszOldBookMarks); }
return bAlreadyInList;
}
return false;
@ -2802,6 +2825,7 @@ bool MRU_Empty(LPMRULIST pmru, bool bExceptLeast, bool bDelete)
pmru->iEncoding[i] = 0;
pmru->iCaretPos[i] = -1;
pmru->iSelAnchPos[i] = -1;
pmru->bDirty[i] = false;
if (pmru->pszBookMarks[i]) {
LocalFree(pmru->pszBookMarks[i]); // StrDup()
pmru->pszBookMarks[i] = NULL;
@ -2940,8 +2964,27 @@ bool MRU_MergeSave(LPMRULIST pmru, bool bAddFiles, bool bRelativePath, bool bUne
if (pmru->pszItems[i]) {
Path_Reset(hpth, pmru->pszItems[i]);
Path_AbsoluteFromApp(hpth, true);
MRU_AddPath(pmruBase, hpth, bRelativePath, bUnexpandMyDocs,
pmru->iEncoding[i], pmru->iCaretPos[i], pmru->iSelAnchPos[i], pmru->pszBookMarks[i]);
int idxInBase = 0;
bool bInBase = MRU_FindPath(pmruBase, hpth, &idxInBase);
if (!bInBase || pmru->bDirty[i]) {
// New entry not in INI, or entry whose metadata was updated
// during this session (visited file): use in-memory props.
MRU_AddPath(pmruBase, hpth, bRelativePath, bUnexpandMyDocs,
pmru->iEncoding[i], pmru->iCaretPos[i],
pmru->iSelAnchPos[i], pmru->pszBookMarks[i]);
} else {
// File is in INI and was NOT visited this session:
// its INI props may have been updated by another instance.
// Preserve the INI values so only ordering is updated.
cpi_enc_t const iBaseEnc = pmruBase->iEncoding[idxInBase];
DocPos const iBasePos = pmruBase->iCaretPos[idxInBase];
DocPos const iBaseAnc = pmruBase->iSelAnchPos[idxInBase];
LPCWSTR const pBaseMarks = pmruBase->pszBookMarks[idxInBase];
MRU_AddPath(pmruBase, hpth, bRelativePath, bUnexpandMyDocs,
iBaseEnc, iBasePos, iBaseAnc, pBaseMarks);
}
}
}
Path_Release(hpth);
@ -2955,6 +2998,7 @@ bool MRU_MergeSave(LPMRULIST pmru, bool bAddFiles, bool bRelativePath, bool bUne
}
MRU_Save(pmruBase);
MRU_Destroy(pmruBase);
pmruBase = NULL;
CloseSettingsFile(__func__, true);

View File

@ -11303,6 +11303,7 @@ bool FileLoad(const HPATHL hfile_pth, const FileLoadFlags fLoadFlags, const DocP
}
if (!(Flags.bDoRelaunchElevated || s_IsThisAnElevatedRelaunch)) {
MRU_AddPath(Globals.pFileMRU, Paths.CurrentFile, Flags.RelativeFileMRU, Flags.PortableMyDocs, fioStatus.iEncoding, iCaretPos, iAnchorPos, pszBookMarks);
pszBookMarks = Globals.pFileMRU->pszBookMarks[0]; // MRU_AddPath freed the old pointer; slot 0 has the fresh copy
AddFilePathToRecentDocs(Paths.CurrentFile);
}
@ -11593,6 +11594,7 @@ static void _MRU_UpdateSession()
Globals.pFileMRU->iEncoding[idx] = Encoding_GetCurrent();
Globals.pFileMRU->iCaretPos[idx] = bSkipCaretMRU ? -1 : SciCall_GetCurrentPos();
Globals.pFileMRU->iSelAnchPos[idx] = bSkipCaretMRU ? -1 : (Sci_IsMultiOrRectangleSelection() ? -1 : SciCall_GetAnchor());
Globals.pFileMRU->bDirty[idx] = true;
WCHAR wchBookMarks[MRU_BMRK_SIZE] = { L'\0' };
EditGetBookmarkList(Globals.hwndEdit, wchBookMarks, COUNTOF(wchBookMarks));
if (Globals.pFileMRU->pszBookMarks[idx]) {

View File

@ -340,6 +340,7 @@ typedef struct MRULIST {
DocPos iCaretPos[MRU_MAXITEMS];
DocPos iSelAnchPos[MRU_MAXITEMS];
LPWSTR pszBookMarks[MRU_MAXITEMS];
bool bDirty[MRU_MAXITEMS];
} MRULIST, *PMRULIST, *LPMRULIST;

View File

@ -1,8 +1,8 @@
# Notepad3 TODO
## Ideas (deliberated)
- [ ] PCRE2 backward search seems to be slow - ask Claude for analysis
## Ideas / New Features (deliberated)
- [ ] Merge/Cleanup all old documentation (Build/Docs/*.txt, etc.) files
- [ ] PCRE2 backward search seems to be slow - ask Claude for analysis
## High Priority
@ -40,9 +40,6 @@
- [x] **(Q2) BUG: Initial window position not working** - Position settings ignored
- [x] **To be analyzed - works as designed ???** - ⚠ Validation ❗
- Issue: [#4725](https://github.com/rizonesoft/Notepad3/issues/4725)
- [x] **(Q3) BUG: Regex replace issue** - Verify if still present - ✅ FIXED
- [x] Issue: [#3531](https://github.com/rizonesoft/Notepad3/issues/3531) - ✅ FIXED
- [x] ✅ FIXED - Was no Bug but bad RegEx pattern design (expectation vs. what regex really does)
- [ ] **(Q2) BUG: Minipath options don't save** - FullRowSelect/TrackSelect broken
- Issue: [#4116](https://github.com/rizonesoft/Notepad3/issues/4116)
- [x] **(Q1) BUG: Monitoring log not saved** - ✅ FIXED
@ -56,16 +53,13 @@
- Issue: [#5151](https://github.com/rizonesoft/Notepad3/issues/5151)
- [ ] **(Q3) BUG: grepWinNP3 crash** - Right-click search results crashes
- Issue: [#5158](https://github.com/rizonesoft/Notepad3/issues/5158)
- [ ] **(Q2) BUG: PHP comment toggle** - Ctrl+Q not working in Web Source Code
- [x] **(Q2) BUG: PHP comment toggle** - Ctrl+Q not working in Web Source Code - ✅ FIXED
- Issue: [#5163](https://github.com/rizonesoft/Notepad3/issues/5163)
- [ ] **(Q2) BUG: AltGr shortcut conflict** - Can't type `}` `@` on non-US keyboards
- Issue: [#5220](https://github.com/rizonesoft/Notepad3/issues/5220)
- [x] **(Q1) BUG: Mouse scroll settings not updated** - ✅ FIXED
- Issue: [#5223](https://github.com/rizonesoft/Notepad3/issues/5223)
- Fix: Forward `WM_SETTINGCHANGE` to Scintilla to refresh cached scroll parameters
- [ ] **(Q2) BUG: Highlight current line broken** - Settings not respected (regression)
- Issue: [#5270](https://github.com/rizonesoft/Notepad3/issues/5270)
- **This is a discussion, about limited line highlite rule language in schema definition **
- [x] **(Q2) BUG: File lock held too long on save** - Blocks FileSystemWatcher - ✅ FIXED
- [ ] **Needs validation**
- Issue: [#5301](https://github.com/rizonesoft/Notepad3/issues/5301)
@ -180,7 +174,14 @@
- [ ] **(Q3) Custom Keyboard Shortcuts** - User-configurable shortcut keys
- Issue: [#595](https://github.com/rizonesoft/Notepad3/issues/595)
## Feature Ideas
## Open Discussions
- [ ] **(Q2) BUG: Highlight current line broken** - Settings not respected (regression)
- Issue: [#5270](https://github.com/rizonesoft/Notepad3/issues/5270)
- **This is a discussion, about limited line highlite rule language in schema definition **
- [x] **(Q3) BUG: Regex replace issue** - Verify if still present - ✅ FIXED
- Issue: [#3531](https://github.com/rizonesoft/Notepad3/issues/3531)
- Was no Bug but bad RegEx pattern design (expectation vs. what regex really does)
### Text Processing
- [ ] **(Q1) Strip Leading Blanks** - Trim leading whitespace (NP3 only has trailing)