This post is again concerning my fixes for bug 459727. One of my goals for this release is to fix the bug link functionality. I’ve made some progress on that front in terms of creating correct bug links for the differnt types of patterns presented. This time I decided to tackle the other issue with bug links.
The problem is that for any given string that contains bug links only the very first bug string is converted into a link. The subsequent ones fail to get converted. Case in point below:
Both the first bug string “bug 437288″ and the second one, “bug 437288″ should be converted into buglinks but only the first one actually gets converted. This is what I’m looking to fix.
Now, this problem had me stumped for a while. I tried solving it using regexp functions in JavaScript but that was a dead end. I tried to think up other ways but none of them seemed to make sense to me.
Yesterday, while staring at my computer and thinking about this issue it just hit me, a perfect example of the light bulb effect. The answer to my problem was RECURSION!!! A concept I had come to dispise during my data structures and alogrithms class. I had never really used it in any of my programs before. This would be the first time.
Lets jump into the code as I explain this further. I have my main work horse function that creates the bug links:
function createBuglink(str) { //Create buglink var matchFound = new Boolean(false); var bugInDesc = 0; var pattern = -1; var bugLink = ""; re = new RegExp("[bB][uU][gG]\s\d{6}"); re2 = new RegExp("b=\d{6}"); re3 = new RegExp("\d{6}\W"); bugInDesc = str.search(re); if(bugInDesc != -1) { matchFound = true; pattern = 1; } else { bugInDesc = str.search(re2); if(bugInDesc != -1) { matchFound = true; pattern = 2; } else { bugInDesc = str.search(re3); if(bugInDesc != -1) { matchFound = true; pattern = 3; } } } if(matchFound == true) { if(pattern == 1) { bugLink = bugLinkify(bugInDesc, str, 4, 10); } else if(pattern == 2) { bugLink = bugLinkify(bugInDesc, str, 2, 8); } else if(pattern == 3) { bugLink = bugLinkify(bugInDesc, str, 0, 6); } } else { //No bug provided bugLink = str; } return bugLink; } |
Then I have a function that does the actual string manipulation to insert the link code into the string which is called within createBugLink():
function bugLinkify(bugInDesc, str, start, end) { var bugLinkName = str.substring(bugInDesc, bugInDesc + end); var bugNumber = bugLinkName.substring(start, end); var bugLink = str.substring(0, bugInDesc) + '<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=' + bugNumber + '">' + bugLinkName + '</a>' + createBuglink(str.substring(bugInDesc + end, str.length)); return bugLink; } |
Now, in bugLinkify() the genius of recursion gets to take over. I just call the createBuglink() function again on the rest of the string that didn’t get converted into a buglink and keeps gettig called until there are no bug strings left to be converted.
The upside to this method is that a string could contain an unlimited amount of bug strings and they would all get converted into bug links. But the thing I love most about this method is that I didn’t have to add even a SINGLE line of code. That fact makes this implementation awesome. Gaining functionality without having to add more lines of code is always great.
The following are the results:
Hi Sid,
Again, a comment on this: you can use the “global” flag for regexps (/foo/g or new RegExp(“foo”, “g”) ) to make it match each link. Now, if you use the “string”.replace(regexp, function) syntax, and make the function return the replacement, it will globally replace all “bug #1234″ occurrences with the right link. Which will work, and doesn’t need recursion (however clever that is).
For more info, check out: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace#Specifying_a_function_as_a_parameter
Cheers,
Gijs