Fix handler positions for regexes without final $ #5

Closed
dylanonelson wants to merge 1 commit from fix-handler-args into master
dylanonelson commented 2020-08-24 18:48:16 +02:00 (Migrated from github.com)

Hi Marijn!

(NB I am opening this PR as an independent developer and not associated with any organization.)

In the current implementation, the following type of input rule produces an unexpected result. The start and end arguments passed to the handler are calculated based on the assumption that the matched input has fallen immediately before the most recent user input, so the end position is always the same as the forward-most position of the selection at the moment when the user typed the input that triggered the match.

I see that the documentation recommends that developers end their regexes with $ to accommodate this behavior. But I would like my users to be able to type, for example, the final backtick before they go back and add the opening backtick, and for the input rule still to work.

The documentation also says “The rule applies when the user typed something and the text directly in front of the cursor matches match,” which is not, strictly speaking, how the matches are executed; because the input rule scans the document backwards on any user input, if a user types later in the paragraph where the rule has matched, it will call the handler.

new InputRule(new RegExp('`(.*?)`', (state, match, start, end) => {
  // replace between start and end with text + marks
  // 'start' and 'end' values will be wrong if user types later in node
});

This leads to some strange behavior if you omit the $ from your pattern, because if you insert the backticks in the wrong order, for example, and then try to type somewhere after them in the same node, you suddenly get a block of code inserted behind your current cursor, the contents of which are the matched code inside the preceding backticks.

# user adds backticks in the wrong order
<p>lorem ipsum `dolor` sit amet</p>

# user tries to type           |
#                              ▼
<p>lorem ipsum `dolor` sit amet</p>

# result
<p>lorem ipsum `dolor` sit<code>dolor</code></p>

This PR changes the way the start and end positions are calculated so they will be correct no matter where the user’s input takes place. It continues to be correct in the standard case and it also corrects the positions in the non-standard case.

The behavior still isn't ideal, because (among other reasons) the input rule will not match until the user types after the matching pattern. So in my example above, the text will not get wrapped with the code mark until the user types somewhere after the wrapped piece of text. But this is better than how the input rules execute now, since if the user either intentionally or unintentionally inserts some matching input, their subsequent input is liable to be disrupted unexpectedly.

Hi Marijn! (NB I am opening this PR as an independent developer and not associated with any organization.) In the current implementation, the following type of input rule produces an unexpected result. The `start` and `end` arguments passed to the handler are calculated based on the assumption that the matched input has fallen immediately before the most recent user input, so the `end` position is always the same as the forward-most position of the selection at the moment when the user typed the input that triggered the match. I see that the documentation recommends that developers end their regexes with `$` to accommodate this behavior. But I would like my users to be able to type, for example, the final backtick before they go back and add the opening backtick, and for the input rule still to work. The documentation also says “The rule applies when the user typed something and the text directly in front of the cursor matches `match`,” which is not, strictly speaking, how the matches are executed; because the input rule scans the document backwards on any user input, if a user types later in the paragraph where the rule has matched, it will call the handler. ``` new InputRule(new RegExp('`(.*?)`', (state, match, start, end) => { // replace between start and end with text + marks // 'start' and 'end' values will be wrong if user types later in node }); ``` This leads to some strange behavior if you omit the `$` from your pattern, because if you insert the backticks in the wrong order, for example, and then try to type somewhere *after* them in the same node, you suddenly get a block of code inserted behind your current cursor, the contents of which are the matched code inside the preceding backticks. ``` # user adds backticks in the wrong order <p>lorem ipsum `dolor` sit amet</p> # user tries to type | # ▼ <p>lorem ipsum `dolor` sit amet</p> # result <p>lorem ipsum `dolor` sit<code>dolor</code></p> ``` This PR changes the way the `start` and `end` positions are calculated so they will be correct no matter where the user’s input takes place. It continues to be correct in the standard case and it also corrects the positions in the non-standard case. The behavior still isn't ideal, because (among other reasons) the input rule will not match until the user types after the matching pattern. So in my example above, the text will not get wrapped with the code mark until the user types somewhere after the wrapped piece of text. But this is better than how the input rules execute now, since if the user either intentionally or unintentionally inserts some matching input, their subsequent input is liable to be disrupted unexpectedly.
marijnh commented 2020-08-25 12:17:40 +02:00 (Migrated from github.com)

Hi. I don't think what you're trying to do here is a good fit for input rules. It should probably be done directly with a handleTextInput handler, since the input rule logic will only get in the way for what you're trying to.

Hi. I don't think what you're trying to do here is a good fit for input rules. It should probably be done directly with a [`handleTextInput`](https://prosemirror.net/docs/ref/#view.EditorProps.handleTextInput) handler, since the input rule logic will only get in the way for what you're trying to.
dylanonelson commented 2020-08-26 19:13:12 +02:00 (Migrated from github.com)

That makes sense. I think in terms of the user facing feature, the approach you recommend would be better. I think what threw me off initially was that the start and end positions were actually wrong when the regex omits the trailing . That seemed unexpected to me, and since it seemed possible theoretically to make the text input handler work for both cases, I took a stab at it. I did get the feature working as described above with this patch, but for now I'm using the trailing in my input rules. If I want to come back to this I can re-implement it as a direct handler.

Feel free to close this PR.

Thanks!

That makes sense. I think in terms of the user facing feature, the approach you recommend would be better. I think what threw me off initially was that the start and end positions were actually wrong when the regex omits the trailing $. That seemed unexpected to me, and since it seemed possible theoretically to make the text input handler work for both cases, I took a stab at it. I did get the feature working as described above with this patch, but for now I'm using the trailing $ in my input rules. If I want to come back to this I can re-implement it as a direct handler. Feel free to close this PR. Thanks!
marijnh commented 2020-09-03 14:58:46 +02:00 (Migrated from github.com)

I've changed the docs to make it clear that you really should pass a regexp anchored to the end of the string in 2d3ae3a

I've changed the docs to make it clear that you really should pass a regexp anchored to the end of the string in 2d3ae3a

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
prosemirror/prosemirror-inputrules!5
No description provided.