KeyMap for bold text in lang-markdown

Just starting out with CodeMirror6, I’m building a Markdown-Editor and want to add basic Markdown KeyMaps, starting with marking a selection as Bold. I got the first part down, but want it to behave like a toggle, so when a selection is already wrapped in **, eg. due to a previous Mod+b, I want to remove the **.

This is what I have so far.

  const insertBoldMarker: StateCommand = ({ state, dispatch }) => {
    const changes = state.changeByRange((range) => {
      return {
        changes: [
          {
            from: range.from,
            insert: Text.of(['**']),
          },
          {
            from: range.to,
            insert: Text.of(['**']),
          },
        ],
        range: EditorSelection.range(range.from + 2, range.to + 2),
      }
    })

    dispatch(
      state.update(changes, {
        scrollIntoView: true,
        annotations: Transaction.userEvent.of('input'),
      })
    )

    return true
  }

  const customKeyMap: KeyBinding[] = [
    {
      key: 'Mod-b',
      run: insertBoldMarker,
    },
  ]

How would I check whether eg (range.from - 2) are "**"? Especially keeping possible Multiselection (not yet enabled) in mind.

I just need some directions :slight_smile:

Update: probably with iterRange, gonna look into that!

1 Like

I think just doing state.sliceDoc(range.from - 2, range.from) == "**" should work here.

1 Like

Of course! I got it to work the way I want.

Really digging the API design of CM6! Thank you so much doing this! For anyone else who might land here via google, this is my result:

  const insertBoldMarker: StateCommand = ({ state, dispatch }) => {
    const changes = state.changeByRange((range) => {
      const isBoldBefore = state.sliceDoc(range.from - 2, range.from) === "**";
      const isBoldAfter = state.sliceDoc(range.to, range.to + 2) === "**";
      const changes = [];

      changes.push(isBoldBefore ? {
        from: range.from - 2,
        to: range.from,
        insert: Text.of([''])
      } : {
        from: range.from,
        insert: Text.of(['**']),
      })

      changes.push(isBoldAfter ? {
        from: range.to,
        to: range.to + 2,
        insert: Text.of([''])
      } : {
        from: range.to,
        insert: Text.of(['**']),
      })

      const extendBefore = isBoldBefore ? -2 : 2;
      const extendAfter = isBoldAfter ? -2 : 2;

      return {
        changes,
        range: EditorSelection.range(range.from + extendBefore, range.to + extendAfter),
      }
    })

    dispatch(
      state.update(changes, {
        scrollIntoView: true,
        annotations: Transaction.userEvent.of('input'),
      })
    )

    return true
  }

  const boldBinding: KeyBinding[] = [
    {
      key: 'Mod-b',
      run: insertBoldMarker,
    },
  ]