Skip to content

Commit 704f966

Browse files
committed
fixed id cschimg in LanguageManager; limited Stack in UndoRedoManager
1 parent 630002b commit 704f966

File tree

5 files changed

+87
-22
lines changed

5 files changed

+87
-22
lines changed

src/LanguageManager.cpp

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,31 @@
2424
#include <windows.h>
2525
#include <map>
2626

27+
namespace {
28+
29+
// Build a cache key from id + placeholders.
30+
static std::wstring makeKey(const std::wstring& id,
31+
const std::vector<std::wstring>& repl)
32+
{
33+
// Use a rarely used unit separator as delimiter.
34+
std::wstring key = id;
35+
key.push_back(L'\x1F');
36+
for (const auto& r : repl) {
37+
key += r;
38+
key.push_back(L'\x1F');
39+
}
40+
return key;
41+
}
42+
43+
// Global cache holder for getLPCW(); single instance per process.
44+
static std::unordered_map<std::wstring, std::wstring>& lpcwCache()
45+
{
46+
static std::unordered_map<std::wstring, std::wstring> cache;
47+
return cache;
48+
}
49+
50+
}
51+
2752
// -----------------------------------------------------------------
2853
// Singleton
2954
// -----------------------------------------------------------------
@@ -59,69 +84,99 @@ bool LanguageManager::loadFromIni(const std::wstring& iniFile,
5984
return false;
6085

6186
const auto& data = _cache.raw();
62-
// 2) override with requested language
6387
if (auto it = data.find(languageCode); it != data.end())
6488
for (const auto& kv : it->second)
6589
_table[kv.first] = kv.second;
6690

91+
invalidateCaches(); // Clear derived caches after language change
6792
return true;
6893
}
6994

95+
void LanguageManager::invalidateCaches()
96+
{
97+
lpcwCache().clear();
98+
}
99+
70100
// -----------------------------------------------------------------
71101
// String getters
72102
// -----------------------------------------------------------------
103+
// Replace <br/>, then $REPLACE_n (descending), then $REPLACE.
73104
std::wstring LanguageManager::get(const std::wstring& id,
74105
const std::vector<std::wstring>& repl) const
75106
{
76107
auto it = _table.find(id);
77-
if (it == _table.end()) return L"Text not found";
108+
if (it == _table.end())
109+
return id; // developer-friendly fallback: show missing key
78110

79111
std::wstring result = it->second;
80112
const std::wstring base = L"$REPLACE_STRING";
81113

82-
// <br/> → CRLF
114+
// 1) Replace <br/> with CRLF (all occurrences)
83115
for (size_t p = result.find(L"<br/>");
84116
p != std::wstring::npos;
85117
p = result.find(L"<br/>", p))
118+
{
86119
result.replace(p, 5, L"\r\n");
120+
p += 2; // advance beyond inserted CRLF to avoid re-scan at same spot
121+
}
122+
123+
// 2) Numbered placeholders: $REPLACE_STRING1, $REPLACE_STRING2, ... (highest index first)
124+
for (size_t i = repl.size(); i > 0; --i)
125+
{
126+
const std::wstring ph = base + std::to_wstring(i);
127+
const std::wstring& val = repl[i - 1];
87128

88-
// numbered placeholders (highest first)
89-
for (size_t i = repl.size(); i > 0; --i) {
90-
std::wstring ph = base + std::to_wstring(i);
91129
for (size_t p = result.find(ph);
92130
p != std::wstring::npos;
93131
p = result.find(ph, p))
94-
result.replace(p, ph.size(), repl[i - 1]);
132+
{
133+
result.replace(p, ph.size(), val);
134+
p += val.size(); // skip over inserted text
135+
}
95136
}
96137

97-
// plain $REPLACE_STRING
98-
for (size_t p = result.find(base);
99-
p != std::wstring::npos;
100-
p = result.find(base, p))
101-
result.replace(p, base.size(),
102-
repl.empty() ? L"" : repl[0]);
138+
// 3) Plain $REPLACE_STRING -> repl[0] (empty if not provided)
139+
{
140+
const std::wstring& val = repl.empty() ? std::wstring() : repl[0];
141+
142+
for (size_t p = result.find(base);
143+
p != std::wstring::npos;
144+
p = result.find(base, p))
145+
{
146+
result.replace(p, base.size(), val);
147+
p += val.size(); // skip over inserted text
148+
}
149+
}
103150

104151
return result;
105152
}
106153

154+
107155
LPCWSTR LanguageManager::getLPCW(const std::wstring& id,
108156
const std::vector<std::wstring>& repl) const
109157
{
110-
static std::map<std::wstring, std::wstring> cache;
111-
auto& ref = cache[id];
112-
if (ref.empty())
113-
ref = get(id, repl);
114-
return ref.c_str();
158+
// Cache per (id + repl) to avoid wrong reuse for different placeholders.
159+
auto& cache = lpcwCache();
160+
const std::wstring key = makeKey(id, repl);
161+
162+
auto it = cache.find(key);
163+
if (it == cache.end())
164+
it = cache.emplace(key, get(id, repl)).first;
165+
166+
return it->second.c_str();
115167
}
116168

169+
117170
LPWSTR LanguageManager::getLPW(const std::wstring& id,
118171
const std::vector<std::wstring>& repl) const
119172
{
120-
static std::wstring buf;
173+
// Use a thread-local buffer to avoid data races and overwrite issues.
174+
thread_local std::wstring buf;
121175
buf = get(id, repl);
122-
return &buf[0];
176+
return buf.empty() ? nullptr : &buf[0];
123177
}
124178

179+
125180
// -----------------------------------------------------------------
126181
// Detect active language from Notepad++ nativeLang.xml
127182
// -----------------------------------------------------------------

src/LanguageManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class LanguageManager
6969
LanguageManager& operator=(const LanguageManager&) = delete;
7070

7171
static std::wstring detectLanguage(const std::wstring& nativeLangXmlPath);
72+
void invalidateCaches();
7273

7374
IniFileCache _cache; // languages.ini only
7475
std::unordered_map<std::wstring, std::wstring> _table; // id → text

src/ResultDock.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@ void ResultDock::applyTheme()
614614
S(SCI_SETCARETLINEBACK, theme.caretLineBg, 0);
615615
S(SCI_SETCARETLINEBACKALPHA, theme.caretLineAlpha);
616616

617-
618617
// Line background indicator
619618
S(SCI_INDICSETSTYLE, INDIC_LINE_BACKGROUND, INDIC_HIDDEN);
620619

src/UndoRedoManager.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void UndoRedoManager::push(Action undoAction,
3939
std::move(redoAction),
4040
label });
4141
_redo.clear();
42+
trim();
4243
}
4344

4445
// -----------------------------------------------------------------------------

src/UndoRedoManager.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ class UndoRedoManager
3939

4040
bool undo(); // returns false if nothing to undo
4141
bool redo(); // returns false if nothing to redo
42-
4342
void clear();
4443

4544
[[nodiscard]] bool canUndo() const { return !_undo.empty(); }
@@ -50,6 +49,9 @@ class UndoRedoManager
5049
[[nodiscard]] std::wstring peekUndoLabel() const;
5150
[[nodiscard]] std::wstring peekRedoLabel() const;
5251

52+
void setCapacity(size_t cap) { _capacity = cap; trim(); }
53+
size_t capacity() const { return _capacity; }
54+
5355
private:
5456
UndoRedoManager() = default;
5557
~UndoRedoManager() = default;
@@ -64,4 +66,11 @@ class UndoRedoManager
6466

6567
std::vector<Item> _undo;
6668
std::vector<Item> _redo;
69+
70+
size_t _capacity = 200; // limited stps
71+
void trim() {
72+
if (_capacity == 0) return;
73+
while (_undo.size() > _capacity) _undo.erase(_undo.begin());
74+
while (_redo.size() > _capacity) _redo.erase(_redo.begin());
75+
}
6776
};

0 commit comments

Comments
 (0)