# Input rules for wrapping marks

**URL:** <https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537>\
**Category:** Uncategorized\
**Created:** [December 21, 2016, 8:31am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537 "2016-12-21T08:31:25Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![davidgeilfus](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/d/e99b99/32.png) [@davidgeilfus](https://discuss.prosemirror.net/u/davidgeilfus)\
**Post date:** [December 21, 2016, 8:31am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/1 "2016-12-21T08:31:25Z")

</div>

Hi all,

I’m having a hard time creating some custom input rules to match and replace the usual Markdown marks (em, strong, etc.) Here is the one I have so far:

`const emRule = wrappingInputRule(/(?:^|[^\*_])(?:\*|_)([^\*_]+)(?:\*|_)$/, schema.marks.em)`

It should match any characters (except asterisk and underscore) preceded and followed by one (not two) asterisk or underscore. But those characters aren’t replaced although I use the schema provided by **prosemirror-markdown**

Any idea? Many thanks in advance!

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)\
**Post date:** [December 21, 2016, 9:04am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/2 "2016-12-21T09:04:06Z")

</div>

`wrappingInputRule` is for wrapping something in a _node_, marks work differently. I should probably add a utility for wrapping something in a mark too. See [#518](https://github.com/ProseMirror/prosemirror/issues/518).

---

<div class="post-metadata">

**Author:** ![davidgeilfus](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/d/e99b99/32.png) [@davidgeilfus](https://discuss.prosemirror.net/u/davidgeilfus)\
**Post date:** [December 21, 2016, 9:56am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/3 "2016-12-21T09:56:42Z")

</div>

@marijn Thank you very much for your quick reply! Do you have an idea when you’ll have the opportunity to look at it? I’d be more than happy to help, but looking at the `wrappingInputRule` function, I don’t really know where to start… Let me know if you have any advice 😉

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [December 21, 2016, 11:07am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/4 "2016-12-21T11:07:29Z")

</div>

I’m using something like this:

```javascript
function textMarkInputRule(regexp, markType, trigger, getAttrs, getLength) {
  return new InputRule(regexp, (state, match, start, end) => {
    const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
    const markLength = getLength instanceof Function ? getLength(match) : getLength;
    return state.tr.addMark(start, start + markLength, markType.create(attrs))
                   .insert(end, schema.text(trigger));
  });
}

```

You should probably remove the “trigger” insert as it’s just something I need for my specific use case.

---

<div class="post-metadata">

**Author:** ![davidgeilfus](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/d/e99b99/32.png) [@davidgeilfus](https://discuss.prosemirror.net/u/davidgeilfus)\
**Post date:** [December 21, 2016, 11:12am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/5 "2016-12-21T11:12:06Z")

</div>

Wow thank you very much @kiejo! It helps a lot…

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)\
**Post date:** [December 21, 2016, 4:20pm UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/6 "2016-12-21T16:20:59Z")

</div>

Here’s an implementation of what I think you’re trying to do:

```javascript
function markInputRule(regexp, markType, getAttrs) {
  return new InputRule(regexp, (state, match, start, end) => {
    let attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs
    let tr = state.tr
    if (match[1]) {
      let textStart = start + match[0].indexOf(match[1])
      let textEnd = textStart + match[1].length
      if (textEnd < end) tr.delete(textEnd, end)
      if (textStart > start) tr.delete(start, textStart)
      end = start + match[1].length
    }
    return tr.addMark(start, end, markType.create(attrs))
  })
}

```

And you can then do something like `markInputRule(/_(\S(?:|.*?\S))_$/, schema.marks.em)` to auto-emphasize text between undescores, but in practice, I found this wasn’t really usable, because after you type the closing underscore, you’re still directly after emphasized text, and if you continue typing, the new text is still emphasized.

So, for now, I’m not adding this to the prosemirror-inputrules package.

---

<div class="post-metadata">

**Author:** ![davidgeilfus](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/d/e99b99/32.png) [@davidgeilfus](https://discuss.prosemirror.net/u/davidgeilfus)\
**Post date:** [December 21, 2016, 4:34pm UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/7 "2016-12-21T16:34:12Z")

</div>

Many thanks @marijn… I’m starting with ProseMirror and it’s good to have such a helpful community!

---

<div class="post-metadata">

**Author:** ![davidgeilfus](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/d/e99b99/32.png) [@davidgeilfus](https://discuss.prosemirror.net/u/davidgeilfus)\
**Post date:** [December 22, 2016, 10:12am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/8 "2016-12-22T10:12:49Z")

</div>

Hi @marijn and @kiejo, here’s what I got based on your answers… It works fine and might find its place in the [prosemirror-inputrules](https://github.com/ProseMirror/prosemirror-inputrules) plugin if you find it useable enough:

```
const markInputRule = (regexp, markType, getAttrs) => {
  const newRegexp = new RegExp(regexp.source.replace(/\$$/, '') + '(.)' + '$')

  return new InputRule(newRegexp, (state, match, start, end) => {
    const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs
    const textStart = start + match[0].indexOf(match[1])
    const textEnd = textStart + match[1].length
    const tr = state.tr

    start = (match[0].match(/^\s/)) ? start + 1 : start

    if (textEnd < end) tr.delete(textEnd, end)
    if (textStart > start) tr.delete(start, textStart)

    end = start + match[1].length

    return tr
      .addMark(start, end, markType.create(attrs))
      .insert(end, schema.text(match[2]))
  })
}

```

You can then use it like this:

```
const buildInputRules = (schema) => {
  let result = [], type

  if (type = schema.marks.strong) result.push(markInputRule(/(?:\*\*|__)([^\*_]+)(?:\*\*|__)$/, type))
  if (type = schema.marks.em) result.push(markInputRule(/(?:^|[^\*_])(?:\*|_)([^\*_]+)(?:\*|_)$/, type))
  
  return result
}
```

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)\
**Post date:** [December 22, 2016, 10:56am UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/9 "2016-12-22T10:56:47Z")

</div>

I considered that approach, but it has the downside that you _have_ to type something after the marked-up text, so if that’s at the end of the line, or you’re just inserting it between other text and then don’t continue typing, the rule doesn’t fire.

---

<div class="post-metadata">

**Author:** ![ncphillips](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/ncphillips/32/387_2.png) [@ncphillips](https://discuss.prosemirror.net/u/ncphillips)\
**Post date:** [September 23, 2017, 5:56pm UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/10 "2017-09-23T17:56:34Z")

</div>

> [@marijn](#):
>
> because after you type the closing underscore, you’re still directly after emphasized text, and if you continue typing, the new text is still emphasized.

Do you have any ideas on how this could be fixed? Would moving the cursor ahead one position work?

---

<div class="post-metadata">

**Author:** ![ncphillips](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/ncphillips/32/387_2.png) [@ncphillips](https://discuss.prosemirror.net/u/ncphillips)\
**Post date:** [September 23, 2017, 6:17pm UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/11 "2017-09-23T18:17:58Z")

</div>

@marijn I got it working so the mark is not applied to the new text! It’s your implementation exactly, except for the second last line

```auto
function markInputRule(regexp, markType, getAttrs) {
  return new InputRule(regexp, (state, match, start, end) => {
    let attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs
    let tr = state.tr
    if (match[1]) {
      let textStart = start + match[0].indexOf(match[1])
      let textEnd = textStart + match[1].length
      if (textEnd < end) tr.delete(textEnd, end)
      if (textStart > start) tr.delete(start, textStart)
      end = start + match[1].length
    }
    tr.addMark(start, end, markType.create(attrs))
    tr.removeStoredMark(markType) // Do not continue with mark.
    return tr
  })
}

```

---

<div class="post-metadata">

**Author:** ![supz](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/supz/32/3599_2.png) [@supz](https://discuss.prosemirror.net/u/supz)\
**Post date:** [March 1, 2022, 12:44pm UTC](https://discuss.prosemirror.net/t/input-rules-for-wrapping-marks/537/12 "2022-03-01T12:44:08Z")

</div>

I came up with this:

```nohighlight
function markInputRule(regexp, markType, getAttrs, skipStart) {
    return new InputRule(regexp, (state, match, start, end) => {
        let attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs
        let tr = state.tr
        if (match[1]) {
            let skipMatch;
            let skipLen = 0;

            if (skipMatch = skipStart && match[0].match(skipStart)) {
                console.log(skipMatch)
                skipLen = skipMatch[0].length;
                start += skipLen;
            }

            let textStart = start + match[0].indexOf(match[1]) - skipLen
            let textEnd = textStart + match[1].length
            if (textEnd < end) tr.delete(textEnd, end)
            if (textStart > start) tr.delete(start, textStart)
            end = start + match[1].length
        }
        tr.addMark(start, end, markType.create(attrs))
        tr.removeStoredMark(markType)
        return tr
    })
}

```

(`skipStart` is a hack for emphasis because some browsers don’t yet support lookbehinds in Regex.)

And, here are the rules I used:

```nohighlight
// strong (** AND __)
markInputRule(/(?:\*\*)([^\*]+)(?:\*\*)$/, marks.strong),
markInputRule(/(?:\s__)([^_]+)(?:__)$/, marks.strong),

// em (* and _)
markInputRule(/(?:^|[^\*])(?:\*)([^\*]+)(?:\*)$/, marks.em, {}, /^[^\*]/),
markInputRule(/(?:^|[^_])(?:_)([^_]+)(?:_)$/, marks.em, {}, /^[^_]/),

// links
markInputRule(/(?:\[([^\]]+)\])(\([^\)]+\))$/, marks.link, function(match) {
    return {href: match[2]}
}),

// code (prosemirror-codemark adds this)
markInputRule(/(?:`)([^`]+)(?:`)$/, marks.code),

// strikethrough
markInputRule(/(?:~~)([^~]+)(?:~~)$/, marks.s),

// sup & sub
markInputRule(/(?:\^)([^\^]+)(?:\^)$/, marks.sup),
markInputRule(/(?:~)([^~]+)(?:~)$/, marks.sub),

// mark
markInputRule(/(?:==)([^=]+)(?:==)/, marks.mark),

```

Instead of the code inputrule, I let [prosemirror-codemark](https://discuss.prosemirror.net/t/new-plugin-prosemirror-codemark-to-handle-inline-code-mark-creation-and-manipulation/4159) handle that (with better cursors).
