diff --git a/CHANGELOG.md b/CHANGELOG.md index bfab7cd..cb12526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ #### Review fixes +- Preserved punctuation immediately before a completion or elapsed-time tag when reopening a task. - Rejected invalid ISO calendar dates in time estimates instead of silently rolling them into another month. - Ignored empty relative file links wrapped in punctuation or spelled with dot path segments, instead of linking to the Todo document's directory. - Kept tag cleanup and hidden-tag labels working after an unmatched backtick, while preserving tags inside complete inline code spans. diff --git a/src/utils/todo-status.ts b/src/utils/todo-status.ts index aba3bbd..fcd23a7 100644 --- a/src/utils/todo-status.ts +++ b/src/utils/todo-status.ts @@ -59,5 +59,9 @@ export const removeTodoStatusTag = (text: string, pattern: RegExp): string => { if (!match) return text; - return text.slice(0, match.index) + text.slice(match.index + match[0].length); + // The tag-boundary regex includes the character before @. Keep punctuation, + // but consume the separating whitespace as before. + const boundary = match[0][0]; + const prefix = boundary !== '@' && !/\s/.test(boundary) ? boundary : ''; + return text.slice(0, match.index) + prefix + text.slice(match.index + match[0].length); }; diff --git a/test/todo-status.spec.ts b/test/todo-status.spec.ts index 29ff21c..e3c4144 100644 --- a/test/todo-status.spec.ts +++ b/test/todo-status.spec.ts @@ -39,4 +39,13 @@ describe('Todo status matching', () => { ); expect(removeTodoStatusTag('☐ Explain `@done`', tagFinished)).to.equal('☐ Explain `@done`'); }); + + it('preserves punctuation before status tags when unfinishing tasks', () => { + const tagFinished = /(?:^|[^a-zA-Z0-9])@(?:done|cancelled)(?:\([^)]*\))?/; + const tagElapsed = /(?:^|[^a-zA-Z0-9])@(?:lasted|wasted)(?:\([^)]*\))?/; + + expect(removeTodoStatusTag('☐ Ship,@done', tagFinished)).to.equal('☐ Ship,'); + expect(removeTodoStatusTag('☐ Ship!@cancelled(reason)', tagFinished)).to.equal('☐ Ship!'); + expect(removeTodoStatusTag('☐ Ship,@lasted(2h)', tagElapsed)).to.equal('☐ Ship,'); + }); });