Skip to content

Fix character disappearing and false matching issues in TiddlyWiki 5.4 Freelink plugin#9397

Merged
Jermolene merged 18 commits into
TiddlyWiki:masterfrom
s793016:freelink-bug-fix
Dec 17, 2025
Merged

Fix character disappearing and false matching issues in TiddlyWiki 5.4 Freelink plugin#9397
Jermolene merged 18 commits into
TiddlyWiki:masterfrom
s793016:freelink-bug-fix

Conversation

@s793016

@s793016 s793016 commented Nov 5, 2025

Copy link
Copy Markdown
Contributor

This PR fixes two critical bugs in the freelinks plugin when running on TiddlyWiki 5.4:

Bug 1: First character disappearing

圖片

Symptom:
When freelinking is enabled, the first character of matched words disappears (e.g., "The" becomes "he", "Filter" becomes "ilter", "5.4.0" becomes ".4.0", ).

Root cause:
When the current tiddler's title was being filtered out, it was done too late in the process (during parse tree construction), causing text rendering issues.

Fix:

  • Move the current tiddler title filtering to the match validation stage (in processTextWithMatches)
  • Use substring instead of slice for better stability
  • Add proper case-insensitive comparison for title matching

Bug 2: False positive matches

圖片

Symptom:
Words like "it is", "Choose", "Set up" are incorrectly linked to tiddler "FooBar" when a tiddler titled "xxx x FooBar" exists.

Root cause:
The Aho-Corasick algorithm's output merging mechanism in buildFailureLinks caused failure link outputs to be incorrectly merged into intermediate nodes, resulting in false matches.

Fix:

  • Remove incorrect output merging in buildFailureLinks
  • Implement proper output collection during search by traversing the failure link chain
  • Add exact match validation: verify that the matched text exactly equals the pattern before accepting it
  • Add cycle detection to prevent infinite loops in failure link traversal

Test case
Import attached file to reproduce both bugs:
test2.json

With Word Boundary Check enabled and Ignore Case disabled, both bugs should be fixed.

False positive matches

Symptom: Words like "it is", "Choose", "Set up" are incorrectly linked to tiddler "FooBar" when a tiddler titled "xxx x FooBar" exists.

Root cause: The Aho-Corasick algorithm's output merging mechanism in buildFailureLinks caused failure link outputs to be incorrectly merged into intermediate nodes, resulting in false matches.

Fix:

Remove incorrect output merging in buildFailureLinks
Implement proper output collection during search by traversing the failure link chain
Add exact match validation: verify that the matched text exactly equals the pattern before accepting it
Add cycle detection to prevent infinite loops in failure link traversal
First character disappearing

Symptom: When freelinking is enabled, the first character of matched words disappears (e.g., "The" becomes "he", "Filter" becomes "ilter").

Root cause: When the current tiddler's title was being filtered out, it was done too late in the process (during parse tree construction), causing text rendering issues.

Fix:

Move the current tiddler title filtering to the match validation stage (in processTextWithMatches)
Use substring instead of slice for better stability
Add proper case-insensitive comparison for title matching
add back description
add back description
@netlify

netlify Bot commented Nov 5, 2025

Copy link
Copy Markdown

Deploy Preview for tiddlywiki-previews ready!

Name Link
🔨 Latest commit 2522705
🔍 Latest deploy log https://app.netlify.com/projects/tiddlywiki-previews/deploys/6913cc6b7e3e3800082cabb0
😎 Deploy Preview https://deploy-preview-9397--tiddlywiki-previews.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions

github-actions Bot commented Nov 5, 2025

Copy link
Copy Markdown

Confirmed: s793016 has already signed the Contributor License Agreement (see contributing.md)

add freelinks plugin for testing
add freelinks plugin for test
child.$.push.apply(child.$, failureOutput.$);
}

// Critical fix: remove incorrect output merging

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI like adding these useless comment. we don't need them in the code.

This is legacy feature of AI that used to work as Edit mode. Modern Agent mode AI can directly say these info in the chat, but they still like to add these things into the code.

@linonetwo

Copy link
Copy Markdown
Contributor

I'm not sure how to test this, can you try read existing test edition and try add two tests for this feature and bug issue?

@twMat

twMat commented Nov 5, 2025

Copy link
Copy Markdown
Contributor

Thanks for looking into this!

Symptom:
When freelinking is enabled, the first character of matched words disappears (e.g., "The" becomes "he", "Filter" becomes "ilter", ...

Hm, that is now quite how it appeared for me. My bug demo here shows the topmost tiddler like this:

image

...when the edit view is actually:
image

...i.e there it is actually the whole first word of those sentences, not just the first letter, that disappear.

Maybe you PR fixes this but I'm saying it, just to make sure this was not missed.

@pmario

pmario commented Nov 5, 2025

Copy link
Copy Markdown
Member

@twMat Did you test with this preview: https://deploy-preview-9397--tiddlywiki-previews.netlify.app/

It contains the freelinks plugin now. So you can directly test from there.

@pmario

pmario commented Nov 5, 2025

Copy link
Copy Markdown
Member

I only did a very short test and it looks better now.

erase comment
erase comment
var failureLink = (fail && fail[char]) ? fail[char] : root;
this.failure[child] = failureLink;

// Critical fix: remove incorrect output merging

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO Critical fix should have been removed, but the rest seems to be important to understand the code. so this may stay

var char = text[i];
var transitionCount = 0;

// Follow failure links to find a valid transition

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iMO should stay

var visitedNodes = new Set();

while(currentNode && collectCount < 10) {
// Prevent infinite loops

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should stay

}
visitedNodes.add(currentNode);

// Only collect outputs from the current node (not merged ones)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should stay

add back some commets
var failureLink = (fail && fail[char]) ? fail[char] : root;
this.failure[child] = failureLink;

// remove incorrect output merging

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I wrote. The comment // remove incorrect output merging can be removed. The rest can probably stay.

}
}

// correctly collect all matches

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// correctly collect all matches

clean comment
@twMat

twMat commented Nov 6, 2025

Copy link
Copy Markdown
Contributor

@pmario

@twMat Did you test with this preview:

The point with my post here was merely that the symptom description in the topmost post here, in spite of being very detailed, didn't quite cover the problems I had reported. Regardless, the PR here does seem to resolve everything. All good.

@s793016

s793016 commented Nov 6, 2025

Copy link
Copy Markdown
Contributor Author

I've prepared another test package here: test by ai3.json

This collection of tiddlers is designed to test the reliability, accuracy, and performance of the Freelinks plugin for TiddlyWiki.

It provides structured test cases to ensure that automatic link generation behaves correctly in various real-world scenarios.


!! 📘 Purpose
The test suite evaluates how Freelinks handles:

  • Overlapping and nested titles – verifying longest-match priority.
  • Case sensitivity – ensuring consistency when tv-freelinks-ignore-case is enabled or disabled.
  • Word boundaries – testing English and multilingual text accuracy.
  • Algorithm stability and speed – stress-testing the Aho–Corasick matcher under heavy load.

!! 🧩 How to Use

  1. Import this JSON file into your TiddlyWiki.
  2. Open the tiddler “Freelinks Debug Test Index”.
  3. Follow the listed test cases one by one:
    • Each page includes bilingual (Chinese–English) explanations.
    • Compare the “Expected Result” section to the live rendered text.

!! ⚙️ Notes

  • Tests cover both English and Chinese content for mixed-language verification.
  • The Performance Stress Test includes a long 1000× alphabet string to benchmark Aho–Corasick’s efficiency.
  • No manual setup is required — all needed titles are already included in the dataset.

!! ✅ Expected Outcome
If the plugin is functioning properly:

  • Only valid titles will auto-link.
  • Overlaps will be skipped.
  • No false or missing links should appear.
  • The stress test should run within a few seconds without errors.

Comment thread editions/tw5.com/tiddlywiki.info Outdated
"tiddlywiki/confetti",
"tiddlywiki/dynannotate",
"tiddlywiki/internals",
"tiddlywiki/freelinks",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This plugin will need to be removed once you are sure, that everything works as expected.

reversed to original
@Jermolene

Copy link
Copy Markdown
Member

Thank you @s793016.

I think it's not clear in the documentation that change notes can have multiple GitHub links as shown in this example. In the case of a bugfix like this, you can just add the bugfix PR to the GitHub links for the original PR.

another link added
@github-actions

github-actions Bot commented Nov 11, 2025

Copy link
Copy Markdown

✅ Change Note Status

All change notes are properly formatted and validated!

📝 $:/changenotes/5.4.0/#9397

Type: bugfix | Category: plugin
Release: 5.4.0

Fix critical freelinks bugs: first character loss and false positive matches in v5.4.0

🔗 #9084 #9397

👥 Contributors: s793016


📖 Change Note Guidelines

Change notes help track and communicate changes effectively. See the full documentation for details.

add "release: 5.4.0"
change-type: bugfix
change-category: plugin
github-links: [https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397](https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397)
github-links: [https://github.com/TiddlyWiki/TiddlyWiki5/pull/9084](https://github.com/TiddlyWiki/TiddlyWiki5/pull/9084), [https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397](https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
github-links: [https://github.com/TiddlyWiki/TiddlyWiki5/pull/9084](https://github.com/TiddlyWiki/TiddlyWiki5/pull/9084), [https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397](https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397)
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9084 https://github.com/TiddlyWiki/TiddlyWiki5/pull/9397

Markdown links do not work with TiddlyWiki.

Comment thread editions/tw5.com/tiddlers/releasenotes/5.4.0/#9397.tid Outdated
some format modified
@pmario

pmario commented Dec 15, 2025

Copy link
Copy Markdown
Member

@Jermolene ... The new freelinks functions have been merged. So IMO this one needs to be merged too.

@Jermolene

Copy link
Copy Markdown
Member

Thanks @s793016

@Jermolene
Jermolene merged commit 7c197f6 into TiddlyWiki:master Dec 17, 2025
9 checks passed
@s793016
s793016 deleted the freelink-bug-fix branch February 21, 2026 10:44
s793016 added a commit to s793016/TiddlyWiki5 that referenced this pull request Feb 22, 2026
update the existing release note with the new PR link instead of creating a new release note.
s793016 added a commit to s793016/TiddlyWiki5 that referenced this pull request Feb 22, 2026
update the existing release note with the new PR link instead of creating a new release note.
s793016 added a commit to s793016/TiddlyWiki5 that referenced this pull request Feb 22, 2026
s793016 added a commit to s793016/TiddlyWiki5 that referenced this pull request Feb 22, 2026
saqimtiaz pushed a commit that referenced this pull request Feb 25, 2026
…t-match, and Unicode safety (#9676)

* Update aho-corasick.js

 fix transition logic; ensure complete outputs (via failure-output merge); clean up stats/build scoping; clarify CJK boundary behavior.

* Update text.js

implement global longest-match priority with overlap suppression; fix refresh invalidation to ignore $:/state and drafts; handle deletions precisely to avoid rebuilding on draft deletion; add defensive check for cached automaton presence.

* Update text.js

remove comment

* Update aho-corasick.js

remove comment

* Create #9672.tid

* Create #2026-0222.tid

* Delete editions/tw5.com/tiddlers/releasenotes/5.4.0/#2026-0222.tid

* Update text.js

remove \"

* Update and rename #9672.tid to #9676.tid

change to right number

* Update #9397.tid

update the existing release note with the new PR link instead of creating a new release note.

* Delete editions/tw5.com/tiddlers/releasenotes/5.4.0/#9676.tid

update the existing release note with the new PR link instead of creating a new release note.

* Rename #9397.tid to #9676.tid

update the existing release note with the new PR link instead of creating a new release note.

* Update and rename #9676.tid to #9397.tid

add link

* Rename #9397.tid to #9676.tid

* Update tiddlywiki.info

add plugin for test build

* Update tiddlywiki.info

reverse change, ready to be merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants