Skip to content

Commit ee3c359

Browse files
committed
Fix multiple date (\d:"format") insertation bug in Unicode texts
1 parent 0399c27 commit ee3c359

3 files changed

Lines changed: 48 additions & 23 deletions

File tree

ReadMe.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ v2.8 — New features (examples)
2828
Notepad++).
2929
- Example tag line in `WebEdit.ini`:
3030
user=Author: \u|
31-
- \d:"format" (experimental)
31+
- \d:"format"
3232
- Replaced with the local date/time. An optional .NET-style date/time
3333
format string may be supplied in quotes.
3434
- Examples:

WebEdit/Resources/WebEdit.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ T&r=<tr>|</tr>
6767
; \u = Windows username
6868
; \x = current filename (without path) / document name
6969
; \p = current full file path (including filename) / document name
70-
; \d:"..." = Local date/time in the format specified between the quotes, e.g. \d:"yyyy-MM-dd HH:mm:ss" (2025-12-31 23:59:59) -- experimental!
70+
; \d:"..." = Local date/time in the format specified between the quotes, e.g. \d:"yyyy-MM-dd HH:mm:ss" (2025-12-31 23:59:59)
7171
; \| = |
7272
; \\ = \ (for the sequences above, e.g. \\c, \\i etc. -- except.: \|, as it is already escaped)
7373

WebEdit/Tags.cs

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@ internal bool FindAndReplace(long startPos)
7171
// track the caret position resulting from the FIRST '\i' replacement
7272
long firstIndentCaret = -1;
7373

74-
Dictionary<string, Action> replacements = new()
74+
Dictionary<string, Func<int>> replacements = new()
7575
{
7676
{"\\f", PasteFileContents},
77-
{"\\c", sci.Paste},
77+
{"\\c", PasteClipboard},
7878
{"\\u", PasteUserName},
7979
{"\\x", PasteFileName},
8080
{"\\p", PasteFilePath},
8181
{"\\d", PasteDateTime},
82-
{"\\i", sci.Tab} // must come last as the caret will be restored here!
82+
{"\\i", PasteTab} // must come last as the caret will be restored here!
8383
};
8484

8585
foreach ((string seq, var replaceFunc) in replacements)
@@ -91,6 +91,7 @@ internal bool FindAndReplace(long startPos)
9191

9292
while (seqStart > -1)
9393
{
94+
var newSeqLength = -1; // seq.Length
9495
var tmpTargetText = sci.GetTargetText().Substring(0, seqStart);
9596
int tmpByteDiff = sci.CodePage.GetByteCount(tmpTargetText) - tmpTargetText.Length;
9697
if (tmpByteDiff > 0)
@@ -99,7 +100,7 @@ internal bool FindAndReplace(long startPos)
99100
sci.SetSelection(selStart, selStart + seq.Length); // sci.CodePage.GetByteCount(seq)
100101
if (seqStart == 0 || sci.GetCharAt(selStart - 1) != 92) // Backspace (\)
101102
{
102-
replaceFunc();
103+
newSeqLength = replaceFunc();
103104
}
104105
else
105106
{
@@ -108,11 +109,7 @@ internal bool FindAndReplace(long startPos)
108109
rangeEnd--;
109110
}
110111
sci.SetCurrentPos(sci.GetSelectionEnd());
111-
rangeEnd += (sci.GetSelectionEnd() - selStart) - seq.Length; // sci.CodePage.GetByteCount(seq)
112-
113-
// Capture the first date only!
114-
if (seq == "\\d")
115-
break; // TODO: replacing the first occurrence (Unicode issue?) -- rangeEnd may be wrong as using `seq.Length`!
112+
rangeEnd += (sci.GetSelectionEnd() - selStart) - (newSeqLength > -1 ? newSeqLength : seq.Length); // sci.CodePage.GetByteCount(seq)
116113

117114
// capture the caret position produced by the first '\i' replacement
118115
if (seq == "\\i" && firstIndentCaret == -1)
@@ -142,13 +139,13 @@ internal bool FindAndReplace(long startPos)
142139
/// <remarks>
143140
/// Adapted from <see href="https://github.com/alex-ilin/WebEdit/blob/7bb4243/Legacy-v2.1/Src/Tags.ob2#L223"/>
144141
/// </remarks>
145-
private void PasteFileContents()
142+
private int PasteFileContents()
146143
{
147144
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
148145
long tagStart = sci.GetSelectionEnd();
149146

150147
if ('[' != sci.GetCharAt(tagStart))
151-
return;
148+
return -1;
152149

153150
long selectionEnd = tagStart;
154151
while (']' != sci.GetCharAt(selectionEnd) && selectionEnd++ < sci.GetLineEndPosition(tagStart)) ;
@@ -164,7 +161,7 @@ private void PasteFileContents()
164161
if (!File.Exists(filePath) ||
165162
/* do not paste the contents of our own INI file */
166163
(string.IsNullOrEmpty(section) && string.Compare(filePath, Main.iniFilePath, StringComparison.InvariantCultureIgnoreCase) == 0))
167-
return;
164+
return -1;
168165

169166
StringBuilder buffer = new();
170167
if (!string.IsNullOrEmpty(section))
@@ -180,11 +177,25 @@ private void PasteFileContents()
180177
}
181178

182179
string replacementText = buffer.ToString().TrimEnd();
180+
var newSeqLength = -1;
183181
if (!string.IsNullOrWhiteSpace(replacementText))
184-
{
182+
{
185183
sci.SetSelection(sci.GetSelectionStart(), selectionEnd + sci.CodePage.GetByteCount("]"));
184+
newSeqLength = (int)(sci.GetSelectionEnd() - sci.GetSelectionStart());
186185
sci.ReplaceSel(replacementText);
187186
}
187+
return newSeqLength;
188+
}
189+
190+
191+
/// <summary>
192+
/// Paste the Windows clipboard content for the '\c' tag.
193+
/// </summary>
194+
private int PasteClipboard()
195+
{
196+
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
197+
sci.Paste();
198+
return -1;
188199
}
189200

190201
/// <summary>
@@ -193,7 +204,7 @@ private void PasteFileContents()
193204
/// <remarks>
194205
/// For custom date/time format strings see: <see href="https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings"/>
195206
/// </remarks>
196-
private void PasteDateTime()
207+
private int PasteDateTime()
197208
{
198209
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
199210
long startPos = sci.GetSelectionStart();
@@ -217,41 +228,55 @@ private void PasteDateTime()
217228
int matchStart = match.Index + offset;
218229
int matchEnd = matchStart + match.Length;
219230
sci.SetSelection(sci.GetTargetStart() + matchStart, sci.GetTargetStart() + matchEnd);
231+
int newSeqLength = (int)(sci.GetSelectionEnd() - sci.GetSelectionStart());
220232
sci.ReplaceSel(formattedDate);
221-
return; // Hotfix: only replace the first occurrence (Unicode issue?)
233+
return newSeqLength; // Hotfix: only replace the first occurrence (Unicode issue?)
222234
// offset += (formattedDate.Length - match.Length);
223235
}
224-
236+
return -1;
225237
}
226238

227239
/// <summary>
228240
/// Paste the short Windows username for the '\u' tag.
229241
/// </summary>
230-
private void PasteUserName()
242+
private int PasteUserName()
231243
{
232244
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
233245
string user = Environment.UserName ?? string.Empty;
234246
sci.ReplaceSel(user);
247+
return -1;
235248
}
236249

237250
/// <summary>
238251
/// Paste the current file name for the '\x' tag e.g. 'example.txt'
239252
/// </summary>
240-
private void PasteFileName()
253+
private int PasteFileName()
241254
{
242255
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
243256
string fileName = Path.GetFileName(PluginData.Notepad.GetCurrentFilePath()); // `PluginData.Notepad.GetCurrentFile()` or similar function (for `NppMsg.NPPM_GETFILENAME`) is not available...
244257
sci.ReplaceSel(fileName);
258+
return -1;
245259
}
246260

247261
/// <summary>
248262
/// Paste the current file name for the '\p' tag e.g. 'C:\path\to\example.txt'
249263
/// </summary>
250-
private void PasteFilePath()
264+
private int PasteFilePath()
251265
{
252266
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
253-
string fileName = PluginData.Notepad.GetCurrentFilePath();
254-
sci.ReplaceSel(fileName);
267+
string filePath = PluginData.Notepad.GetCurrentFilePath();
268+
sci.ReplaceSel(filePath);
269+
return -1;
270+
}
271+
272+
/// <summary>
273+
/// Paste tab for the '\t' tag
274+
/// </summary>
275+
private int PasteTab()
276+
{
277+
ScintillaGateway sci = new(Utils.GetCurrentScintilla());
278+
sci.Tab();
279+
return -1;
255280
}
256281

257282
/// <summary>

0 commit comments

Comments
 (0)