Hi,
Is there a way to automatically create links to passages without manually inserting [[ ]]? For example, if I have a [[London]] passage and ‘London’ appears in multiple passages is there an easy way for these to be linked? I’m asking because I have a large dataset with lots of recurring words that I would like to link. Sorry if this is actually very easy and I’m missing something basic.
Thanks!
Twine Version: 2.3.9
Story Format: SugarCube 2.31.1
I don’t know of any feature of Twine/Sugarcube that lets you automate that process, and a brief skim on Google doesn’t yield anything for me either. I’ve also only been using Twine/Sugarcube for a couple of months, so maybe such a feature exists. Out of curiosity, I’ll watch your post and see if you get an answer.
I did want to comment this idea in case it turns out that Twine doesn’t support such a thing. I don’t know how many passages you’re talking here, but would it be feasible for you to copy your large dataset from your many passages into a single Word Document (or something of the like) and Find/Replace all “London” words to “[[London]]”? I apologize if you’ve already considered this. I figure it’s better than manually going through and inserting [[ ]] for all of your Twine passages.
Yeah, Harlowe lets you say (click-goto: "London" "London passage") and it will find all occurrences of London in the current passage and make them link to London passage, but SugarCube doesn’t have that built in. Of course, it’s possible to do anything with JavaScript, but I don’t know the code for that off the top of my head…
As long as you’re using a newer version of SugarCube, you can plop this into your Story’s Javascript (click the story title in the bottom left of the editor and click “Edit Story Javascript”) and it’ll automatically work on every single passage.
// List of keywords to turn into links
const keywords = ["London", "England"]
// This creates a regular expression which searches for any of the given keywords
// Thanks to @tayruh for the updated regex
const keywordRegex = new RegExp("(?<!\\[\\[(?:\\s*[^|\\]]+\\|)?\\s*)\\b(" + keywords.join("|") + ")\\b", "g");
// This is called before each passage's text is processed
Config.passages.onProcess = function (p) {
// We use the regular expression made above to replace any instances of those keywords with a link
return p.text.replace(keywordRegex, "[[$1]]");
};
Just tested it in the online editor and it works. Right now it’s case sensitive (meaning it’ll replace London but not london). If you want it to match both, change the “g” in the regex line with a “gi”.
It’ll also only match whole words. So if you have “Londonish” in a passage, it won’t replace that. Thanks to @tayruh, it also won’t break existing links that include any of the words.
If you want to have the keyword list created automatically, change the first line of code to
// Find all codex passages and get their names
const keywords = Story.lookup("tags", "codex").map(p => p.title);
This will create the list of keywords from any passages that have the tag codex. So instead of needing to maintain the list, just tag your London passage with codex and it’ll automatically get picked up.
The only issue I see with this is that perhaps the RegExp should do a check to see if it’s already inside a [[ ]] section? Otherwise it’ll be impossible to link to a location without using the full name. IOW, “It’s time to go [[home|England]]” would render as “It’s time to go [[home|[[England]]]]” and break.
That’s a really good point. Unless I’m missing a galaxy brain Regex solution, I’m not sure what a good way is to detect that with pure regex? There are plenty of solutions that involve a lot more complex javascript to do some parsing but maybe it’ll be good enough for the OP for now? But yeah, the caveat is that manually linking to these pages will get messed up by the replace.
Oh right. I knew using the look behind was ringing warning bells for some reason. I’ve been mostly coding in node.js lately so I’ve been spoiled when using RegExp. I had to avoid look behind when coding up Sadako to support Safari and IE.
I’ll see if I can maybe come up with a better solution.
// List of keywords to turn into links
const keywords = ["London", "England"]
// This creates a regular expression which searches for any of the given keywords
const keywordRegex = new RegExp("(\\[\\[(?:\\s*[^|\\]]+\\|)?\\s*)?\\b(" + keywords.join("|") + ")\\b", "g");
// This is called before each passage's text is processed
Config.passages.onProcess = function (p) {
// We use the regular expression made above to replace any instances of those keywords with a link
return p.text.replace(keywordRegex, function(m, p1, p2) {
// returns original text if inside brackets
if (p1 !== undefined) return m;
return "[[" + p2 + "]]";
});
};
Thank you all so much. It works perfectly.
As you can tell I’m a complete newbie to this and really appreciate the help.
Can I ask a general question - am i right in thinking twine isn’t very well suited to stories with lots of passages and links? Like 1000s.
I gather the visual editor starts getting slow when you get up toward 1000 passages, but if you don’t mind working in a purely text format, things like Tweego should still be fine. And I think some people do write bigger stories and just live with the slowness? Not sure.