Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Fixing issue with double dollars in replace string #5840

Merged
merged 10 commits into from
Nov 8, 2013

Conversation

marcelgerber
Copy link
Contributor

I picked this idea from #5772 (comment).
This should be exactly the same dollar-signs-in-replace-with-string behaviour as JavaScript itself haves.

I did a bit of testing and everything worked fine (for example $1, $$1, $$$1, $, $$).

FindReplace tests passing, too.

behaves like javascript itself
@ghost ghost assigned njx Nov 4, 2013
@njx
Copy link

njx commented Nov 6, 2013

Hey--don't have time right now to fully think through/test this, but a couple of notes:

  • I believe "$$" should turn into a single "$" in the actual replace string (i.e., it acts like the first dollar is just escaping the second).
  • Now that this function is getting more complex, it would be good to factor it out into a separate function rather than duplicating it in both places. (You'll need to patch the appropriate match array into that function since it will no longer be inside the closure.)
  • A couple of things that are not new issues but that I realized while looking at the code:
    • If there is no entry in the match array corresponding to the given reference, we should leave the reference unchanged instead of replacing it with "undefined".
    • We should handle references with multiple digits ($10, $11, etc.), though that's obviously not super common.
    • Let's change the function parameters to be more meaningful than w, d, i (I know that was in the original code but we can make it better :))
  • This is getting complex enough that I think we should add unit tests for it.

@njx
Copy link

njx commented Nov 6, 2013

BTW, here's a useful reference for the JS behavior: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace - under "Specifying a string as a parameter".

(This made me think...Instead of doing our own replacement function, would it make more sense to just use the actual JS replace function, calling it on the previously matched string, passing it the regexp and the user's substitution string? That way we wouldn't have to write all this logic to simulate the JS behavior--we would just get it for free. The precede/follow substitutions wouldn't work, but we haven't implemented those anyway.)

@marcelgerber
Copy link
Contributor Author

  1. $$ gets $ already
  2. I tried this already, but the function wasn't executed, but passed to CM. But maybe I will give another try.
  3. I will try to implement these. Shouldn't be difficult.
  4. I've never done this, but I will give it a try.

I don't know how you want to pass matches to the js replace function, but I won't say anything against.

@marcelgerber
Copy link
Contributor Author

Sorry, not the right commit name ;) It should be Fixed a bug where subexpressions like $01 weren't accepted

@marcelgerber
Copy link
Contributor Author

Just added unit tests, so this PR is completely (in my view).
As these are my first unit tests, I hope they are ok (but I think so).
I wondered why there are no unit tests for Replace All?

@marcelgerber
Copy link
Contributor Author

@njx Even if we would use another method to replace with subexpressions, the unit tests could be used anyway.

@@ -117,6 +117,12 @@ define(function (require, exports, module) {
}
}

function parseDollars(replaceWith, match) {
replaceWith = replaceWith.replace(/(\$+)(\d{1,2})/g, function (whole, dollars, index) { return dollars.length % 2 === 1 ? dollars.substr(1) + ((match.hasOwnProperty("result") ? match.result[parseInt(index, 10)] : match[parseInt(index, 10)]) || "") : dollars + index; });
Copy link

Choose a reason for hiding this comment

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

It would be cleaner and easier to understand if you just pass in match.result from the replaceAll case instead of having to deal with both cases here.

Copy link

Choose a reason for hiding this comment

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

Seems like the "else" case could just be whole instead of dollars + index.

Copy link

Choose a reason for hiding this comment

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

After those fixes, it might still be okay for this to be on a single line, but it might be nicer to just break it out into separate lines anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it would be good if there were several lines, but I dunno where to break and how to indent.

@njx
Copy link

njx commented Nov 7, 2013

Finished re-review. Looks good, just a few nits.

It seems like it would be good to add at least one Replace All case (I probably should have done this when I added the original one)...although that's more complex since you'd have to mock clicking the button in the Replace All panel (or add an API to directly invoke the replace all function). If you feel like looking into that, that would be great, but if not I think it's fine to just do some basic manual testing around it since it's pretty clear now that the behavior in all the edge cases will be consistent.

Longer term, when we rewrite the find/replace stuff (which hopefully won't be too long from now), we'll be refactoroing out the actual editing code from the UI, so these can become true unit tests instead of interacting with UI elements.

@njx
Copy link

njx commented Nov 7, 2013

BTW, the other idea I mentioned (about just using replace() itself on the original matched text to handle the dollar substitution) won't work because of lookahead and other contextual patterns (since that matched text will no longer be in the context of the original text).

@marcelgerber
Copy link
Contributor Author

Just pushed fixes for these nits. I will try to add one or more test(s) for Replace All, so don't merge yet.

@marcelgerber
Copy link
Contributor Author

Just pushed some unit tests for "Replace All". Just say if these are too much 😀

We should add some other tests for this, but that isn't my job.

});
// we need to escape (\$) these chars in the regexp to avoid to get these parsed as
// normal regexp anchors
replaceWith = replaceWith.replace(/\$\$/g, "$$");
Copy link

Choose a reason for hiding this comment

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

Actually, my comment here was about the "$$" in the replacement string being confusing (because it looks like you're replacing "$$" with "$$"--but the replacement "$$" is really just an escaped "$"), not the backslashes in the regexp. Like I mentioned before, I don't think you need the double-dollar in the replacement string since it won't be interpreted as a metacharacter there if it doesn't have anything after it. But this isn't a big deal.

@njx
Copy link

njx commented Nov 7, 2013

Thanks for all the additional unit tests! But I'm getting one failure in the new "$0" test--it doesn't seem to be matching the expected text. Are you seeing the same failure?

@marcelgerber
Copy link
Contributor Author

No, for me every test is working. Which error message do you get?

@njx
Copy link

njx commented Nov 8, 2013

Hmmm, it's working fine for me now--not sure what was wrong. Thanks for working on this! Merging.

njx pushed a commit that referenced this pull request Nov 8, 2013
Fixing issue with double dollars in replace string
@njx njx merged commit 08eb10b into adobe:master Nov 8, 2013
@marcelgerber marcelgerber deleted the replace-double-dollar branch November 8, 2013 19:18
@marcelgerber
Copy link
Contributor Author

Thank you. You should add unit tests for normal "Replace All" cases.

@marcelgerber
Copy link
Contributor Author

@njx I would also like to add the functionality of $&, $ and $' (in another PR). (see [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace)) $& is easy (just match[0]), but in the case of $ should we use the whole text that is before the match or should we just use the beginning of the line (and then, should we include leading whitespace or not?)

@marcelgerber
Copy link
Contributor Author

Or maybe we shouldn't include $` and $' at all, just $&?

@njx
Copy link

njx commented Nov 10, 2013

It would make sense to add $& (though not really critical IMO). I don't really know about $` or $'...like you said their meaning is somewhat ambiguous in our context and I don't know how commonly they would be used anyway.

@marcelgerber
Copy link
Contributor Author

Okay, I don't know what to use them for, too.
But $& can be helpful. I will add it soon.

@marcelgerber
Copy link
Contributor Author

Just pushed some unit tests for "Replace All". Just say if these are too much
We should add some other tests for this, but that isn't my job.

@njx Would you mind adding some more, general unit tests for Replace All?

@njx
Copy link

njx commented Jan 31, 2014

We have an open card for adding real unit tests for Find/Replace, so that should get done soon. I wouldn't worry about it for this PR as long as your own cases are tested.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants